/// <summary>Hit when the user wants to delete the selected Aopplication Server.</summary> /// <param name="sender">btnDelAcct</param> /// <param name="e">RoutedEventArgs</param> private void btnDelApp_Click(object sender, RoutedEventArgs e) { if (this.lstApplicationServers.SelectedItem is ApplicationSystem) { //Ask if they're sure.. MessageBoxResult ans = MessageBox.Show(Main.Main_DeleteApp_AreYouSure_Msg, Main.Main_DeleteApp_AreYouSure_Title, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes); if (ans == MessageBoxResult.Yes) { //Remove the server. ApplicationSystem system = (ApplicationSystem)this.lstApplicationServers.SelectedItem; this.settings.Application_Servers.Remove(system); //Go through each email account, and if it uses this app server, set it to null. foreach (AccountDetails acct in this.settings.Email_Accounts) { if (acct.ApplicationServerID.HasValue && acct.ApplicationServerID.Value == system.ServerID.Value) { acct.ApplicationServerID = null; } } //Refresh list. this.lstApplicationServers.Items.Refresh(); } } }
/// <summary>Hit when the timer expires. This does the hard work!</summary> /// <param name="state">This object.</param> private void TimerEvent(object state) { const string METHOD = CLASS + "TimerEvent()"; _eventLog.EntryLog(METHOD); //Pause the timer, set thread name. _eventLog.WriteTrace(METHOD, "Pausing timer."); _timer.Change(Timeout.Infinite, Timeout.Infinite); Thread.CurrentThread.Name = Common.APP_NAME + ": Email Polling Thread"; //Now loop through each email account. foreach (AccountDetails account in _settings.Email_Accounts) { try { _eventLog.WriteTrace(METHOD, "Running on account: '" + account.AccountEmail + "' (" + account.AccountID.ToString() + ")"); //Get the appl's server definition to make sure it exists. ApplicationSystem serverDef = _settings.Application_Servers.Where(ap => ap.ServerID == account.ApplicationServerID).SingleOrDefault(); if (account.ApplicationServerID > 0 && //There is a App Server selected. serverDef != null && //And the AppServer exists. (account.ProductOrProjectId.HasValue && account.ProductOrProjectId.Value > 0)) //And there's a defined default Product/Project. { //Get the POP3 client, first. //TODO: This should be moved to inside each App Process. Pop3Client clientPOP3 = popConnect(account); if (serverDef.ServerType == ApplicationSystem.ApplServerTypeEnum.Spira) { processSpiraAccount(clientPOP3, account, serverDef); } else if (serverDef.ServerType == ApplicationSystem.ApplServerTypeEnum.Krono) { processKronoAccount(clientPOP3, account, serverDef); } } else { string msg = METHOD + Environment.NewLine + "Not running on account:" + Environment.NewLine + "Name: " + account.AccountEmail + Environment.NewLine + "ID: " + account.AccountID.ToString() + Environment.NewLine + "Server: " + account.ServerNameOrIP + Environment.NewLine + "Username: "******"No application server or default product or project is defined. Configuration needs to be updated."; _eventLog.WriteMessage(msg, EventLogEntryType.Error); } } catch (Exception ex) { //Log the error, so we know this one failed. _eventLog.WriteMessage(METHOD, ex); } } //Resume timer. _timer.Change(_settings.PollInterval * MILI, _settings.PollInterval * MILI); }
void Awake() { if (ApplicationSystem.IsIphoneX()) { detail.GetComponent <GridLayoutGroup>().padding.top = 500; } }
/// <summary>Saves the user's information into the ApplicationSystem object. Will return true is save successful, or false if verification errors.</summary> /// <remarks>Status of data - TRUE all fields are valid, and saved. FALSE one or more fields need attention.</remarks> private bool saveData() { //Check required fields, first. bool retValue = this.checkForm(); if (retValue) { //Create a new one, if we didn't have one loaded.. if (this.AppSystem == null) { this._appSystem = new ApplicationSystem(); } //App Server type.. this.AppSystem.ServerType = ((this.rdoKrono.IsChecked.Value) ? ApplicationSystem.ApplServerTypeEnum.Krono : ApplicationSystem.ApplServerTypeEnum.Spira); this.AppSystem.ServerURL = this.cmbHttps.Text + this.txtServerURL.Text.Trim(); this.AppSystem.UserID = this.txtUserName.Text.Trim(); this.AppSystem.UserPassword = this.txtUserPass.Password.Trim(); if (!this.AppSystem.ServerID.HasValue) { this.AppSystem.ServerID = 0; } //Set flag.. retValue = true; } return(retValue); }
/// <summary>Hit when the application server selection is changed. Fires a background event to load up projects or products.</summary> /// <param name="sender">cmbApplicationServer</param> /// <param name="e">SelectionChangedEventArgs</param> private void cmbApplicationServer_SelectionChanged(object sender, SelectionChangedEventArgs e) { //Mark controls as hidden... this.markControlsAsHidden(true); //Now fire off a background thread if they selected a server. if (e.AddedItems.Count == 1) { //We have to fire off the client and get a list of products or projects. ApplicationSystem selectedApp = (ApplicationSystem)e.AddedItems[0]; //Set common stuff.. this.Cursor = Cursors.Wait; this.cmbSelectedProjectOrProduct.IsEnabled = false; this.divUpdating.Visibility = System.Windows.Visibility.Visible; this.txtUpdating.Foreground = Brushes.Black; this.spnSpinner.Visibility = System.Windows.Visibility.Visible; if (selectedApp.ServerType == ApplicationSystem.ApplServerTypeEnum.Spira) { //Set cursor and disable product/project dropdown.. this.lblDefault.Content = "Default Project:"; this.txtUpdating.Text = "Loading SpiraTeam projects..."; //Start the thread.. Thread_Spira_GetProjects proc = new Thread_Spira_GetProjects(selectedApp.ServerURL, selectedApp.UserID, selectedApp.UserPassword); proc.ProgressFinished += new EventHandler <SpiraFinishArgs>(proc_ProgressFinished); Thread thread = new Thread(proc.StartProcess); thread.IsBackground = true; thread.Name = "Thread - Get SpiraTeam Projects"; thread.Start(); //Disable the default project & use regex. //this.Cursor = Cursors.Arrow; } else if (selectedApp.ServerType == ApplicationSystem.ApplServerTypeEnum.Krono) { //Set cursor and disable product/project dropdown.. this.lblDefault.Content = Common.LABEL_DEFAULT_PRODUCT; this.txtUpdating.Text = "Loading KronoDesk products from server..."; //Start the thread.. Thread_Krono_GetProducts proc = new Thread_Krono_GetProducts(selectedApp.ServerURL, selectedApp.UserID, selectedApp.UserPassword); proc.ProgressFinished += new EventHandler <KronoFinishArgs>(proc_ProgressFinishedKrono); Thread thread = new Thread(proc.StartProcess); thread.IsBackground = true; thread.Name = "Thread - Get KronoDesk Products"; thread.Start(); } } e.Handled = true; }
/// <summary>Creates and returns a WSDL client for the given application system. Will try to connect and log on and select project if applicable. If any fails, an exception will be thrown.</summary> /// <param name="applicationSystem">The application system definition.</param> /// <returns>A client, as a dynamic type.</returns> private dynamic CreateApplicationClient(ApplicationSystem applicationSystem, AccountDetails emailSystem) { const string METHOD = CLASS + "CreateApplicationClient()"; _eventLog.EntryLog(METHOD); //Create our application server. dynamic clientApp; if (applicationSystem.ServerType == ApplicationSystem.ApplServerTypeEnum.Spira) { //Create the client. clientApp = ClientFactory.CreateClient_Spira(new Uri(applicationSystem.ServerAPIUrl)); //Connect. _eventLog.WriteTrace(METHOD, "Logging into Spira Client."); Settings.SpiraClient.SoapServiceClient spiraClient = (Settings.SpiraClient.SoapServiceClient)clientApp; if (spiraClient.Connection_Authenticate2(applicationSystem.UserID, applicationSystem.UserPassword, Common.APP_NAME)) { _eventLog.WriteTrace(METHOD, "Selecting project in Spira Client."); if (emailSystem.ProductOrProjectId.HasValue && spiraClient.Connection_ConnectToProject(emailSystem.ProductOrProjectId.Value)) { //We're successful. } else { throw new Exception("Could not log into project #" + emailSystem.ProductOrProjectId.Value.ToSafeString()); } } else { throw new Exception("Could not log into server."); } } else { //Create the client. clientApp = ClientFactory.CreateClient_Krono(new Uri(applicationSystem.ServerAPIUrl)); //Connect. _eventLog.WriteTrace(METHOD, "Logging into Krono Client."); Settings.KronoClient.SoapServiceClient kronoClient = (Settings.KronoClient.SoapServiceClient)clientApp; if (kronoClient.Connection_Authenticate(applicationSystem.UserID, applicationSystem.UserPassword, Common.APP_NAME, true)) { } else { throw new Exception("Could not log into server."); } } return(clientApp); }
void Awake() { if (GameObject.FindGameObjectsWithTag("ApplicationSystem").Length > 1) { Destroy(this.gameObject); } if (instance == null) { instance = this; } DontDestroyOnLoad(this); }
/// <summary>Given the Application System, this will either add it or update an existing one in the list.</summary> /// <param name="appSys">The Application System to add or update.</param> private void AddOrUpdateApplicationSystem(ApplicationSystem appSystem) { if (appSystem != null && appSystem.ServerID.HasValue) { //It's a real server, so we need to add it to the list, or update an existing one. //Find the item.. if (appSystem.ServerID.Value > 0 && this.settings.Application_Servers.Count(aps => aps.ServerID == appSystem.ServerID) == 1) { ApplicationSystem exisSystem = this.settings.Application_Servers.Where(aps => aps.ServerID == appSystem.ServerID).SingleOrDefault(); if (exisSystem != null) { exisSystem.ServerType = appSystem.ServerType; exisSystem.ServerURL = appSystem.ServerURL; exisSystem.UserID = appSystem.UserID; exisSystem.UserPassword = appSystem.UserPassword; } } else { //Get the next server ID number.. Get the last server, first.. if (this.settings.Application_Servers.Count > 0) { ApplicationSystem highestSystem = this.settings.Application_Servers.OrderBy(aps => aps.ServerID).ToList()[this.settings.Application_Servers.Count - 1]; appSystem.ServerID = highestSystem.ServerID + 1; } else { appSystem.ServerID = 1; } //Add it to the list. this.settings.Application_Servers.Add(appSystem); } } //Flag the window as having changes. this.WindowSetUnsaved(true); //Refresh display. this.lstApplicationServers.Items.Refresh(); }
/// <summary>Hit when the user wants to edit an existing application.</summary> /// <param name="sender">lstApplicationServers.Item</param> /// <param name="e"></param> private void lstApplicationServersItem_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (e.ClickCount == 2) { //Get the data item.. if (sender is Grid) { if (((Grid)sender).DataContext is ApplicationSystem) { ApplicationSystem appSys = (ApplicationSystem)((Grid)sender).DataContext; //Display the form.. Details_ApplicationServer win = new Details_ApplicationServer(appSys); bool?resp = win.ShowDialog(); if (resp.HasValue && resp.Value) { //Add or update the list.. this.AddOrUpdateApplicationSystem(appSys); } } } } }
private void processSpiraAccount(Pop3Client clientPOP3, AccountDetails account, ApplicationSystem appServer) { const string METHOD = CLASS + "processSpiraAccount()"; this._eventLog.EntryLog(METHOD); //Create the application client and connect to our project and get users.. SoapServiceClient clientAppl = (SoapServiceClient)this.CreateApplicationClient(appServer, account); //Get users in the project.. List <RemoteProjectUser> spiraUsers = clientAppl.Project_RetrieveUserMembership(); //Get the known message IDs.. List <string> seenUIDs = this.readMessageIDsForAccount(account.AccountID.Value); //Get new emails from the client. List <Message> newMsgs = this.popGetNewMessages(clientPOP3, account, seenUIDs); //Get all projects.. List <RemoteProject> spiraProjs = clientAppl.Project_Retrieve(); //Loop through each email. foreach (Message msg in newMsgs) { this._eventLog.WriteTrace(METHOD, "Starting on message " + msg.MessageLogID + "..."); //Make sure we have a from address, otherwise skip (Delivery Returned messages have no FROM address) //First see if the message should be skipped. (Keywords, Headers, or Email Addresses) if (msg.Headers != null && msg.Headers.From != null && !String.IsNullOrWhiteSpace(msg.Headers.From.Address) && msg.Headers.From.Address.ToLowerInvariant().Trim() != account.AccountEmail.ToLowerInvariant().Trim()) { string filterMsg; if (this.doesMessageClearFilters(msg, out filterMsg)) { //First see if there's a header we can get the artifact ID from.. ArtifactTypeEnum artType = ArtifactTypeEnum.None; int artId = -1; if (msg.Headers.UnknownHeaders[Common.MESSAGEHEADER_SPIRA_ARTIFACT] != null && rgxArtifactToken.IsMatch(msg.Headers.UnknownHeaders[Common.MESSAGEHEADER_SPIRA_ARTIFACT])) { //Get the art type and the id.. Match matches = rgxArtifactToken.Match(msg.Headers.UnknownHeaders[Common.MESSAGEHEADER_SPIRA_ARTIFACT]); this.retrieveArtTypeAndId(matches.Groups["type"].Value, matches.Groups["id"].Value, out artType, out artId); } if (artId == -1 || artType == ArtifactTypeEnum.None) { if (rgxArtifactToken.IsMatch(msg.Headers.Subject)) { //Get the art type and the id.. Match matches = rgxArtifactToken.Match(msg.Headers.Subject); this.retrieveArtTypeAndId(matches.Groups["type"].Value, matches.Groups["id"].Value, out artType, out artId); } } //Change projects, if necessary, and if we're able to.. try { int projNum = clientAppl.System_GetProjectIdForArtifact((int)artType, artId); if (projNum != 0) { bool succNewProject = clientAppl.Connection_ConnectToProject(projNum); if (!succNewProject) { //Couldn't connect to the project this item belongs to. Throw an error. this._eventLog.WriteMessage("Message " + msg.MessageLogID + " contains information for a project [PR:" + projNum.ToString() + "] that the client could not connect to. Skipping.", System.Diagnostics.EventLogEntryType.Information); artType = ArtifactTypeEnum.Skip; artId = 0; } } } catch (Exception ex) { this._eventLog.WriteMessage(METHOD, ex, "Message " + msg.MessageLogID + " - while trying to retrieve project number from artifact. Skipping."); } //If we have a match, find the user.. if (artId > 0 && artType != ArtifactTypeEnum.None) { //Detect if more than one user is found.. int userCnt = spiraUsers.Where(su => su.EmailAddress.ToLowerInvariant() == msg.Headers.From.MailAddress.Address.ToLowerInvariant()).Count(); if (userCnt == 1) { RemoteProjectUser selUser = spiraUsers.Where(su => su.EmailAddress.ToLowerInvariant() == msg.Headers.From.MailAddress.Address.ToLowerInvariant()).Single(); //See if the item exists in the server.. RemoteArtifact remArt = null; try { switch (artType) { case ArtifactTypeEnum.Requirement: remArt = clientAppl.Requirement_RetrieveById(artId); break; case ArtifactTypeEnum.Test_Case: remArt = clientAppl.TestCase_RetrieveById(artId); break; case ArtifactTypeEnum.Incident: remArt = clientAppl.Incident_RetrieveById(artId); break; case ArtifactTypeEnum.Release: remArt = clientAppl.Release_RetrieveById(artId); break; case ArtifactTypeEnum.Task: remArt = clientAppl.Task_RetrieveById(artId); break; case ArtifactTypeEnum.Test_Set: remArt = clientAppl.TestSet_RetrieveById(artId); break; } if (remArt == null) { throw new Exception("Artifact did not exist: " + artType.ToString() + " #" + artId.ToString()); } } catch (Exception ex) { this._eventLog.WriteMessage(METHOD, ex, "For message " + msg.MessageLogID + ", referenced artifact did not exist."); continue; } try { //The artifact exists, let's add a comment.. RemoteComment comment = new RemoteComment(); comment.ArtifactId = artId; comment.CreationDate = DateTime.UtcNow; comment.UserId = selUser.UserId; comment.Text = this.getTextFromMessage(msg, true, true); switch (artType) { case ArtifactTypeEnum.Requirement: comment = clientAppl.Requirement_CreateComment(comment); break; case ArtifactTypeEnum.Test_Case: comment = clientAppl.TestCase_CreateComment(comment); break; case ArtifactTypeEnum.Incident: comment = clientAppl.Incident_AddComments(new List <RemoteComment>() { comment }).FirstOrDefault(); break; case ArtifactTypeEnum.Release: comment = clientAppl.Release_CreateComment(comment); break; case ArtifactTypeEnum.Task: comment = clientAppl.Task_CreateComment(comment); break; case ArtifactTypeEnum.Test_Set: comment = clientAppl.TestSet_CreateComment(comment); break; } if (comment != null && comment.CommentId.HasValue) { //Now check for attachments try { foreach (MessagePart attach in msg.FindAllAttachments().Where(aa => aa.IsMultiPart == false && aa.IsText == false)) { //Add the file.. RemoteLinkedArtifact artifactLink = new RemoteLinkedArtifact(); artifactLink.ArtifactId = comment.ArtifactId; artifactLink.ArtifactTypeId = (int)artType; RemoteDocument newDoc = new RemoteDocument(); newDoc.AttachedArtifacts = new List <RemoteLinkedArtifact>() { artifactLink }; newDoc.AttachmentTypeId = 1; newDoc.AuthorId = selUser.UserId; newDoc.FilenameOrUrl = attach.FileName; newDoc.UploadDate = DateTime.UtcNow; //Check for string overrun and add extension if necessary. if (newDoc.FilenameOrUrl.Length > 250) { newDoc.FilenameOrUrl = newDoc.FilenameOrUrl.Substring(0, 250); } if (string.IsNullOrWhiteSpace(Path.GetExtension(newDoc.FilenameOrUrl)) && attach.ContentType != null) { string tempFileExtension = Utils.GetExtensionFromMimeType(attach.ContentType.MediaType); if (!string.IsNullOrWhiteSpace(tempFileExtension)) { newDoc.FilenameOrUrl += "." + tempFileExtension; } } //Call the function to upload the file to Spira newDoc = clientAppl.Document_AddFile(newDoc, attach.Body); //Log it. this._eventLog.WriteMessage("Attachment #" + newDoc.AttachmentId.ToSafeString() + " created from file '" + attach.FileName + "' for Artifact " + artType + " #:" + comment.ArtifactId + " from message " + msg.MessageLogID + ".", System.Diagnostics.EventLogEntryType.Information); } } catch (Exception ex) { //Log and continue this._eventLog.WriteMessage(METHOD, ex, "Saving attachment for message " + msg.MessageLogID); } } } catch (Exception ex) { this._eventLog.WriteMessage(METHOD, ex, "While trying to save message '" + msg.MessageLogID + "' as a new comment."); continue; } //If we get this far, mark the message as processed. try { //Add it to our list.. seenUIDs.Add(msg.MessageUID); if (account.RemoveFromServer) { clientPOP3.DeleteMessage(msg.MessageIndex); } } catch (Exception ex) { this._eventLog.WriteMessage(METHOD, ex, "Trying to delete message " + msg.MessageLogID + " from server."); } } else { string msgLog = ""; if (userCnt == 0) { msgLog = "Message " + msg.MessageLogID + " was sent from a user not a mamber of the specified project. Not importing unknown users."; } else if (userCnt > 1) { msgLog = "Message " + msg.MessageLogID + " was sent from a user that did not have a unique email address. Cannot import to avoid selecting the wrong user."; } this._eventLog.WriteMessage(msgLog, System.Diagnostics.EventLogEntryType.Information); } } else { if (artType != ArtifactTypeEnum.Skip) { int userCnt = spiraUsers.Where(su => su.EmailAddress.ToLowerInvariant() == msg.Headers.From.MailAddress.Address.ToLowerInvariant()).Count(); if (userCnt == 1) { RemoteProjectUser selUser = spiraUsers.Where(su => su.EmailAddress.ToLowerInvariant() == msg.Headers.From.MailAddress.Address.ToLowerInvariant()).Single(); //Create a new Incident.. RemoteIncident newIncident = new RemoteIncident(); newIncident.CreationDate = DateTime.Now; newIncident.Description = this.getTextFromMessage(msg, true, false); newIncident.Name = msg.Headers.Subject; newIncident.OpenerId = selUser.UserId; //Check regex other projects if (account.UseRegexToMatch) { Regex regProj1 = new Regex(@"\[PR[\:\-\s](\d*?)\]", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (regProj1.IsMatch(newIncident.Description) || regProj1.IsMatch(newIncident.Name)) { //Someone used the PR tag in the email body, we'll use it, if possible. string matchNum = ""; if (regProj1.IsMatch(newIncident.Name)) { matchNum = regProj1.Matches(newIncident.Name)[0].Groups[1].Value; } else if (regProj1.IsMatch(newIncident.Description)) { matchNum = regProj1.Matches(newIncident.Description)[0].Groups[1].Value; } else { this._eventLog.WriteMessage("ERROR: At least one RegEx returned IsMatch, but none contained match.", System.Diagnostics.EventLogEntryType.Information); continue; } int projNum = 0; if (int.TryParse(matchNum, out projNum)) { //We had a number, let's see if it's a valid product. RemoteProject proj = spiraProjs.FirstOrDefault(prd => prd.ProjectId == projNum); if (proj != null) { //Connect to project.. if (clientAppl.Connection_ConnectToProject(proj.ProjectId.Value)) { newIncident.ProjectId = proj.ProjectId.Value; this._eventLog.WriteMessage("Message " + msg.MessageLogID + " changed to Project '" + proj.Name + "' due to having [PR:xx] tag.", System.Diagnostics.EventLogEntryType.Information); } else { this._eventLog.WriteMessage("Message " + msg.MessageLogID + " contained project token for project '" + proj.Name + "', but email import has no access to that project. Using default.", System.Diagnostics.EventLogEntryType.Information); } } else { this._eventLog.WriteMessage("Message '" + msg.MessageLogID + "' contained token for project " + projNum.ToString() + " but project was inaccessible. Using default.", System.Diagnostics.EventLogEntryType.Information); } } } else { foreach (RemoteProject prod in spiraProjs) { Regex regProd3 = new Regex(@"\b" + prod.Name + @"\b", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); if (regProd3.IsMatch(newIncident.Description) || regProd3.IsMatch(newIncident.Name)) { newIncident.ProjectId = prod.ProjectId.Value; this._eventLog.WriteMessage("Message " + msg.MessageLogID + " changed to Product '" + prod.Name + "' due to having Product name '" + prod.Name + "'", System.Diagnostics.EventLogEntryType.Information); break; } } } } //Now save the Incident.. try { newIncident = clientAppl.Incident_Create(newIncident); if (newIncident.IncidentId.HasValue) { //Now check for attachments try { foreach (MessagePart attach in msg.FindAllAttachments().Where(aa => aa.IsMultiPart == false && aa.IsText == false)) { //Add the file.. RemoteLinkedArtifact artifactLink = new RemoteLinkedArtifact(); artifactLink.ArtifactId = newIncident.IncidentId.Value; artifactLink.ArtifactTypeId = 3; /* Incident */ RemoteDocument newDoc = new RemoteDocument(); newDoc.AttachedArtifacts = new List <RemoteLinkedArtifact>() { artifactLink }; newDoc.AttachmentTypeId = 1; newDoc.AuthorId = selUser.UserId; newDoc.FilenameOrUrl = attach.FileName; newDoc.UploadDate = DateTime.UtcNow; //Check for string overrun and add extension if necessary. if (newDoc.FilenameOrUrl.Length > 250) { newDoc.FilenameOrUrl = newDoc.FilenameOrUrl.Substring(0, 250); } if (string.IsNullOrWhiteSpace(Path.GetExtension(newDoc.FilenameOrUrl)) && attach.ContentType != null) { string tempFileExtension = Utils.GetExtensionFromMimeType(attach.ContentType.MediaType); if (!string.IsNullOrWhiteSpace(tempFileExtension)) { newDoc.FilenameOrUrl += "." + tempFileExtension; } } //Call the function to upload the file to Spira newDoc = clientAppl.Document_AddFile(newDoc, attach.Body); //Log it. this._eventLog.WriteMessage("Attachment #" + newDoc.AttachmentId.ToSafeString() + " created from file '" + attach.FileName + "' for Incident IN:" + newIncident.IncidentId.Value + " from message " + msg.MessageLogID + ".", System.Diagnostics.EventLogEntryType.Information); } } catch (Exception ex) { //Log and continue this._eventLog.WriteMessage(METHOD, ex, "Saving attachment for message " + msg.MessageLogID); } } //If we get this far, mark the message as processed. try { //Add it to our list.. seenUIDs.Add(msg.MessageUID); if (account.RemoveFromServer) { clientPOP3.DeleteMessage(msg.MessageIndex); } } catch (Exception ex) { this._eventLog.WriteMessage(METHOD, ex, "Trying to delete message " + msg.MessageLogID + " from server."); } } catch (Exception ex) { this._eventLog.WriteMessage(METHOD, ex, "While trying to save message '" + msg.MessageLogID + "' as an incident."); } } else { string msgLog = ""; if (userCnt == 0) { msgLog = "Message " + msg.MessageLogID + " was sent from a user not a mamber of the specified project. Not importing unknown users."; } else if (userCnt > 1) { msgLog = "Message " + msg.MessageLogID + " was sent from a user that did not have a unique email address. Cannot import to avoid selecting the wrong user."; } this._eventLog.WriteMessage(msgLog, System.Diagnostics.EventLogEntryType.Information); } } else { } } } else { //Log it.. this._eventLog.WriteMessage("Message " + msg.MessageLogID + " on the server did not pass filters:" + Environment.NewLine + "Subject: " + msg.Headers.Subject + Environment.NewLine + "Reasons: " + Environment.NewLine + filterMsg, System.Diagnostics.EventLogEntryType.Warning); } } else { //Log it.. this._eventLog.WriteMessage("Message " + msg.MessageLogID + " had no From address or was from the import account --" + Environment.NewLine + "Subject: " + msg.Headers.Subject + Environment.NewLine + "Msg UID: " + msg.Headers.MessageId + Environment.NewLine + "For reason: From Email address same as importing account, or was null.", System.Diagnostics.EventLogEntryType.Warning); } } //Save the seen message IDs.. this.saveMessageIDsForAccount(account.AccountID.Value, seenUIDs); //Disconnect client and POP3.. try { clientPOP3.Disconnect(); clientAppl.Connection_Disconnect(); } catch (Exception ex) { this._eventLog.WriteMessage(METHOD, ex, "Trying to close connections."); } }
private void processKronoAccount(Pop3Client clientPOP3, AccountDetails account, ApplicationSystem appServer) { const string METHOD = CLASS + "processKronoAccount()"; _eventLog.EntryLog(METHOD); //Create the application client and connect to our project and get users.. SoapServiceClient clientAppl = (SoapServiceClient)this.CreateApplicationClient(appServer, account); //Get the products and settings from Kronodesk. List <RemoteProduct> krnProds = clientAppl.Product_Retrieve(false); //Get list of blocked emails.. List <string> blockedEmails = clientAppl.System_GetBlockedEmails(); //Get list of seperator lines.. List <string> seperatorLines = clientAppl.System_GetEmailSeparator(); //Get the known message IDs.. List <string> seenUIDs = readMessageIDsForAccount(account.AccountID.Value); //Get new emails from the client. List <Message> newMsgs = popGetNewMessages(clientPOP3, account, seenUIDs); //Loop through each email. foreach (Message msg in newMsgs) { try { _eventLog.WriteTrace(METHOD, "Starting on message " + msg.MessageLogID + "..."); //First see if the message should be skipped. (Keywords, Headers, or Email Addresses) if (msg.Headers != null && msg.Headers.From != null && !string.IsNullOrWhiteSpace(msg.Headers.From.Address) && msg.Headers.From.Address.ToLowerInvariant().Trim() != account.AccountEmail.ToLowerInvariant().Trim()) { string filterMsg; //Run it though our own filters. if (doesMessageClearFilters(msg, out filterMsg, blockedEmails)) { long?tktId = null; //See if we can get a ticket ID.. if ((!tktId.HasValue) && msg.Headers.UnknownHeaders[Common.MESSAGEHEADER_KRONO_TICKET] != null) { tktId = retrieveTicketId(msg.Headers.UnknownHeaders[Common.MESSAGEHEADER_KRONO_TICKET]); } if (!tktId.HasValue) { Regex rgx = new Regex(@"\[[a-zA-Z]{2}[\:-][0-9]+\]", RegexOptions.IgnoreCase | RegexOptions.Singleline); tktId = retrieveTicketId(rgx.Match(msg.Headers.Subject).Value); } //Get user that this email is from.. RemoteUser usrFrom = clientAppl.User_RetrieveByEmailAddress(msg.Headers.From.MailAddress.Address); //See if we have any CC users List <string> ccList = null; if (msg.Headers.Cc != null && msg.Headers.Cc.Count > 0) { ccList = msg.Headers.Cc.Select(c => c.MailAddress.Address).ToList(); } //Now process the email. RemoteTicket newTicket = null; RemoteTicketNote newTktNote = null; if (tktId.HasValue) { try { //The ticket exists, we're going to add the text as a new comment. //The flag on whether we need to make it a '3rd party' note. bool add3rd = (usrFrom == null); //If at least one user exists.. if (!add3rd) { //Create the note.. newTktNote = new RemoteTicketNote(); newTktNote.CreationDate = DateTime.UtcNow; newTktNote.AuthorId = usrFrom.UserId; newTktNote.TicketId = tktId.Value; newTktNote.Text = getTextFromMessage(msg, true, true, seperatorLines); try { newTktNote = clientAppl.Ticket_AddNote(newTktNote); } catch (Exception ex) { _eventLog.WriteMessage("Error adding note to message. Adding it as third-party."); add3rd = true; } if (!add3rd) { _eventLog.WriteMessage("Note #" + newTktNote.NoteId.ToSafeString() + " added to Ticket #" + newTktNote.TicketId.ToSafeString() + " created from message " + msg.MessageLogID + ".", System.Diagnostics.EventLogEntryType.Information); //If we get this far, mark the message as processed. try { if (account.RemoveFromServer) { clientPOP3.DeleteMessage(msg.MessageIndex); } } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Trying to delete message " + msg.MessageLogID + " from server."); } //We processed the message, add it. seenUIDs.Add(msg.MessageUID); } } if (add3rd) { try { //An email was sent in from a third party. string strDescDetails = "Full Subject: " + msg.Headers.Subject + Environment.NewLine + "From Address: " + ((string.IsNullOrWhiteSpace(msg.Headers.From.Address)) ? "< empty >" : msg.Headers.From.Address) + Environment.NewLine + "From Name: " + ((string.IsNullOrWhiteSpace(msg.Headers.From.DisplayName)) ? "< empty >" : msg.Headers.From.DisplayName); RemoteDocument rawMsg = getMsgAsAttachment(msg, tktId.Value, null, "3rd Party Email:" + Environment.NewLine + strDescDetails); rawMsg = clientAppl.Document_AddFile(rawMsg, msg.RawMessage); //Add comment. newTktNote = new RemoteTicketNote(); newTktNote.CreationDate = DateTime.UtcNow; newTktNote.TicketId = tktId.Value; newTktNote.Text = "An email for this ticket was recieved from a third unknown party, and has been attached to this ticket as a file. Details:" + Environment.NewLine + "<pre>" + strDescDetails + Environment.NewLine + "Attachment: " + rawMsg.FilenameOrUrl + "</pre>"; newTktNote.Text = newTktNote.Text.Replace(Environment.NewLine, "<br />"); //Convert to HTML. newTktNote = clientAppl.Ticket_AddNote(newTktNote); _eventLog.WriteMessage("Message from 3rd party to ticket. Message " + msg.MessageLogID + " saved as Attachment #" + rawMsg.AttachmentId.ToSafeString() + " & Note #" + newTktNote.NoteId + " added.", System.Diagnostics.EventLogEntryType.Information); //If we get this far, mark the message as processed. try { if (account.RemoveFromServer) { clientPOP3.DeleteMessage(msg.MessageIndex); } } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Trying to delete message " + msg.MessageLogID + " from server."); } //We processed the message, add it. seenUIDs.Add(msg.MessageUID); } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Error adding 3rd party email to ticket from message " + msg.MessageLogID); } } } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Error adding note to ticket from message " + msg.MessageLogID + "."); break; } } else { try { //Create the fake user first.. if (usrFrom == null) { RemoteUser newUser = new RemoteUser(); newUser.Active = true; newUser.Approved = false; newUser.EmailAddress = msg.Headers.From.MailAddress.Address; newUser.Login = msg.Headers.From.MailAddress.Address; Dictionary <string, string> names = getFullNameFromAddress(msg.Headers.From); newUser.FirstName = names["first"]; newUser.LastName = names["last"]; //Check for too-long strings.. if (newUser.FirstName.Length > 49) { newUser.FirstName = newUser.FirstName.Substring(0, 49); } if (newUser.LastName.Length > 49) { newUser.LastName = newUser.LastName.Substring(0, 49); } if (newUser.Login.Length > 49) { newUser.Login = newUser.Login.Substring(0, 49); } if (newUser.EmailAddress.Length > 49) { newUser.EmailAddress = newUser.EmailAddress.Substring(0, 49); } usrFrom = clientAppl.User_Create(newUser, "abcdefghijkLMNOPQ1", "Registration Code", Membership.GeneratePassword(10, 0), new List <string>()); _eventLog.WriteMessage("Temporary user '" + newUser.Login + "' created, user ID#" + usrFrom.UserId.ToSafeString(), System.Diagnostics.EventLogEntryType.Information); } //Need to create a new ticket. newTicket = new RemoteTicket(); newTicket.CreationDate = DateTime.UtcNow; newTicket.Name = msg.Headers.Subject; newTicket.Description = getTextFromMessage(msg, true); newTicket.OpenerId = usrFrom.UserId; newTicket.ProductId = account.ProductOrProjectId.Value; //Add any CC users newTicket.CCList = ccList; //Add the source newTicket.SourceId = -2; //Email //Check regex other products if (account.UseRegexToMatch) { Regex regProd1 = new Regex(@"\[PR[\:\-\s](\d*?)\]", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); if (regProd1.IsMatch(newTicket.Description) || regProd1.IsMatch(newTicket.Name)) { //Someone used the PR tag in the email body, we'll use it, if possible. string matchNum = ""; if (regProd1.IsMatch(newTicket.Name)) { matchNum = regProd1.Matches(newTicket.Name)[0].Groups[1].Value; } else if (regProd1.IsMatch(newTicket.Description)) { matchNum = regProd1.Matches(newTicket.Description)[0].Groups[1].Value; } else { _eventLog.WriteMessage("ERROR: At least one RegEx returned IsMatch, but none contained match.", System.Diagnostics.EventLogEntryType.Information); continue; } int prodNum = 0; if (int.TryParse(matchNum, out prodNum)) { //We had a number, let's see if it's a valid product. RemoteProduct prod = krnProds.Where(prd => prd.ProductId == prodNum).SingleOrDefault(); if (prod != null) { newTicket.ProductId = (int)prod.ProductId.Value; _eventLog.WriteMessage("Message " + msg.MessageLogID + " changed to Product '" + prod.Name + "' due to having [PR:xx] tag.", System.Diagnostics.EventLogEntryType.Information); } } } else { bool foundToken = false; foreach (RemoteProduct prod in krnProds) { if (!string.IsNullOrWhiteSpace(prod.ProductToken)) { Regex regProd2 = new Regex(@"\b" + prod.ProductToken + @"\b", RegexOptions.CultureInvariant | RegexOptions.Compiled); if (regProd2.IsMatch(newTicket.Description) || regProd2.IsMatch(newTicket.Name)) { newTicket.ProductId = (int)prod.ProductId.Value; foundToken = true; _eventLog.WriteMessage("Message " + msg.MessageLogID + " changed to Product '" + prod.Name + "' due to having Product token '" + prod.ProductToken + "'", System.Diagnostics.EventLogEntryType.Information); break; } } } if (!foundToken) { foreach (RemoteProduct prod in krnProds) { if (!string.IsNullOrWhiteSpace(prod.Name)) { Regex regProd3 = new Regex(@"\b" + prod.Name + @"\b", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); if (regProd3.IsMatch(newTicket.Description) || regProd3.IsMatch(newTicket.Name)) { newTicket.ProductId = (int)prod.ProductId.Value; _eventLog.WriteMessage("Message " + msg.MessageLogID + " changed to Product '" + prod.Name + "' due to having Product name '" + prod.Name + "'", System.Diagnostics.EventLogEntryType.Information); break; } } } } } } //Check for string overrun.. if (newTicket.Name.Length > 254) { newTicket.Name = newTicket.Name.Substring(0, 254); } //Check for null (or empty) Name.. if (string.IsNullOrWhiteSpace(newTicket.Name)) { newTicket.Name = "(no subject)"; } newTicket = clientAppl.Ticket_Create(newTicket); tktId = newTicket.TicketId; _eventLog.WriteMessage("Ticket #" + newTicket.TicketId.ToSafeString() + " created from message " + msg.MessageLogID + ".", System.Diagnostics.EventLogEntryType.Information); //If we get this far, mark the message as processed. try { //Add it to our list.. seenUIDs.Add(msg.MessageUID); if (account.RemoveFromServer) { clientPOP3.DeleteMessage(msg.MessageIndex); } } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Trying to delete message " + msg.MessageLogID + " from server."); } } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Creating new ticket/user for message " + msg.MessageLogID); continue; } } //Check for attachments now.. if (tktId.HasValue) { //The list of contentID's mapped to URLs.. Dictionary <string, string> mappedURLs = new Dictionary <string, string>(); try { //Get existing attachments and add them to the list. List <RemoteDocument> tktDocs = clientAppl.Document_GetForArtifact(6, tktId.Value, true); Dictionary <string, RemoteDocument> savedHashes = new Dictionary <string, RemoteDocument>(); foreach (RemoteDocument doc in tktDocs) { string hash = System.Text.ASCIIEncoding.ASCII.GetString(doc.Hash).Trim(); if (!savedHashes.ContainsKey(hash)) { savedHashes.Add(hash.Trim(), doc); } } foreach (MessagePart attach in msg.FindAllAttachments().Where(aa => aa.IsMultiPart == false && aa.IsText == false)) { //First get the MD5 of the attachment.. string attHash; using (var md5 = new MD5CryptoServiceProvider()) attHash = System.Text.ASCIIEncoding.ASCII.GetString(md5.ComputeHash(attach.Body)).Trim(); //Make sure the hash dosen't already exist.. bool doesExist = false; if (savedHashes.ContainsKey(attHash)) { //It exists, so se tthe flag and add the URL and Id to our dictionary.. doesExist = true; if (!mappedURLs.ContainsKey(attach.ContentId)) { mappedURLs.Add(attach.ContentId, savedHashes[attHash].DocumentURL); } } if (!doesExist) { //Add the file.. RemoteDocument newDoc = new RemoteDocument(); newDoc.ArtifactId = tktId.Value; newDoc.ArtifactTypeId = 6; newDoc.AttachmentTypeId = 1; newDoc.AuthorId = usrFrom.UserId; newDoc.FilenameOrUrl = attach.FileName; newDoc.UploadDate = DateTime.UtcNow; //Check for string overrun and add extension if necessary. if (newDoc.FilenameOrUrl.Length > 250) { newDoc.FilenameOrUrl = newDoc.FilenameOrUrl.Substring(0, 250); } if (string.IsNullOrWhiteSpace(Path.GetExtension(newDoc.FilenameOrUrl)) && attach.ContentType != null) { string tempFileExtension = clientAppl.System_GetExtensionFromMimeType(attach.ContentType.MediaType); if (!string.IsNullOrWhiteSpace(tempFileExtension)) { newDoc.FilenameOrUrl += "." + tempFileExtension; } } //Call the function and update mappings.. newDoc = clientAppl.Document_AddFile(newDoc, attach.Body); savedHashes.Add(attHash, newDoc); if (!string.IsNullOrWhiteSpace(attach.ContentId)) { mappedURLs.Add(attach.ContentId, newDoc.DocumentURL); } //Loggit. _eventLog.WriteMessage("Attachment #" + newDoc.AttachmentId.ToSafeString() + " created from file '" + attach.FileName + "' for Ticket #" + tktId.ToSafeString() + " from message " + msg.MessageLogID + ".", System.Diagnostics.EventLogEntryType.Information); } else { _eventLog.WriteMessage("Attachment file '" + attach.FileName + "' not uploaded from message " + msg.MessageLogID + ", hash already exists in Ticket #" + tktId.ToSafeString() + ".", System.Diagnostics.EventLogEntryType.Information); } } } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Saving attachment for message " + msg.MessageLogID); break; } //If the flag's set, get the entire message.. if (account.SaveRawEmailAsAttachment) { try { RemoteDocument rawMsg = getMsgAsAttachment(msg, tktId.Value, usrFrom.UserId, null); rawMsg = clientAppl.Document_AddFile(rawMsg, msg.RawMessage); _eventLog.WriteMessage("Message " + msg.MessageLogID + " saved as Attachment #" + rawMsg.AttachmentId.ToSafeString() + ".", System.Diagnostics.EventLogEntryType.Information); } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Saving message " + msg.MessageLogID + " as attachment:"); break; } } //Now loop through each saved attachment, and update URLs.. bool needsTktUpdating = false; bool needsNoteUpdating = false; foreach (KeyValuePair <string, string> kvpURL in mappedURLs) { //See if we need to updat ethe note or the ticket.. if (newTicket == null && newTktNote != null) { if (newTktNote.Text.Contains(kvpURL.Key)) { newTktNote.Text = newTktNote.Text.Replace("cid:" + kvpURL.Key, kvpURL.Value); needsNoteUpdating = true; } } else if (newTicket != null && newTktNote == null) { if (newTicket.Description.Contains(kvpURL.Key)) { newTicket.Description = newTicket.Description.Replace("cid:" + kvpURL.Key, kvpURL.Value); needsTktUpdating = true; } } else { //Log warning message here. _eventLog.WriteMessage("Both newTicket and newTktNote were null or not null while processing message " + msg.MessageLogID + ".", System.Diagnostics.EventLogEntryType.Warning); } } if (needsTktUpdating) { try { //The date is set to 4/26/1976 so that the KronoDesk code knows not to record history changes and send out another notification. //All we're doing is converting the description URLs for the newly-uploaded attachments. _eventLog.WriteTrace(METHOD, "Updating ticket description with attachment URLs for message " + msg.MessageLogID + "."); newTicket.LastUpdateDate = new DateTime(1976, 4, 26); clientAppl.Ticket_Update(newTicket); } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Trying to update ticket description for message " + msg.MessageLogID + "."); } } else if (needsNoteUpdating) { try { _eventLog.WriteTrace(METHOD, "Updating note text with attachment URLs for message " + msg.MessageLogID + "."); clientAppl.Ticket_UpdateNote(newTktNote); } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "Trying to update note text for message " + msg.MessageLogID + "."); } } } } else { //Log it.. _eventLog.WriteMessage("Message " + msg.MessageLogID + " on the server did not pass filters:" + Environment.NewLine + "Subject: " + msg.Headers.Subject + Environment.NewLine + "Reasons: " + Environment.NewLine + filterMsg, System.Diagnostics.EventLogEntryType.Warning); } } else { //Log it.. _eventLog.WriteMessage("Message " + msg.MessageLogID + " had no From address or was from the import account --" + Environment.NewLine + "Subject: " + msg.Headers.Subject + Environment.NewLine + "Msg UID: " + msg.Headers.MessageId + Environment.NewLine + "For reason: From Email address same as importing account, or was null.", System.Diagnostics.EventLogEntryType.Warning); } } catch (Exception ex) { _eventLog.WriteMessage(METHOD, ex, "While importing message " + msg.MessageLogID); } } //Save the seen message IDs first, in case there's a problem disconnecting. saveMessageIDsForAccount(account.AccountID.Value, seenUIDs); //Disconnect client and POP3.. try { clientPOP3.Disconnect(); clientAppl.Connection_Disconnect(); } catch (Exception ex) { _eventLog.WriteMessage("Trying to disconnect from server.", ex); } }
/// <summary>Creates a new instance of the window.</summary> /// <param name="system">The Application System the user wants to view or edit.</param> public Details_ApplicationServer(ApplicationSystem system) { this.InitializeComponent(); this.AppSystem = system; }