예제 #1
0
        /// <summary>
        ///     Performs an UI manipulations required for GUI depicted status.
        /// </summary>
        private void UpdateStatus()
        {
            // Simple updates
            labelCounts.Text = String.Join(
                Resources.Stats_Join,
                FormatCount(
                    intelReporter.IntelSent,
                    Resources.IntelCount_Zero,
                    Resources.IntelCount_One,
                    Resources.IntelCount_Many),
                FormatCount(
                    intelReporter.IntelDropped,
                    Resources.DropCount_Zero,
                    Resources.DropCount_One,
                    Resources.DropCount_Many),
                FormatCount(
                    intelReporter.Users,
                    Resources.UserCount_Zero,
                    Resources.UserCount_One,
                    Resources.UserCount_Many),
                FormatCount(
                    this.noveltyCount,
                    Resources.NoveltyCount_Zero,
                    Resources.NoveltyCount_One,
                    Resources.NoveltyCount_Many)
            );

            // Authentication errors are handled specially
            if (this.configError && !panelAuthentication.Visible) {
                this.ShowAuthWindow();
            }

            // Update the status string
            var status = intelReporter.Status;
            var statusString = Resources.ResourceManager.GetString(
                    String.Format(
                        CultureInfo.InvariantCulture,
                        "StatusString_{0}", status))
                ?? Resources.StatusString_Unknown;
            this.labelStatusString.Text = String.Format(
                CultureInfo.CurrentCulture,
                statusString,
                status,
                intelReporter.Path);

            // Status changes
            switch (status) {
            case IntelStatus.Starting:
                // Starting up...
                break;
            case IntelStatus.Active:
                // Normal operation
                this.ShowChannelList();
                if (this.updateEvent != null) {
                    this.notifyIcon.Text = Resources.NotifyIcon_Upgrade;
                } else {
                    this.notifyIcon.Text = Resources.NotifyIcon_Active;
                }
                break;
            case IntelStatus.Waiting:
                // Normal operation
                if (this.updateEvent != null) {
                    this.ShowChannelList();
                    this.notifyIcon.Text = Resources.NotifyIcon_Upgrade;
                } else {
                    this.ShowStatus(
                        Resources.IntelStatus_IdleTitle,
                        Resources.IntelStatus_Idle);
                    this.notifyIcon.Text = Resources.NotifyIcon_Inactive;
                }
                break;
            case IntelStatus.AuthenticationError:
                // Doesn't like our password
                if (!this.configError) {
                    this.ShowAuthError(
                        Resources.IntelStatus_AuthTitle,
                        Resources.IntelStatus_Auth);
                }
                if (!this.lastAuthBalloon.HasValue
                    || (this.lastAuthBalloon + new TimeSpan(TimeSpan.TicksPerDay) < DateTime.Now)) {
                    this.notifyIcon.ShowBalloonTip(10000,
                        Resources.Auth_NotificationTitle,
                        Resources.Auth_NotificationText,
                        ToolTipIcon.Error);
                    this.lastAuthBalloon = DateTime.Now;
                }
                this.notifyIcon.Text = Resources.NotifyIcon_AuthError;
                break;
            case IntelStatus.InvalidPath:
                // Couldn't find the log directory
                this.ShowStatus(
                    Resources.IntelStatus_MissingTitle,
                    Resources.IntelStatus_Missing);
                this.notifyIcon.Text = Resources.NotifyIcon_Error;
                break;
            case IntelStatus.NetworkError:
                // Unable to contact the network server
                this.ShowStatus(
                    Resources.IntelStatus_ErrorTitle,
                    Resources.IntelStatus_Error);
                this.notifyIcon.Text = Resources.NotifyIcon_Error;
                break;
            default:
                // This represents a pretty critical failure of the
                // system, so it gets priority over everything, including
                // user entry.
                panelAuthentication.Visible = false;
                this.ShowStatus(
                    Resources.IntelStatus_FatalTitle,
                    Resources.IntelStatus_Fatal);
                this.notifyIcon.Text = Resources.NotifyIcon_Error;
                break;
            }
            this.oldStatus = status;
        }
        /// <summary>
        /// Releases the unmanaged resources used by the
        /// <see cref="IntelChannelContainer"/> and optionally releases
        /// the managed resources.
        /// </summary>
        /// <param name="disposing">
        /// <see langword="true"/> to release both managed and unmanaged
        /// resources; <see langword="false"/> to release only unmanaged
        /// resources.
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            Contract.Ensures(Status == IntelStatus.Disposed);
            Contract.Ensures(!IsRunning);

            try {
                if (disposing) {
                    lock (this.syncRoot) {
                        if (this.status != IntelStatus.Disposed) {
                            this.Status = IntelStatus.Disposing;
                            this.updateTimer.Dispose();
                            channels.ForEach(x => x.Dispose());
                        }
                    }
                    this.IntelReported = null;
                    this.PropertyChanged = null;
                }
            } finally {
                this.status = IntelStatus.Disposed;
            }
        }
