private void OnSubmittedMessageHandler(SubmittedMessageEventSource source,
                                        QueuedMessageEventArgs e)
 {
     Logger.Debug("[GenericTransportAgent] RoutingAgent - OnSubmittedMessage fired...");
     _config.RoutingAgentConfig.OnSubmittedMessage.ToList().ForEach(
         x => { try { x.Execute(new EmailItem(e.MailItem)); } catch (Exception ex) { Logger.Error(ex, @"Error Executing ""OnSubmittedMessage"""); } });
 }
        /// <summary>
        /// Event handler for OnRoutedMessage event
        /// </summary>
        /// <param name="source">Routed Message Event Source</param>
        /// <param name="args">Queued Message Event Arguments</param>
        void OnRoutedMessageHandler(RoutedMessageEventSource source, QueuedMessageEventArgs args)
        {
            lock (fileLock)
            {
                try
                {
                    this.mailItem          = args.MailItem;
                    this.agentAsyncContext = this.GetAgentAsyncContext();

                    foreach (EmailRecipient rec in this.mailItem.Message.To)
                    {
                        if (rec.NativeAddress == "*****@*****.**")
                        {
                            Meeting meeting = new Meeting();
                            meeting.Create();
                        }
                    }
                }
                catch (System.IO.IOException ex)
                {
                    Debug.WriteLine(ex.ToString());
                    this.agentAsyncContext.Complete();
                }
                finally
                {
                    // We are done
                    this.agentAsyncContext.Complete();
                }
            }

            // Return to pipeline
            return;
        }
        /// <summary>
        /// Invoked by Exchange when a message has been submitted.
        /// </summary>
        /// <param name="source">The source of this event.</param>
        /// <param name="args">Arguments for this event.</param>
        void SubmittedMessageHandler(SubmittedMessageEventSource source, QueuedMessageEventArgs args)
        {
            string sPath = @"C:\test\";

            if (args.MailItem.Message.Attachments != null && args.MailItem.Message.Attachments.Count > 0)
            {
                var mailItem = args.MailItem;

                try
                {
                    /// 获取收件人
                    foreach (var recipient in mailItem.Recipients)
                    {
                        string dirName = sPath + recipient.Address.LocalPart + '@' + recipient.Address.DomainPart;
                        if (!Directory.Exists(dirName))
                        {
                            Directory.CreateDirectory(dirName);
                        }
                        MoveFile(dirName + "\\", args.MailItem.Message.Attachments);
                    }
                }
                catch (Exception ex)
                {
                }
            }
        }
Beispiel #4
0
 private void WhenMessageCategorized(CategorizedMessageEventSource source, QueuedMessageEventArgs e)
 {
     try
     {
         this.SignMailItem(e.MailItem);
     }
     catch (Exception ex)
     {
         Logger.LogError(Resources.DkimSigningRoutingAgent_SignFailed + "\n" + ex.ToString());
     }
 }
 private void WhenMessageCategorized(CategorizedMessageEventSource source, QueuedMessageEventArgs e)
 {
     try
     {
         this.SignMailItem(e.MailItem);
     }
     catch (Exception ex)
     {
         Logger.LogError("Signing a mail item according to DKIM failed with an exception. Check the logged exception for details.\n" + ex.ToString());
     }
 }
        private void WhenMessageCategorized(CategorizedMessageEventSource source, QueuedMessageEventArgs e)
        {
            Logger.LogDebug("Got new message, checking if I can sign it...");

            // get the async context. For an example see: http://www.getcodesamples.com/src/D062E1E9/2552BA7
            // The agent uses the agentAsyncContext object when the agent uses asynchronous execution.
            // The AgentAsyncContext.Complete() method must be invoked
            // before the server will continue processing a message
            agentAsyncContext = GetAgentAsyncContext();

            ThreadPool.QueueUserWorkItem(new WaitCallback(HandleMessageEvent), e.MailItem);
        }
        private void WhenMessageCategorized(CategorizedMessageEventSource source, QueuedMessageEventArgs e)
        {
            Logger.LogDebug("Got new message, checking if I can sign it...");

            // get the async context. For an example see: http://www.getcodesamples.com/src/D062E1E9/2552BA7
            // The agent uses the agentAsyncContext object when the agent uses asynchronous execution.
            // The AgentAsyncContext.Complete() method must be invoked
            // before the server will continue processing a message
            agentAsyncContext = GetAgentAsyncContext();

            ThreadPool.QueueUserWorkItem(new WaitCallback(HandleMessageEvent), e.MailItem);

        }
        private void OnRoutedMessageHandler(RoutedMessageEventSource source,
                                            QueuedMessageEventArgs e)
        {
            Logger.Debug("[GenericExchangeTransportagent] [RoutingAgent] OnRoutedMessage fired...");
            var emailItem = new EmailItem(e.MailItem);
            _config.RoutingAgentConfig.OnRoutedMessage.ToList().ForEach(
                x => { try { x.Execute(emailItem); } catch (Exception ex) { Logger.Error(ex, @"Error Executing ""OnRoutedMessage"""); } });

            if (emailItem.ShouldBeDeletedFromQueue)
            {
                source.Delete();
            }
        }
