コード例 #1
0
        private static List <RemoteArtifactCustomProperty> MergeCustomFieldsWithConcurrency(RemoteArtifact userSaved, RemoteArtifact original, RemoteArtifact serverModded)
        {
            List <RemoteArtifactCustomProperty> retList = new List <RemoteArtifactCustomProperty>();

            //First get all the ones our user entered in.
            foreach (RemoteArtifactCustomProperty prop in userSaved.CustomProperties)
            {
                if (((original.CustomProperties.Count(cp => cp.PropertyNumber == prop.PropertyNumber) == 0) &&                  //If the property does not exist in the original
                     serverModded.CustomProperties.Count(cp => cp.PropertyNumber == prop.PropertyNumber) == 0))                 // or the concurrent artifact.
                {
                    retList.Add(prop);
                }
                else                  //There is either an original one or a concurrent one,
                {
                    //If the user one is different than the original, use the user one.
                    // Otherwise, use the one from the concurrent.
                    bool useUser = false;

                    RemoteArtifactCustomProperty orig = original.CustomProperties.SingleOrDefault(cp => cp.PropertyNumber == prop.PropertyNumber);

                    if (orig != null)
                    {
                        RemoteArtifactCustomProperty concur = serverModded.CustomProperties.SingleOrDefault(cp => cp.PropertyNumber == prop.PropertyNumber);

                        switch (prop.Definition.CustomPropertyTypeId)
                        {
                        case 1:                                 // String (String)
                        case 9:                                 // URL (String)
                            if (prop.StringValue.Equals(orig.StringValue))
                            {
                                retList.Add(concur);
                            }
                            else
                            {
                                retList.Add(prop);
                            }
                            break;

                        case 2:                                 // Integer (Int)
                        case 6:                                 // List (Int)
                        case 8:                                 // User (Int)
                            if (prop.IntegerValue.Equals(orig.IntegerValue))
                            {
                                retList.Add(concur);
                            }
                            else
                            {
                                retList.Add(prop);
                            }
                            break;

                        case 3:                                 // Decimal (Decimal)
                            if (prop.DecimalValue.Equals(orig.DecimalValue))
                            {
                                retList.Add(concur);
                            }
                            else
                            {
                                retList.Add(prop);
                            }
                            break;

                        case 4:                                 // Boolean (Bool)
                            if (prop.BooleanValue.Equals(orig.BooleanValue))
                            {
                                retList.Add(concur);
                            }
                            else
                            {
                                retList.Add(prop);
                            }
                            break;

                        case 5:                                 // DateTime (DateTime)
                            if (prop.DateTimeValue.Equals(orig.DateTimeValue))
                            {
                                retList.Add(concur);
                            }
                            else
                            {
                                retList.Add(prop);
                            }
                            break;

                        case 7:                                 // Multilist (List<int>)
                            prop.IntegerListValue.Sort();
                            orig.IntegerListValue.Sort();
                            if (prop.IntegerListValue.SequenceEqual(orig.IntegerListValue))
                            {
                                retList.Add(concur);
                            }
                            else
                            {
                                retList.Add(prop);
                            }
                            break;
                        }
                    }
                    else
                    {
                        useUser = true;
                    }
                }
            }

            return(retList);
        }
