public void Show(Message message)
        {
            this.message = message;

            RockScroll.Value = 0;
            timer.IsEnabled = true;
        }
示例#2
0
        public static void Delete(Message source)
        {
            var oldMessage = source.DuckCopy<Message>();

            #region Do action

            Action doAction = delegate
              	{
              		source.MessageFolder = Folders.Trash;
              		source.TargetMessageState = EntityStates.Deleted;

                    AsyncUpdateQueue.Enqueue(source);
              	};

            #endregion

            #region Undo action

            Action undoAction = delegate
                {
                    source.MessageFolder = oldMessage.MessageFolder;
                    source.TargetMessageState = oldMessage.TargetMessageState;

                    AsyncUpdateQueue.Enqueue(source);
                };

            #endregion

            ClientState.Current.UndoManager.Execute(new HistoryAction(doAction, undoAction));
        }
 public UpdateMessageStateTask(ChannelConfiguration config, IReadStateChannel channel, List<ChannelFolder> availableFolders, Message message)
 {
     this.config = config;
     this.channel = channel;
     this.availableFolders = availableFolders;
     this.message = message;
 }
示例#4
0
        /// <summary>
        /// Matches the message to a conversation.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        internal Conversation MatchToConversation(Message message)
        {
            Logger.Debug("Trying to match conversation for message {0}", LogSource.MessageMatcher, message);

            Conversation conversation;

            if (MatchOnConversationId(message, out conversation) == ExecutionResult.Break)
            {
                UpdateConversation(conversation);

                return conversation;
            }

            if (MatchOnInReplyTo(message, out conversation, 1) == ExecutionResult.Break)
            {
                UpdateConversation(conversation);

                return conversation;
            }

            if (MatchOnSubject(message, out conversation) == ExecutionResult.Break)
            {
                UpdateConversation(conversation);

                return conversation;
            }

            throw new ApplicationException("Unable to match message to conversation!");
        }
示例#5
0
 public static void Forward(Message source)
 {
     ClientState.Current.ViewController.MoveTo(
         PluginsManager.Current.GetPlugin<ConversationsPlugin>().NewItemView,
         new NewMessageDataHelper
             {
                 SourceMessageId = source.MessageId,
                 Context = "Fw: " + source.Context,
                 Body = MessageBodyGenerator.CreateBodyTextForForward(source, true),
                 AttachedFiles = source.Documents.Select(d => new AttachmentDataHelper(d)).ToList()
             });
 }
        public ClientMessageAccess(Message message)
        {
            this.message = message;

            if (message.BodyHtmlStreamName.HasValue)
                using (var s = ClientState.Current.Storage.Read("m", message.BodyHtmlStreamName.ToString()))
                    bodyHtml = s.ReadString();

            if (message.BodyTextStreamName.HasValue)
                using (var s = ClientState.Current.Storage.Read("m", message.BodyTextStreamName.ToString()))
                    bodyText = s.ReadString();
        }
示例#7
0
 public static void Reply(Message source)
 {
     ClientState.Current.ViewController.MoveTo(
         PluginsManager.Current.GetPlugin<ConversationsPlugin>().NewItemView,
         new NewMessageDataHelper
             {
                 SourceMessageId = source.MessageId,
                 SelectedChannelId = source.SourceChannelId,
                 Context = "Re: " + source.Context,
                 To = source.From.ToList(),
                 Body = MessageBodyGenerator.CreateBodyTextForReply(source, true)
             });
 }
示例#8
0
        public void Show(Message message)
        {
            // This is for our fake message
            if (message.MessageId < 0)
            {
                return;
            }

            this.message = message;

            QuickReplyAll.Text = String.Empty;

            // if document hasn't loaded (the first time), loadcomplete will take care of show for us
            if (initialized)
            {
                BuildAndShowMessage();
            }

            // When message is shown due to system selection, do not track the read action
            if (!ThreadFlag.IsSet)
            {
                message.TrackAction(ActionType.Read);
            }

            if (flipper != null)
            {
                flipper.Dispose();
            }

            // Mark message read if after setting is enabled
            var markReadAFter = SettingsManager.ClientSettings.AppConfiguration.MarkReadWhenViewingAfter;

            if (markReadAFter.HasValue)
            {
                flipper = new Flipper(TimeSpan.FromSeconds(markReadAFter.Value), delegate
                {
                    if (!message.IsRead)
                    {
                        message.MarkRead();
                    }
                });

                flipper.Delay();
            }
            else if (SettingsManager.ClientSettings.AppConfiguration.MarkReadWhenViewing)
            {
                message.MarkRead();
            }

            OnPropertyChanged("Message");
        }