예제 #3
0
 /// <inheritdoc/>
 protected override void Dispose(bool disposing)
 {
     try {
         if (disposing) {
             // Clean up
             lock (this.syncRoot) {
                 if (this.Status != IntelStatus.Disposed) {
                     this.Status = IntelStatus.Disposing;
                     if (this.session != null) {
                         this.session.Dispose();
                         this.session = null;
                     }
                     this.timerSession.Dispose();
                     this.channels.Dispose();
                 }
             }
         } else {
             // Cannot safely clean up
         }
     } finally {
         this.status = IntelStatus.Disposed;
         base.Dispose(disposing);
     }
 }
예제 #4
0
        /// <summary>
        /// Called after <see cref="Start" /> has been called.
        /// </summary>
        /// <remarks>
        /// <see cref="OnStart" /> will be called from within a synchronized
        /// context so derived classes should not attempt to perform any
        /// additional synchronization themselves.
        /// </remarks>
        protected virtual void OnStart()
        {
            Contract.Requires<InvalidOperationException>(
                Status == IntelStatus.Starting);
            Contract.Ensures((Status == IntelStatus.Active)
                || (Status == IntelStatus.Waiting)
                || (Status == IntelStatus.InvalidPath));

            // Create the file system watcher object
            try {
                this.watcher = this.CreateFileSystemWatcher();
            } catch(ArgumentException) {
                this.Status = IntelStatus.InvalidPath;
            }

            // Open the log file with the latest timestamp in its filename
            this.ScanFiles();
        }