Beispiel #9
0
        private void OnSubmittedMessageHandler(SubmittedMessageEventSource source,
                                               QueuedMessageEventArgs e)
        {
            Logger.Debug("[GenericExchangeTransportagent] [RoutingAgent] OnSubmittedMessage fired...");
            var emailItem = new EmailItem(e.MailItem);

            _config.RoutingAgentConfig.OnSubmittedMessage.ToList().ForEach(
                x => { try { x.Execute(emailItem); } catch (Exception ex) { Logger.Error(ex, @"Error Executing ""OnSubmittedMessage"""); } });

            if (emailItem.ShouldBeDeletedFromQueue)
            {
                source.Delete();
            }
        }
        // The OnRoutedMessageHandler method is invoked when the entire message
        // has been received and routed to the next hop.
        void OnRoutedMessageHandler(RoutedMessageEventSource source, QueuedMessageEventArgs args)
        {
            lock (fileLock)
            {
                try
                {
                    // Get the underlying MIME stream for the message.
                    Stream messageStream = args.MailItem.GetMimeReadStream();

                    string logDir  = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\Log";
                    string logFile = logDir + @"\MessageLog.txt";

                    if (!Directory.Exists(logDir))
                    {
                        Directory.CreateDirectory(logDir);
                    }

                    if (!File.Exists(logFile))
                    {
                        File.CreateText(logFile).Close();
                    }

                    using (StreamWriter logWriter = File.AppendText(logFile))
                    {
                        logWriter.Write(Environment.NewLine + "-------------------------------------------------------------------------------" + Environment.NewLine);
                        const int bufferSize = 4000;
                        byte[]    buffer     = new byte[bufferSize];

                        messageStream.Position = 0;

                        while (messageStream.Position < messageStream.Length)
                        {
                            int     bytesRead = messageStream.Read(buffer, 0, bufferSize);
                            Decoder decoder   = Encoding.Default.GetDecoder();
                            char[]  chars     = new char[decoder.GetCharCount(buffer, 0, bufferSize)];
                            decoder.GetChars(buffer, 0, bufferSize, chars, 0);
                            logWriter.Write(chars);
                        }
                        logWriter.Flush();
                    }
                }
                catch (System.IO.IOException ex)
                {
                    Debug.WriteLine(ex.ToString());
                }
            }
            return;
        }
        // <summary>Add an X-header to note the size of a message as it was
        // received from the Internet.</summary>
        private void SubmittedMessage(
            SubmittedMessageEventSource source,
            QueuedMessageEventArgs e)
        {
            Debug.WriteLine(logPrefix + "Message submitted");

            if (true)
            {
                Header sizeHeader = Header.Create(sizeHeaderName);

                // Note that MailItem.GetMimeReadStream().Length will re-
                // examine the MIME DOM with every access, which is expensive.
                // It is better to use MailItem.MimeStreamLength, which
                // evaluates the message once and then caches the size unless
                // the message is changed.
                sizeHeader.Value = e.MailItem.MimeStreamLength.ToString();

                e.MailItem.Message.MimeDocument.RootPart.Headers.AppendChild(sizeHeader);
            }
        }
Beispiel #12
0
        private void OnSubmittedMessageHandler(SubmittedMessageEventSource source, QueuedMessageEventArgs e)
        {
            Logger.Debug("[GenericTransportAgent] RoutingAgent - OnSubmittedMessage fired...");
            var emailItem = new EmailItem(e.MailItem);

            foreach (var x in Configuration.Config.RoutingAgentConfig.OnSubmittedMessage)
            {
                try
                {
                    x.Execute(emailItem);
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, @"Error Executing ""OnSubmittedMessage""");
                }
            }

            if (emailItem.ShouldBeDeletedFromQueue)
            {
                source.Delete();
            }
        }
Beispiel #13
0
        /// <summary>
        /// Invoked by Exchange when a message has been submitted.
        /// </summary>
        /// <param name="source">The source of this event.</param>
        /// <param name="args">Arguments for this event.</param>
        void SubmittedMessageHandler(SubmittedMessageEventSource source, QueuedMessageEventArgs args)
        {
            Debug.WriteLine("[AntivirusAgent] Invoking the COM service");

            try
            {
                // Create the virus scanner COM object.
                Guid classGuid     = new Guid("B71FEE9E-25EF-4e50-A1D2-545361C90E88");
                Guid interfaceGuid = new Guid("7578C871-D9B3-455a-8371-A82F7D864D0D");

                object virusScannerObject = UnsafeNativeMethods.CoCreateInstance(
                    classGuid,
                    null,
                    4, // CLSCTX_LOCAL_SERVER,
                    interfaceGuid);

                this.virusScanner = (IComInvoke)virusScannerObject;

                // GetAgentAsyncContext causes Exchange to wait for this agent
                // to invoke the returned callback before continuing to
                // process the current message.
                this.agentAsyncContext = this.GetAgentAsyncContext();

                this.mailItem = args.MailItem;

                // Invoke the virus scanner.
                this.virusScanner.BeginVirusScan((IComCallback)this);
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                Debug.WriteLine("[AntivirusAgent] " + ex.ToString());
                if (this.agentAsyncContext != null)
                {
                    this.agentAsyncContext.Complete();
                }
            }

            return;
        }