示例#9
0
        public static void MessageStored(Message message)
        {
            var mailbox = VirtualMailBox.Current;

            // Match thread
            MessageMatcher.Match(message);

            mailbox.Messages.Add(message);

            ViewFilter.Current.UpdateCurrentViewAsync();

            // Add to search index
            ClientState.Current.Search.Store(message);
        }
        static string GetMessageHtmlView(Message source)
        {
            // Hack: load core assembly directly (should be in memory anyway)
            Assembly asm = Assembly.LoadFrom("Inbox2.Core.Streams.dll");

            //Load HTML File:
            Stream htmlFile = asm.GetManifestResourceStream("Inbox2.Core.Streams.ThreadView.html");
            string path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

            var access = new ClientMessageAccess(source);
            var sanitized = HtmlSanitizer.Sanitize(access.GetBestBodyMatch(TextConversion.ToHtml));

            return htmlFile.ReadString()
                .Replace("#rootfolder#", "file://" + path.Replace("\\", "//") + "/")
                .Replace("#Title#", HttpUtility.HtmlEncode(source.Context))
                .Replace("#HtmlSource#", sanitized);
        }
        protected virtual bool CheckReadStates(Message message, ChannelMessageHeader header)
        {
            // Channel doesn't support readstates, no point in checking
            if (!config.Charasteristics.SupportsReadStates)
                return false;

            // Message has been marked for channel update, ignore for now
            if (message.TargetMessageState.HasValue)
                return false;

            // Check readstate of message
            if (header.IsRead)
            {
                if (!message.IsRead)
                    message.MarkRead(false);
            }
            else
            {
                if (message.IsRead)
                    message.MarkUnread(false);
            }

            if (header.IsStarred)
            {
                // Star
                if (!message.IsStarred)
                    message.SetStarred(false);
            }
            else
            {
                // Unstar
                if (message.IsStarred)
                    message.SetUnstarred(false);
            }

            return true;
        }
        void SaveDocuments(Message message, bool isDraft)
        {
            if (isDraft)
            {
                // Delete old attachments from message, will be re-added again below
                SourceMessage.Documents.ToList()
                    .ForEach(d => d.DeleteFrom(SourceMessage));
            }

            // Add attachments to message
            foreach (var file in attachedFiles)
            {
                var document = new Document
                {
                    Message = message,
                    Filename = file.Filename,
                    ContentType = ContentType.Attachment,
                    SourceChannelId = message.SourceChannelId,
                    DateCreated = DateTime.Now,
                    DateSent = DateTime.Now,
                    DocumentFolder = Folders.SentItems
                };

                document.StreamName = Guid.NewGuid().GetHash(12) + "_" + Path.GetExtension(document.Filename);
                document.ContentStream = new FileStream(file.Streamname, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                EventBroker.Publish(AppEvents.DocumentReceived, document);

                // Might needs this when deleting an attachment from a draft message
                file.DocumentId = document.DocumentId;
            }
        }
 public SendMessageCommand(Message message)
 {
     this.message = message;
     this.mailbox = VirtualMailBox.Current;
 }
示例#14
0
        /// <summary>
        /// Creates a new conversation.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        Conversation CreateNewConversation(Message message)
        {
            Conversation conversation = DispatcherActivator<Conversation>.Create();

            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);

            Debug.Assert(!String.IsNullOrEmpty(message.ConversationIdentifier), "Message can not have an empty ConversationIdentifier!");

            mailbox.Conversations.Add(conversation);

            return conversation;
        }