예제 #5
0
        /// <summary>
        /// Called every couple of seconds to sweep the log file for
        /// new entries.
        /// </summary>
        /// <remarks>
        /// <see cref="OnTick" /> will be called from within a synchronized
        /// context so derived classes should not attempt to perform any
        /// additional synchronization themselves.
        /// </remarks>
        protected virtual void OnTick()
        {
            if (this.watcher == null) {
                // Try (again) to create the watcher object
                try {
                    this.watcher = this.CreateFileSystemWatcher();
                    this.Status = IntelStatus.Waiting;
                    this.ScanFiles();
                } catch (ArgumentException) {
                    // Still doesn't seem to exist
                }
            }

            if (this.reader != null) {
                // Read new log entries from the current log
                try {
                    string line;
                    while ((line = reader.ReadLine()) != null) {
                        Trace.WriteLine("R " + line, IntelExtensions.WebTraceCategory);
                        var match = Parser.Match(line);
                        if (match.Success && !match.Groups[7].Value.StartsWith(MotdPrefix)) {
                            var e = new IntelEventArgs(
                                this.Name,
                                new DateTime(
                                    match.Groups[1].ToInt32(),
                                    match.Groups[2].ToInt32(),
                                    match.Groups[3].ToInt32(),
                                    match.Groups[4].ToInt32(),
                                    match.Groups[5].ToInt32(),
                                    match.Groups[6].ToInt32(),
                                    DateTimeKind.Utc),
                                match.Groups[7].Value);
                            this.OnIntelReported(e);
                        }
                    }
                } catch (IOException) {
                    this.CloseFile();
                }

                // Close the log if it has been idle for too long
                if (this.lastEntry + this.expireLog < DateTime.UtcNow) {
                    this.CloseFile();
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Releases the unmanaged resources used by the <see cref="IntelChannel"/>
        /// and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">
        /// <see langword="true"/> to release both managed and unmanaged
        /// resources; <see langword="false"/> to release only unmanaged
        /// resources.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            Contract.Ensures(Status == IntelStatus.Disposed);
            try {
                if (disposing) {
                    lock (this.syncRoot) {
                        if (this.status != IntelStatus.Disposed) {
                            // Normal shutdown
                            var isRunning = this.IsRunning;
                            this.Status = IntelStatus.Disposing;
                            if (isRunning) {
                                this.OnStop();
                            }

                            // Dispose child objects
                            this.logTimer.Dispose();

                            // Clear any lingering object references
                            this.IntelReported = null;
                            this.PropertyChanged = null;
                        }
                    }
                }
            } finally {
                this.status = IntelStatus.Disposed;
            }
            base.Dispose(disposing);
        }
예제 #7
0
        /// <summary>
        /// Closes the log file we are currently monitoring (if any).
        /// </summary>
        protected void CloseFile()
        {
            Contract.Ensures((Status == IntelStatus.Waiting)
                || (Status == IntelStatus.InvalidPath));

            if (this.reader != null) {
                try {
                    this.reader.Close();
                } catch (IOException) {
                } finally {
                    this.reader = null;
                }
            }

            this.LogFile = null;
            this.Status = (this.watcher != null)
                ? IntelStatus.Waiting
                : IntelStatus.InvalidPath;
        }
예제 #8
0
        /// <summary>
        /// Closes the existing log file and opens a new log file.
        /// </summary>
        /// <param name="fileInfo">The new log file to track.</param>
        /// <returns>
        /// <see langword="true" /> if we were able to open the file;
        /// otherwise, <see langword="false" />.
        /// </returns>
        protected internal bool OpenFile(FileInfo fileInfo)
        {
            Contract.Requires<ArgumentNullException>(fileInfo != null, "fileInfo");

            // Defer raising PropertyChanged until final decision is made
            var status = this.status;
            FileInfo logFile = null;
            try {
                // Close the existing file (if any)
                if (this.reader != null) {
                    try {
                        this.reader.Close();
                    } catch (IOException) {
                    } finally {
                        this.reader = null;
                    }
                }

                // Clear the status
                status = (this.watcher != null)
                    ? IntelStatus.Waiting
                    : IntelStatus.InvalidPath;

                // Try to open the file stream
                FileStream stream = null;
                try {
                    stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    stream.Seek(0, SeekOrigin.End);
                    // XXX: We rely upon StreamReader's BOM detection.  EVE seems
                    // to generate Little Endian UTF-16 log files.  We could hard
                    // code that, but we don't know if that would cause other
                    // problems.
                    this.reader = new StreamReader(stream, true);
                    status = IntelStatus.Active;
                    logFile = fileInfo;
                    this.lastEntry = DateTime.UtcNow;
                } catch (IOException) {
                    // Don't leak FileStream references
                    if (stream != null) {
                        try {
                            stream.Close();
                        } catch (IOException) {
                        }
                    }
                }
            } catch {
                // Unexpected failure
                status = IntelStatus.FatalError;
                throw;
            } finally {
                // Raise any deferred PropertyChanged events
                this.Status = status;
                this.LogFile = logFile;
            }

            // Success if we opened a reader
            return (this.reader != null);
        }
예제 #9
0
        /// <summary>
        /// Stops the <see cref="IntelChannel"/> from monitoring for new log
        /// entries.
        /// </summary>
        /// <seealso cref="Start"/>
        public virtual void Stop()
        {
            Contract.Ensures((Status == IntelStatus.Stopped)
                || (Status == IntelStatus.Disposed));
            Contract.Ensures(!IsRunning);

            lock (this.syncRoot) {
                if ((this.status != IntelStatus.Stopped)
                        && (this.status != IntelStatus.Disposed)) {
                    try {
                        this.Status = IntelStatus.Stopping;
                        this.OnStop();
                        this.Status = IntelStatus.Stopped;
                    } catch {
                        this.status = IntelStatus.FatalError;
                        throw;
                    }
                }
            }
        }
예제 #10
0
        /// <summary>
        /// Initiate the acquisition of log entries from the EVE chat logs. This
        /// method enables <see cref="IntelReported"/> events.
        /// </summary>
        /// <seealso cref="Stop"/>
        public virtual void Start()
        {
            Contract.Requires<ObjectDisposedException>(
                Status != IntelStatus.Disposed,
                null);
            Contract.Requires<InvalidOperationException>(
                !String.IsNullOrEmpty(Name));
            Contract.Ensures(Status != IntelStatus.Stopped);
            Contract.Ensures(IsRunning);

            lock (this.syncRoot) {
                try {
                    if (this.status == IntelStatus.Stopped) {
                        this.Status = IntelStatus.Starting;
                        this.channelFileName = this.Name;
                        this.OnStart();
                        if (this.status == IntelStatus.Starting) {
                            this.Status = IntelStatus.Waiting;
                        }
                    }
                } catch {
                    this.Status = IntelStatus.FatalError;
                    throw;
                }
            }
        }