コード例 #2
0
        /// <summary>Checks the given properties on the artifact the user is modifying against the given artifact to report wether the fields can be merged or not.</summary>
        /// <param name="original">The original artifact before any edits.</param>
        /// <param name="serverModded">The new artifact form the server - edited by someone else.</param>
        /// <param name="userEntered">The modified artifact from our user.</param>
        /// <returns>True if fields can be merged. False otherwise.</returns>
        private static bool CanCustomPropertiesBeMergedWith(this RemoteArtifact userEntered, RemoteArtifact original, RemoteArtifact serverModded)
        {
            bool retValue = false;

            //Loop through custom fields..
            foreach (RemoteArtifactCustomProperty newProp in userEntered.CustomProperties)
            {
                //See if the user changed this property.
                RemoteArtifactCustomProperty origProp = original.CustomProperties.FirstOrDefault(cp => cp.PropertyNumber == newProp.PropertyNumber);

                bool userChanged  = false;
                bool otherChanged = false;
                if (origProp == null)
                {
                    userChanged = true;
                }
                else
                {
                    //Pull the original value..
                    switch (newProp.Definition.CustomPropertyTypeId)
                    {
                    case 1:                             // String (String)
                    case 9:                             // URL (String)
                        userChanged = (newProp.StringValue.Equals(origProp.StringValue));
                        break;

                    case 2:                             // Integer (Int)
                    case 6:                             // List (Int)
                    case 8:                             // User (Int)
                        userChanged = (newProp.IntegerValue.Equals(origProp.IntegerValue));
                        break;

                    case 3:                             // Decimal (Decimal)
                        userChanged = (newProp.DecimalValue.Equals(origProp.DecimalValue));
                        break;

                    case 4:                             // Boolean (Bool)
                        userChanged = (newProp.BooleanValue.Equals(origProp.BooleanValue));
                        break;

                    case 5:                             // DateTime (DateTime)
                        userChanged = (newProp.DateTimeValue.Equals(origProp.DateTimeValue));
                        break;

                    case 7:                             // Multilist (List<int>)
                        newProp.IntegerListValue.Sort();
                        origProp.IntegerListValue.Sort();
                        userChanged = (newProp.IntegerListValue.SequenceEqual(origProp.IntegerListValue));
                        break;
                    }
                }

                //If the user changed the field, check to see if the remote user also changed the field.
                // If so, then we can't merge.
                if (userChanged)
                {
                    RemoteArtifactCustomProperty remProp = serverModded.CustomProperties.FirstOrDefault(cp => cp.PropertyNumber == newProp.PropertyNumber);

                    if (remProp == null)
                    {
                        //If the original was null, (unset) and this one isn't, we don't care at checking values.
                        if (origProp != null)
                        {
                            otherChanged = true;
                        }
                    }
                    else
                    {
                        //Pull the original value..
                        switch (remProp.Definition.CustomPropertyTypeId)
                        {
                        case 1:                                 // String (String)
                        case 9:                                 // URL (String)
                            otherChanged = (remProp.StringValue.Equals(origProp.StringValue));
                            break;

                        case 2:                                 // Integer (Int)
                        case 6:                                 // List (Int)
                        case 8:                                 // User (Int)
                            otherChanged = (remProp.IntegerValue.Equals(origProp.IntegerValue));
                            break;

                        case 3:                                 // Decimal (Decimal)
                            otherChanged = (remProp.DecimalValue.Equals(origProp.DecimalValue));
                            break;

                        case 4:                                 // Boolean (Bool)
                            otherChanged = (remProp.BooleanValue.Equals(origProp.BooleanValue));
                            break;

                        case 5:                                 // DateTime (DateTime)
                            otherChanged = (remProp.DateTimeValue.Equals(origProp.DateTimeValue));
                            break;

                        case 7:                                 // Multilist (List<int>)
                            remProp.IntegerListValue.Sort();
                            origProp.IntegerListValue.Sort();
                            otherChanged = (remProp.IntegerListValue.SequenceEqual(origProp.IntegerListValue));
                            break;
                        }
                    }
                }

                //Now set our final value.
                if (userChanged && otherChanged)
                {
                    retValue = false;
                    //Escape early..
                    break;
                }
                else
                {
                    retValue = true;
                }
            }

            return(retValue);
        }