示例#15
0
 /// <summary>
 /// Matches the specified message.
 /// </summary>
 /// <param name="message">The message.</param>
 /// <returns></returns>
 public static Conversation Match(Message message)
 {
     return new MessageMatcher().MatchToConversation(message);
 }
示例#16
0
 public ProfileMatcher(Message message)
 {
     this.message = message;
     this.mailbox = VirtualMailBox.Current;
 }
 public ClientMessageAccess(Message message, string bodyText, string bodyHtml)
 {
     this.message = message;
     this.bodyText = bodyText;
     this.bodyHtml = bodyHtml;
 }
        public void Show(Message message)
        {
            // This is for our fake message
            if (message.MessageId < 0)
                return;

            this.message = message;

            QuickReplyAll.Text = String.Empty;

            // if document hasn't loaded (the first time), loadcomplete will take care of show for us
            if (initialized)
                BuildAndShowMessage();

            // When message is shown due to system selection, do not track the read action
            if (!ThreadFlag.IsSet)
                message.TrackAction(ActionType.Read);

            if (flipper != null)
                flipper.Dispose();

            // Mark message read if after setting is enabled
            var markReadAFter = SettingsManager.ClientSettings.AppConfiguration.MarkReadWhenViewingAfter;

            if (markReadAFter.HasValue)
            {
                flipper = new Flipper(TimeSpan.FromSeconds(markReadAFter.Value), delegate
                {
                    if (!message.IsRead)
                        message.MarkRead();
                });

                flipper.Delay();
            }
            else if (SettingsManager.ClientSettings.AppConfiguration.MarkReadWhenViewing)
                message.MarkRead();

            OnPropertyChanged("Message");
        }
示例#19
0
 public ProfileMatcher(Message message)
 {
     this.message = message;
     this.dataService = ClientState.Current.DataService;
 }
示例#20
0
        void UpdateMessage(Message message, Conversation conversation)
        {
            message.ConversationIdentifier = conversation.ConversationIdentifier;
            ClientState.Current.DataService.Update(message);

            Thread.CurrentThread.ExecuteOnUIThread(() => conversation.Add(message));
        }
        void Send_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ClientStats.LogEvent("Quick reply all send");

            if (String.IsNullOrEmpty(QuickReplyAll.Text.Trim()))
                return;

            var newMessage = new Message();

            #region Create message

            var channel = message.SourceChannelId == 0 ?
                ChannelsManager.GetDefaultChannel() :
                ChannelsManager.GetChannelObject(Message.SourceChannelId);

            var recipients = new SourceAddressCollection();
            var sourceAddress = channel.InputChannel.GetSourceAddress();

            recipients.Add(Message.From);
            recipients.AddRange(Message.To);

            // Remove our own address from recipient list
            if (recipients.Contains(sourceAddress))
                recipients.Remove(sourceAddress);

            newMessage.InReplyTo = Message.MessageIdentifier;
            newMessage.ConversationIdentifier = Message.ConversationIdentifier;
            newMessage.Context = "Re: " + Message.Context;
            newMessage.From = channel.InputChannel.GetSourceAddress();
            newMessage.TargetChannelId = channel.Configuration.ChannelId;
            newMessage.To.AddRange(recipients);
            newMessage.CC.AddRange(Message.CC);

            var access = new ClientMessageAccess(newMessage, null,
                MessageBodyGenerator.CreateBodyTextForReply(Message, QuickReplyAll.Text.Nl2Br()));

            newMessage.BodyHtmlStreamName = access.WriteBodyHtml();
            newMessage.BodyPreview = access.GetBodyPreview();
            newMessage.IsRead = true;
            newMessage.DateSent = DateTime.Now;
            newMessage.MessageFolder = Folders.SentItems;
            newMessage.DateSent = DateTime.Now;
            newMessage.DateCreated = DateTime.Now;

            #endregion

            #region Send message

            ClientState.Current.DataService.Save(newMessage);

            // Add message to mailbox
            EventBroker.Publish(AppEvents.MessageStored, newMessage);

            // Save command
            CommandQueue.Enqueue(AppCommands.SendMessage, newMessage);

            if (!NetworkInterface.GetIsNetworkAvailable())
            {
                ClientState.Current.ShowMessage(
                    new AppMessage(Strings.MessageWillBeSentLater)
                        {
                            EntityId = newMessage.MessageId.Value,
                            EntityType = EntityType.Message
                        }, MessageType.Success);
            }

            QuickReplyAll.Text = String.Empty;

            message.TrackAction(ActionType.ReplyForward);

            #endregion
        }