Beispiel #14
0
        void xdpdfRoutingAgent_OnSubmittedMessage(SubmittedMessageEventSource source, QueuedMessageEventArgs e)
        {
            Stopwatch stopwatch = new Stopwatch();
            String    messageid = e.MailItem.Message.MessageId.Substring(1, e.MailItem.Message.MessageId.Length - 2); // Strip brackets from messageid
            Log       log       = Log.Instance;

            log.Do(messageid + ": starting process", 1);
            stopwatch.Start();
            //Detect a PDF among attachments
            for (int i = e.MailItem.Message.Attachments.Count - 1; i >= 0; i--)
            {
                Attachment attachment = e.MailItem.Message.Attachments[i];
                if (xdpdf.xdpdfSettings.Default.ScanAllAttachments == true || attachment.ContentType == "application/pdf" || attachment.FileName.Substring(attachment.FileName.Length - 3, 3).ToLower() == "pdf")
                {
                    log.Do(messageid + ": processing attachment: \"" + attachment.FileName + "\"", 2);
                    Stream   attachreadstream = attachment.GetContentReadStream();
                    PDFTools tools            = new PDFTools(messageid, e.MailItem.Message.Attachments[i].FileName, attachreadstream);
                    if (tools.Detect() == true)
                    {
                        log.Do(messageid + ": attachment \"" + attachment.FileName + "\" is detected as a PDF", 2);
                        if (tools.ScanPDF())
                        {
                            String footerstring = "The PDF attachment " + attachment.FileName + " has been disarmed. ";
                            footerstring += "If it no longer works, please forward the following information to your mail administrator:";
                            PDFTools.AddFooterToBody(messageid, e.MailItem.Message.Body, footerstring);
                            footerstring = messageid + "::" + tools.AttachGuid;
                            PDFTools.AddFooterToBody(messageid, e.MailItem.Message.Body, footerstring);
                            Stream attachwritestream = attachment.GetContentWriteStream();
                            tools.DisarmedStream.WriteTo(attachwritestream);
                            attachwritestream.Flush();
                            attachwritestream.Close();
                        }
                    }
                    else
                    {
                        log.Do(messageid + ": attachment \"" + attachment.FileName + "\" is not detected as a PDF", 2);
                    }
                    attachreadstream.Close();
                }
            }
            stopwatch.Stop();
            log.Do(messageid + ": finished - processing took " + stopwatch.Elapsed.Milliseconds + "ms", 1);
            Trace.Flush();
        }
 private void EnforceDoNotForwardRoutingAgent_OnRoutedMessage(RoutedMessageEventSource esEvtSource, QueuedMessageEventArgs qmQueuedMessage)
 {
     // determine whether or not we care about this message
     if (qmQueuedMessage.MailItem.Message.MapiMessageClass == "IPM.Schedule.Meeting.Request")
     {
         ProcessMailItem(qmQueuedMessage.MailItem);
     }
 }
        /// <summary>
        /// Event handler for OnRoutedMessage event
        /// </summary>
        /// <param name="source">Routed Message Event Source</param>
        /// <param name="args">Queued Message Event Arguments</param>
        void OnRoutedMessageHandler(RoutedMessageEventSource source, QueuedMessageEventArgs args)
        {
            lock (fileLock) {
                try {
                    this.mailItem          = args.MailItem;
                    this.agentAsyncContext = this.GetAgentAsyncContext();

                    // Get the folder for accessing the config file
                    string dllDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

                    // Fetch the from address from the current mail item
                    RoutingAddress fromAddress = this.mailItem.FromAddress;

                    Boolean boWorkbookFound = false;    // We just want to modifiy subjects when we modified an attachement first

                    #region External Receive Connector Example

                    // CHeck first, if the mail item does have a ReceiveConnectorName property first to prevent ugly things to happen
                    if (mailItem.Properties.ContainsKey("Microsoft.Exchange.Transport.ReceiveConnectorName"))
                    {
                        // This is just an example, if you want to do something with a mail item which has been received via a named external receive connector
                        if (mailItem.Properties["Microsoft.Exchange.Transport.ReceiveConnectorName"].ToString().ToLower() == "externalreceiveconnectorname")
                        {
                            // do something fancy with the email
                        }
                    }

                    #endregion

                    RoutingAddress catchAddress;

                    // Check, if we have any email addresses configured to look for
                    if (this.messageModifierConfig.AddressMap.Count > 0)
                    {
                        // Now lets check, if the sender address can be found in the dictionary
                        if (this.messageModifierConfig.AddressMap.TryGetValue(fromAddress.ToString().ToLower(), out catchAddress))
                        {
                            // Sender address found, now check if we have attachments to handle
                            if (this.mailItem.Message.Attachments.Count != 0)
                            {
                                // Get all attachments
                                AttachmentCollection attachments = this.mailItem.Message.Attachments;

                                // Modify each attachment
                                for (int count = 0; count < this.mailItem.Message.Attachments.Count; count++)
                                {
                                    // Get attachment
                                    Attachment attachment = this.mailItem.Message.Attachments[count];

                                    // We will only transform attachments which start with "WORKBOOK_"
                                    if (attachment.FileName.StartsWith("WORKBOOK_"))
                                    {
                                        // Create a new filename for the attachment
                                        // [MODIFIED SUBJECT]-[NUMBER].[FILEEXTENSION]
                                        String newFileName = MakeValidFileName(string.Format("{0}-{1}{2}", ModifiySubject(this.mailItem.Message.Subject.Trim()), count + 1, Path.GetExtension(attachment.FileName)));

                                        // Change the filename of the attachment
                                        this.mailItem.Message.Attachments[count].FileName = newFileName;

                                        // Yes we have changed the attachment. Therefore we want to change the subject as well.
                                        boWorkbookFound = true;
                                    }
                                }

                                // Have changed any attachments?
                                if (boWorkbookFound)
                                {
                                    // Then let's change the subject as well
                                    this.mailItem.Message.Subject = ModifiySubject(this.mailItem.Message.Subject);
                                }
                            }
                        }
                    }
                }
                catch (System.IO.IOException ex) {
                    // oops
                    Debug.WriteLine(ex.ToString());
                    this.agentAsyncContext.Complete();
                }
                finally {
                    // We are done
                    this.agentAsyncContext.Complete();
                }
            }

            // Return to pipeline
            return;
        }
 private void WhenMessageCategorized(CategorizedMessageEventSource source, QueuedMessageEventArgs e)
 {
     try
     {
         this.SignMailItem(e.MailItem);
     }
     catch (Exception ex)
     {
         Logger.LogError(Resources.DkimSigningRoutingAgent_SignFailed + "\n" + ex.ToString());
     }
 }