コード例 #3
0
        /// <summary>
        /// Sets a custom property value on an artifact, even if it doesn't have an entry yet, can handle the various types
        /// </summary>
        /// <param name="remoteArtifact">The artifact we're setting the properties on</param>
        /// <param name="propertyNumber">The position number (1-30) of the custom property</param>
        /// <param name="propertyValue">The typed property value</param>
        /// <returns>True if any changes were made</returns>
        public static bool SetCustomPropertyValue <T>(RemoteArtifact remoteArtifact, int propertyNumber, T propertyValue, bool changesMade = false)
        {
            //First see if we have any custom properties at all for this artifact, if not, create a collection
            List <RemoteArtifactCustomProperty> artifactCustomProperties;

            if (remoteArtifact.CustomProperties == null)
            {
                artifactCustomProperties = new List <RemoteArtifactCustomProperty>();
            }
            else
            {
                artifactCustomProperties = remoteArtifact.CustomProperties.ToList();
            }

            //Now see if we have a matching property already in the list
            RemoteArtifactCustomProperty artifactCustomProperty = artifactCustomProperties.FirstOrDefault(c => c.PropertyNumber == propertyNumber);

            if (artifactCustomProperty == null)
            {
                artifactCustomProperty = new RemoteArtifactCustomProperty();
                artifactCustomProperty.PropertyNumber = propertyNumber;
                artifactCustomProperties.Add(artifactCustomProperty);
            }

            //Set the value that matches this type
            if (typeof(T) == typeof(String))
            {
                string newValue = ((T)propertyValue as String);
                if (artifactCustomProperty.StringValue != newValue)
                {
                    artifactCustomProperty.StringValue = newValue;
                    changesMade = true;
                }
            }
            if (typeof(T) == typeof(Int32) || typeof(T) == typeof(Nullable <Int32>))
            {
                int?newValue = ((T)propertyValue as Int32?);
                if (artifactCustomProperty.IntegerValue != newValue)
                {
                    artifactCustomProperty.IntegerValue = newValue;
                    changesMade = true;
                }
            }

            if (typeof(T) == typeof(Boolean) || typeof(T) == typeof(Nullable <Boolean>))
            {
                bool?newValue = ((T)propertyValue as bool?);
                if (artifactCustomProperty.BooleanValue != newValue)
                {
                    artifactCustomProperty.BooleanValue = newValue;
                    changesMade = true;
                }
            }

            if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(Nullable <DateTime>))
            {
                DateTime?newValue = ((T)propertyValue as DateTime?);
                if (artifactCustomProperty.DateTimeValue != newValue)
                {
                    artifactCustomProperty.DateTimeValue = newValue;
                    changesMade = true;
                }
            }

            if (typeof(T) == typeof(Decimal) || typeof(T) == typeof(Nullable <Decimal>))
            {
                decimal?newValue = ((T)propertyValue as Decimal?);
                if (artifactCustomProperty.DecimalValue != newValue)
                {
                    artifactCustomProperty.DecimalValue = newValue;
                    changesMade = true;
                }
            }

            if (typeof(T) == typeof(Int32[]))
            {
                int[] newValue = ((T)propertyValue as Int32[]);
                if (newValue == null || newValue.Length == 0)
                {
                    if (artifactCustomProperty.IntegerListValue != null && artifactCustomProperty.IntegerListValue.Length > 0)
                    {
                        artifactCustomProperty.IntegerListValue = null;
                        changesMade = true;
                    }
                }
                else if (artifactCustomProperty.IntegerListValue == null || artifactCustomProperty.IntegerListValue.Length == 0)
                {
                    artifactCustomProperty.IntegerListValue = newValue;
                    changesMade = true;
                }
                else if (newValue.Any(v => !artifactCustomProperty.IntegerListValue.Contains(v)) || artifactCustomProperty.IntegerListValue.Any(v => !newValue.Contains(v)))
                {
                    artifactCustomProperty.IntegerListValue = newValue;
                    changesMade = true;
                }
            }

            if (typeof(T) == typeof(List <Int32>))
            {
                List <Int32> intList = (List <Int32>)((T)propertyValue as List <Int32>);
                if (intList == null || intList.Count == 0)
                {
                    if (artifactCustomProperty.IntegerListValue != null && artifactCustomProperty.IntegerListValue.Length > 0)
                    {
                        artifactCustomProperty.IntegerListValue = null;
                        changesMade = true;
                    }
                }
                else if (artifactCustomProperty.IntegerListValue == null || artifactCustomProperty.IntegerListValue.Length == 0)
                {
                    artifactCustomProperty.IntegerListValue = intList.ToArray();
                    changesMade = true;
                }
                else if (intList.Any(v => !artifactCustomProperty.IntegerListValue.Contains(v)) || artifactCustomProperty.IntegerListValue.Any(v => !intList.Contains(v)))
                {
                    artifactCustomProperty.IntegerListValue = intList.ToArray();
                    changesMade = true;
                }
            }

            //Finally we need to update the artifact's array
            remoteArtifact.CustomProperties = artifactCustomProperties.ToArray();

            return(changesMade);
        }