示例#22
0
 public static void MessageStored(Message message)
 {
     new ProfileMatcher(message).Execute();
 }
示例#23
0
        bool FilterMessage(Message message)
        {
            if (message == null)
                return false;

            // For our fake message work-around
            if (message.MessageId == -1)
                return true;

            // This is a expunged message
            if (message.ConversationIdentifier == "-1")
                return false;

            // Break out if source/target channel is not visible
            if (!message.IsChannelVisible)
                return false;

            if (Filter.CurrentView == ActivityView.MyInbox && message.Conversation.Messages.Count(m => m.MessageFolder != Folders.SentItems) == 0)
                return false;

            if (Filter.CurrentView == ActivityView.MyInbox &&
                (message.MessageFolder == Folders.Trash
                    || message.MessageFolder == Folders.Archive
                    || message.MessageFolder == Folders.Drafts
                    || message.MessageFolder == Folders.Spam))
                return false;

            if (Filter.CurrentView == ActivityView.Archive && message.MessageFolder != Folders.Archive)
                return false;

            if (Filter.CurrentView == ActivityView.Received && message.MessageFolder != Folders.Inbox)
                return false;

            if (Filter.CurrentView == ActivityView.Sent && message.MessageFolder != Folders.SentItems)
                return false;

            if (Filter.CurrentView == ActivityView.Drafts && message.MessageFolder != Folders.Drafts)
                return false;

            if (Filter.CurrentView == ActivityView.Trash && message.MessageFolder != Folders.Trash)
                return false;

            if (Filter.CurrentView == ActivityView.Starred && message.IsStarred == false)
                return false;

            if (Filter.CurrentView == ActivityView.Unread && (message.IsRead ||
                message.MessageFolder == Folders.Trash || message.MessageFolder == Folders.Spam))
                return false;

            if (Filter.CurrentView == ActivityView.Todo && message.IsTodo == false)
                return false;

            if (Filter.CurrentView == ActivityView.WaitingFor && message.IsWaitingFor == false)
                return false;

            if (Filter.CurrentView == ActivityView.Someday && message.IsSomeday == false)
                return false;

            if (Filter.CurrentView == ActivityView.Label && (message.IsTrash || message.HasLabel(Filter.Label) == false))
                return false;

            return true;
        }
示例#24
0
        public void DeleteFrom(Message message)
        {
            var mailbox = VirtualMailBox.Current;

            // Get all versions associated with the message we want to detach
            // this document from.
            var versionsForMessage = Versions
                .Where(v => v.MessageId == message.MessageId.Value)
                .ToList();

            // Remove all versions for this message
            foreach (var version in versionsForMessage)
            {
                Versions.Remove(version);

                ClientState.Current.DataService.Delete(version);
            }

            if (Versions.Count == 0)
            {
                // No versions left, delete document and stream from disk
                ClientState.Current.Storage.Delete(".", StreamName);

                // todo remove stream from search-index

                using (mailbox.Documents.WriterLock)
                    mailbox.Documents.Remove(this);

                ClientState.Current.DataService.Delete(this);
            }

            message.Documents.Remove(this);
        }
