/// <summary> /// Load conditions /// </summary> public static void LoadConditions() { try { //Clear conditions and active matches Core.conditions.Clear(); Core.activeMatches.Clear(); //Parse conditions file JObject conditionJson; using (FileStream filestream = new FileStream("conditions.json", FileMode.Open)) using (StreamReader reader = new StreamReader(filestream)) using (JsonTextReader jsonreader = new JsonTextReader(reader)) conditionJson = JsonSerializer.Create().Deserialize <JObject>(jsonreader); if (conditionJson == null) { return; } //Iterate parsed conditions for (int conditionid = 0; conditionid < conditionJson.Count; conditionid++) { JToken condition = conditionJson[conditionid.ToString()]; //Create condition and copy values Core.Condition newCondition = new Core.Condition { conditionName = condition["conditionName"].ToString(), emailProperty = (Core.vrsProperty)Enum.Parse(typeof(Core.vrsProperty), condition["emailProperty"].ToString()), alertType = (Core.AlertType)Enum.Parse(typeof(Core.AlertType), condition["alertType"].ToString()), ignoreFollowing = (bool)condition["ignoreFollowing"] }; List <string> emailsArray = new List <string>(); foreach (JToken email in condition["recieverEmails"]) { emailsArray.Add(email.ToString()); } newCondition.recieverEmails = emailsArray; foreach (JToken trigger in condition["triggers"].Values()) { newCondition.triggers.Add(newCondition.triggers.Count, new Core.Trigger((Core.vrsProperty)Enum.Parse(typeof(Core.vrsProperty), trigger["Property"].ToString()), trigger["Value"].ToString(), trigger["ComparisonType"].ToString())); } //Add condition to list Core.conditions.Add(conditionid, newCondition); } //Try to clean up json parsing conditionJson.RemoveAll(); conditionJson = null; //Update condition list Core.UI.Invoke((MethodInvoker)(() => { Core.UI.updateConditionList(); })); Core.UI.conditionTreeView.Nodes[0].Expand(); //Log to UI Core.UI.writeToConsole("Conditions Loaded", Color.White); //Restart threads if (ThreadManager.threadStatus != ThreadManager.CheckerStatus.WaitingForLoad) { ThreadManager.StartOrRestart(); } } catch (Exception e) { MessageBox.Show(e.Message + "\n\n" + e.StackTrace); } }
/// <summary> /// Update settings /// </summary> /// <param name="update">Is this an update?</param> public static void updateSettings(bool update) { if (Core.loopThread != null) { Core.UI.writeToConsole("Reloading Settings...", Color.White); } VRSAuthenticate = (VRSUsr != ""); //Update mail client info Email.mailClient = new SmtpClient(SMTPHost); Email.mailClient.Port = SMTPPort; Email.mailClient.Credentials = new NetworkCredential(SMTPUsr, SMTPPwd); Email.mailClient.EnableSsl = SMTPSSL; //Update UI foreach (TreeNode settingsGroupNode in Core.UI.conditionTreeView.Nodes[1].Nodes) { settingsGroupNode.Nodes.Clear(); } Core.UI.conditionTreeView.Nodes[1].Nodes[0].Nodes.Add("Sender Email: " + senderEmail); Core.UI.conditionTreeView.Nodes[1].Nodes[0].Nodes.Add("SMTP Host: " + SMTPHost + ":" + SMTPPort); Core.UI.conditionTreeView.Nodes[1].Nodes[0].Nodes.Add("SMTP SSL: " + SMTPSSL); Core.UI.conditionTreeView.Nodes[1].Nodes[0].Nodes.Add("SMTP Username: "******"AircraftList.json Url: " + acListUrl); Core.UI.conditionTreeView.Nodes[1].Nodes[1].Nodes.Add("VRS Radar Url: " + radarUrl); if (VRSAuthenticate) { Core.UI.conditionTreeView.Nodes[1].Nodes[1].Nodes.Add("VRS Authentication: " + VRSAuthenticate); Core.UI.conditionTreeView.Nodes[1].Nodes[1].Nodes.Add("VRS Username: "******"VRS Authentication: " + VRSAuthenticate); } Core.UI.conditionTreeView.Nodes[1].Nodes[1].Nodes.Add("Removal Timeout: " + removalTimeout + " secs"); //If its an update, restart threads if (update) { ThreadManager.StartOrRestart(); } }
/// <summary> /// Constructor /// </summary> public PlaneAlerter() { //Stop the annoying cross-thread problems //This is probably not a good thing but I'm too lazy CheckForIllegalCrossThreadCalls = false; //Initialise UI components InitializeComponent(); //Set UI to this form Core.UI = this; //When shown, wait until everything has loaded then start threads Shown += delegate { while (!Settings.SettingsLoaded || !Checker.ConditionsLoaded) { Thread.Sleep(100); } ThreadManager.StartOrRestart(); }; }
/// <summary> /// Reload conditions button click /// </summary> /// <param name="sender">Sender</param> /// <param name="e">Event Args</param> void ReloadConditionsToolStripMenuItemClick(object sender, EventArgs e) { //Disable button then restart threads reloadConditionsToolStripMenuItem.Enabled = false; ThreadManager.StartOrRestart(); }
/// <summary> /// Send alert email /// </summary> /// <param name="emailaddress">Email address to send to</param> /// <param name="message">Message to send</param> /// <param name="condition">Condition that triggered alert</param> /// <param name="aircraft">Aircraft information for matched aircraft</param> /// <param name="recieverName">Name of receiver that got the last aircraft information</param> /// <param name="emailPropertyInfo">String for displaying email property value</param> /// <param name="isDetection">Is this a detection, not a removal?</param> public static void SendEmail(string emailaddress, MailMessage message, Core.Condition condition, Core.Aircraft aircraft, string recieverName, string emailPropertyInfo, bool isDetection) { //Array to store position trail Dictionary <int, string[]> pathArray = new Dictionary <int, string[]>(); //Google status map for position trail's url string staticMapUrl = ""; //Google maps url string googleMapsUrl = ""; //Transponder type from aircraft info string transponderName = ""; //Types of transponders string[] transponderTypes = new string[] { "Unknown", "Mode-S", "ADS-B", "ADS-Bv1", "ADS-Bv2" }; //Aircraft image urls string[] imageLinks = new string[2]; //Table for displaying aircraft property values string aircraftTable = "<table style='border: 2px solid;border-radius: 10px;border-spacing: 0px;' id='acTable'>"; //HTML for aircraft images string imageHTML = ""; //Airframes.org url string airframesUrl = ""; //Report url string reportUrl = ""; //Set message type to html message.IsBodyHtml = true; //Add email to message receiver list try { message.To.Clear(); message.To.Add(emailaddress); } catch { Core.UI.writeToConsole("ERROR: Email to send to is invalid (" + emailaddress + ")", Color.Red); return; } //Set sender email to the one set in settings try { message.From = new MailAddress(Settings.senderEmail, "PlaneAlerter Alerts"); } catch { Core.UI.writeToConsole("ERROR: Email to send from is invalid (" + Settings.senderEmail + ")", Color.Red); return; } if (Settings.EmailContentConfig.TwitterOptimised) { string typestring = "First Contact"; string regostring = "No rego, "; string callsignstring = "No callsign, "; string operatorstring = "No operator, "; string emailpropertystring = "No " + condition.emailProperty.ToString(); if (!isDetection) { typestring = "Last Contact"; } if (aircraft.GetProperty("Reg") != null) { regostring = aircraft.GetProperty("Reg") + ", "; } if (aircraft.GetProperty("Call") != null) { callsignstring = aircraft.GetProperty("Call") + ", "; } if (aircraft.GetProperty("OpIcao") != null) { operatorstring = aircraft.GetProperty("OpIcao") + ", "; } string emailpropertyvalue = aircraft.GetProperty(Core.vrsPropertyData[condition.emailProperty][2]); if (emailpropertyvalue != null) { emailpropertystring = emailpropertyvalue; } message.Body = "[" + typestring + "] " + condition.conditionName + " (" + emailpropertystring + "), " + regostring + operatorstring + aircraft.GetProperty("Type") + ", " + callsignstring + Settings.radarUrl; //[Last Contact] USAF (RCH9701), 79-1951, RCH, DC10, RCH9701 http://seqldradar.net } else { //Create request for aircraft image urls HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Settings.acListUrl.Substring(0, Settings.acListUrl.LastIndexOf("/") + 1) + "AirportDataThumbnails.json?icao=" + aircraft.ICAO + "&numThumbs=" + imageLinks.Length); request.Method = "GET"; request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; request.Timeout = 5000; //If vrs authentication is used, add credentials to request if (Settings.VRSAuthenticate) { string encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(Settings.VRSUsr + ":" + Settings.VRSPwd)); request.Headers.Add("Authorization", "Basic " + encoded); } //Send request and parse response try { //Get response HttpWebResponse imageResponse = (HttpWebResponse)request.GetResponse(); byte[] imageResponseBytes = new byte[32768]; imageResponse.GetResponseStream().Read(imageResponseBytes, 0, 32768); string imageResponseText = Encoding.ASCII.GetString(imageResponseBytes); //Parse json JObject imageResponseJson = (JObject)JsonConvert.DeserializeObject(imageResponseText); //If status is not 404, add images to image HTML if (imageResponseJson["status"].ToString() != "404") { foreach (JObject image in imageResponseJson["data"]) { imageHTML += "<img style='margin: 5px;border: 2px solid;border-radius: 10px;' src='" + image + "' />"; } } imageHTML += "<br>"; } catch (Exception) { } //If aircraft has a position, generate a google map url if (aircraft.GetProperty("Lat") != null) { if (aircraft.Trail.Count() != 3) { staticMapUrl = "http://maps.googleapis.com/maps/api/staticmap?center=" + aircraft.GetProperty("Lat") + "," + aircraft.GetProperty("Long") + "&size=800x800&markers=" + aircraft.GetProperty("Lat") + "," + aircraft.GetProperty("Long") + "&key=AIzaSyCJxiyiDWBHiYSMm7sjSTJkQubuo3XuR7s&path=color:0x000000|"; } else { staticMapUrl = "http://maps.googleapis.com/maps/api/staticmap?center=" + aircraft.GetProperty("Lat") + "," + aircraft.GetProperty("Long") + "&size=800x800&zoom=8&markers=" + aircraft.GetProperty("Lat") + "," + aircraft.GetProperty("Long") + "&key=AIzaSyCJxiyiDWBHiYSMm7sjSTJkQubuo3XuR7s&path=color:0x000000|"; } } //Process aircraft trail for (int i = 0; i < aircraft.Trail.Count() / 3; i++) { //Get coordinate string[] coord = new string[] { aircraft.Trail[i * 3].ToString(), aircraft.Trail[i * 3 + 1].ToString(), aircraft.Trail[i * 3 + 2].ToString() }; //Add coordinate to google map url staticMapUrl += coord[0] + "," + coord[1]; //If this is not the last coordinate, add a separator if (i != (aircraft.Trail.Count() / 3) - 1) { staticMapUrl += "|"; } } //Generate google maps url googleMapsUrl = "https://www.google.com.au/maps/search/" + aircraft.GetProperty("Lat") + "," + aircraft.GetProperty("Long"); //Generate airframes.org url if (aircraft.GetProperty("Reg") != null && aircraft.GetProperty("Reg") != "") { airframesUrl = "<h3><a style='text-decoration: none;' href='http://www.airframes.org/reg/" + aircraft.GetProperty("Reg").Replace("-", "").ToUpper() + "'>Airframes.org Lookup</a></h3>"; } //Generate radar url try { if (Settings.radarUrl[Settings.radarUrl.Length - 1] == '/') { reportUrl = Settings.radarUrl + "desktopReport.html?icao-Q=" + aircraft.ICAO; } else { reportUrl = Settings.radarUrl + "/desktopReport.html?icao-Q=" + aircraft.ICAO; } } catch { Core.UI.writeToConsole("ERROR: No radar url specified.", Color.Red); ThreadManager.StartOrRestart(); } //Get name of transponder type transponderName = transponderTypes[Convert.ToInt32(aircraft.GetProperty("Trt")) - 1]; //Write to log and UI Core.logFileSW.WriteLine(DateTime.Now.ToLongTimeString() + " | SENDING ALERT: " + Environment.NewLine + aircraft.ToString() + Environment.NewLine + Environment.NewLine); Core.UI.writeToConsole(DateTime.Now.ToLongTimeString() + " | SENDING | " + aircraft.ICAO + " | Condition: " + condition.conditionName + " (" + emailPropertyInfo + ")", Color.LightBlue); //Generate aircraft property value table bool isAlternateStyle = false; foreach (string child in aircraft.GetPropertyKeys()) { //TODO ADD TO VRSPROPERTIES string parameter = "UNKNOWN_PARAMETER"; //Set parameter to a readable name if it's not included in vrs property info switch (child.ToString()) { case "CNum": parameter = "Aircraft_Serial"; break; case "EngMount": parameter = "Engine_Mount"; break; case "FSeen": parameter = "First_Seen"; break; case "HasPic": parameter = "Has_Picture"; break; case "Id": parameter = "Id"; break; case "Lat": parameter = "Latitude"; break; case "Long": parameter = "Longitude"; break; case "PosTime": parameter = "Position_Time"; break; case "ResetTrail": parameter = "Reset_Trail"; break; case "Tisb": parameter = "TIS-B"; break; case "Trak": parameter = "Track"; break; case "TrkH": parameter = "Is_Track_Heading"; break; case "Year": parameter = "Year"; break; } //If parameter is set (not in vrs property info list) and property list type is set to essentials, skip this property if (parameter != "UNKNOWN_PARAMETER" && Settings.EmailContentConfig.PropertyList == Core.PropertyListType.Essentials) { continue; } //Get parameter information from vrs property info if (parameter == "UNKNOWN_PARAMETER") { foreach (Core.vrsProperty property in Core.vrsPropertyData.Keys) { if (Core.vrsPropertyData[property][2] == child.ToString()) { //If property list type is essentials and this property is not in the list of essentials, leave this property as unknown so it can be skipped if (Settings.EmailContentConfig.PropertyList == Core.PropertyListType.Essentials && !Core.essentialProperties.Contains(property)) { continue; } parameter = property.ToString(); } } if (parameter == "UNKNOWN_PARAMETER") { continue; } } //Add html for property if (isAlternateStyle) { aircraftTable += "<tr style='background-color:#CCC'>"; } else { aircraftTable += "<tr>"; } aircraftTable += "<td style='padding: 3px;font-weight:bold;'>" + parameter + "</td>"; aircraftTable += "<td style='padding: 3px'>" + aircraft.GetProperty(child) + "</td>"; aircraftTable += "</tr>"; isAlternateStyle = !isAlternateStyle; } aircraftTable += "</table>"; //Create the main html document message.Body = "<!DOCTYPE html PUBLIC ' -W3CDTD XHTML 1.0 TransitionalEN' 'http:www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html><body>"; if (isDetection) { message.Body += "<h1>Plane Alert - Last Contact</h1>"; } else { message.Body += "<h1>Plane Alert - First Contact</h1>"; } //Condition name + email property message.Body += "<h2 style='margin: 0px;margin-bottom: 2px;margin-left: 10px;'>Condition: " + condition.conditionName + " (" + emailPropertyInfo + ")</h2>"; //Receiver name if (Settings.EmailContentConfig.ReceiverName) { message.Body += "<h2 style='margin: 0px;margin-bottom: 2px;margin-left: 10px;'>Reciever: " + recieverName + "</h2>"; } //Transponder type if (Settings.EmailContentConfig.TransponderType) { message.Body += "<h2 style='margin: 0px;margin-bottom: 2px;margin-left: 10px;'>Transponder: " + transponderName + "</h2>"; } //Radar url if (Settings.EmailContentConfig.RadarLink) { message.Body += "<h3><a style='text-decoration: none;' href='" + Settings.radarUrl + "'>Goto Radar</a></h3>"; } //Report url if (Settings.EmailContentConfig.ReportLink) { message.Body += "<h3><a style='text-decoration: none;' href='" + reportUrl + "'>VRS Report Lookup</a></h3>"; } //Airframes.org url if (Settings.EmailContentConfig.AfLookup) { message.Body += airframesUrl; } message.Body += "<table><tr><td>"; //Property list if (Settings.EmailContentConfig.PropertyList != Core.PropertyListType.Hidden) { message.Body += aircraftTable; } message.Body += "</td><td style='padding: 10px;vertical-align: top;'>"; //Aircraft photos if (Settings.EmailContentConfig.AircraftPhotos) { message.Body += imageHTML; } //Map if (Settings.EmailContentConfig.Map && aircraft.GetProperty("Lat") != null) { message.Body += "<h3 style='margin: 0px'><a style='text-decoration: none' href=" + googleMapsUrl + ">Open in Google Maps</a></h3><br />" + "<img style='border: 2px solid;border-radius: 10px;' alt='Loading Map...' src='" + staticMapUrl + "' />"; } message.Body += "</td></tr></table></body></html>"; } //Send the alert try { mailClient.Send(message); } catch (SmtpException e) { if (e.InnerException != null) { Core.UI.writeToConsole("SMTP ERROR: " + e.Message + " (" + e.InnerException.Message + ")", Color.Red); return; } Core.UI.writeToConsole("SMTP ERROR: " + e.Message, Color.Red); return; } catch (InvalidOperationException e) { if (e.InnerException != null) { Core.UI.writeToConsole("SMTP ERROR: " + e.Message + " (" + e.InnerException.Message + ")", Color.Red); return; } Core.UI.writeToConsole("SMTP ERROR: " + e.Message, Color.Red); return; } //Increase sent emails for condition and update stats condition.increaseSentEmails(); Stats.updateStats(); //Log to UI Core.UI.writeToConsole(DateTime.Now.ToLongTimeString() + " | SENT | " + aircraft.ICAO + " | Condition: " + condition.conditionName + " (" + emailPropertyInfo + ")", Color.LightBlue); }