コード例 #4
0
        /// <summary>
        /// Sets a custom property value on an artifact, even if it doesn't have an entry yet, can handle the various types
        /// </summary>
        /// <param name="remoteArtifact">The artifact we're setting the properties on</param>
        /// <param name="propertyNumber">The position number (1-30) of the custom property</param>
        /// <param name="propertyValue">The typed property value</param>
        public static void SetCustomPropertyValue <T>(RemoteArtifact remoteArtifact, int propertyNumber, T propertyValue)
        {
            //First see if we have any custom properties at all for this artifact, if not, create a collection
            List <RemoteArtifactCustomProperty> artifactCustomProperties;

            if (remoteArtifact.CustomProperties == null)
            {
                artifactCustomProperties = new List <RemoteArtifactCustomProperty>();
            }
            else
            {
                artifactCustomProperties = remoteArtifact.CustomProperties.ToList();
            }

            //Now see if we have a matching property already in the list
            RemoteArtifactCustomProperty artifactCustomProperty = artifactCustomProperties.FirstOrDefault(c => c.PropertyNumber == propertyNumber);

            if (artifactCustomProperty == null)
            {
                artifactCustomProperty = new RemoteArtifactCustomProperty();
                artifactCustomProperty.PropertyNumber = propertyNumber;
                artifactCustomProperties.Add(artifactCustomProperty);
            }

            //Set the value that matches this type
            if (typeof(T) == typeof(String))
            {
                artifactCustomProperty.StringValue = ((T)propertyValue as String);
            }
            if (typeof(T) == typeof(Int32) || typeof(T) == typeof(Nullable <Int32>))
            {
                artifactCustomProperty.IntegerValue = ((T)propertyValue as Int32?);
            }

            if (typeof(T) == typeof(Boolean) || typeof(T) == typeof(Nullable <Boolean>))
            {
                artifactCustomProperty.BooleanValue = ((T)propertyValue as bool?);
            }

            if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(Nullable <DateTime>))
            {
                artifactCustomProperty.DateTimeValue = ((T)propertyValue as DateTime?);
            }

            if (typeof(T) == typeof(Decimal) || typeof(T) == typeof(Nullable <Decimal>))
            {
                artifactCustomProperty.DecimalValue = ((T)propertyValue as Decimal?);
            }

            if (typeof(T) == typeof(Int32[]))
            {
                artifactCustomProperty.IntegerListValue = ((T)propertyValue as Int32[]);
            }

            if (typeof(T) == typeof(List <Int32>))
            {
                List <Int32> intList = (List <Int32>)((T)propertyValue as List <Int32>);
                if (intList == null || intList.Count == 0)
                {
                    artifactCustomProperty.IntegerListValue = null;
                }
                else
                {
                    artifactCustomProperty.IntegerListValue = intList.ToArray();
                }
            }

            //Finally we need to update the artifact's array
            remoteArtifact.CustomProperties = artifactCustomProperties.ToArray();
        }
        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.");
            }
        }