示例#25
0
        public static void ReplyAll(Message source, string text)
        {
            var recipients = new SourceAddressCollection();
            recipients.AddRange(source.To);
            recipients.AddRange(source.CC);

            long channelid;

            // Remove receivers own address from list
            if (source.SourceChannelId != 0)
            {
                var channel = ChannelsManager.GetChannelObject(source.SourceChannelId);
                var sourceAddress = channel.InputChannel.GetSourceAddress();

                if (recipients.Contains(sourceAddress))
                    recipients.Remove(sourceAddress);

                channelid = source.SourceChannelId;
            }
            else
            {
                var channel = ChannelsManager.GetChannelObject(source.TargetChannelId);
                var sourceAddress = channel.InputChannel.GetSourceAddress();

                if (recipients.Contains(sourceAddress))
                    recipients.Remove(sourceAddress);

                channelid = source.TargetChannelId;
            }

            ClientState.Current.ViewController.MoveTo(
                PluginsManager.Current.GetPlugin<ConversationsPlugin>().NewItemView,
                new NewMessageDataHelper
                    {
                        SourceMessageId = source.MessageId,
                        SelectedChannelId = channelid,
                        Context = "Re: " + source.Context,
                        To = source.From.ToList(),
                        Cc = recipients,
                        Body = MessageBodyGenerator.CreateBodyTextForReply(source, text),
                        SuppressSignature = !String.IsNullOrEmpty(text)
                    });
        }
示例#26
0
 public static void ReplyAll(Message source)
 {
     ReplyAll(source, String.Empty);
 }
        protected override void ExecuteCore()
        {
            try
            {
                Logger.Debug("Retreiving message {0} from {1}", LogSource.Receive, header, config.DisplayName);

                foreach (var channelMessage in channel.GetMessage(header))
                {
                    var message = new Message
                        {
                            MessageNumber = header.MessageNumber,
                            MessageIdentifier = channelMessage.MessageIdentifier,
                            From = channelMessage.From,
                            ReturnTo = channelMessage.ReturnTo,
                            To = channelMessage.To,
                            CC = channelMessage.CC,
                            BCC = channelMessage.BCC,
                            InReplyTo = channelMessage.InReplyTo,
                            Size = header.Size,
                            Context = channelMessage.Context,
                            ConversationIdentifier = channelMessage.ConversationId,
                            SourceFolder = channelMessage.SourceFolder,
                            Metadata = channelMessage.Metadata,
                            IsRead = channelMessage.IsRead,
                            IsStarred = channelMessage.IsStarred,
                            DateReceived = channelMessage.DateReceived,
                            DateSent = channelMessage.DateSent
                        };

                    message.Context = message.Context != null ? message.Context.Trim() : String.Empty;

                    string bodyText = channelMessage.BodyText.ReadString();
                    string bodyHtml = channelMessage.BodyHtml.ReadString();

                    var access = new ClientMessageAccess(message, bodyText, bodyHtml);

                    if (folder.ToStorageFolder() == Folders.SentItems)
                    {
                        // For sent items we sent the TargetChannelId
                        message.SourceChannelId = 0;
                        message.TargetChannelId = config.ChannelId;
                    }
                    else
                    {
                        // For all other items we sent the SourceChannelId
                        message.SourceChannelId = config.ChannelId;
                    }

                    // Create BodyPreview field from reader
                    message.BodyPreview = access.GetBodyPreview();
                    message.BodyHtmlStreamName = access.WriteBodyHtml();
                    message.BodyTextStreamName = access.WriteBodyText();
                    message.MessageFolder = folder.ToStorageFolder();
                    message.Metadata = header.Metadata;

                    // Fix for messages which have a timestamp in the future
                    if (message.DateReceived > DateTime.Now)
                        message.DateReceived = DateTime.Now;

                    // Set IsNew state for message
                    if (!message.IsRead)
                        message.IsNew = true;

                    // Save message
                    ClientState.Current.DataService.Save(message);

                    // Message received, process attachments
                    foreach (var attachment in channelMessage.Attachments)
                    {
                        var document = new Document
                            {
                                Filename = attachment.Filename,
                                TargetChannelId = attachment.TargetChannelId,
                                DocumentFolder = folder.ToStorageFolder(),
                                ContentType = attachment.ContentType,
                                ContentId = attachment.ContentId,
                                ContentStream = attachment.ContentStream,
                                SourceChannelId = config.ChannelId,
                                DateReceived = message.DateReceived,
                                DateSent = message.DateSent,
                                Message = message
                            };

                        EventBroker.Publish(AppEvents.DocumentReceived, document);

                        if (attachment.ContentStream != null)
                        {
                            attachment.ContentStream.Dispose();
                            attachment.ContentStream = null;
                        }
                    }

                    if (channelMessage.BodyText != null)
                        channelMessage.BodyText.Dispose();

                    if (channelMessage.BodyHtml != null)
                        channelMessage.BodyHtml.Dispose();

                    EventBroker.Publish(AppEvents.MessageStored, message);
                }
            }
            catch (Exception ex)
            {
                Logger.Error("An error occured when trying to download header {0}. Exception = {1}", LogSource.BackgroundTask, header, ex);

                throw;
            }
        }
