diff --git a/EmailSendService.lib/EmailSendService.lib.csproj b/EmailSendService.lib/EmailSendService.lib.csproj
new file mode 100644
index 0000000..2392443
--- /dev/null
+++ b/EmailSendService.lib/EmailSendService.lib.csproj
@@ -0,0 +1,54 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {1C081ED6-B778-44E9-B0D8-36FAAB09A87A}
+ Library
+ Properties
+ EmailSendService.lib
+ EmailSendService.lib
+ v4.6.1
+ 512
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {772FEDB7-183B-40F1-89D1-4415997A0D1E}
+ SpamTools.lib
+
+
+
+
\ No newline at end of file
diff --git a/EmailSendService.lib/Properties/AssemblyInfo.cs b/EmailSendService.lib/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..74cb91c
--- /dev/null
+++ b/EmailSendService.lib/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Общие сведения об этой сборке предоставляются следующим набором
+// набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения,
+// связанные со сборкой.
+[assembly: AssemblyTitle("EmailSendService.lib")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("EmailSendService.lib")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
+// для компонентов COM. Если необходимо обратиться к типу в этой сборке через
+// COM, задайте атрибуту ComVisible значение TRUE для этого типа.
+[assembly: ComVisible(false)]
+
+// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM
+[assembly: Guid("1c081ed6-b778-44e9-b0d8-36faab09a87a")]
+
+// Сведения о версии сборки состоят из следующих четырех значений:
+//
+// Основной номер версии
+// Дополнительный номер версии
+// Номер сборки
+// Редакция
+//
+// Можно задать все значения или принять номер сборки и номер редакции по умолчанию.
+// используя "*", как показано ниже:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/EmailSendService.lib/SenderService.cs b/EmailSendService.lib/SenderService.cs
new file mode 100644
index 0000000..dcf5bf1
--- /dev/null
+++ b/EmailSendService.lib/SenderService.cs
@@ -0,0 +1,83 @@
+using SpamTools.lib.Data;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Net;
+using System.Net.Mail;
+using System.Security;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using SpamTools.lib.Database;
+
+namespace EmailSendService.lib
+{
+ public class SenderService
+ {
+ private string _ServerAdress;
+ private int _Port;
+ private bool _UseSSL;
+ private string _FromLogin;
+ private SecureString _FromPassword;
+ public string Subject { get; set; }
+
+ public SenderService(string ServerAdress, int Port, bool UseSSL, string FromLogin, SecureString FromPassword)
+ {
+ _ServerAdress = ServerAdress;
+ _Port = Port;
+ _UseSSL = UseSSL;
+ _FromLogin = FromLogin;
+ _FromPassword = FromPassword;
+ }
+
+ public void Send(string to, string subject, string body)
+ {
+ //string response = default(string);
+ using (var message = new MailMessage(_FromLogin, to))
+ {
+ message.Subject = subject;
+ message.Body = body;
+
+ using (var client = new SmtpClient(_ServerAdress, _Port))
+ {
+ client.EnableSsl = _UseSSL;
+ client.Credentials = new NetworkCredential(_FromLogin, _FromPassword);
+ try
+ {
+ client.Send(message);
+ //response = $"Письмо успешно отправлено на почту {to}";
+ }
+ catch (Exception ex)
+ {
+ //response = "Ошибка: "+ex.Message;
+ }
+ }
+ }
+ //return response;
+ }
+ ///
+ /// массовое отправление писем
+ ///
+ /// тема письма
+ /// тело письма
+ /// получатели письма
+ public void SendParallel(string subject, string body, IEnumerable recipients)
+ {
+ foreach (var recipient in recipients)
+ {
+ var sending_thread = new Thread(() => Send(recipient.EmailAdress, subject, body));
+ sending_thread.IsBackground = true;
+ sending_thread.Start();
+ }
+ }
+ public void Send(string subject, string body, IEnumerable recipients)
+ {
+ foreach (var recipient in recipients)
+ {
+ Task.Factory.StartNew(()=> Send(subject, body, recipient.EmailAdress));
+ }
+ }
+ }
+}
diff --git a/MailSender.sln b/MailSender.sln
index 9da86fb..ddb4fae 100644
--- a/MailSender.sln
+++ b/MailSender.sln
@@ -5,6 +5,20 @@ VisualStudioVersion = 15.0.28307.168
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MailSender", "MailSender\MailSender.csproj", "{F41CB514-4BD5-4D18-8411-7B0579F510F2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpamTools.lib", "SpamTools.lib\SpamTools.lib.csproj", "{772FEDB7-183B-40F1-89D1-4415997A0D1E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmailSendService.lib", "EmailSendService.lib\EmailSendService.lib.csproj", "{1C081ED6-B778-44E9-B0D8-36FAAB09A87A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8BB062CE-B09C-4B1F-9E7B-612FA41317E0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpamTools.lib.Tests", "SpamTools.lib.Tests\SpamTools.lib.Tests.csproj", "{F28BF459-9A95-4B66-AC0A-D50D9216108E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "hw5", "hw5\hw5.csproj", "{7BE85544-8D56-4E23-8E2E-8C1939D21427}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "hw6-1", "hw6\hw6-1.csproj", "{941649D3-FC29-44DC-914B-91C388ACB211}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "hw6-2", "hw6-2\hw6-2.csproj", "{749183D2-F08B-4730-B6D3-D9F410ADE740}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,10 +29,37 @@ Global
{F41CB514-4BD5-4D18-8411-7B0579F510F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F41CB514-4BD5-4D18-8411-7B0579F510F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F41CB514-4BD5-4D18-8411-7B0579F510F2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {772FEDB7-183B-40F1-89D1-4415997A0D1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {772FEDB7-183B-40F1-89D1-4415997A0D1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {772FEDB7-183B-40F1-89D1-4415997A0D1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {772FEDB7-183B-40F1-89D1-4415997A0D1E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1C081ED6-B778-44E9-B0D8-36FAAB09A87A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1C081ED6-B778-44E9-B0D8-36FAAB09A87A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1C081ED6-B778-44E9-B0D8-36FAAB09A87A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1C081ED6-B778-44E9-B0D8-36FAAB09A87A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F28BF459-9A95-4B66-AC0A-D50D9216108E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F28BF459-9A95-4B66-AC0A-D50D9216108E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F28BF459-9A95-4B66-AC0A-D50D9216108E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F28BF459-9A95-4B66-AC0A-D50D9216108E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7BE85544-8D56-4E23-8E2E-8C1939D21427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7BE85544-8D56-4E23-8E2E-8C1939D21427}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7BE85544-8D56-4E23-8E2E-8C1939D21427}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7BE85544-8D56-4E23-8E2E-8C1939D21427}.Release|Any CPU.Build.0 = Release|Any CPU
+ {941649D3-FC29-44DC-914B-91C388ACB211}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {941649D3-FC29-44DC-914B-91C388ACB211}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {941649D3-FC29-44DC-914B-91C388ACB211}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {941649D3-FC29-44DC-914B-91C388ACB211}.Release|Any CPU.Build.0 = Release|Any CPU
+ {749183D2-F08B-4730-B6D3-D9F410ADE740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {749183D2-F08B-4730-B6D3-D9F410ADE740}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {749183D2-F08B-4730-B6D3-D9F410ADE740}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {749183D2-F08B-4730-B6D3-D9F410ADE740}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F28BF459-9A95-4B66-AC0A-D50D9216108E} = {8BB062CE-B09C-4B1F-9E7B-612FA41317E0}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F5A42F05-4853-4892-8AB8-28B2CD3F0A5E}
EndGlobalSection
diff --git a/MailSender/App.config b/MailSender/App.config
index 731f6de..983f06a 100644
--- a/MailSender/App.config
+++ b/MailSender/App.config
@@ -1,6 +1,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MailSender/App.xaml b/MailSender/App.xaml
index 2216690..9c6a5b4 100644
--- a/MailSender/App.xaml
+++ b/MailSender/App.xaml
@@ -1,13 +1,14 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MailSender/Controls/ListViewItemScheduler-custom.xaml b/MailSender/Controls/ListViewItemScheduler-custom.xaml
new file mode 100644
index 0000000..d2a6b73
--- /dev/null
+++ b/MailSender/Controls/ListViewItemScheduler-custom.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+ Время:
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MailSender/Controls/ListViewItemScheduler-custom.xaml.cs b/MailSender/Controls/ListViewItemScheduler-custom.xaml.cs
new file mode 100644
index 0000000..b109c24
--- /dev/null
+++ b/MailSender/Controls/ListViewItemScheduler-custom.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MailSender.Controls
+{
+ ///
+ /// Логика взаимодействия для ListViewItemScheduler_custom.xaml
+ ///
+ public partial class ListViewItemScheduler_custom : UserControl
+ {
+ public ListViewItemScheduler_custom()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MailSender/Controls/ListViewItemScheduler.xaml b/MailSender/Controls/ListViewItemScheduler.xaml
new file mode 100644
index 0000000..39f570e
--- /dev/null
+++ b/MailSender/Controls/ListViewItemScheduler.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/MailSender/Controls/ListViewItemScheduler.xaml.cs b/MailSender/Controls/ListViewItemScheduler.xaml.cs
new file mode 100644
index 0000000..d84234d
--- /dev/null
+++ b/MailSender/Controls/ListViewItemScheduler.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MailSender.Controls
+{
+ ///
+ /// Логика взаимодействия для ListViewItemScheduler.xaml
+ ///
+ public partial class ListViewItemScheduler : UserControl
+ {
+ public ListViewItemScheduler()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MailSender/Controls/Otpraviteli.xaml b/MailSender/Controls/Otpraviteli.xaml
new file mode 100644
index 0000000..5e10aeb
--- /dev/null
+++ b/MailSender/Controls/Otpraviteli.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MailSender/Controls/Otpraviteli.xaml.cs b/MailSender/Controls/Otpraviteli.xaml.cs
new file mode 100644
index 0000000..bd03f77
--- /dev/null
+++ b/MailSender/Controls/Otpraviteli.xaml.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MailSender.Controls
+{
+ ///
+ /// Логика взаимодействия для Otpraviteli.xaml
+ ///
+ public partial class Otpraviteli : UserControl
+ {
+ public Otpraviteli()
+ {
+ InitializeComponent();
+ }
+
+ #region PanelText
+ public static readonly DependencyProperty PanelTextProperty = DependencyProperty.Register(
+ "PanelText", typeof(string), typeof(Otpraviteli), new PropertyMetadata("Текст панели"));
+
+ public string PanelText
+ {
+ get { return (string)GetValue(PanelTextProperty); }
+ set { SetValue(PanelTextProperty, value); }
+ }
+ #endregion
+ #region ItemsSource
+ public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
+ "ItemsSource", typeof(IEnumerable), typeof(Otpraviteli), new PropertyMetadata(default(IEnumerable)));
+
+ public IEnumerable ItemsSource
+ {
+ get { return (IEnumerable)GetValue(ItemsSourceProperty); }
+ set { SetValue(ItemsSourceProperty, value); }
+ }
+ #endregion
+ #region ItemTemplate
+
+ public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
+ "ItemTemplate", typeof(DataTemplate), typeof(Otpraviteli), new PropertyMetadata(default(DataTemplate)));
+
+ public DataTemplate ItemTemplate
+ {
+ get { return (DataTemplate) GetValue(ItemTemplateProperty); }
+ set { SetValue(ItemTemplateProperty, value); }
+ }
+ #endregion
+ #region SelectedIndex
+
+ public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register(
+ "SelectedIndex", typeof(int), typeof(Otpraviteli), new PropertyMetadata(default(int)));
+
+ public int SelectedIndex
+ {
+ get { return (int) GetValue(SelectedIndexProperty); }
+ set { SetValue(SelectedIndexProperty, value); }
+ }
+
+
+ #endregion
+ #region SelectedItem
+ public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
+ "SelectedItem", typeof(object), typeof(Otpraviteli), new PropertyMetadata(default(object)));
+
+ public object SelectedItem
+ {
+ get { return (object)GetValue(SelectedItemProperty); }
+ set { SetValue(SelectedItemProperty, value); }
+ }
+ #endregion
+
+ #region CreateItemCommand
+
+ public static readonly DependencyProperty CreateItemCommandProperty = DependencyProperty.Register(
+ "CreateItemCommand", typeof(ICommand), typeof(Otpraviteli), new PropertyMetadata(default(ICommand)));
+
+ public ICommand CreateItemCommand
+ {
+ get { return (ICommand) GetValue(CreateItemCommandProperty); }
+ set { SetValue(CreateItemCommandProperty, value); }
+ }
+ #endregion
+ #region RemoveItemCommand
+
+ public static readonly DependencyProperty RemoveItemCommandProperty = DependencyProperty.Register(
+ "RemoveItemCommand", typeof(ICommand), typeof(Otpraviteli), new PropertyMetadata(default(ICommand)));
+
+ public ICommand RemoveItemCommand
+ {
+ get { return (ICommand) GetValue(RemoveItemCommandProperty); }
+ set { SetValue(RemoveItemCommandProperty, value); }
+ }
+ #endregion
+ #region EditItemCommand
+ public static readonly DependencyProperty EditItemCommandProperty = DependencyProperty.Register(
+ "EditItemCommand", typeof(ICommand), typeof(Otpraviteli), new PropertyMetadata(default(ICommand)));
+
+ public ICommand EditItemCommand
+ {
+ get { return (ICommand) GetValue(EditItemCommandProperty); }
+ set { SetValue(EditItemCommandProperty, value); }
+ }
+ #endregion
+ }
+}
diff --git a/MailSender/Controls/Servers.xaml b/MailSender/Controls/Servers.xaml
new file mode 100644
index 0000000..dad24ba
--- /dev/null
+++ b/MailSender/Controls/Servers.xaml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MailSender/Controls/Servers.xaml.cs b/MailSender/Controls/Servers.xaml.cs
new file mode 100644
index 0000000..102860e
--- /dev/null
+++ b/MailSender/Controls/Servers.xaml.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MailSender.Controls
+{
+ ///
+ /// Логика взаимодействия для Servers.xaml
+ ///
+ public partial class Servers : UserControl
+ {
+ public Servers()
+ {
+ InitializeComponent();
+ }
+ #region PanelText
+ public static readonly DependencyProperty PanelTextProperty = DependencyProperty.Register(
+ "PanelText", typeof(string), typeof(Servers), new PropertyMetadata("Текст панели"));
+
+ public string PanelText
+ {
+ get { return (string)GetValue(PanelTextProperty); }
+ set { SetValue(PanelTextProperty, value); }
+ }
+ #endregion
+ #region ItemsSource
+ public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
+ "ItemsSource", typeof(IEnumerable), typeof(Servers), new PropertyMetadata(default(IEnumerable)));
+
+ public IEnumerable ItemsSource
+ {
+ get { return (IEnumerable)GetValue(ItemsSourceProperty); }
+ set { SetValue(ItemsSourceProperty, value); }
+ }
+ #endregion
+ #region ItemTemplate
+
+ public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
+ "ItemTemplate", typeof(DataTemplate), typeof(Servers), new PropertyMetadata(default(DataTemplate)));
+
+ public DataTemplate ItemTemplate
+ {
+ get { return (DataTemplate)GetValue(ItemTemplateProperty); }
+ set { SetValue(ItemTemplateProperty, value); }
+ }
+ #endregion
+ #region SelectedIndex
+
+ public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register(
+ "SelectedIndex", typeof(int), typeof(Servers), new PropertyMetadata(default(int)));
+
+ public int SelectedIndex
+ {
+ get { return (int)GetValue(SelectedIndexProperty); }
+ set { SetValue(SelectedIndexProperty, value); }
+ }
+
+
+ #endregion
+ #region SelectedItem
+ public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
+ "SelectedItem", typeof(object), typeof(Servers), new PropertyMetadata(default(object)));
+
+ public object SelectedItem
+ {
+ get { return (object)GetValue(SelectedItemProperty); }
+ set { SetValue(SelectedItemProperty, value); }
+ }
+ #endregion
+
+ #region CreateItemCommand
+
+ public static readonly DependencyProperty CreateItemCommandProperty = DependencyProperty.Register(
+ "CreateItemCommand", typeof(ICommand), typeof(Servers), new PropertyMetadata(default(ICommand)));
+
+ public ICommand CreateItemCommand
+ {
+ get { return (ICommand)GetValue(CreateItemCommandProperty); }
+ set { SetValue(CreateItemCommandProperty, value); }
+ }
+ #endregion
+ #region RemoveItemCommand
+
+ public static readonly DependencyProperty RemoveItemCommandProperty = DependencyProperty.Register(
+ "RemoveItemCommand", typeof(ICommand), typeof(Servers), new PropertyMetadata(default(ICommand)));
+
+ public ICommand RemoveItemCommand
+ {
+ get { return (ICommand)GetValue(RemoveItemCommandProperty); }
+ set { SetValue(RemoveItemCommandProperty, value); }
+ }
+ #endregion
+ #region EditItemCommand
+ public static readonly DependencyProperty EditItemCommandProperty = DependencyProperty.Register(
+ "EditItemCommand", typeof(ICommand), typeof(Servers), new PropertyMetadata(default(ICommand)));
+
+ public ICommand EditItemCommand
+ {
+ get { return (ICommand)GetValue(EditItemCommandProperty); }
+ set { SetValue(EditItemCommandProperty, value); }
+ }
+ #endregion
+ }
+}
diff --git a/MailSender/DBClass.cs b/MailSender/DBClass.cs
index 40df5f5..6f03d4c 100644
--- a/MailSender/DBClass.cs
+++ b/MailSender/DBClass.cs
@@ -8,5 +8,13 @@ namespace MailSender
{
class DBClass
{
+ //private EmailsDataContext emails = new EmailsDataContext();
+ //public IQueryable Emails
+ //{
+ // get
+ // {
+ // return from c in emails.Emails select c;
+ // }
+ //}
}
}
diff --git a/MailSender/EmailSendServiceClass.cs b/MailSender/EmailSendServiceClass.cs
index 4233bb0..3696b4a 100644
--- a/MailSender/EmailSendServiceClass.cs
+++ b/MailSender/EmailSendServiceClass.cs
@@ -1,18 +1,62 @@
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Mail;
+using System.Security;
+using System.Windows;
+using SpamTools.lib.Data;
+using SpamTools.lib.Database;
namespace MailSender
{
class EmailSendServiceClass
- {
- public void Send(MainWindow mw)
+ {
+ #region vars
+ private string strLogin;
+ private string strPassword;
+ private string strSmtp = "smtp.yandex.ru";
+ private int iSmtpPort = 25;
+ private string strBody;
+ private string strSubject;
+ #endregion
+ public EmailSendServiceClass(string sLogin, string sPassword)
{
-
+ strLogin = sLogin;
+ strPassword = sPassword;
}
- }
+ private void SendMail(string mail, string name)
+ {
+ using (MailMessage mm = new MailMessage(strLogin, mail))
+ {
+ mm.Subject = strSubject;
+ mm.Body = "Hello world!";
+ mm.IsBodyHtml = false;
+ SmtpClient sc = new SmtpClient(strSmtp, iSmtpPort);
+ sc.EnableSsl = true;
+ sc.DeliveryMethod = SmtpDeliveryMethod.Network;
+ sc.UseDefaultCredentials = false;
+ sc.Credentials = new NetworkCredential(strLogin, strPassword);
+ try
+ {
+ sc.Send(mm);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Невозможно отправить письмо " + ex.ToString());
+ }
+ }
+ }//private void SendMail(string mail, string name)
+ public void SendMails(ObservableCollection emails)
+ {
+ foreach (Sender email in emails)
+ {
+ SendMail(email.Adress, email.Name);
+ }
+ }
+
+ } //private void SendMail(string mail, string name)
}
diff --git a/MailSender/MailSender.csproj b/MailSender/MailSender.csproj
index 3a73bb3..ab2f033 100644
--- a/MailSender/MailSender.csproj
+++ b/MailSender/MailSender.csproj
@@ -35,8 +35,29 @@
4
+
+ ..\packages\CommonServiceLocator.2.0.4\lib\net46\CommonServiceLocator.dll
+
+
+ ..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll
+
+
+ ..\packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.dll
+
+
+ ..\packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Extras.dll
+
+
+ ..\packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Platform.dll
+
+
+ ..\SpamTools.lib\bin\Debug\SpamTools.lib.dll
+
+
+ ..\packages\MvvmLightLibs.5.4.1.1\lib\net45\System.Windows.Interactivity.dll
+
@@ -49,6 +70,24 @@
+
+ ..\packages\Extended.Wpf.Toolkit.3.4.0\lib\net40\Xceed.Wpf.AvalonDock.dll
+
+
+ ..\packages\Extended.Wpf.Toolkit.3.4.0\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll
+
+
+ ..\packages\Extended.Wpf.Toolkit.3.4.0\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll
+
+
+ ..\packages\Extended.Wpf.Toolkit.3.4.0\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll
+
+
+ ..\packages\Extended.Wpf.Toolkit.3.4.0\lib\net40\Xceed.Wpf.DataGrid.dll
+
+
+ ..\packages\Extended.Wpf.Toolkit.3.4.0\lib\net40\Xceed.Wpf.Toolkit.dll
+
@@ -56,13 +95,54 @@
Designer
+
+ ListViewItemScheduler-custom.xaml
+
+
+ ListViewItemScheduler.xaml
+
+
+ Otpraviteli.xaml
+
+
+ Servers.xaml
+
-
+
SendEndWindow.xaml
+
+
+
+
+
+ NewEmailWindowView.xaml
+
+
+ RecipientsEditorView.xaml
+
+
+ RecipientsView.xaml
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
@@ -83,6 +163,18 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
@@ -102,6 +194,7 @@
ResXFileCodeGenerator
Resources.Designer.cs
+
SettingsSingleFileGenerator
Settings.Designer.cs
@@ -110,5 +203,17 @@
+
+
+
+
+
+ {1c081ed6-b778-44e9-b0d8-36faab09a87a}
+ EmailSendService.lib
+
+
+
+
+
\ No newline at end of file
diff --git a/MailSender/MainWindow.xaml b/MailSender/MainWindow.xaml
index 568d53a..837e239 100644
--- a/MailSender/MainWindow.xaml
+++ b/MailSender/MainWindow.xaml
@@ -4,8 +4,16 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MailSender"
+ xmlns:data="clr-namespace:SpamTools.lib.Data;assembly=SpamTools.lib"
+ xmlns:db="clr-namespace:SpamTools.lib.Database;assembly=SpamTools.lib"
+ xmlns:fa="http://schemas.fontawesome.io/icons/"
+ xmlns:xwt="http://schemas.xceed.com/wpf/xaml/toolkit"
+ xmlns:view="clr-namespace:MailSender.View"
+ xmlns:controls="clr-namespace:MailSender.Controls"
mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
+ Title="{Binding Title}" Height="450" Width="800"
+ DataContext="{Binding MainWindowModel, Source={StaticResource Locator}}">
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
diff --git a/MailSender/MainWindow.xaml.cs b/MailSender/MainWindow.xaml.cs
index 64cbf30..a8ab9e9 100644
--- a/MailSender/MainWindow.xaml.cs
+++ b/MailSender/MainWindow.xaml.cs
@@ -15,6 +15,7 @@
using System.ComponentModel;
using System.Net.Mail;
using System.Net;
+using System.Security;
namespace MailSender
{
@@ -27,29 +28,10 @@ public MainWindow()
{
InitializeComponent();
}
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- List emails = to.Text.Split(',').ToList();
- foreach (var email_addr in emails)
- {
- using (var mm = new MailMessage(this.email.Text, email_addr/*to.Text*/, subject.Text, message.Text))
- {
- using (var sc = new SmtpClient(WpfTestMailSender.smtp_adress, WpfTestMailSender.smtp_port))
- {
- sc.EnableSsl = true;
- sc.DeliveryMethod = SmtpDeliveryMethod.Network;
- sc.UseDefaultCredentials = false;
- sc.Credentials = new NetworkCredential(this.email.Text, psw.Password);
- try
- {
- sc.Send(mm);
- }
- catch (Exception ex) { new SendEndWindow($"{email_addr}: {ex.Message}").Show(); }
- }
- }
- }
-
+ private void PlannerClick(object sender, RoutedEventArgs e)
+ {
+ planner.IsSelected = true;
}
}
}
diff --git a/MailSender/Resources/clock.png b/MailSender/Resources/clock.png
new file mode 100644
index 0000000..b0b9c64
Binary files /dev/null and b/MailSender/Resources/clock.png differ
diff --git a/MailSender/Scheduler.cs b/MailSender/Scheduler.cs
new file mode 100644
index 0000000..92b64ac
--- /dev/null
+++ b/MailSender/Scheduler.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+using EmailSendService.lib;
+using System.Windows.Threading;
+using SpamTools.lib.Data;
+using SpamTools.lib.Database;
+
+namespace MailSender
+{
+ public class Scheduler
+ {
+ private readonly ObservableCollection _Tasks;
+ public ObservableCollection Tasks => _Tasks;
+
+ public ObservableCollection strs { get; set; } =
+ new ObservableCollection();
+
+ public Scheduler()
+ {
+ strs.Add("111");
+ strs.Add("222");
+ _Tasks = new ObservableCollection
+ {
+ new SchedulerTask
+ {
+ DateTime = DateTime.Now.Add(TimeSpan.FromMinutes(20)),
+ Recipients = new[]
+ {
+ new EmailRecipients
+ {
+ Id = 1, Name = "Recipient 1", EmailAdress = "recipient1@mail.ru",
+ },
+ new EmailRecipients
+ {
+ Id = 2, Name = "Recipient 2", EmailAdress = "recipient2@mail.ru",
+ },
+ new EmailRecipients
+ {
+ Id = 3, Name = "Recipient 3", EmailAdress = "recipient3@mail.ru",
+ }
+ },
+ MailServer = new MailServer {Adress = "", Port = 2, UseSSL = true},
+ Sender = new Sender
+ {
+ Adress = "sender@mail.ru",
+ Name = "Sender1",
+ Password = "pas"
+ },
+ Mail = new Mail("subject1", "body1"),
+ },
+ new SchedulerTask
+ {
+ DateTime = DateTime.Now.Add(TimeSpan.FromMinutes(40)),
+ Recipients = new[]
+ {
+ new EmailRecipients
+ {
+ Id = 1, Name = "Recipient 1", EmailAdress = "recipient1@mail.ru",
+ },
+ new EmailRecipients
+ {
+ Id = 2, Name = "Recipient 2", EmailAdress = "recipient2@mail.ru",
+ },
+ new EmailRecipients
+ {
+ Id = 3, Name = "Recipient 3", EmailAdress = "recipient3@mail.ru",
+ }
+ },
+ MailServer = new MailServer {Adress = "", Port = 2, UseSSL = true},
+ Sender = new Sender
+ {
+ Adress = "sender@mail.ru",
+ Name = "Sender1",
+ Password = "pas"
+ },
+ Mail = new Mail("subject2", "body2"),
+ }
+ };
+ }
+
+ public Scheduler(IEnumerable tasks)
+ {
+ _Tasks = new ObservableCollection(tasks);
+ }
+
+ public void Start() { }
+
+ public void AddTask(SchedulerTask task)
+ {
+ if (_Tasks.Contains(task)) return;
+ _Tasks.Add(task);
+ }
+
+ public bool RemoveTask(SchedulerTask task)
+ {
+ return _Tasks.Remove(task);
+ }
+
+ }
+}
diff --git a/MailSender/SchedulerClass.cs b/MailSender/SchedulerClass.cs
index ab994b7..da5c102 100644
--- a/MailSender/SchedulerClass.cs
+++ b/MailSender/SchedulerClass.cs
@@ -1,12 +1,50 @@
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+using EmailSendService.lib;
+using System.Windows.Threading;
+using SpamTools.lib.Data;
namespace MailSender
{
class SchedulerClass
{
+ DispatcherTimer timer = new DispatcherTimer();
+ private EmailSendService.lib.SenderService emailSender;
+ private DateTime dtSend;
+ private ObservableCollection emails;
+ public TimeSpan GetSendTime(string strSendTime)
+ {
+ TimeSpan tsSendTime = new TimeSpan();
+ try
+ {
+ tsSendTime = TimeSpan.Parse(strSendTime);
+ }
+ catch { }
+ return tsSendTime;
+ }
+ public void SendEmails(DateTime dtSend, SenderService emailSender, ObservableCollection emails)
+ {
+ this.emailSender = emailSender;
+ this.dtSend = dtSend;
+ this.emails = emails;
+ timer.Tick += Timer_Tick;
+ timer.Interval = new TimeSpan(0, 0, 1);
+ timer.Start();
+ }
+ private void Timer_Tick(object sender, EventArgs e)
+ {
+ if (dtSend.ToShortTimeString() == DateTime.Now.ToShortTimeString())
+ {
+ emailSender.SendMails(emails);
+ timer.Stop();
+ MessageBox.Show("Письма отправлены.");
+ }
+ }
}
}
diff --git a/MailSender/TestMainViewModel.cs b/MailSender/TestMainViewModel.cs
new file mode 100644
index 0000000..b2c65d8
--- /dev/null
+++ b/MailSender/TestMainViewModel.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SpamTools.lib.MVVM;
+
+namespace MailSender
+{
+ //public class TestMainViewModel: ViewModel
+ //{
+ // private string _TestTextValue;
+ // public string TestTextValue
+ // {
+ // get => _TestTextValue;
+ // set => Set(ref _TestTextValue, value);
+ // }
+ //}
+}
diff --git a/MailSender/View/NewEmailWindowView.xaml b/MailSender/View/NewEmailWindowView.xaml
new file mode 100644
index 0000000..7753b77
--- /dev/null
+++ b/MailSender/View/NewEmailWindowView.xaml
@@ -0,0 +1,44 @@
+
+
+ Выберите дату и время отправки:
+
+ Выберите отправителя:
+
+
+
+
+
+
+
+ Выберите получателей:
+
+
+
+
+
+
+
+
+
+
+
+
+ Укажите тему
+
+ Укажите текст письма
+
+
+
+
+
diff --git a/MailSender/View/NewEmailWindowView.xaml.cs b/MailSender/View/NewEmailWindowView.xaml.cs
new file mode 100644
index 0000000..a2ee155
--- /dev/null
+++ b/MailSender/View/NewEmailWindowView.xaml.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace MailSender.View
+{
+ ///
+ /// Логика взаимодействия для NewEmailWindowView.xaml
+ ///
+ public partial class NewEmailWindowView : Window
+ {
+ public NewEmailWindowView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MailSender/View/RecipientsEditorView.xaml b/MailSender/View/RecipientsEditorView.xaml
new file mode 100644
index 0000000..1001b8a
--- /dev/null
+++ b/MailSender/View/RecipientsEditorView.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MailSender/View/RecipientsEditorView.xaml.cs b/MailSender/View/RecipientsEditorView.xaml.cs
new file mode 100644
index 0000000..cf12590
--- /dev/null
+++ b/MailSender/View/RecipientsEditorView.xaml.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace MailSender.View
+{
+ ///
+ /// Логика взаимодействия для RecipientsEditorView.xaml
+ ///
+ public partial class RecipientsEditorView : UserControl
+ {
+ public RecipientsEditorView()
+ {
+ InitializeComponent();
+ }
+
+ private void Validation_OnError(object sender, ValidationErrorEventArgs e)
+ {
+ var event_sender = (Control) sender;
+ if (e.Action == ValidationErrorEventAction.Added)
+ {
+ event_sender.ToolTip = e.Error.ErrorContent.ToString();
+ }
+ else event_sender.ToolTip = "";
+ }
+ }
+}
diff --git a/MailSender/View/RecipientsView.xaml b/MailSender/View/RecipientsView.xaml
new file mode 100644
index 0000000..c1b8d74
--- /dev/null
+++ b/MailSender/View/RecipientsView.xaml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MailSender/View/RecipientsView.xaml.cs b/MailSender/View/RecipientsView.xaml.cs
new file mode 100644
index 0000000..f3fdb1d
--- /dev/null
+++ b/MailSender/View/RecipientsView.xaml.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using SpamTools.lib.Database;
+
+namespace MailSender.View
+{
+ ///
+ /// Логика взаимодействия для RecipientsView.xaml
+ ///
+ public partial class RecipientsView : UserControl
+ {
+ public RecipientsView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/MailSender/ViewModel/MainViewModel.cs b/MailSender/ViewModel/MainViewModel.cs
new file mode 100644
index 0000000..b0d3efa
--- /dev/null
+++ b/MailSender/ViewModel/MainViewModel.cs
@@ -0,0 +1,34 @@
+using GalaSoft.MvvmLight;
+
+namespace MailSender.ViewModel
+{
+ ///
+ /// This class contains properties that the main View can data bind to.
+ ///
+ /// Use the mvvminpc snippet to add bindable properties to this ViewModel.
+ ///
+ ///
+ /// You can also use Blend to data bind with the tool's support.
+ ///
+ ///
+ /// See http://www.galasoft.ch/mvvm
+ ///
+ ///
+ public class MainViewModel : ViewModelBase
+ {
+ ///
+ /// Initializes a new instance of the MainViewModel class.
+ ///
+ public MainViewModel()
+ {
+ ////if (IsInDesignMode)
+ ////{
+ //// // Code runs in Blend --> create design time data.
+ ////}
+ ////else
+ ////{
+ //// // Code runs "for real"
+ ////}
+ }
+ }
+}
\ No newline at end of file
diff --git a/MailSender/ViewModel/MainWindowViewModel.cs b/MailSender/ViewModel/MainWindowViewModel.cs
new file mode 100644
index 0000000..3186739
--- /dev/null
+++ b/MailSender/ViewModel/MainWindowViewModel.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Security;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using GalaSoft.MvvmLight;
+using GalaSoft.MvvmLight.Command;
+using GalaSoft.MvvmLight.CommandWpf;
+using SpamTools.lib;
+using SpamTools.lib.Data;
+using SpamTools.lib.Database;
+using SpamTools.lib.MVVM;
+using SpamTools.lib.Service;
+using RelayCommand = GalaSoft.MvvmLight.Command.RelayCommand;
+
+namespace MailSender.ViewModel
+{
+ public class MainWindowViewModel: ViewModelBase
+ {
+ private readonly IDataService _DataService;
+
+ private readonly Scheduler _Scheduler = new Scheduler();
+ public Scheduler Scheduler => _Scheduler;
+
+ private string _Title = "Рассыльщик почты";
+ public string Title
+ {
+ get => _Title;
+ set => Set(ref _Title, value);
+ }
+
+ private string _Status = "Готов";
+ public string Status
+ {
+ get => _Status;
+ set => Set(ref _Status, value);
+ }
+
+ private EmailRecipients _CurrentRecipient;
+ public EmailRecipients CurrentRecipient
+ {
+ get => _CurrentRecipient;
+ set => Set(ref _CurrentRecipient, value);
+ }
+
+ //public IEnumerable Recipients => _DataService.GetEmailRecipients();
+ public MainWindowViewModel(IDataService DataService)
+ {
+ _DataService = DataService;
+ UpdateRecipientsCommand = new RelayCommand(OnUpdateRecipientsCommandExecuted, CanUpdateRecipientsCommandExecute);
+ CreateNewRecipientCommand = new GalaSoft.MvvmLight.CommandWpf.RelayCommand(OnCreateNewRecipientCommandExecute);
+ UpdateRecipientCommand = new GalaSoft.MvvmLight.Command.RelayCommand(OnUpdateRecipientCommandExecuted, UpdateRecipientCommandExecute);
+ FindRecipientCommand = new RelayCommand(OnFindRecipientCommandExecute,true);
+ SendMailCommand = new RelayCommand(OnSendMailCommandExecute, true);
+ AddNewEmailCommand = new RelayCommand(OnAddNewEmailCommandExecute, true);
+ }
+
+ private void OnUpdateRecipientsCommandExecuted()
+ {
+ Recipients.Clear();
+ var db_recipients = _DataService.GetEmailRecipients();
+ foreach (var recipient in db_recipients)
+ {
+ Recipients.Add(recipient);
+ }
+ }
+ private bool CanUpdateRecipientsCommandExecute()
+ {
+ return true;
+ }
+
+ public ObservableCollection Recipients { get; } = new ObservableCollection();
+ public ICommand UpdateRecipientsCommand { get; }
+
+ public ICommand CreateNewRecipientCommand { get; }
+ public ICommand UpdateRecipientCommand { get; }
+
+ private void OnCreateNewRecipientCommandExecute()
+ {
+ var recipient = new EmailRecipients {Name = "3841832", EmailAdress = "3841832@gmail.com" };
+ if (_DataService.CreateRecipien(recipient))
+ {
+ CurrentRecipient = recipient;
+ Recipients.Add(recipient);
+ }
+ }
+
+ private bool UpdateRecipientCommandExecute(EmailRecipients Recipient)
+ {
+ return true; //Recipient != null || _CurrentRecipient != null;
+ }
+
+ private void OnUpdateRecipientCommandExecuted(EmailRecipients Recipient)
+ {
+ var recipient = Recipient ?? _CurrentRecipient;
+ if (recipient is null) return;
+ _DataService.UpdateRecipien(recipient);
+ }
+ private string _SearchValue;
+ public string SearchValue
+ {
+ get => _SearchValue;
+ set => Set(ref _SearchValue, value);
+ }
+ public ICommand FindRecipientCommand { get; }
+
+ public void OnFindRecipientCommandExecute()
+ {
+ if(SearchValue is null)
+ return;
+ Recipients.Clear();
+ var db_recipients = _DataService.GetEmailRecipients();
+ //var filter = db_recipients.Where(recipient => recipient.Name.Contains(SearchValue));
+ var filter = from recipient in db_recipients
+ where recipient.Name.Contains(SearchValue)
+ select recipient;
+ foreach (var recipient in filter)
+ Recipients.Add(recipient);
+ }
+
+ public MailServer SelectedServer { set; get; }
+ public Sender SelectedSender { set; get; }
+ public ICommand SendMailCommand { get; }
+ private void OnSendMailCommandExecute()
+ {
+
+ var password = new SecureString();
+ foreach (var password_char in SpamTools.lib.Service.PasswordService.Decode(SelectedSender.Password))
+ password.AppendChar(password_char);
+
+ var from = SelectedSender.Adress;
+ var to = CurrentRecipient.EmailAdress;
+ var senderService = new EmailSendService.lib.SenderService(
+ SelectedServer.Adress,
+ SelectedServer.Port,
+ SelectedServer.UseSSL,
+ SelectedSender.Adress,
+ password
+ );
+ var p2 = PasswordService.Decode(SelectedSender.Password);
+ senderService.Send(to, "subject", "body");
+ }
+
+ public ICommand AddNewEmailCommand { get; set; }
+
+ private void OnAddNewEmailCommandExecute()
+ {
+ var a = new View.NewEmailWindowView().ShowDialog();
+ }
+ }
+}
diff --git a/MailSender/ViewModel/ViewModelLocator.cs b/MailSender/ViewModel/ViewModelLocator.cs
new file mode 100644
index 0000000..58d6828
--- /dev/null
+++ b/MailSender/ViewModel/ViewModelLocator.cs
@@ -0,0 +1,46 @@
+using CommonServiceLocator;
+using GalaSoft.MvvmLight;
+using GalaSoft.MvvmLight.Ioc;
+using MailSender.View;
+using SpamTools.lib;
+using SpamTools.lib.Database;
+
+//using Microsoft.Practices.ServiceLocation;
+
+namespace MailSender.ViewModel
+{
+ ///
+ /// This class contains static references to all the view models in the
+ /// application and provides an entry point for the bindings.
+ ///
+ public class ViewModelLocator
+ {
+ ///
+ /// Initializes a new instance of the ViewModelLocator class.
+ ///
+ public ViewModelLocator()
+ {
+ ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
+ SimpleIoc.Default.Register(() => new MailDatabaseDataContext());
+ SimpleIoc.Default.Register();
+ SimpleIoc.Default.Register();
+ SimpleIoc.Default.Register();
+ SimpleIoc.Default.Register();
+ }
+
+ public MainViewModel Main
+ {
+ get
+ {
+ return ServiceLocator.Current.GetInstance();
+ }
+ }
+
+ public MainWindowViewModel MainWindowModel => ServiceLocator.Current.GetInstance();
+
+ public static void Cleanup()
+ {
+ // TODO Clear the ViewModels
+ }
+ }
+}
\ No newline at end of file
diff --git a/MailSender/packages.config b/MailSender/packages.config
new file mode 100644
index 0000000..9363e12
--- /dev/null
+++ b/MailSender/packages.config
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SpamTools.lib.Tests/Properties/AssemblyInfo.cs b/SpamTools.lib.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8d9a95c
--- /dev/null
+++ b/SpamTools.lib.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("SpamTools.lib.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SpamTools.lib.Tests")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("f28bf459-9a95-4b66-ac0a-d50d9216108e")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/SpamTools.lib.Tests/Service/PasswordServiceTests.cs b/SpamTools.lib.Tests/Service/PasswordServiceTests.cs
new file mode 100644
index 0000000..0ee0b9b
--- /dev/null
+++ b/SpamTools.lib.Tests/Service/PasswordServiceTests.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using SpamTools.lib.Service;
+
+namespace SpamTools.lib.Tests.Service
+{
+ [TestClass]
+ public class PasswordServiceTests
+ {
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ Debug.WriteLine("Инициализация теста "+this.GetType());
+ }
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ Debug.WriteLine("Очистка данных теста " + this.GetType());
+
+ }
+ [TestMethod]
+ public void Encode_123_234_Test()
+ {
+ var str = "123";
+ var expected_encrypted_str = "234";
+ var key = 1;
+
+ var actual_encrypted_str = PasswordService.Encode(str, key);
+
+ Assert.AreEqual(expected_encrypted_str, actual_encrypted_str, "Ошибка кодирования");
+ StringAssert.Matches(actual_encrypted_str, new Regex(@"^234$"));
+ }
+
+ [TestMethod]
+ public void Decode_234_123_Test()
+ {
+ string str = "234";
+ string expected_decrypted_str = "123";
+ int key = 1;
+
+ string actual_decrypred_string = PasswordService.Decode(str, key);
+
+ Assert.AreEqual(actual_decrypred_string,expected_decrypted_str);
+ }
+ }
+}
diff --git a/SpamTools.lib.Tests/SpamTools.lib.Tests.csproj b/SpamTools.lib.Tests/SpamTools.lib.Tests.csproj
new file mode 100644
index 0000000..90120a3
--- /dev/null
+++ b/SpamTools.lib.Tests/SpamTools.lib.Tests.csproj
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+ {F28BF459-9A95-4B66-AC0A-D50D9216108E}
+ Library
+ Properties
+ SpamTools.lib.Tests
+ SpamTools.lib.Tests
+ v4.6.1
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 15.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
+
+
+ ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {772fedb7-183b-40f1-89d1-4415997a0d1e}
+ SpamTools.lib
+
+
+
+
+
+
+ Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их. Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SpamTools.lib.Tests/packages.config b/SpamTools.lib.Tests/packages.config
new file mode 100644
index 0000000..102a45c
--- /dev/null
+++ b/SpamTools.lib.Tests/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/SpamTools.lib/Data/Email.cs b/SpamTools.lib/Data/Email.cs
new file mode 100644
index 0000000..ffcfbb3
--- /dev/null
+++ b/SpamTools.lib/Data/Email.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SpamTools.lib.Database;
+
+namespace SpamTools.lib.Data
+{
+ public class Email
+ {
+ public DateTime Time { get; set; }
+ public Sender From { get; set; }
+ public EmailRecipients To { get; }
+ public string Subject { get; set; }
+ public string Content { get; set; }
+
+ public Email(DateTime time, EmailRecipients to, string subject, string content)
+ {
+ Time = time;
+ To = to;
+ Subject = subject;
+ Content = content;
+ }
+ }
+}
diff --git a/SpamTools.lib/Data/Mail.cs b/SpamTools.lib/Data/Mail.cs
new file mode 100644
index 0000000..4ede4a7
--- /dev/null
+++ b/SpamTools.lib/Data/Mail.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SpamTools.lib.Database;
+
+namespace SpamTools.lib.Data
+{
+ public class Mail
+ {
+ public string Subject { get; set; }
+ public string Body { get; set; }
+
+ public Mail( string subject, string body)
+ {
+ Subject = subject;
+ Body = body;
+ }
+ }
+}
diff --git a/SpamTools.lib/Data/MailServer.cs b/SpamTools.lib/Data/MailServer.cs
new file mode 100644
index 0000000..c1fbfe9
--- /dev/null
+++ b/SpamTools.lib/Data/MailServer.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpamTools.lib.Data
+{
+ public class MailServer
+ {
+ public MailServer() { }
+
+ public MailServer(string adress, int port = 25, bool useSSL = true)
+ {
+ Adress = adress;
+ Port = port;
+ UseSSL = useSSL;
+ }
+
+ public string Adress { get; set; }
+ public int Port { get; set; } = 25;
+ public bool UseSSL { get; set; } = true;
+ }
+}
diff --git a/SpamTools.lib/Data/MailServers.cs b/SpamTools.lib/Data/MailServers.cs
new file mode 100644
index 0000000..1a43ade
--- /dev/null
+++ b/SpamTools.lib/Data/MailServers.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpamTools.lib.Data
+{
+ public class MailServers
+ {
+ public static List servers { get; } = new List
+ {
+ new MailServer("smtp.yandex.ru"),
+ new MailServer("smtp.mail.ru"),
+ new MailServer("smtp.google.com",125)
+ };
+ }
+}
diff --git a/SpamTools.lib/Data/SchedulerTask.cs b/SpamTools.lib/Data/SchedulerTask.cs
new file mode 100644
index 0000000..c563039
--- /dev/null
+++ b/SpamTools.lib/Data/SchedulerTask.cs
@@ -0,0 +1,18 @@
+using SpamTools.lib.Database;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpamTools.lib.Data
+{
+ public class SchedulerTask
+ {
+ public DateTime DateTime { get; set; }
+ public IEnumerable Recipients { get; set; }
+ public MailServer MailServer { get; set; }
+ public Sender Sender { get; set; }
+ public Mail Mail { get; set; }
+ }
+}
diff --git a/SpamTools.lib/Data/Sender.cs b/SpamTools.lib/Data/Sender.cs
new file mode 100644
index 0000000..9df200b
--- /dev/null
+++ b/SpamTools.lib/Data/Sender.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpamTools.lib.Data
+{
+ public class Sender
+ {
+ public string Name { get; set; }
+ public string Adress { get; set; }
+ public string Password;
+ }
+}
diff --git a/SpamTools.lib/Data/Senders.cs b/SpamTools.lib/Data/Senders.cs
new file mode 100644
index 0000000..8566e69
--- /dev/null
+++ b/SpamTools.lib/Data/Senders.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SpamTools.lib.Service;
+
+namespace SpamTools.lib.Data
+{
+ public class Senders
+ {
+ public static List List { get; } = new List
+ {
+ new Sender {Name = "Ivanov", Adress="ivanov@mail.ru"},
+ new Sender {Name = "Petrov", Adress="petrov@mail.ru"},
+ new Sender {Name = "Sidorov", Adress="sidorov@mail.ru"},
+ new Sender {Name = "Ya", Adress="berlin.22014@yandex.ru", Password = PasswordService.Encode("password")}
+ };
+ }
+}
diff --git a/SpamTools.lib/DataServiceDB.cs b/SpamTools.lib/DataServiceDB.cs
new file mode 100644
index 0000000..e091a30
--- /dev/null
+++ b/SpamTools.lib/DataServiceDB.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SpamTools.lib.Database;
+
+namespace SpamTools.lib
+{
+ public class DataServiceDB: IDataService
+ {
+ private MailDatabaseDataContext _DataBaseContext;
+
+ public DataServiceDB(MailDatabaseDataContext DataBaseContext)
+ {
+ _DataBaseContext = DataBaseContext;
+ }
+
+
+
+ public IEnumerable GetEmailRecipients()
+ {
+ return new ObservableCollection(_DataBaseContext.EmailRecipients);
+ }
+
+ public bool UpdateRecipien(EmailRecipients Recipient)
+ {
+ _DataBaseContext.SubmitChanges();
+ return true;
+ }
+ public bool CreateRecipien(EmailRecipients Recipient)
+ {
+ _DataBaseContext.EmailRecipients.InsertOnSubmit(Recipient);
+ _DataBaseContext.SubmitChanges();
+ return Recipient.Id != 0;
+ }
+ }
+}
diff --git a/SpamTools.lib/Database/EmailRecipient.cs b/SpamTools.lib/Database/EmailRecipient.cs
new file mode 100644
index 0000000..cf99d27
--- /dev/null
+++ b/SpamTools.lib/Database/EmailRecipient.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpamTools.lib.Database
+{
+ public partial class EmailRecipient : IDataErrorInfo
+ {
+ public string this[string columnName]
+ {
+ get
+ {
+ switch (columnName)
+ {
+ case "Name": if (columnName.Length < 3) return $"Имя {columnName} имеет длину меньше 3 символов."; break;
+ }
+
+ return "";
+ }
+ }
+
+ public string Error => "";
+ }
+}
diff --git a/SpamTools.lib/Database/MailDatabase.cs b/SpamTools.lib/Database/MailDatabase.cs
new file mode 100644
index 0000000..e69de29
diff --git a/SpamTools.lib/Database/MailDatabase.dbml b/SpamTools.lib/Database/MailDatabase.dbml
new file mode 100644
index 0000000..a823ad0
--- /dev/null
+++ b/SpamTools.lib/Database/MailDatabase.dbml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/SpamTools.lib/Database/MailDatabase.dbml.layout b/SpamTools.lib/Database/MailDatabase.dbml.layout
new file mode 100644
index 0000000..3673eb9
--- /dev/null
+++ b/SpamTools.lib/Database/MailDatabase.dbml.layout
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SpamTools.lib/Database/MailDatabase.designer.cs b/SpamTools.lib/Database/MailDatabase.designer.cs
new file mode 100644
index 0000000..a964d7c
--- /dev/null
+++ b/SpamTools.lib/Database/MailDatabase.designer.cs
@@ -0,0 +1,192 @@
+#pragma warning disable 1591
+//------------------------------------------------------------------------------
+//
+// Этот код создан программой.
+// Исполняемая версия:4.0.30319.42000
+//
+// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
+// повторной генерации кода.
+//
+//------------------------------------------------------------------------------
+
+namespace SpamTools.lib.Database
+{
+ using System.Data.Linq;
+ using System.Data.Linq.Mapping;
+ using System.Data;
+ using System.Collections.Generic;
+ using System.Reflection;
+ using System.Linq;
+ using System.Linq.Expressions;
+ using System.ComponentModel;
+ using System;
+
+
+ [global::System.Data.Linq.Mapping.DatabaseAttribute(Name="MailDB")]
+ public partial class MailDatabaseDataContext : System.Data.Linq.DataContext
+ {
+
+ private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();
+
+ #region Определения метода расширяемости
+ partial void OnCreated();
+ partial void InsertEmailRecipients(EmailRecipients instance);
+ partial void UpdateEmailRecipients(EmailRecipients instance);
+ partial void DeleteEmailRecipients(EmailRecipients instance);
+ #endregion
+
+ public MailDatabaseDataContext() :
+ base(global::SpamTools.lib.Properties.Settings.Default.MailDBConnectionString, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public MailDatabaseDataContext(string connection) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public MailDatabaseDataContext(System.Data.IDbConnection connection) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public MailDatabaseDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public MailDatabaseDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
+ base(connection, mappingSource)
+ {
+ OnCreated();
+ }
+
+ public System.Data.Linq.Table EmailRecipients
+ {
+ get
+ {
+ return this.GetTable();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.EmailRecipients")]
+ public partial class EmailRecipients : INotifyPropertyChanging, INotifyPropertyChanged
+ {
+
+ private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
+
+ private int _Id;
+
+ private string _Name;
+
+ private string _EmailAdress;
+
+ #region Определения метода расширяемости
+ partial void OnLoaded();
+ partial void OnValidate(System.Data.Linq.ChangeAction action);
+ partial void OnCreated();
+ partial void OnIdChanging(int value);
+ partial void OnIdChanged();
+ partial void OnNameChanging(string value);
+ partial void OnNameChanged();
+ partial void OnEmailAdressChanging(string value);
+ partial void OnEmailAdressChanged();
+ #endregion
+
+ public EmailRecipients()
+ {
+ OnCreated();
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Id", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
+ public int Id
+ {
+ get
+ {
+ return this._Id;
+ }
+ set
+ {
+ if ((this._Id != value))
+ {
+ this.OnIdChanging(value);
+ this.SendPropertyChanging();
+ this._Id = value;
+ this.SendPropertyChanged("Id");
+ this.OnIdChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Name", DbType="NVarChar(MAX) NOT NULL", CanBeNull=false)]
+ public string Name
+ {
+ get
+ {
+ return this._Name;
+ }
+ set
+ {
+ if ((this._Name != value))
+ {
+ this.OnNameChanging(value);
+ this.SendPropertyChanging();
+ this._Name = value;
+ this.SendPropertyChanged("Name");
+ this.OnNameChanged();
+ }
+ }
+ }
+
+ [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_EmailAdress", DbType="NVarChar(MAX) NOT NULL", CanBeNull=false)]
+ public string EmailAdress
+ {
+ get
+ {
+ return this._EmailAdress;
+ }
+ set
+ {
+ if ((this._EmailAdress != value))
+ {
+ this.OnEmailAdressChanging(value);
+ this.SendPropertyChanging();
+ this._EmailAdress = value;
+ this.SendPropertyChanged("EmailAdress");
+ this.OnEmailAdressChanged();
+ }
+ }
+ }
+
+ public event PropertyChangingEventHandler PropertyChanging;
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected virtual void SendPropertyChanging()
+ {
+ if ((this.PropertyChanging != null))
+ {
+ this.PropertyChanging(this, emptyChangingEventArgs);
+ }
+ }
+
+ protected virtual void SendPropertyChanged(String propertyName)
+ {
+ if ((this.PropertyChanged != null))
+ {
+ this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+
+ public override string ToString()
+ {
+ return EmailAdress;
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/SpamTools.lib/IDataService.cs b/SpamTools.lib/IDataService.cs
new file mode 100644
index 0000000..a66592a
--- /dev/null
+++ b/SpamTools.lib/IDataService.cs
@@ -0,0 +1,17 @@
+using SpamTools.lib.Database;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpamTools.lib
+{
+ public interface IDataService
+ {
+ IEnumerable GetEmailRecipients();
+
+ bool UpdateRecipien(EmailRecipients Recipient);
+ bool CreateRecipien(EmailRecipients Recipient);
+ }
+}
diff --git a/SpamTools.lib/MVVM/LambdaCommand.cs b/SpamTools.lib/MVVM/LambdaCommand.cs
new file mode 100644
index 0000000..9881b28
--- /dev/null
+++ b/SpamTools.lib/MVVM/LambdaCommand.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace SpamTools.lib.MVVM
+{
+ public class LambdaCommand : ICommand
+ {
+ public event EventHandler CanExecuteChanged
+ {
+ add => CommandManager.RequerySuggested += value;
+ remove => CommandManager.RequerySuggested -= value;
+ }
+
+ private Action