void UpdateMessage(Message message, Conversation conversation)
        {
            message.ConversationIdentifier = conversation.ConversationIdentifier;
            ClientState.Current.DataService.Update(message);

            Thread.CurrentThread.ExecuteOnUIThread(() => conversation.Add(message));
        }
Exemple #2
0
        void LoadConversations()
        {
            using (new CodeTimer("VirtualMailBox/Load/Conversations"))
            {
                const string query = "select ConversationId, ConversationIdentifier, Context from Conversations";

                using (var reader = ClientState.Current.DataService.ExecuteReader(query))
                {
                    while (reader.Read())
                    {
                        var conversation = new Conversation(reader);

                        conversations.Add(conversation);
                        keyedConversations.Add(conversation.ConversationIdentifier, conversation);
                    }
                }
            }
        }
        /// <summary>
        /// Matches the conversation on the the subject field.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="conversation">The conversation.</param>
        /// <returns></returns>
        ExecutionResult MatchOnSubject(Message message, out Conversation conversation)
        {
            if (message.MessageFolder == Folders.SentItems)
            {
                Logger.Debug("MatchOnSubject: Message {0} is a sent item. Creating new conversation because it is not a reply but a new message", LogSource.MessageMatcher, message);

                conversation = CreateNewConversation(message);

                return ExecutionResult.Break;
            }

            if (message.MessageFolder == Folders.Drafts)
            {
                Logger.Debug("MatchOnSubject: Message {0} is a concept message. Creating new conversation", LogSource.MessageMatcher, message);

                conversation = CreateNewConversation(message);

                return ExecutionResult.Break;
            }

            if (String.IsNullOrEmpty(message.Context) || String.IsNullOrEmpty(message.Context.ToClearSubject()) || message.Context.Trim().Length == 0)
            {
                Logger.Debug("MatchOnSubject: Message {0} has an empty context. Creating new conversation", LogSource.MessageMatcher, message);

                conversation = CreateNewConversation(message);

                return ExecutionResult.Break;
            }

            Logger.Debug("MatchOnSubject: trying to find conversation for Message {0} with Context {1}", LogSource.MessageMatcher, message, message.Context.ToClearSubject());

            string context = message.Context.ToClearSubject();

            // Determine if the recipients in the message match with the current recipients
            List<Message> messagesWithSameContext;

            using (mailbox.Messages.ReaderLock)
                messagesWithSameContext = mailbox.Messages.Where(
                    m => m.MessageId != message.MessageId && (m.Context == context || m.Context.ToClearSubject() == context))
                    .ToList();

            string conversationId = null;

            var recentRelatedMessage = messagesWithSameContext.Where(m => DateTime.Compare((m.SortDate).AddDays(3), DateTime.Now) >= 0).FirstOrDefault();

            if (recentRelatedMessage != null)
            {
                conversationId = recentRelatedMessage.ConversationIdentifier;
            }
            else
            {
                if (message.MessageFolder == Folders.Inbox)
                {
                    if (messagesWithSameContext.Count > 0)
                    {
                        // This is an incoming message
                        SourceAddress from = message.From;
                        bool isEmailChannel = SourceAddress.IsValidEmail(from.Address);

                        //Get all channels for user
                        var addresses = ChannelsManager
                            .Channels
                            .Where(c => c.InputChannel != null)
                            .Select(c => c.InputChannel.SourceAdress)
                            .ToList();

                        foreach (var contextMessage in messagesWithSameContext)
                        {
                            var addressCollection = new SourceAddressCollection();
                            addressCollection.AddRange(contextMessage.To);
                            addressCollection.AddRange(contextMessage.CC);
                            addressCollection.AddRange(contextMessage.BCC);
                            addressCollection.Add(contextMessage.From);

                            if (addressCollection.Contains(from, new SourceAddressComparer()))
                            {
                                bool hasMatchedConversation = false;

                                if (message.To.Count(
                                        c => addresses.Contains(c.Address) || addressCollection.Contains(c)) > 0)
                                    hasMatchedConversation = true;

                                if (!hasMatchedConversation && !isEmailChannel)
                                {
                                    if (message.To.Count(addressCollection.Contains) > 0)
                                        hasMatchedConversation = true;
                                }

                                if (hasMatchedConversation)
                                {
                                    conversationId = contextMessage.ConversationIdentifier;
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            if (String.IsNullOrEmpty(conversationId))
            {
                Logger.Debug("MatchOnSubject: Message {0} has no matching conversation, creating a new one", LogSource.MessageMatcher, message);

                // Nothing found, create new conversation
                conversation = CreateNewConversation(message);
            }
            else
            {
                using (mailbox.Conversations.ReaderLock)
                    conversation = mailbox.Conversations.FirstOrDefault(c => c.ConversationIdentifier == conversationId);

                Logger.Debug("MatchOnSubject: Message {0} has matching conversation with ConversationId {1}", LogSource.MessageMatcher, message, conversation.ConversationId);

                UpdateMessage(message, conversation);

                Logger.Debug("MatchOnSubject: Message {0} now has ConversationId {1}", LogSource.MessageMatcher, message, message.ConversationIdentifier);
            }

            // End of line
            return ExecutionResult.Break;
        }
 /// <summary>
 /// Updates the conversation.
 /// </summary>
 /// <param name="conversation">The conversation.</param>
 void UpdateConversation(Conversation conversation)
 {
     conversation.UpdateProperty("Last");
     conversation.UpdateProperty("ProcessingHints");
     conversation.UpdateProperty("TotalMessageCount");
 }
        /// <summary>
        /// Matches the conversation on the in reply to field.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="conversation">The conversation.</param>
        /// <returns></returns>
        ExecutionResult MatchOnInReplyTo(Message message, out Conversation conversation, int nrtry)
        {
            conversation = null;

            if (String.IsNullOrEmpty(message.InReplyTo))
                return ExecutionResult.Continue;

            Logger.Debug("MatchOnInReplyTo: Message {0} had In-Reply-To {1}", LogSource.MessageMatcher, message, message.InReplyTo);

            Message msg;

            using (mailbox.Messages.ReaderLock)
                msg = mailbox.Messages.FirstOrDefault(m => m.MessageIdentifier == message.InReplyTo);

            if (msg != null)
            {
                // Update source message stats
                msg.TrackAction(ActionType.ReplyForward, message.SortDate);

                // Found a conversationId
                using (mailbox.Conversations.ReaderLock)
                    conversation = mailbox.Conversations.FirstOrDefault(c => c.ConversationIdentifier == msg.ConversationIdentifier);

                if (conversation == null)
                {
                    if (nrtry == 3)
                    {
                        // We are unable to find the conversation after two tries,
                        // match the message being replied to, to fix this.
                        Match(msg);

                        return MatchOnInReplyTo(message, out conversation, ++nrtry);
                    }

                    // Seems we have a conversationId but the actual conversation has not been written to disk yet
                    // Sleep for 500 ms and then try again
                    Thread.Sleep(500);

                    return MatchOnInReplyTo(message, out conversation, ++nrtry);
                }

                Logger.Debug("MatchOnInReplyTo: Found conversation with ConversationIdentifier [{0}] for Message {1}", LogSource.MessageMatcher, conversation, message);

                UpdateMessage(message, conversation);

                return ExecutionResult.Break;
            }

            // Continue as our other rules might generate a hit
            return ExecutionResult.Continue;
        }
        /// <summary>
        /// Matches the conversation on the conversation id field.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="conversation">The conversation.</param>
        /// <returns></returns>
        ExecutionResult MatchOnConversationId(Message message, out Conversation conversation)
        {
            conversation = null;

            if (String.IsNullOrEmpty(message.ConversationIdentifier))
                return ExecutionResult.Continue;

            Logger.Debug("MatchOnConversationId: Message {0} had ConversationIdentifier {1}", LogSource.MessageMatcher, message, message.ConversationIdentifier);

            // Retreive conversation from database
            using (mailbox.Conversations.ReaderLock)
                conversation = mailbox.Conversations.FirstOrDefault(c => c.ConversationIdentifier == message.ConversationIdentifier);

            if (conversation == null)
            {
                Logger.Debug("MatchOnConversationId: Conversation did not exist, creating a new one with ConversationIdentifier {0}", LogSource.MessageMatcher, message.ConversationIdentifier);

                // Not found, create new one
                conversation = CreateNewConversation(message);
            }
            else
            {
                UpdateMessage(message, conversation);
            }

            return ExecutionResult.Break;
        }
        /// <summary>
        /// Creates a new conversation.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        Conversation CreateNewConversation(Message message)
        {
            var conversation = new Conversation();

            string conversationId = message.ConversationIdentifier;

            if (String.IsNullOrEmpty(message.ConversationIdentifier))
            {
                // Create new conversation id
                conversationId = Guid.NewGuid().ToConversationId();
            }

            conversation.ConversationIdentifier = conversationId;
            conversation.Context = message.Context.ToClearSubject();

            ClientState.Current.DataService.Save(conversation);

            Logger.Debug("Conversation {0} was created successfully", LogSource.MessageMatcher, conversation);
            Logger.Debug("Message {0} now has ConversationIdentifier {1}", LogSource.MessageMatcher, message, conversationId);

            UpdateMessage(message, conversation);

            return conversation;
        }
 void UpdateMessage(Message message, Conversation conversation)
 {
     message.ConversationIdentifier = conversation.ConversationIdentifier;
     ClientState.Current.DataService.Update(message);
 }
        /// <summary>
        /// Matches the conversation on the conversation id field.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="conversation">The conversation.</param>
        /// <returns></returns>
        ExecutionResult MatchOnConversationId(Message message, out Conversation conversation)
        {
            conversation = null;

            if (String.IsNullOrEmpty(message.ConversationIdentifier))
                return ExecutionResult.Continue;

            Logger.Debug("MatchOnConversationId: Message {0} had ConversationIdentifier {1}", LogSource.MessageMatcher, message, message.ConversationIdentifier);

            // Retreive conversation from database
            conversation = dataService.SelectBy<Conversation>(new { ConversationIdentifier = message.ConversationIdentifier });

            if (conversation == null)
            {
                Logger.Debug("MatchOnConversationId: Conversation did not exist, creating a new one with ConversationIdentifier {0}", LogSource.MessageMatcher, message.ConversationIdentifier);

                // Not found, create new one
                conversation = CreateNewConversation(message);
            }
            else
            {
                UpdateMessage(message, conversation);
            }

            return ExecutionResult.Break;
        }