示例#28
0
        void Send_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ClientStats.LogEvent("Quick reply all send");

            if (String.IsNullOrEmpty(QuickReplyAll.Text.Trim()))
            {
                return;
            }

            var newMessage = new Message();

            #region Create message

            var channel = message.SourceChannelId == 0 ?
                          ChannelsManager.GetDefaultChannel() :
                          ChannelsManager.GetChannelObject(Message.SourceChannelId);

            var recipients    = new SourceAddressCollection();
            var sourceAddress = channel.InputChannel.GetSourceAddress();

            recipients.Add(Message.From);
            recipients.AddRange(Message.To);

            // Remove our own address from recipient list
            if (recipients.Contains(sourceAddress))
            {
                recipients.Remove(sourceAddress);
            }

            newMessage.InReplyTo = Message.MessageIdentifier;
            newMessage.ConversationIdentifier = Message.ConversationIdentifier;
            newMessage.Context         = "Re: " + Message.Context;
            newMessage.From            = channel.InputChannel.GetSourceAddress();
            newMessage.TargetChannelId = channel.Configuration.ChannelId;
            newMessage.To.AddRange(recipients);
            newMessage.CC.AddRange(Message.CC);

            var access = new ClientMessageAccess(newMessage, null,
                                                 MessageBodyGenerator.CreateBodyTextForReply(Message, QuickReplyAll.Text.Nl2Br()));

            newMessage.BodyHtmlStreamName = access.WriteBodyHtml();
            newMessage.BodyPreview        = access.GetBodyPreview();
            newMessage.IsRead             = true;
            newMessage.DateSent           = DateTime.Now;
            newMessage.MessageFolder      = Folders.SentItems;
            newMessage.DateSent           = DateTime.Now;
            newMessage.DateCreated        = DateTime.Now;

            #endregion

            #region Send message

            ClientState.Current.DataService.Save(newMessage);

            // Add message to mailbox
            EventBroker.Publish(AppEvents.MessageStored, newMessage);

            // Save command
            CommandQueue.Enqueue(AppCommands.SendMessage, newMessage);

            if (!NetworkInterface.GetIsNetworkAvailable())
            {
                ClientState.Current.ShowMessage(
                    new AppMessage(Strings.MessageWillBeSentLater)
                {
                    EntityId   = newMessage.MessageId.Value,
                    EntityType = EntityType.Message
                }, MessageType.Success);
            }

            QuickReplyAll.Text = String.Empty;

            message.TrackAction(ActionType.ReplyForward);

            #endregion
        }
示例#29
0
        bool IsMessageVisible(Message message)
        {
            if (FilterMessage(message))
            {
                if (Filter.IsActivityViewVisible)
                {
                    if (SettingsManager.ClientSettings.AppConfiguration.RollUpConversations)
                    {
                        // Default behavior for my inbox
                        if (Filter.CurrentView == ActivityView.MyInbox || Filter.CurrentView == ActivityView.Archive)
                            return message.IsLast;
                    }
                }
                else
                {
                    if (Filter.CurrentView == ActivityView.MyInbox || Filter.CurrentView == ActivityView.Archive)
                        return message.IsLast;
                }

                return true;
            }

            return false;
        }
 public MessageContentMapper(Message message)
 {
     this.message = message;
 }
示例#31
0
 public MessageBuilder(Message source)
 {
     this.source = source;
 }
示例#32
0
        /// <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;
        }