//****************************************************************************************************** // EmailNotifier.cs - Gbtc // // Copyright © 2016, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this // file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 05/16/2016 - J. Ritchie Carroll // Generated original version of source code. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using GSF; using GSF.Net.Smtp; using GSF.TimeSeries; using GSF.TimeSeries.Adapters; namespace DynamicCalculator { /// /// The EmailNotifier is an action adapter which takes multiple input measurements and defines /// a boolean expression such that when the expression is true an e-mail is triggered. /// [Description("E-Mail Notifier: Sends an e-mail based on a custom boolean expression")] public class EmailNotifier : DynamicCalculator { #region [ Members ] // Constants private const string DefaultExpressionText = "x > 0"; private const int DefaultFramesPerSecond = 30; private const double DefaultLagTime = 5.0D; private const double DefaultLeadTime = 5.0D; // Fields private readonly Mail m_mailClient; private long m_expressionSuccesses; private long m_expressionFailures; private long m_totalEmailOperations; #endregion #region [ Constructors ] /// /// Creates a new instance of the . /// public EmailNotifier() { m_mailClient = new Mail(); } #endregion #region [ Properties ] /// /// Gets or sets the textual representation of the boolean expression. /// [ConnectionStringParameter] [Description("Define the boolean expression used to determine if an e-mail should be sent.")] [DefaultValue(DefaultExpressionText)] public new string ExpressionText // Redeclared to provide a more relevant description and example value for this adapter { get => base.ExpressionText; set => base.ExpressionText = value; } /// /// Gets or sets the e-mail address of the message sender. /// /// Value being assigned is a null or empty string. [ConnectionStringParameter, Description("Define the e-mail address of the message sender.")] public string From { get => m_mailClient.From; set => m_mailClient.From = value; } /// /// Gets or sets the comma-separated or semicolon-separated e-mail address list of the message recipients. /// /// Value being assigned is a null or empty string. [ConnectionStringParameter, Description("Define the comma-separated or semicolon-separated e-mail address list of the e-mail message recipients."), DefaultValue("")] public string ToRecipients { get => m_mailClient.ToRecipients; set => m_mailClient.ToRecipients = value; } /// /// Gets or sets the comma-separated or semicolon-separated e-mail address list of the message carbon copy (CC) recipients. /// [ConnectionStringParameter, Description("Define the comma-separated or semicolon-separated e-mail address list of the e-mail message carbon copy (CC) recipients."), DefaultValue("")] public string CcRecipients { get => m_mailClient.CcRecipients; set => m_mailClient.CcRecipients = value; } /// /// Gets or sets the comma-separated or semicolon-separated e-mail address list of the message blank carbon copy (BCC) recipients. /// [ConnectionStringParameter, Description("Define the comma-separated or semicolon-separated e-mail address list of the e-mail message blank carbon copy (BCC) recipients."), DefaultValue("")] public string BccRecipients { get => m_mailClient.BccRecipients; set => m_mailClient.BccRecipients = value; } /// /// Gets or sets the subject of the message. /// [ConnectionStringParameter, Description("Define the subject of the e-mail message.")] public string Subject { get => m_mailClient.Subject; set => m_mailClient.Subject = value; } /// /// Gets or sets the body of the message. /// [ConnectionStringParameter, Description("Define the body of the e-mail message.")] public string Body { get; set; } /// /// Gets or sets the name or IP address of the SMTP server to be used for sending the message. /// /// Value being assigned is a null or empty string. [ConnectionStringParameter, Description("Define the name or IP address of the SMTP server to be used for sending the e-mail message.")] public string SmtpServer { get => m_mailClient.SmtpServer; set => m_mailClient.SmtpServer = value; } /// /// Gets or sets a boolean value that indicating whether the message body is to be formatted as HTML. /// [ConnectionStringParameter, Description("Define the boolean value that indicating whether the message body is to be formatted as HTML."), DefaultValue(false)] public bool IsBodyHtml { get => m_mailClient.IsBodyHtml; set => m_mailClient.IsBodyHtml = value; } /// /// Gets or sets the username used to authenticate to the SMTP server. /// [ConnectionStringParameter, Description("Define the username used to authenticate to the SMTP server."), DefaultValue("")] public string Username { get => m_mailClient.Username; set => m_mailClient.Username = value; } /// /// Gets or sets the password used to authenticate to the SMTP server. /// [ConnectionStringParameter, Description("Define the password used to authenticate to the SMTP server."), DefaultValue("")] public string Password { get => m_mailClient.Password; set => m_mailClient.Password = value; } /// /// Gets or sets the flag that determines whether to use SSL when communicating with the SMTP server. /// [ConnectionStringParameter, Description("Define the flag that determines whether to use SSL when communicating with the SMTP server."), DefaultValue(false)] public bool EnableSSL { get => m_mailClient.EnableSSL; set => m_mailClient.EnableSSL = value; } /// /// Gets or sets the number of frames per second. /// /// /// Valid frame rates for a are greater than 0 frames per second. /// [ConnectionStringParameter] [Description("Defines the number of frames per second expected by the adapter.")] [DefaultValue(DefaultFramesPerSecond)] public new int FramesPerSecond // Redeclared to provide a default value since property is not commonly used { get => base.FramesPerSecond; set => base.FramesPerSecond = value; } /// /// Gets or sets the allowed past time deviation tolerance, in seconds (can be sub-second). /// /// /// Defines the time sensitivity to past measurement timestamps. /// The number of seconds allowed before assuming a measurement timestamp is too old. /// This becomes the amount of delay introduced by the concentrator to allow time for data to flow into the system. /// /// LagTime must be greater than zero, but it can be less than one. [ConnectionStringParameter] [Description("Defines the allowed past time deviation tolerance, in seconds (can be sub-second).")] [DefaultValue(DefaultLagTime)] public new double LagTime // Redeclared to provide a default value since property is not commonly used { get => base.LagTime; set => base.LagTime = value; } /// /// Gets or sets the allowed future time deviation tolerance, in seconds (can be sub-second). /// /// /// Defines the time sensitivity to future measurement timestamps. /// The number of seconds allowed before assuming a measurement timestamp is too advanced. /// This becomes the tolerated +/- accuracy of the local clock to real-time. /// /// LeadTime must be greater than zero, but it can be less than one. [ConnectionStringParameter] [Description("Defines the allowed future time deviation tolerance, in seconds (can be sub-second).")] [DefaultValue(DefaultLeadTime)] public new double LeadTime // Redeclared to provide a default value since property is not commonly used { get => base.LeadTime; set => base.LeadTime = value; } /// /// Gets or sets output measurements that the action adapter will produce, if any. /// [EditorBrowsable(EditorBrowsableState.Never)] public override IMeasurement[] OutputMeasurements // Redeclared to hide property - not relevant to this adapter { get => base.OutputMeasurements; set => base.OutputMeasurements = value; } /// /// Gets or sets the source of the timestamps of the calculated values. /// public new TimestampSource TimestampSource // Redeclared to hide property - not relevant to this adapter { get => base.TimestampSource; set => base.TimestampSource = value; } /// /// Gets flag that determines if the implementation of the requires an output measurement. /// protected override bool ExpectsOutputMeasurement => false; /// /// Returns the detailed status of the data input source. /// public override string Status { get { StringBuilder status = new StringBuilder(); status.Append(base.Status); status.AppendLine(); status.AppendFormat(" Expression Successes: {0:N0}", m_expressionSuccesses); status.AppendLine(); status.AppendFormat(" Expression Failures: {0:N0}", m_expressionFailures); status.AppendLine(); status.AppendFormat(" Total E-mail Operations: {0:N0}", m_totalEmailOperations); status.AppendLine(); return status.ToString(); } } #endregion #region [ Methods ] /// /// Initializes . /// public override void Initialize() { const string MissingRequiredMailSetting = "Missing required e-mail setting: \"{0}\""; Dictionary settings = Settings; if (!settings.TryGetValue(nameof(ExpressionText), out _)) settings[nameof(ExpressionText)] = DefaultExpressionText; if (!settings.TryGetValue(nameof(FramesPerSecond), out _)) settings[nameof(FramesPerSecond)] = DefaultFramesPerSecond.ToString(); if (!settings.TryGetValue(nameof(LagTime), out _)) settings[nameof(LagTime)] = DefaultLagTime.ToString(); if (!settings.TryGetValue(nameof(LeadTime), out _)) settings[nameof(LeadTime)] = DefaultLeadTime.ToString(); base.Initialize(); // Load required mail settings if (settings.TryGetValue("from", out string setting) && !string.IsNullOrWhiteSpace(setting)) From = setting; else throw new ArgumentException(string.Format(MissingRequiredMailSetting, "from")); if (settings.TryGetValue("subject", out setting) && !string.IsNullOrWhiteSpace(setting)) Subject = setting; else throw new ArgumentException(string.Format(MissingRequiredMailSetting, "subject")); if (settings.TryGetValue("body", out setting) && !string.IsNullOrWhiteSpace(setting)) Body = setting; else throw new ArgumentException(string.Format(MissingRequiredMailSetting, "body")); if (settings.TryGetValue("smtpServer", out setting) && !string.IsNullOrWhiteSpace(setting)) SmtpServer = setting; else throw new ArgumentException(string.Format(MissingRequiredMailSetting, "smtpServer")); // Load optional mail settings if (settings.TryGetValue("toRecipients", out setting) && !string.IsNullOrWhiteSpace(setting)) ToRecipients = setting; if (settings.TryGetValue("ccRecipients", out setting) && !string.IsNullOrWhiteSpace(setting)) CcRecipients = setting; if (settings.TryGetValue("bccRecipients", out setting) && !string.IsNullOrWhiteSpace(setting)) BccRecipients = setting; if (string.IsNullOrWhiteSpace(ToRecipients) && string.IsNullOrWhiteSpace(CcRecipients) && string.IsNullOrWhiteSpace(BccRecipients)) throw new ArgumentException("At least one destination e-mail address for one of ToRecipients, CcRecipients or BccRecipients must be defined"); if (settings.TryGetValue("isBodyHtml", out setting) && !string.IsNullOrWhiteSpace(setting)) IsBodyHtml = setting.ParseBoolean(); if (settings.TryGetValue("username", out setting) && !string.IsNullOrWhiteSpace(setting)) Username = setting; if (settings.TryGetValue("password", out setting) && !string.IsNullOrWhiteSpace(setting)) Password = setting; if (settings.TryGetValue("enableSSL", out setting) && !string.IsNullOrWhiteSpace(setting)) EnableSSL = setting.ParseBoolean(); } /// /// Handler for the values calculated by the . /// /// The value calculated by the . protected override void HandleCalculatedValue(object value) { if (value.ToString().ParseBoolean()) { m_expressionSuccesses++; m_mailClient.Body = Body.Interpolate(Variables); m_mailClient.Send(); m_totalEmailOperations++; } else { m_expressionFailures++; } } #endregion } }