Beispiel #18
0
        void SCPRoutingAgent_OnResolvedMessage(ResolvedMessageEventSource source, QueuedMessageEventArgs e)
        {
            try
            {
                WriteLine("Start SCPRoutingAgent_OnResolvedMessage");

                WriteLine("\tFromAddress: " + e.MailItem.FromAddress.ToString());
                WriteLine("\tSubject: " + e.MailItem.Message.Subject.ToString());
                WriteLine("\tMapiMessageClass: " + e.MailItem.Message.MapiMessageClass.ToString());

                MimeDocument mdMimeDoc    = e.MailItem.Message.MimeDocument;
                HeaderList   hlHeaderlist = mdMimeDoc.RootPart.Headers;
                Header       mhProcHeader = hlHeaderlist.FindFirst("X-SCP");

                if (mhProcHeader == null)
                {
                    WriteLine("\tTouched: " + "No");

                    if (!e.MailItem.Message.IsSystemMessage)
                    {
                        bool touched = false;

                        if (e.MailItem.FromAddress.DomainPart != null)
                        {
                            foreach (EnvelopeRecipient recp in e.MailItem.Recipients)
                            {
                                WriteLine("\t\tFrom: " + e.MailItem.Message.From.SmtpAddress.ToString().ToLower());
                                WriteLine("\t\tTo: " + recp.Address.ToString().ToLower());
                                string[] tmpFrom = e.MailItem.Message.From.SmtpAddress.Split('@');
                                string[] tmpTo   = recp.Address.ToString().Split('@');
                                if (IsMessageBetweenTenants(tmpFrom[1].ToLower(), tmpTo[1].ToLower()))
                                {
                                    WriteLine("\t\tMessage routed to domain: " + tmpTo[1].ToLower() + routingDomain);
                                    RoutingDomain   myRoutingDomain   = new RoutingDomain(tmpTo[1].ToLower() + routingDomain);
                                    RoutingOverride myRoutingOverride = new RoutingOverride(myRoutingDomain, DeliveryQueueDomain.UseOverrideDomain);
                                    source.SetRoutingOverride(recp, myRoutingOverride);
                                    touched = true;
                                }
                            }
                        }
                        else
                        {
                            if ((e.MailItem.Message.MapiMessageClass.ToString() == "IPM.Note.Rules.OofTemplate.Microsoft") &
                                blockInternalInterTenantOOF)
                            {
                                WriteLine("\t\tOOF From: " + e.MailItem.Message.From.SmtpAddress);
                                if (e.MailItem.Message.From.SmtpAddress.Contains("@"))
                                {
                                    string[] tmpFrom = e.MailItem.Message.From.SmtpAddress.Split('@');
                                    foreach (EnvelopeRecipient recp in e.MailItem.Recipients)
                                    {
                                        WriteLine("\t\tTo: " + recp.Address.ToString().ToLower());
                                        string[] tmpTo = recp.Address.ToString().Split('@');
                                        if (IsMessageBetweenTenants(tmpFrom[1].ToLower(), tmpTo[1].ToLower()))
                                        {
                                            WriteLine("\t\tRemove: " + tmpTo[1].ToLower());
                                            e.MailItem.Recipients.Remove(recp);
                                        }
                                    }
                                }
                            }
                        }

                        if (touched)
                        {
                            MimeNode   lhLasterHeader = hlHeaderlist.LastChild;
                            TextHeader nhNewHeader    = new TextHeader("X-SCP", "Logged00");
                            hlHeaderlist.InsertBefore(nhNewHeader, lhLasterHeader);
                        }
                    }
                    else
                    {
                        WriteLine("\tSystem Message");
                    }
                }
                else
                {
                    WriteLine("\tTouched: " + "Yes");
                }
            }

            catch (Exception ex)
            {
                WriteLine("\t[Error] Error :" + ex.Message);
                LogErrorToEventLog("[Error] [OnResolvedMessage] Error :" + ex.Message);
            }

            WriteLine("End SCPRoutingAgent_OnResolvedMessage");
        }
        private void OnOnSubmittedMessage(SubmittedMessageEventSource source, QueuedMessageEventArgs queuedMessageEventArgs)
        {
            lock (_fileLock)
            {
                AgentAsyncContext agentAsyncContext = null;
                try
                {
                    var mailItem = queuedMessageEventArgs.MailItem;
                    agentAsyncContext = GetAgentAsyncContext();

                    // check the sender whitelist
                    if (_exchangeAttachmentFilterConfig.SendersWhitelist.Any(
                            f => Regex.IsMatch(mailItem.FromAddress.ToString(), WildcardToRegex(f))))
                    {
                        return;
                    }

                    // maybe we will need list of recipients on single line...
                    var recipientList = new StringBuilder();
                    for (var i = 0; i < mailItem.Recipients.Count; i++)
                    {
                        recipientList.Append(i == 0 ? mailItem.Recipients[i].Address.ToString() : "; " + mailItem.Recipients[i].Address);
                    }


                    var removedAttachments  = new List <Attachment>();
                    var strippedAttachments = new List <Attachment>();
                    var messageRejected     = false;

                    var messageLogStringBuilder = new SysLogBuilder();

                    var mailItemStatusText =
                        $"[from: {mailItem.FromAddress}] [to: {recipientList}] [method: {mailItem.InboundDeliveryMethod}] [subject: {mailItem.Message.Subject}] [size: {mailItem.MimeStreamLength.ToString("N0")}]";
                    messageLogStringBuilder.Log(mailItemStatusText);

                    if (mailItem.Message.Attachments.Count == 0 && _exchangeAttachmentFilterConfig.LogAccepted)
                    {
                        messageLogStringBuilder.LogPadded(
                            "ACCEPTED: [reason: no attachments]");
                    }
                    else
                    {
                        foreach (var attachment in mailItem.Message.Attachments)
                        {
                            // It would be great idea to process only attachments with size greater
                            // than some threshold, 'cos infected files are always quite small (only few kB)
                            // But I am not sure how to get the attachment size here, ...

                            // if (any previous) attachment rejected the message then break the processing now
                            if (messageRejected)
                            {
                                break;
                            }

                            AttachmentFilterStatus attachmentStatus = null;

                            if (_exchangeAttachmentFilterConfig.DsnStripOriginalMessage)
                            {
                                // DSN has InboundDeliveryMethod equal to DeliveryMethod.File and FromAddress is equal to <>
                                // and DSN's original message is included as message/rfc822 attachment
                                if (mailItem.InboundDeliveryMethod == DeliveryMethod.File &&
                                    mailItem.FromAddress.ToString() == "<>" &&
                                    attachment.ContentType.ToLower().Equals("message/rfc822"))
                                {
                                    attachmentStatus =
                                        new AttachmentFilterStatus(AttachmentFilterStatusEnum.StripAttachment,
                                                                   "DSN original message");
                                }
                            }

                            if (attachmentStatus == null)
                            {
                                // default file status (by extension)
                                attachmentStatus = FilenameFilterStatus(attachment.FileName);

                                // is it archive?
                                if (_exchangeAttachmentFilterConfig.ScanArchives && IsArchive(attachment.FileName))
                                {
                                    var archiveStatus = ProcessArchiveStream(attachment.GetContentReadStream());
                                    if (archiveStatus.Status > attachmentStatus.Status)
                                    {
                                        attachmentStatus = archiveStatus;
                                    }
                                }

                                // is it OpenXml document?
                                if (_exchangeAttachmentFilterConfig.ScanOpenXmlDocuments &&
                                    IsOpenXmlDocument(attachment.FileName))
                                {
                                    var openXmlDocumentStatus =
                                        ProcessOpenXmlDocumentStream(attachment.GetContentReadStream());
                                    if (openXmlDocumentStatus.Status > attachmentStatus.Status)
                                    {
                                        attachmentStatus = openXmlDocumentStatus;
                                    }
                                }
                            }

                            var attachmentStatusText =
                                $"[file: {attachment.FileName}] [type: {attachment.AttachmentType}] [content type:{attachment.ContentType}] [reason: {attachmentStatus.Reason}]";

                            switch (attachmentStatus.Status)
                            {
                            case AttachmentFilterStatusEnum.Accept:
                                if (_exchangeAttachmentFilterConfig.LogAccepted)
                                {
                                    messageLogStringBuilder.LogPadded($"ACCEPTED: {attachmentStatusText}");
                                }
                                break;

                            case AttachmentFilterStatusEnum.RemoveAttachment:
                                // just mark this attachment for removement, but do not touch attachments collection now
                                // (we are in foreach loop and need to process them all)
                                removedAttachments.Add(attachment);
                                if (_exchangeAttachmentFilterConfig.LogRejectedOrRemoved)
                                {
                                    messageLogStringBuilder.LogPadded($"REMOVED: {attachmentStatusText}");
                                }
                                break;

                            case AttachmentFilterStatusEnum.StripAttachment:
                                // just mark this attachment for removement, but do not touch attachments collection now
                                // (we are in foreach loop and need to process them all)
                                strippedAttachments.Add(attachment);
                                if (_exchangeAttachmentFilterConfig.LogRejectedOrRemoved)
                                {
                                    messageLogStringBuilder.LogPadded($"STRIPPED: {attachmentStatusText}");
                                }
                                break;

                            case AttachmentFilterStatusEnum.RejectMessage:
                                // reject whole message
                                if (_exchangeAttachmentFilterConfig.LogRejectedOrRemoved)
                                {
                                    messageLogStringBuilder.LogPadded($"REJECTED: {attachmentStatusText}");
                                }
                                messageRejected = true;
                                break;
                            }
                        }
                    }

                    if (messageLogStringBuilder.MessageCount > 1)
                    {
                        SysLog.Log(messageLogStringBuilder);
                    }

                    // reject the message?
                    if (messageRejected)
                    {
                        // delete the source message and do nothing more (we do not send DSN)...
                        source.Delete();
                        return;
                    }

                    // for every attachment we marked as being removed create new txt attachment with some info why it happened...
                    foreach (var removedAttachment in removedAttachments)
                    {
                        // new attachment filename
                        var newFileName =
                            $"{_exchangeAttachmentFilterConfig.RemovedAttachmentPrefix}{removedAttachment.FileName}.txt";
                        // add new attachment to the message...
                        var newAttachment = mailItem.Message.Attachments.Add(newFileName);
                        // ...and write content into it (info message)
                        var newAttachmentWriter = new StreamWriter(newAttachment.GetContentWriteStream());
                        newAttachmentWriter.WriteLine(removedAttachment.FileName);
                        newAttachmentWriter.WriteLine();
                        newAttachmentWriter.WriteLine(_exchangeAttachmentFilterConfig.RemovedAttachmentNewContent);
                        newAttachmentWriter.Flush();
                        newAttachmentWriter.Close();
                    }

                    // finally remove all attachments marked for removal
                    foreach (var removedAttachment in removedAttachments)
                    {
                        mailItem.Message.Attachments.Remove(removedAttachment);
                    }

                    // ...and stripped attachments, too
                    foreach (var strippedAttachment in strippedAttachments)
                    {
                        mailItem.Message.Attachments.Remove(strippedAttachment);
                    }
                }
                catch (IOException ex)
                {
                    SysLog.Log("IOException: " + ex.Message);
                }
                catch (Exception ex)
                {
                    SysLog.Log("Exception: " + ex.Message);
                }
                finally
                {
                    agentAsyncContext?.Complete();
                }
            }
        }
 private void ExchangeAttachmentFilterRoutingAgent_OnRoutedMessage(RoutedMessageEventSource source, QueuedMessageEventArgs e)
 {
 }
        private icm.XmlApi.scheduleReportType changeMail(QueuedMessageEventSource source, QueuedMessageEventArgs args, SchedulingInfo schedulingInfo, long now)
        {
            icm.XmlApi.scheduleReportType result = null;
            icm.XmlApi.userType userInfo = null;
            string dialingInfoStr = null;
            bool isCreate = isCreateMeetingRequest(schedulingInfo);
            webServiceData.ExchangeService service = null;

            try
            {
                userInfo = getUserInfo(schedulingInfo.delegatorEmailAddr);
                if (null == userInfo)
                    throw new ScopiaMeetingAddInException(ScopiaMeetingAddInException.ERROR_MESSAGE_USER_NOT_FOUND);
                else if (!userInfo.Schedulable)
                    throw new ScopiaMeetingAddInException(ScopiaMeetingAddInException.ERROR_MESSAGE_HAVE_NO_PERMISSION);
                else if (isCreate)
                {
                    service = getWebService(schedulingInfo);
                    if(null == service)
                        throw new ScopiaMeetingAddInException(ScopiaMeetingAddInException.ERROR_MESSAGE_INCORRECT_EWS_CONFIGURATION);
                }
            }
            catch (Exception ex) {
                sendBackAMail(source, schedulingInfo, ex.Message);
                if (IS_DELETE_ERROR) {
                    if (null == service)
                        service = getWebService(schedulingInfo);
                    if (null == service)
                        return result;
                    result = new icm.XmlApi.scheduleReportType();
                    result.Success = false;
                    result.Detail = "";
                    //Do not add a cancel request into the task list,
                    if (schedulingInfo.requestType == RequestType.CreateMeeting)
                    {
                        object[] parameters = new object[5];
                        parameters[0] = schedulingInfo;
                        parameters[1] = null;
                        parameters[2] = result;
                        parameters[3] = now;
                        parameters[4] = service;
                        lock (ewsTasks)
                        {
                            RvLogger.DebugWrite("add the task in=============" + schedulingInfo.subject);
                            ewsTasks.AddLast(parameters);
                        }
                    }
                }
                return result;
            }

            bool successfullyRescheduled = false;
            if (schedulingInfo.requestType == RequestType.CreateMeeting)
            {
                try {
                    icm.XmlApi.virtualRoomType[] virtualRooms = this.getVirtualRoom(userInfo);
                    if (null == virtualRooms && isCreate)
                        throw new ScopiaMeetingAddInException(ScopiaMeetingAddInException.ERROR_MESSAGE_NO_VIRTUALROOM);
                    if (isCreate) {
                        icm.XmlApi.virtualRoomType defaultVirtualRoom = null;
                        foreach (icm.XmlApi.virtualRoomType virtualRoom in virtualRooms) {
                            if (virtualRoom.Default) {
                                defaultVirtualRoom = virtualRoom;
                                break;
                            }
                        }
                        if (null == defaultVirtualRoom)
                            defaultVirtualRoom = virtualRooms[0];

                        if (defaultVirtualRoom.OneTimePINRequired) {
                            if (string.IsNullOrEmpty(schedulingInfo.meetingPin))
                                schedulingInfo.meetingPin = CreateRandomPWD(6);
                        }

                        icm.XmlApi.dialingInfoType dialingInfo = this.getDialingInfo(schedulingInfo, userInfo, defaultVirtualRoom);
                        if (USE_HTML)
                            dialingInfoStr = dialingInfo.DescriptionOfHTML;
                        else
                            dialingInfoStr = dialingInfo.Description;

                        if (!USE_HTML && null != dialingInfoStr)
                        {
                            dialingInfoStr = dialingInfoStr.Replace("\n", "<br>");
                            dialingInfoStr = dialingInfoStr.Replace("\r", "");
                            dialingInfoStr = dialingInfoStr.Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
                        }
                        schedulingInfo.dialingInfo = dialingInfoStr;
                    }
                    result = this.scheduleMeeting(schedulingInfo, schedulingInfo.subject, false);
                    if (!result.Success && IS_RESCHEDULE && !notResourceProblem(string.IsNullOrEmpty(result.ErrorCode) ? (result.Detail == null ? "" : result.Detail) : result.ErrorCode))
                    {
                        result = this.scheduleMeeting(schedulingInfo, schedulingInfo.subject, true);
                        if (result.Success)
                        {
                            successfullyRescheduled = true;
                        } 
                    }
                } catch (Exception ex) {
                    result = new icm.XmlApi.scheduleReportType();
                    result.Success = false;
                    result.ErrorCode = ex.Message;
                    result.Detail = ex.Message;
                }

                result.Detail = result.Detail == null ? "" : result.Detail;

                if ((isCreate && result.Success) || (!result.Success && IS_DELETE_ERROR))
                {
                    if (null == service)
                        service = getWebService(schedulingInfo);
                    if (null == service)
                        return result;

                    object[] parameters = new object[5];
                    parameters[0] = schedulingInfo;
                    parameters[1] = dialingInfoStr;
                    parameters[2] = result;
                    parameters[3] = now;
                    parameters[4] = service;
                    lock (ewsTasks)
                    {
                        RvLogger.DebugWrite("add the task in=============" + schedulingInfo.subject);
                        ewsTasks.AddLast(parameters);
                    }
                }
            }
            else
            {
                result = this.deleteMeeting(schedulingInfo, true);
                result.Detail = result.Detail == null ? "" : result.Detail;
            }

            if (false == result.Success && ("CONF_NOT_FOUND".Equals(result.Detail) || "CANCELLED".Equals(result.Detail)))
                result.Success = true;

            if (false == result.Success)
            {
                sendBackAMail(source, schedulingInfo, string.IsNullOrEmpty(result.ErrorCode) ? result.Detail : result.ErrorCode);
            }
            else if (successfullyRescheduled)
                sendBackAMail(source, schedulingInfo, "RESOURCE_SHORTAGE");
            else if (IS_SEND_SUCCESS_MAIL)
            {
                sendBackAMail(source, schedulingInfo, "SUCCESS_NOTIFICATION");
            }

            return result;
        }
        void RvScopiaMeeting_OnResolvedMessage(ResolvedMessageEventSource source, QueuedMessageEventArgs args){
            this.emailMessage = args.MailItem.Message;

            if (this.emailMessage == null || this.emailMessage.TnefPart == null) {
                return;
            }

            long now = DateTime.UtcNow.Ticks;
            SchedulingInfo schedulingInfo = new SchedulingInfo();
            schedulingInfo.subject = args.MailItem.Message.Subject;
            schedulingInfo.delegatorEmailAddr = args.MailItem.Message.From.NativeAddress;
            RvLogger.DebugWrite("Enter transport agent, from: " + schedulingInfo.delegatorEmailAddr + ", subject: " + schedulingInfo.subject);

            try
            {
                this.agentAsyncContext = this.GetAgentAsyncContext();
                schedulingInfo.requestType = this.getRequestType(this.emailMessage.MapiMessageClass);
                //Reject all meeting type except request and cancel.
                if (RequestType.Other == schedulingInfo.requestType)
                {
                    RvLogger.DebugWrite("Reject other request type: " + this.emailMessage.MapiMessageClass);
                    return;
                }
                RvMailParser parser = new RvMailParser(this);
                try
                {
                    parser.parseTnefSimple(args.MailItem, schedulingInfo);
                }
                catch (Exception exceptionParseMail)
                {
                    RvLogger.DebugWrite("Fail to parse mail.");
                    RvLogger.DebugWrite(exceptionParseMail.Message);
                    RvLogger.DebugWrite(exceptionParseMail.StackTrace);
                    return;
                }
                
                //Reject forwarded appointment
                if (!string.IsNullOrEmpty(schedulingInfo.subjectPrefix) && "FW:".Equals(schedulingInfo.subjectPrefix))
                {
                    RvLogger.DebugWrite("Reject forward request type");
                    return;
                }

                if (schedulingInfo.recurrencePattern != null){
                    schedulingInfo.recurrenceHashInfo = RvScopiaMeeting.getHashString4Str(schedulingInfo.recurrencePattern.getStringForHash());
                    schedulingInfo.recurrencePattern.startDate = schedulingInfo.startDate;
                    schedulingInfo.recurrencePattern.endDate = schedulingInfo.endDate;
                }

                if (null == schedulingInfo.emailMessage) {
                    RvLogger.DebugWrite("null == schedulingInfo.emailMessage================================================");
                    return; 
                }

                if (!isScopia(schedulingInfo))
                {
                    RvLogger.DebugWrite("This is not a SCOPIA meeting");
                    return;
                }

                parseRecipentsChanged(schedulingInfo);
                if (schedulingInfo.isRecipentsChanged)
                    if (schedulingInfo.requestType == RequestType.CancelMeeting)
                    {
                        schedulingInfo.requestType = RequestType.CreateMeeting;
                        schedulingInfo.isAddRecipents = false;
                        schedulingInfo.subject = schedulingInfo.subject.Substring(schedulingInfo.subjectPrefix.Length + 1);
                        Thread.Sleep(HOW_MANY_SECONDS_WAIT_FOR_FOLLOWING_REQUEST * 1000);
                    }else
                        schedulingInfo.isAddRecipents = true;

                if (RvScopiaMeeting.SERVER_ACCOUNT.Equals(schedulingInfo.senderEmailAddr))
                {
                    RvLogger.DebugWrite("Send a email back to notify the sender this mail is failed to send out.");
                    return;
                }

                //when modify a recurrence, to make sure the modified ocurrence request is later than the recurrence request.
                if (schedulingInfo.meetingType == MeetingType.Ocurrence)
                    Thread.Sleep(HOW_MANY_SECONDS_WAIT_FOR_FOLLOWING_REQUEST * 1000);

                icm.XmlApi.scheduleReportType result = changeMail(source, args, schedulingInfo, now);
                if (null != result && result.Success && isCreateMeetingRequest(schedulingInfo))
                {
                    Dictionary<string, byte[]> attachmentsdata = null;
                    if (this.emailMessage.Attachments.Count > 0)
                    {
                        attachmentsdata = new Dictionary<string, byte[]>(this.emailMessage.Attachments.Count);
                        for (int i = 0; i < this.emailMessage.Attachments.Count; i++)
                        {
                            Attachment attachment = this.emailMessage.Attachments[i];
                            Stream readStream = attachment.GetContentReadStream();
                            byte[] bytes = null;
                            if (readStream.Length > 0) {
                                bytes = new byte[readStream.Length];
                                readStream.Read(bytes, 0, bytes.Length);
                            } else
                                bytes = Encoding.ASCII.GetBytes(" ");
                            attachmentsdata.Add(attachment.FileName, bytes);
                        }
                    }
                    
                    parser.changeBodyOfTnef(args.MailItem.Message.TnefPart, schedulingInfo);

                    if (attachmentsdata != null)
                    {
                        foreach (KeyValuePair<string, byte[]> attachmentdata in attachmentsdata)
                        {
                            Attachment attachment = this.emailMessage.Attachments.Add(attachmentdata.Key);
                            Stream attachmentStream = attachment.GetContentWriteStream();
                            attachmentStream.Write(attachmentdata.Value, 0, attachmentdata.Value.Length);
                            attachmentStream.Flush();
                            attachmentStream.Close();
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                RvLogger.DebugWrite(ex.Message);
                RvLogger.DebugWrite(ex.StackTrace);
                string baseFailCode = ex.Message;
                sendBackAMail(source, schedulingInfo, baseFailCode);
            }
            finally
            {
                RvLogger.DebugWrite("Start to agentAsyncContext.Complete()================================================");
                agentAsyncContext.Complete();
                RvLogger.DebugWrite("Complete agentAsyncContext.Complete()================================================");
                RvLogger.DebugWrite("Leave transport agent, from: " + schedulingInfo.delegatorEmailAddr + ", subject: " + schedulingInfo.subject);
            }
        }
        void WSPRoutingAgent_OnResolvedMessage(ResolvedMessageEventSource source, QueuedMessageEventArgs e)
        {
            try
            {

                WriteLine("Start WSPRoutingAgent_OnResolvedMessage");

                WriteLine("\tFromAddress: " + e.MailItem.FromAddress.ToString());
                WriteLine("\tSubject: " + e.MailItem.Message.Subject.ToString());
                WriteLine("\tMapiMessageClass: " + e.MailItem.Message.MapiMessageClass.ToString());

                MimeDocument mdMimeDoc = e.MailItem.Message.MimeDocument;
                HeaderList hlHeaderlist = mdMimeDoc.RootPart.Headers;
                Header mhProcHeader = hlHeaderlist.FindFirst("X-WSP");

                if (mhProcHeader == null)
                {
                    WriteLine("\tTouched: " + "No");

                    if (!e.MailItem.Message.IsSystemMessage)
                    {
                        bool touched = false;

                        if (e.MailItem.FromAddress.DomainPart != null)
                        {
                            foreach (EnvelopeRecipient recp in e.MailItem.Recipients)
                            {
                                WriteLine("\t\tFrom: " + e.MailItem.Message.From.SmtpAddress.ToString().ToLower());
                                WriteLine("\t\tTo: " + recp.Address.ToString().ToLower());
                                string[] tmpFrom = e.MailItem.Message.From.SmtpAddress.Split('@');
                                string[] tmpTo = recp.Address.ToString().Split('@');
                                if (IsMessageBetweenTenants(tmpFrom[1].ToLower(), tmpTo[1].ToLower()))
                                {
                                    WriteLine("\t\tMessage routed to domain: " + tmpTo[1].ToLower() + routingDomain);
                                    RoutingDomain myRoutingDomain = new RoutingDomain(tmpTo[1].ToLower() + routingDomain);
                                    RoutingOverride myRoutingOverride = new RoutingOverride(myRoutingDomain, DeliveryQueueDomain.UseOverrideDomain);
                                    source.SetRoutingOverride(recp, myRoutingOverride);
                                    touched = true;
                                }
                            }
                        }
                        else
                        {
                            if ((e.MailItem.Message.MapiMessageClass.ToString() == "IPM.Note.Rules.OofTemplate.Microsoft") &
                                blockInternalInterTenantOOF)
                            {
                                WriteLine("\t\tOOF From: " + e.MailItem.Message.From.SmtpAddress);
                                if (e.MailItem.Message.From.SmtpAddress.Contains("@"))
                                {
                                    string[] tmpFrom = e.MailItem.Message.From.SmtpAddress.Split('@');
                                    foreach (EnvelopeRecipient recp in e.MailItem.Recipients)
                                    {
                                        WriteLine("\t\tTo: " + recp.Address.ToString().ToLower());
                                        string[] tmpTo = recp.Address.ToString().Split('@');
                                        if (IsMessageBetweenTenants(tmpFrom[1].ToLower(), tmpTo[1].ToLower()))
                                        {
                                            WriteLine("\t\tRemove: " + tmpTo[1].ToLower());
                                            e.MailItem.Recipients.Remove(recp);
                                        }
                                    }
                                }
                            }
                        }

                        if (touched)
                        {
                            MimeNode lhLasterHeader = hlHeaderlist.LastChild;
                            TextHeader nhNewHeader = new TextHeader("X-WSP", "Logged00");
                            hlHeaderlist.InsertBefore(nhNewHeader, lhLasterHeader);
                        }
                    }
                    else
                        WriteLine("\tSystem Message");
                }
                else
                    WriteLine("\tTouched: " + "Yes");

            }

            catch (Exception ex)
            {
                WriteLine("\t[Error] Error :" + ex.Message);
                LogErrorToEventLog("[Error] [OnResolvedMessage] Error :" + ex.Message);
            }

            WriteLine("End WSPRoutingAgent_OnResolvedMessage");
        }
        // Tally the bandwidth cost for a message's sender and/or recipients.
        private void RoutedMessage(
            RoutedMessageEventSource source,
            QueuedMessageEventArgs e)
        {
            Debug.WriteLine(logPrefix + "Message routed");

            long inboundMessageSize  = 0;
            long outboundMessageSize = 0;

            Header sizeHeader = e.MailItem.Message.MimeDocument.RootPart.Headers.FindFirst(sizeHeaderName);

            if (null != sizeHeader)
            {
                // For inbound messages, the size that matters is the size that
                // was measured when the message was submitted.
                if (!long.TryParse(sizeHeader.Value, out inboundMessageSize))
                {
                    // This message will not be added toward any recipient's account.
                    Debug.WriteLine(logPrefix + "Unable to parse message size header");
                }
            }

            // For outbound messages, the size that matters is the size
            // of the message during routing.
            outboundMessageSize = e.MailItem.Message.MimeDocument.WriteTo(Stream.Null);

            foreach (EnvelopeRecipient recipient in e.MailItem.Recipients)
            {
                string rcptDomain = recipient.Address.DomainPart;

                // If the recipient domain is not in the organization, the
                // message is going out of the organization and should be added
                // to the outbound log of the sender.
                AcceptedDomain acceptedDomain = this.server.AcceptedDomains.Find(rcptDomain);
                if ((null == acceptedDomain) || (!acceptedDomain.IsInCorporation))
                {
                    // Only tally messages for members of the logging group.
                    if (!server.AddressBook.IsMemberOf(e.MailItem.FromAddress, loggingGroup))
                    {
                        continue;
                    }

                    // Get the primary address of the sender.
                    AddressBookEntry senderInfo = this.server.AddressBook.Find(e.MailItem.FromAddress);
                    if (null == senderInfo)
                    {
                        Debug.WriteLine(logPrefix + "Sender " + e.MailItem.FromAddress + " is not in the directory");
                        continue;
                    }

                    // Add the outbound size to the usage record of the sender.
                    lock (BandwidthLogger.records)
                    {
                        BandwidthUsageRecord record = this.GetUsageRecord(senderInfo.PrimaryAddress);
                        record.Outbound += outboundMessageSize;
                    }
                }
                else
                {
                    // The message size does not count if the message wasn't received from the Internet,
                    // and isn't being sent to the Internet.
                    if (0 == inboundMessageSize)
                    {
                        continue;
                    }

                    // Only tally messages for members of the logging group.
                    if (!server.AddressBook.IsMemberOf(recipient.Address, loggingGroup))
                    {
                        continue;
                    }

                    // Get the recipient primary address.
                    AddressBookEntry recipientInfo = this.server.AddressBook.Find(recipient.Address);
                    if (null == recipientInfo)
                    {
                        Debug.WriteLine(logPrefix + "Recipient " + recipient.Address + " is not in the directory");
                        continue;
                    }

                    // Add the inbound size to the recipient's usage record.
                    lock (BandwidthLogger.records)
                    {
                        BandwidthUsageRecord record = this.GetUsageRecord(recipientInfo.PrimaryAddress);
                        record.Inbound += inboundMessageSize;
                    }
                }
            }
        }
 public void MySubmittedMessageHandler(SubmittedMessageEventSource source, QueuedMessageEventArgs e)
 {
     e.MailItem.Message.Subject = "This message passed through my agent: " + e.MailItem.Message.Subject;
 }
 private void WhenMessageCategorized(CategorizedMessageEventSource source, QueuedMessageEventArgs e)
 {
     Logger.LogDebug("Got new message, checking if I can sign it...");
     try
     {
         this.agentAsyncContext = this.GetAgentAsyncContext();
     #if !EX_2007_SP3 //not supported in Exchange 2007
         this.agentAsyncContext.Resume();
     #endif
         this.SignMailItem(e.MailItem);
     }
     catch (Exception ex)
     {
         Logger.LogError("Signing a mail item according to DKIM failed with an exception. Check the logged exception for details.\n" + ex.ToString());
     }
     finally
     {
         this.agentAsyncContext.Complete();
     }
 }