Пример #1
0
        /// <summary>
        /// Publish requested mail content to the stream.
        /// </summary>
        /// <param name="cancel"></param>
        /// <param name="uid"></param>
        /// <returns></returns>
        private async Task PublishRequestedByUidMailContent(CancellationToken cancel, string uid)
        {
            try
            {
                using (IMailStorage <MailContentEntity> storage = _mailContentStorageFactory())
                {
                    // 1. Check if content already exists in the database.
                    if (storage.Exists(x => x.Uid == uid))
                    {
                        var mailContentEntity = storage.FindOne(x => x.Uid == uid);

                        if (mailContentEntity == null || !mailContentEntity.IsComplete)
                        {
                            // 2. If content is not yet downloaded of any reason, download it and publish afterwards.
                            await RunDownloadContentAsyncLoop(cancel, new List <string>() { uid });
                        }
                        else
                        {
                            _mailContentStream.OnNext(new MailContent(mailContentEntity));
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error(e, "PublishRequestedByUidMailContent");
            }
        }
Пример #2
0
        /// <summary>
        /// Reset the connection state.
        /// </summary>
        private void Rset(Pop3Context context)
        {
            if (context.LastCommand != -1)
            {
                if (context != null && !String.IsNullOrEmpty(context.Username))
                {
                    IMailStorage mail = (_storage != null ? _storage as IMailStorage : null);

                    if (mail != null)
                    {
                        mail.Logout(context.Username);
                    }
                }

                context.Reset();
                context.Username    = null;
                context.Password    = null;
                context.LastCommand = -1;

                context.WriteLine(MESSAGE_OK);
            }
            else
            {
                context.WriteLine(MESSAGE_INVALID_COMMAND_ORDER);
            }
        }
Пример #3
0
        /// <summary>
        /// Handels the PASS command.
        /// </summary>
        private void Pass(Pop3Context context, String[] inputs)
        {
            if (context.LastCommand == COMMAND_USER)
            {
                if (inputs.Length == 2)
                {
                    IMailStorage mail = (_storage != null ? _storage as IMailStorage : null);

                    if (mail == null || mail.Login(context.Username, inputs[1]) == true)
                    {
                        context.Password    = inputs[1];
                        context.LastCommand = COMMAND_PASS;
                        context.WriteLine(MESSAGE_PASSWORD_OK);
                    }
                    else
                    {
                        context.Username    = null;
                        context.Password    = null;
                        context.LastCommand = -1;
                        context.WriteLine(MESSAGE_PASSWORD_INVALID);
                    }
                }
                else
                {
                    context.WriteLine(MESSAGE_INVALID_ARGUMENT_COUNT);
                }
            }
            else
            {
                context.WriteLine(MESSAGE_INVALID_COMMAND_ORDER);
            }
        }
Пример #4
0
 public MessageProcessor(IMailDeliverer deliverer, IMailStorage storage, IDistributedCache cache, ILogger <MessageProcessor> logger)
 {
     this.deliverer = deliverer;
     this.storage   = storage;
     this.logger    = logger;
     this.cache     = cache;
 }
Пример #5
0
 public ApplicationWorker(AccountsSettingsModel accountsSettings,
                          EventBus eventBus,
                          OutgoingMailServiceResolver serviceResolver,
                          AsyncObservableCollection <EmailGroupModel> emailGroupList,
                          ApplicationSettingsModel appSettings,
                          IMailStorage mailStorage)
 {
     _accountsSettings = accountsSettings;
     _eventBus         = eventBus;
     _serviceResolver  = serviceResolver;
     _emailGroupList   = emailGroupList;
     _appSettings      = appSettings;
     _mailStorage      = mailStorage;
 }
Пример #6
0
 public ApplicationWorker(AccountsSettingsModel accountsSettings, 
     EventBus eventBus, 
     OutgoingMailServiceResolver serviceResolver, 
     AsyncObservableCollection<EmailGroupModel> emailGroupList,
     ApplicationSettingsModel appSettings,
     IMailStorage mailStorage)
 {
     _accountsSettings = accountsSettings;
     _eventBus = eventBus;
     _serviceResolver = serviceResolver;
     _emailGroupList = emailGroupList;
     _appSettings = appSettings;
     _mailStorage = mailStorage;
 }
Пример #7
0
 /// <summary>
 /// Loads all existing mail headers in local database and publish them to the stream.
 /// </summary>
 public async void LoadAllExistingMailHeaders()
 {
     try
     {
         await Task.Run(() =>
         {
             // Loads all existing mail headers in local database and publish them to subscribers.
             using (IMailStorage <MailHeaderEntity> storage = _mailHeaderStorageFactory())
             {
                 var mailHeaderEntities = storage.FindAll().ToList();
                 if (mailHeaderEntities.Count > 0)
                 {
                     // Publish mail headers.
                     mailHeaderEntities.ForEach(mailHeaderEntity => { _mailHeaderStream.OnNext(new MailHeader(mailHeaderEntity)); });
                 }
             }
         });
     }
     catch (Exception e)
     {
         Logger.Error(e, "LoadAllExistingMailHeaders");
     }
 }
Пример #8
0
 public MailClient(IMailDelivery delivery, IMailStorage storage, IMailLogger logger)
 {
     this.delivery = delivery;
     this.storage  = storage;
     this.logger   = logger;
 }
Пример #9
0
        /// <summary>
        /// Download MailContent for given uids.
        /// </summary>
        /// <param name="cancel"></param>
        /// <param name="uids"></param>
        /// <returns></returns>
        private async Task RunDownloadContentAsyncLoop(CancellationToken cancel, List <string> uids)
        {
            if (uids == null || uids.Count == 0)
            {
                return;
            }

            // Create mail client.
            IMailClient client = (new TrivialMailDllFactory()).Build(_serverType);

            try
            {
                await Task.Factory.StartNew(() =>
                {
                    client.Connect(_serverEncryption, _host);
                    client.Login(_user, _password);

                    // If is not connected or encrypted (if req) then will break and try to reconnect.
                    if (client.IsConnected && (_serverEncryption == MailServerEncryption.Unencrypted || client.IsEncrypted))
                    {
                        using (IMailStorage <MailContentEntity> storage = _mailContentStorageFactory())
                        {
                            foreach (var uid in uids)
                            {
                                if (string.IsNullOrWhiteSpace(uid))
                                {
                                    continue;
                                }

                                if (cancel.IsCancellationRequested)
                                {
                                    break;
                                }

                                var downloadRequired = true;
                                MailContentEntity mailContentEntity = null;
                                if (storage.Exists(x => x.Uid == uid))
                                {
                                    mailContentEntity = storage.FindOne(x => x.Uid == uid);

                                    if (mailContentEntity != null && mailContentEntity.IsComplete)
                                    {
                                        downloadRequired = false;
                                    }
                                }

                                if (downloadRequired)
                                {
                                    // 1. Insert empty MailContent with only uid set to prevent other concurrent method to download same content.
                                    mailContentEntity = new MailContentEntity()
                                    {
                                        Uid        = uid,
                                        IsComplete = false
                                    };
                                    storage.Insert(new List <MailContentEntity>()
                                    {
                                        mailContentEntity
                                    });

                                    // 2. Download complete email.
                                    var message = client.GetMessageByUid(uid);

                                    // Note: MailDll documentation states that message can be null.
                                    if (message != null)
                                    {
                                        IMail email = new MailBuilder().CreateFromEml(message);
                                        if (email != null)
                                        {
                                            // 3. Update database with downloaded email content.
                                            mailContentEntity = new MailContentEntity()
                                            {
                                                Uid          = uid,
                                                Date         = email?.Date == null ? DateTime.MinValue : email.Date.Value,
                                                Html         = email.Html,
                                                MessageId    = email.MessageID,
                                                Text         = email.Text,
                                                CustomHeader = email?.Document.Root.Headers["x-spam"],
                                                IsComplete   = true
                                            };

                                            storage.Update(new List <MailContentEntity>()
                                            {
                                                mailContentEntity
                                            });

                                            // Publish MailContent.
                                            _mailContentStream.OnNext(new MailContent(mailContentEntity));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }, cancel, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
            }
            catch (Exception e)
            {
                Logger.Error(e, $"RunDownloadContentAsync");
            }
            finally
            {
                client?.Close();
            }
        }
Пример #10
0
        /// <summary>
        /// Every 30s queries mail server for new email.
        /// When there are new emails available it first download all mail headers and publishes them to the stream.
        /// Afterwards start downloading all mail content for just downloaded mail headers.
        /// </summary>
        /// <param name="cancel"></param>
        /// <returns></returns>
        private async Task RunCheckForNewMailAsyncLoop(CancellationToken cancel)
        {
            // Create mail client.
            IMailClient client = (new TrivialMailDllFactory()).Build(_serverType);

            try
            {
                // Publish Connecting state.
                _controllerStateStream.OnNext(ControllerState.Connecting);
                client.Connect(_serverEncryption, _host);

                // Publish LoggingIn state.
                _controllerStateStream.OnNext(ControllerState.LoggingIn);
                client.Login(_user, _password);

                // Publish Connected state.
                _controllerStateStream.OnNext(ControllerState.Connected);

                // Main loop
                while (!cancel.IsCancellationRequested)
                {
                    // If disconnect or not encrypted (when should be) then reconnect.
                    if (client.IsConnected && (_serverEncryption == MailServerEncryption.Unencrypted || client.IsEncrypted))
                    {
                        // MailHeaderList contains new headers which will be published to subscribers.
                        List <MailHeaderEntity> mailHeaderEntities = new List <MailHeaderEntity>();

                        using (IMailStorage <MailHeaderEntity> storage = _mailHeaderStorageFactory())
                        {
                            // 1. Get from mail server all uids (emails).
                            // ToDo: for Imap this could be improved.
                            List <string> newUids = client.GetAllUids().ToList();

                            // 2. Distinct list of uids which are not yet stored in the database.
                            // Let's reverse and start checking with the most recent email (the latest uid).
                            newUids.Reverse();
                            List <string> uidList = new List <string>();
                            foreach (var uid in newUids)
                            {
                                if (!storage.Exists(x => x.Uid == uid))
                                {
                                    uidList.Add(uid);
                                }
                                else
                                {
                                    break;
                                }
                                // Note: if any first exists, break the loop other emails are probably downloaded.
                            }

                            if (uidList.Count > 0)
                            {
                                // 3. Download mail headers.
                                foreach (var uid in uidList)
                                {
                                    // Download message header.
                                    var header = client.GetHeadersByUid(uid);

                                    // Note: MailDll documentation states that header can be null.
                                    if (header == null)
                                    {
                                        throw new ArgumentNullException(nameof(header), $"Downloaded an empty email header ({uid}).");
                                    }

                                    var email            = new MailBuilder().CreateFromEml(header);
                                    var emailFrom        = email?.From.FirstOrDefault();
                                    var mailHeaderEntity = new MailHeaderEntity()
                                    {
                                        Uid            = uid,
                                        Date           = email?.Date ?? DateTime.MinValue,
                                        Subject        = email?.Subject,
                                        MailFromEntity = new MailFromEntity()
                                        {
                                            Address    = emailFrom?.Address,
                                            Name       = emailFrom?.Name,
                                            LocalPart  = emailFrom?.LocalPart,
                                            DomainPart = emailFrom?.DomainPart
                                        }
                                    };

                                    mailHeaderEntities.Add(mailHeaderEntity);
                                }

                                // 4. Insert all new mail headers into the storage.
                                storage.Insert(mailHeaderEntities);
                            }
                        }

                        // For all new email headers publish them to the subscribers and download the content.
                        // Note: This whole block is taken out from above using() to release storage handle asap.
                        if (mailHeaderEntities.Count > 0)
                        {
                            // 5. Publish all new mail headers to the stream.
                            mailHeaderEntities.ForEach(mailHeaderEntity => { _mailHeaderStream.OnNext(new MailHeader(mailHeaderEntity)); });

                            // 6. Start downloading content loop
                            // It's not done in above foreach loop to not to keep storage open for too long
                            // when running over slow internet connection.
                            RunDownloadContentAsyncLoop(cancel, mailHeaderEntities.Select(x => x.Uid).ToList());
                        }
                    }
                    else
                    {
                        break;
                    }

                    // Check for new email again in 30s
                    await Observable.Return(0).Delay(TimeSpan.FromSeconds(30), Scheduler.CurrentThread).ToTask(cancel);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e, $"RunCheckForNewMailAsyncLoop");
            }
            finally
            {
                client?.Close();

                if (!cancel.IsCancellationRequested)
                {
                    // Publish Disconnected state.
                    _controllerStateStream.OnNext(ControllerState.Disconnected);
                }
            }
        }
Пример #11
0
 public MailService RegisterStorage(IMailStorage storage)
 {
     this.storage = storage;
     return this;
 }