From 21ab0f38186427de5f19ea68c976a5c3f7da9548 Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 20 Mar 2018 09:41:08 +0300 Subject: [PATCH 001/100] Move ScadaAgent to the parent folder --- ScadaAgent/{ScadaAgent => }/ScadaAgent.sln | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCore/ScadaAgentCore.csproj | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCore/ScadaManager.cs | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/App.config | 0 .../Connected Services/ServiceReference1/AgentSvc.wsdl | 0 .../Connected Services/ServiceReference1/Reference.cs | 0 .../Connected Services/ServiceReference1/Reference.svcmap | 0 .../Connected Services/ServiceReference1/configuration.svcinfo | 0 .../Connected Services/ServiceReference1/configuration91.svcinfo | 0 .../Connected Services/ServiceReference1/item.disco | 0 .../ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd | 0 .../ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/FrmMain.Designer.cs | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/FrmMain.cs | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/FrmMain.resx | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Program.cs | 0 .../{ScadaAgent => }/ScadaAgentCtrl/Properties/AssemblyInfo.cs | 0 .../ScadaAgentCtrl/Properties/Resources.Designer.cs | 0 .../{ScadaAgent => }/ScadaAgentCtrl/Properties/Resources.resx | 0 .../ScadaAgentCtrl/Properties/Settings.Designer.cs | 0 .../{ScadaAgent => }/ScadaAgentCtrl/Properties/Settings.settings | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/ScadaAgentCtrl.csproj | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentMono/App.config | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentMono/Program.cs | 0 .../{ScadaAgent => }/ScadaAgentMono/Properties/AssemblyInfo.cs | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentMono/ScadaAgentMono.csproj | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentService/App.config | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentService/Program.cs | 0 .../{ScadaAgent => }/ScadaAgentService/Properties/AssemblyInfo.cs | 0 .../{ScadaAgent => }/ScadaAgentService/ScadaAgentService.csproj | 0 .../{ScadaAgent => }/ScadaAgentService/Service1.Designer.cs | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentService/Service1.cs | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentWcf/AgentSvc.cs | 0 .../{ScadaAgent => }/ScadaAgentWcf/Properties/AssemblyInfo.cs | 0 ScadaAgent/{ScadaAgent => }/ScadaAgentWcf/ScadaAgentWcf.csproj | 0 35 files changed, 0 insertions(+), 0 deletions(-) rename ScadaAgent/{ScadaAgent => }/ScadaAgent.sln (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCore/ScadaAgentCore.csproj (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCore/ScadaManager.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/App.config (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/FrmMain.Designer.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/FrmMain.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/FrmMain.resx (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Program.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Properties/AssemblyInfo.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Properties/Resources.Designer.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Properties/Resources.resx (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Properties/Settings.Designer.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/Properties/Settings.settings (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentCtrl/ScadaAgentCtrl.csproj (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentMono/App.config (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentMono/Program.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentMono/Properties/AssemblyInfo.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentMono/ScadaAgentMono.csproj (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentService/App.config (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentService/Program.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentService/Properties/AssemblyInfo.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentService/ScadaAgentService.csproj (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentService/Service1.Designer.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentService/Service1.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentWcf/AgentSvc.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentWcf/Properties/AssemblyInfo.cs (100%) rename ScadaAgent/{ScadaAgent => }/ScadaAgentWcf/ScadaAgentWcf.csproj (100%) diff --git a/ScadaAgent/ScadaAgent/ScadaAgent.sln b/ScadaAgent/ScadaAgent.sln similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgent.sln rename to ScadaAgent/ScadaAgent.sln diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj b/ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj rename to ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCore/ScadaManager.cs b/ScadaAgent/ScadaAgentCore/ScadaManager.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCore/ScadaManager.cs rename to ScadaAgent/ScadaAgentCore/ScadaManager.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/App.config b/ScadaAgent/ScadaAgentCtrl/App.config similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/App.config rename to ScadaAgent/ScadaAgentCtrl/App.config diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs rename to ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.cs rename to ScadaAgent/ScadaAgentCtrl/FrmMain.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.resx b/ScadaAgent/ScadaAgentCtrl/FrmMain.resx similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.resx rename to ScadaAgent/ScadaAgentCtrl/FrmMain.resx diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Program.cs b/ScadaAgent/ScadaAgentCtrl/Program.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Program.cs rename to ScadaAgent/ScadaAgentCtrl/Program.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs rename to ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs b/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs rename to ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx b/ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx rename to ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs b/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs rename to ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings b/ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings rename to ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj rename to ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj diff --git a/ScadaAgent/ScadaAgent/ScadaAgentMono/App.config b/ScadaAgent/ScadaAgentMono/App.config similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentMono/App.config rename to ScadaAgent/ScadaAgentMono/App.config diff --git a/ScadaAgent/ScadaAgent/ScadaAgentMono/Program.cs b/ScadaAgent/ScadaAgentMono/Program.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentMono/Program.cs rename to ScadaAgent/ScadaAgentMono/Program.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs rename to ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj rename to ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/App.config b/ScadaAgent/ScadaAgentService/App.config similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentService/App.config rename to ScadaAgent/ScadaAgentService/App.config diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/Program.cs b/ScadaAgent/ScadaAgentService/Program.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentService/Program.cs rename to ScadaAgent/ScadaAgentService/Program.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs rename to ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/ScadaAgentService.csproj b/ScadaAgent/ScadaAgentService/ScadaAgentService.csproj similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentService/ScadaAgentService.csproj rename to ScadaAgent/ScadaAgentService/ScadaAgentService.csproj diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/Service1.Designer.cs b/ScadaAgent/ScadaAgentService/Service1.Designer.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentService/Service1.Designer.cs rename to ScadaAgent/ScadaAgentService/Service1.Designer.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/Service1.cs b/ScadaAgent/ScadaAgentService/Service1.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentService/Service1.cs rename to ScadaAgent/ScadaAgentService/Service1.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentWcf/AgentSvc.cs rename to ScadaAgent/ScadaAgentWcf/AgentSvc.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentWcf/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentWcf/Properties/AssemblyInfo.cs similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentWcf/Properties/AssemblyInfo.cs rename to ScadaAgent/ScadaAgentWcf/Properties/AssemblyInfo.cs diff --git a/ScadaAgent/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj b/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj rename to ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj From c88cd5571acdea42fc828c7fd5a845d8278bfea0 Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 20 Mar 2018 14:35:23 +0300 Subject: [PATCH 002/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/CryptoUtils.cs | 25 ++++++++ ScadaAgent/ScadaAgentCore/ScadaApps.cs | 13 +++++ ScadaAgent/ScadaAgentCore/ServiceCommands.cs | 9 +++ .../ServiceReference1/AgentSvc.wsdl | 58 +++++++++++++++++++ .../ServiceReference1/Reference.cs | 42 ++++++++++++++ .../ServiceReference1/Reference.svcmap | 1 + .../ServiceReference1/item.xsd | 44 ++++++++++++++ .../ServiceReference1/item2.xsd | 11 ++++ ScadaAgent/ScadaAgentCtrl/FrmMain.cs | 1 + .../ScadaAgentCtrl/ScadaAgentCtrl.csproj | 9 +++ ScadaAgent/ScadaAgentMono/Program.cs | 1 + ScadaAgent/ScadaAgentWcf/AgentSvc.cs | 36 +++++++++++- 12 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 ScadaAgent/ScadaAgentCore/CryptoUtils.cs create mode 100644 ScadaAgent/ScadaAgentCore/ScadaApps.cs create mode 100644 ScadaAgent/ScadaAgentCore/ServiceCommands.cs create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd diff --git a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs new file mode 100644 index 000000000..e02757897 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace Scada.Agent +{ + public static class CryptoUtils + { + /// + /// Генератор криптографически защищённых случайных чисел + /// + private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider(); + + /// + /// Получить случайное 64-битное целое + /// + public static long GetRandomLong() + { + byte[] randomArr = new byte[8]; + Rng.GetBytes(randomArr); + return BitConverter.ToInt64(randomArr, 0); + } + } +} diff --git a/ScadaAgent/ScadaAgentCore/ScadaApps.cs b/ScadaAgent/ScadaAgentCore/ScadaApps.cs new file mode 100644 index 000000000..e5fe8f76b --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/ScadaApps.cs @@ -0,0 +1,13 @@ +using System; + +namespace Scada.Agent +{ + [Flags] + public enum ScadaApps + { + None = 0, + Server = 1, + Communicator = 2, + Webstation = 4 + } +} diff --git a/ScadaAgent/ScadaAgentCore/ServiceCommands.cs b/ScadaAgent/ScadaAgentCore/ServiceCommands.cs new file mode 100644 index 000000000..9ae4223bc --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/ServiceCommands.cs @@ -0,0 +1,9 @@ +namespace Scada.Agent +{ + public enum ServiceCommands + { + Start, + Stop, + Restart + } +} diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl index 0bb556aa0..93b178a58 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl @@ -4,6 +4,7 @@ + @@ -12,11 +13,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -29,6 +60,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs index 221dfaff5..fe8c41361 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs @@ -20,6 +20,24 @@ public interface AgentSvc { [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Sum", ReplyAction="http://tempuri.org/AgentSvc/SumResponse")] System.Threading.Tasks.Task SumAsync(double a, double b); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetSessionID", ReplyAction="http://tempuri.org/AgentSvc/GetSessionIDResponse")] + long GetSessionID(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetSessionID", ReplyAction="http://tempuri.org/AgentSvc/GetSessionIDResponse")] + System.Threading.Tasks.Task GetSessionIDAsync(); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] + bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] + System.Threading.Tasks.Task LoginAsync(long sessionID, string username, string encryptedPassword, string scadaInstanceName); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ServiceCommand", ReplyAction="http://tempuri.org/AgentSvc/ServiceCommandResponse")] + void ServiceCommand(long sessionID, Scada.Agent.ServiceCommands command, int service); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ServiceCommand", ReplyAction="http://tempuri.org/AgentSvc/ServiceCommandResponse")] + System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommands command, int service); } [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] @@ -56,5 +74,29 @@ public double Sum(double a, double b) { public System.Threading.Tasks.Task SumAsync(double a, double b) { return base.Channel.SumAsync(a, b); } + + public long GetSessionID() { + return base.Channel.GetSessionID(); + } + + public System.Threading.Tasks.Task GetSessionIDAsync() { + return base.Channel.GetSessionIDAsync(); + } + + public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName) { + return base.Channel.Login(sessionID, username, encryptedPassword, scadaInstanceName); + } + + public System.Threading.Tasks.Task LoginAsync(long sessionID, string username, string encryptedPassword, string scadaInstanceName) { + return base.Channel.LoginAsync(sessionID, username, encryptedPassword, scadaInstanceName); + } + + public void ServiceCommand(long sessionID, Scada.Agent.ServiceCommands command, int service) { + base.Channel.ServiceCommand(sessionID, command, service); + } + + public System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommands command, int service) { + return base.Channel.ServiceCommandAsync(sessionID, command, service); + } } } diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap index 04424c815..d1706ae71 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap @@ -22,6 +22,7 @@ + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd index ff9b03574..334462be5 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd @@ -1,5 +1,6 @@ + @@ -15,4 +16,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd new file mode 100644 index 000000000..9c3a6f272 --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs index df0d57d8f..76d2606af 100644 --- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs +++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs @@ -14,6 +14,7 @@ private void button1_Click(object sender, System.EventArgs e) { AgentSvcClient client = new AgentSvcClient(); double sum = client.Sum(2, 2); + //client.ServiceCommand(0, ServiceCommands.Restart, 0); client.Close(); MessageBox.Show(sum.ToString()); diff --git a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj index a611faa34..d2cbbfa92 100644 --- a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj +++ b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj @@ -74,6 +74,9 @@ Designer + + Designer + SettingsSingleFileGenerator Settings.Designer.cs @@ -108,5 +111,11 @@ Reference.cs + + + {5163526d-91e4-414d-97fe-090e1e7fda6b} + ScadaAgentCore + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentMono/Program.cs b/ScadaAgent/ScadaAgentMono/Program.cs index 83f05f8fb..9911478fc 100644 --- a/ScadaAgent/ScadaAgentMono/Program.cs +++ b/ScadaAgent/ScadaAgentMono/Program.cs @@ -18,6 +18,7 @@ private static bool StartWcfService(out string serviceUrl) agentSvcHost = new ServiceHost(typeof(AgentSvc)); ServiceBehaviorAttribute behavior = agentSvcHost.Description.Behaviors.Find(); + behavior.ConcurrencyMode = ConcurrencyMode.Multiple; behavior.InstanceContextMode = InstanceContextMode.Single; behavior.UseSynchronizationContext = false; agentSvcHost.Open(); diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs index f64445367..394ae7341 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs @@ -1,4 +1,5 @@ -using System.ServiceModel; +using System.IO; +using System.ServiceModel; namespace Scada.Agent.Wcf { @@ -12,5 +13,38 @@ public double Sum(double a, double b) { return mngr.Sum(a, b); } + + [OperationContract] + public bool GetSessionID(out long sessionID) + { + sessionID = CryptoUtils.GetRandomLong(); + return true; + } + + [OperationContract] + public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName) + { + return true; + } + + [OperationContract] + public bool ControlService(long sessionID, ScadaApps service, ServiceCommands command) + { + return true; + } + + [OperationContract] + public bool GetInstalledApps(long sessionID, out ScadaApps installedApps) + { + installedApps = ScadaApps.None; + return true; + } + + [OperationContract] + public bool GetConfig(long sessionID, ScadaApps app, out Stream stream) + { + stream = null; + return true; + } } } From a9b6bc3b321c9adaac4f1d655ce2f0ae5871d122 Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 20 Mar 2018 17:27:14 +0300 Subject: [PATCH 003/100] LangPack: add instructions --- LangPack/readme.txt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/LangPack/readme.txt b/LangPack/readme.txt index 882e840db..a4ccb1363 100644 --- a/LangPack/readme.txt +++ b/LangPack/readme.txt @@ -4,4 +4,19 @@ Language Installation 2. Copy the language files from the folder SCADA of the language pack to the installation directory of Rapid SCADA maintaining the hierarchy of the directories. 3. Run SCADA-Administrator application. 4. Go to Settings -> Language and type the culture name, e.g. es-LA, and click OK button. -5. Restart Rapid SCADA applications to apply changes. \ No newline at end of file +5. Restart Rapid SCADA applications to apply changes. + + +How to Localize UI to Any Language +---------------------------------- +Most of Rapid SCADA applications contain special localization files. Usually they are located in a Lang folder: +C:\SCADA\ScadaAdmin\Lang +C:\SCADA\ScadaComm\Lang +C:\SCADA\ScadaSchemeEditor\lang +C:\SCADA\ScadaServer\Lang +C:\SCADA\ScadaTableEditor\Lang +C:\SCADA\ScadaWeb\lang +C:\SCADA\ScadaWebConfig\Lang + +To add a new language support, create copies of *.en-GB.xml files and give the file names according to your culture. In this example en means English language and GB Great Britain. +Using your favorite text editor (Notepad++ is OK) translate the phrases in the created xml files. Then open SCADA-Administrator application, go to Settings > Language menu and enter your localization name, for example, es-LA From d42011df20252902b44174c0075094e9194a7bc0 Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 20 Mar 2018 17:28:35 +0300 Subject: [PATCH 004/100] Update readme of LangPack --- LangPack/readme.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/LangPack/readme.txt b/LangPack/readme.txt index a4ccb1363..f930fbe54 100644 --- a/LangPack/readme.txt +++ b/LangPack/readme.txt @@ -12,11 +12,10 @@ How to Localize UI to Any Language Most of Rapid SCADA applications contain special localization files. Usually they are located in a Lang folder: C:\SCADA\ScadaAdmin\Lang C:\SCADA\ScadaComm\Lang -C:\SCADA\ScadaSchemeEditor\lang +C:\SCADA\ScadaSchemeEditor\Lang C:\SCADA\ScadaServer\Lang C:\SCADA\ScadaTableEditor\Lang C:\SCADA\ScadaWeb\lang -C:\SCADA\ScadaWebConfig\Lang To add a new language support, create copies of *.en-GB.xml files and give the file names according to your culture. In this example en means English language and GB Great Britain. Using your favorite text editor (Notepad++ is OK) translate the phrases in the created xml files. Then open SCADA-Administrator application, go to Settings > Language menu and enter your localization name, for example, es-LA From 2e9c0fee49afc0d003be419a27aeda327f8dd92a Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 20 Mar 2018 17:29:31 +0300 Subject: [PATCH 005/100] Update readme of Lang Pack 2 --- LangPack/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LangPack/readme.txt b/LangPack/readme.txt index f930fbe54..c1cc1d2d7 100644 --- a/LangPack/readme.txt +++ b/LangPack/readme.txt @@ -17,5 +17,5 @@ C:\SCADA\ScadaServer\Lang C:\SCADA\ScadaTableEditor\Lang C:\SCADA\ScadaWeb\lang -To add a new language support, create copies of *.en-GB.xml files and give the file names according to your culture. In this example en means English language and GB Great Britain. +To add a new language support, create copies of *.en-GB.xml files and give the file names according to your culture. In this example en means English language and GB is Great Britain. Using your favorite text editor (Notepad++ is OK) translate the phrases in the created xml files. Then open SCADA-Administrator application, go to Settings > Language menu and enter your localization name, for example, es-LA From 805c04ce14b115e3daf9e0bd4c9618796eb61cb4 Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 20 Mar 2018 17:30:47 +0300 Subject: [PATCH 006/100] LangPack: readme 3 --- LangPack/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LangPack/readme.txt b/LangPack/readme.txt index c1cc1d2d7..3a7a3c91b 100644 --- a/LangPack/readme.txt +++ b/LangPack/readme.txt @@ -18,4 +18,4 @@ C:\SCADA\ScadaTableEditor\Lang C:\SCADA\ScadaWeb\lang To add a new language support, create copies of *.en-GB.xml files and give the file names according to your culture. In this example en means English language and GB is Great Britain. -Using your favorite text editor (Notepad++ is OK) translate the phrases in the created xml files. Then open SCADA-Administrator application, go to Settings > Language menu and enter your localization name, for example, es-LA +Using your favorite text editor (Notepad++ is OK) translate the phrases in the created xml files. Then open the Administrator application, go to Settings > Language menu and enter your localization name, for example, es-LA From b68e3ad9ff3f5860c29fcd3363a78853f8488d6c Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 20 Mar 2018 19:46:00 +0300 Subject: [PATCH 007/100] ScadaAgent: service interface --- ScadaAgent/ScadaAgentCore/AppFolder.cs | 54 ++++++++++++++ ScadaAgent/ScadaAgentCore/AppPath.cs | 74 +++++++++++++++++++ ScadaAgent/ScadaAgentCore/ConfigOptions.cs | 51 +++++++++++++ ScadaAgent/ScadaAgentCore/CryptoUtils.cs | 33 ++++++++- ScadaAgent/ScadaAgentCore/ScadaApps.cs | 46 +++++++++++- ScadaAgent/ScadaAgentCore/ServiceCommand.cs | 49 ++++++++++++ ScadaAgent/ScadaAgentCore/ServiceCommands.cs | 9 --- .../ServiceReference1/Reference.cs | 8 +- ScadaAgent/ScadaAgentWcf/AgentSvc.cs | 39 +++++++++- 9 files changed, 343 insertions(+), 20 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/AppFolder.cs create mode 100644 ScadaAgent/ScadaAgentCore/AppPath.cs create mode 100644 ScadaAgent/ScadaAgentCore/ConfigOptions.cs create mode 100644 ScadaAgent/ScadaAgentCore/ServiceCommand.cs delete mode 100644 ScadaAgent/ScadaAgentCore/ServiceCommands.cs diff --git a/ScadaAgent/ScadaAgentCore/AppFolder.cs b/ScadaAgent/ScadaAgentCore/AppFolder.cs new file mode 100644 index 000000000..ba2c04210 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/AppFolder.cs @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Application folders + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +namespace Scada.Agent +{ + /// + /// Application folders + /// Папки приложения + /// + public enum AppFolder + { + /// + /// Не определена + /// + Undef, + + /// + /// Конфигурация + /// + Config, + + /// + /// Журналы + /// + Log, + + /// + /// Хранилище + /// + Storage + } +} diff --git a/ScadaAgent/ScadaAgentCore/AppPath.cs b/ScadaAgent/ScadaAgentCore/AppPath.cs new file mode 100644 index 000000000..237c7de7d --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/AppPath.cs @@ -0,0 +1,74 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Path relative to an application + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +namespace Scada.Agent +{ + /// + /// Path relative to an application + /// Путь относительно приложения + /// + public class AppPath + { + /// + /// Путь базы конфигурации + /// + public static AppPath Base = new AppPath(ScadaApps.None, AppFolder.Config, ""); + + + /// + /// Конструктор + /// + public AppPath() + : this(ScadaApps.None, AppFolder.Undef, "") + { + } + + /// + /// Конструктор + /// + public AppPath(ScadaApps scadaApp, AppFolder appFolder, string path) + { + ScadaApp = scadaApp; + AppFolder = appFolder; + Path = path ?? ""; + } + + + /// + /// Получить или установить приложение + /// + public ScadaApps ScadaApp { get; set; } + + /// + /// Получить или установить папку приложения + /// + public AppFolder AppFolder { get; set; } + + /// + /// Получить или установить путь относительно папки приложения + /// + public string Path { get; set; } + } +} diff --git a/ScadaAgent/ScadaAgentCore/ConfigOptions.cs b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs new file mode 100644 index 000000000..cdd11b5cf --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Configuration transfer parameters + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System.Collections.Generic; + +namespace Scada.Agent +{ + /// + /// Configuration transfer parameters + /// Параметры передачи конфигурации + /// + public class ConfigOptions + { + /// + /// Получить или установить приложение + /// + public ScadaApps ScadaApp { get; set; } + + /// + /// Получить или установить директорию приложения + /// + public AppFolder AppFolder { get; set; } + + /// + /// Получить или установить исключаемые пути + /// + public ICollection ExcludedPaths { get; private set; } + } +} diff --git a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs index e02757897..686321b88 100644 --- a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs +++ b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs @@ -1,10 +1,37 @@ -using System; -using System.Collections.Generic; +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : The class contains utility cryptographic methods + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; using System.Security.Cryptography; -using System.Text; namespace Scada.Agent { + /// + /// The class contains utility cryptographic methods + /// Класс, содержащий вспомогательные криптографические методы + /// public static class CryptoUtils { /// diff --git a/ScadaAgent/ScadaAgentCore/ScadaApps.cs b/ScadaAgent/ScadaAgentCore/ScadaApps.cs index e5fe8f76b..828f74f98 100644 --- a/ScadaAgent/ScadaAgentCore/ScadaApps.cs +++ b/ScadaAgent/ScadaAgentCore/ScadaApps.cs @@ -1,13 +1,57 @@ -using System; +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Applications + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; namespace Scada.Agent { + /// + /// Applications + /// Приложения + /// [Flags] public enum ScadaApps { + /// + /// Не задано + /// None = 0, + + /// + /// Сервер + /// Server = 1, + + /// + /// Коммуникатор + /// Communicator = 2, + + /// + /// Вебстанция + /// Webstation = 4 } } diff --git a/ScadaAgent/ScadaAgentCore/ServiceCommand.cs b/ScadaAgent/ScadaAgentCore/ServiceCommand.cs new file mode 100644 index 000000000..02f697178 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/ServiceCommand.cs @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Service commands + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +namespace Scada.Agent +{ + /// + /// Service commands + /// Команды сервиса + /// + public enum ServiceCommand + { + /// + /// Запустить + /// + Start, + + /// + /// Остановить + /// + Stop, + + /// + /// Перезапустить + /// + Restart + } +} diff --git a/ScadaAgent/ScadaAgentCore/ServiceCommands.cs b/ScadaAgent/ScadaAgentCore/ServiceCommands.cs deleted file mode 100644 index 9ae4223bc..000000000 --- a/ScadaAgent/ScadaAgentCore/ServiceCommands.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Scada.Agent -{ - public enum ServiceCommands - { - Start, - Stop, - Restart - } -} diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs index fe8c41361..2f2442255 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs @@ -34,10 +34,10 @@ public interface AgentSvc { System.Threading.Tasks.Task LoginAsync(long sessionID, string username, string encryptedPassword, string scadaInstanceName); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ServiceCommand", ReplyAction="http://tempuri.org/AgentSvc/ServiceCommandResponse")] - void ServiceCommand(long sessionID, Scada.Agent.ServiceCommands command, int service); + void ServiceCommand(long sessionID, Scada.Agent.ServiceCommand command, int service); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ServiceCommand", ReplyAction="http://tempuri.org/AgentSvc/ServiceCommandResponse")] - System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommands command, int service); + System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommand command, int service); } [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] @@ -91,11 +91,11 @@ public System.Threading.Tasks.Task LoginAsync(long sessionID, string usern return base.Channel.LoginAsync(sessionID, username, encryptedPassword, scadaInstanceName); } - public void ServiceCommand(long sessionID, Scada.Agent.ServiceCommands command, int service) { + public void ServiceCommand(long sessionID, Scada.Agent.ServiceCommand command, int service) { base.Channel.ServiceCommand(sessionID, command, service); } - public System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommands command, int service) { + public System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommand command, int service) { return base.Channel.ServiceCommandAsync(sessionID, command, service); } } diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs index 394ae7341..50ddac0fd 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using System.ServiceModel; namespace Scada.Agent.Wcf @@ -28,11 +29,18 @@ public bool Login(long sessionID, string username, string encryptedPassword, str } [OperationContract] - public bool ControlService(long sessionID, ScadaApps service, ServiceCommands command) + public bool ControlService(long sessionID, ScadaApps service, ServiceCommand command) { return true; } + [OperationContract] + public bool GetServiceStatus(long sessionID, ScadaApps service, out bool isRunning) + { + isRunning = true; + return true; + } + [OperationContract] public bool GetInstalledApps(long sessionID, out ScadaApps installedApps) { @@ -41,10 +49,35 @@ public bool GetInstalledApps(long sessionID, out ScadaApps installedApps) } [OperationContract] - public bool GetConfig(long sessionID, ScadaApps app, out Stream stream) + public Stream DownloadConfig(long sessionID, ConfigOptions configOptions) + { + return null; + } + + [OperationContract] + public bool UploadConfig(/*long sessionID, ConfigOptions configOptions,*/ Stream stream) { stream = null; return true; } + + [OperationContract] + public bool FindFiles(long sessionID, AppPath appPath, out ICollection paths) + { + paths = null; + return true; + } + + [OperationContract] + public Stream DownloadFile(long sessionID, AppPath appPath) + { + return null; + } + + [OperationContract] + public Stream DownloadFileRest(long sessionID, AppPath appPath, long position) + { + return null; + } } } From e4647ca68b548e007e5e01530afe410887d152d1 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 21 Mar 2018 12:18:10 +0300 Subject: [PATCH 008/100] ScadaAgent: wcf streaming --- ScadaAgent/ScadaAgentCtrl/App.config | 2 +- .../ServiceReference1/AgentSvc.wsdl | 153 ++++++++- .../ServiceReference1/Reference.cs | 312 +++++++++++++++++- .../ServiceReference1/Reference.svcmap | 4 +- ...iceReference1.FindFilesResponse.datasource | 10 + ...rence1.GetInstalledAppsResponse.datasource | 10 + ...rence1.GetServiceStatusResponse.datasource | 10 + ...Reference1.GetSessionIDResponse.datasource | 10 + .../ServiceReference1/item.xsd | 124 ++++++- .../ServiceReference1/item2.xsd | 66 +++- .../ServiceReference1/item3.xsd | 9 + .../ServiceReference1/item31.xsd | 6 + ScadaAgent/ScadaAgentCtrl/FrmMain.cs | 27 +- .../ScadaAgentCtrl/ScadaAgentCtrl.csproj | 18 + ScadaAgent/ScadaAgentWcf/AgentSvc.cs | 6 +- 15 files changed, 729 insertions(+), 38 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item3.xsd create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item31.xsd diff --git a/ScadaAgent/ScadaAgentCtrl/App.config b/ScadaAgent/ScadaAgentCtrl/App.config index 8f0e07bf3..24b813d12 100644 --- a/ScadaAgent/ScadaAgentCtrl/App.config +++ b/ScadaAgent/ScadaAgentCtrl/App.config @@ -6,7 +6,7 @@ - + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl index 93b178a58..80a2d3bf4 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl @@ -5,6 +5,8 @@ + + @@ -25,11 +27,53 @@ - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -44,9 +88,37 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -78,8 +150,71 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs index 2f2442255..42b956fbb 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs @@ -22,10 +22,11 @@ public interface AgentSvc { System.Threading.Tasks.Task SumAsync(double a, double b); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetSessionID", ReplyAction="http://tempuri.org/AgentSvc/GetSessionIDResponse")] - long GetSessionID(); + Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse GetSessionID(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request); + // CODEGEN: Generating message contract since the operation has multiple return values. [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetSessionID", ReplyAction="http://tempuri.org/AgentSvc/GetSessionIDResponse")] - System.Threading.Tasks.Task GetSessionIDAsync(); + System.Threading.Tasks.Task GetSessionIDAsync(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName); @@ -33,11 +34,201 @@ public interface AgentSvc { [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] System.Threading.Tasks.Task LoginAsync(long sessionID, string username, string encryptedPassword, string scadaInstanceName); - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ServiceCommand", ReplyAction="http://tempuri.org/AgentSvc/ServiceCommandResponse")] - void ServiceCommand(long sessionID, Scada.Agent.ServiceCommand command, int service); + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")] + bool ControlService(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command); - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ServiceCommand", ReplyAction="http://tempuri.org/AgentSvc/ServiceCommandResponse")] - System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommand command, int service); + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")] + System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")] + Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse GetServiceStatus(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")] + System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetInstalledApps", ReplyAction="http://tempuri.org/AgentSvc/GetInstalledAppsResponse")] + Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse GetInstalledApps(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetInstalledApps", ReplyAction="http://tempuri.org/AgentSvc/GetInstalledAppsResponse")] + System.Threading.Tasks.Task GetInstalledAppsAsync(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")] + System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions configOptions); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")] + System.Threading.Tasks.Task DownloadConfigAsync(long sessionID, Scada.Agent.ConfigOptions configOptions); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")] + bool UploadConfig(System.IO.Stream stream); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")] + System.Threading.Tasks.Task UploadConfigAsync(System.IO.Stream stream); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/FindFiles", ReplyAction="http://tempuri.org/AgentSvc/FindFilesResponse")] + Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse FindFiles(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/FindFiles", ReplyAction="http://tempuri.org/AgentSvc/FindFilesResponse")] + System.Threading.Tasks.Task FindFilesAsync(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")] + System.IO.Stream DownloadFile(long sessionID, Scada.Agent.AppPath appPath); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")] + System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.AppPath appPath); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")] + System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.AppPath appPath, long position); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")] + System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.AppPath appPath, long position); + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetSessionID", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetSessionIDRequest { + + public GetSessionIDRequest() { + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetSessionIDResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetSessionIDResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool GetSessionIDResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public long sessionID; + + public GetSessionIDResponse() { + } + + public GetSessionIDResponse(bool GetSessionIDResult, long sessionID) { + this.GetSessionIDResult = GetSessionIDResult; + this.sessionID = sessionID; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetServiceStatus", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetServiceStatusRequest { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public long sessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public Scada.Agent.ScadaApps service; + + public GetServiceStatusRequest() { + } + + public GetServiceStatusRequest(long sessionID, Scada.Agent.ScadaApps service) { + this.sessionID = sessionID; + this.service = service; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetServiceStatusResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetServiceStatusResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool GetServiceStatusResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public bool isRunning; + + public GetServiceStatusResponse() { + } + + public GetServiceStatusResponse(bool GetServiceStatusResult, bool isRunning) { + this.GetServiceStatusResult = GetServiceStatusResult; + this.isRunning = isRunning; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetInstalledApps", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetInstalledAppsRequest { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public long sessionID; + + public GetInstalledAppsRequest() { + } + + public GetInstalledAppsRequest(long sessionID) { + this.sessionID = sessionID; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetInstalledAppsResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetInstalledAppsResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool GetInstalledAppsResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public Scada.Agent.ScadaApps installedApps; + + public GetInstalledAppsResponse() { + } + + public GetInstalledAppsResponse(bool GetInstalledAppsResult, Scada.Agent.ScadaApps installedApps) { + this.GetInstalledAppsResult = GetInstalledAppsResult; + this.installedApps = installedApps; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="FindFiles", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class FindFilesRequest { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public long sessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public Scada.Agent.AppPath appPath; + + public FindFilesRequest() { + } + + public FindFilesRequest(long sessionID, Scada.Agent.AppPath appPath) { + this.sessionID = sessionID; + this.appPath = appPath; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="FindFilesResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class FindFilesResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool FindFilesResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public string[] paths; + + public FindFilesResponse() { + } + + public FindFilesResponse(bool FindFilesResult, string[] paths) { + this.FindFilesResult = FindFilesResult; + this.paths = paths; + } } [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] @@ -75,12 +266,20 @@ public System.Threading.Tasks.Task SumAsync(double a, double b) { return base.Channel.SumAsync(a, b); } - public long GetSessionID() { - return base.Channel.GetSessionID(); + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetSessionID(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request) { + return base.Channel.GetSessionID(request); + } + + public bool GetSessionID(out long sessionID) { + Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest(); + Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetSessionID(inValue); + sessionID = retVal.sessionID; + return retVal.GetSessionIDResult; } - public System.Threading.Tasks.Task GetSessionIDAsync() { - return base.Channel.GetSessionIDAsync(); + public System.Threading.Tasks.Task GetSessionIDAsync(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request) { + return base.Channel.GetSessionIDAsync(request); } public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName) { @@ -91,12 +290,97 @@ public System.Threading.Tasks.Task LoginAsync(long sessionID, string usern return base.Channel.LoginAsync(sessionID, username, encryptedPassword, scadaInstanceName); } - public void ServiceCommand(long sessionID, Scada.Agent.ServiceCommand command, int service) { - base.Channel.ServiceCommand(sessionID, command, service); + public bool ControlService(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command) { + return base.Channel.ControlService(sessionID, service, command); + } + + public System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command) { + return base.Channel.ControlServiceAsync(sessionID, service, command); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetServiceStatus(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request) { + return base.Channel.GetServiceStatus(request); + } + + public bool GetServiceStatus(long sessionID, Scada.Agent.ScadaApps service, out bool isRunning) { + Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest(); + inValue.sessionID = sessionID; + inValue.service = service; + Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetServiceStatus(inValue); + isRunning = retVal.isRunning; + return retVal.GetServiceStatusResult; + } + + public System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request) { + return base.Channel.GetServiceStatusAsync(request); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetInstalledApps(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request) { + return base.Channel.GetInstalledApps(request); + } + + public bool GetInstalledApps(long sessionID, out Scada.Agent.ScadaApps installedApps) { + Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest(); + inValue.sessionID = sessionID; + Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetInstalledApps(inValue); + installedApps = retVal.installedApps; + return retVal.GetInstalledAppsResult; + } + + public System.Threading.Tasks.Task GetInstalledAppsAsync(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request) { + return base.Channel.GetInstalledAppsAsync(request); + } + + public System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions configOptions) { + return base.Channel.DownloadConfig(sessionID, configOptions); + } + + public System.Threading.Tasks.Task DownloadConfigAsync(long sessionID, Scada.Agent.ConfigOptions configOptions) { + return base.Channel.DownloadConfigAsync(sessionID, configOptions); + } + + public bool UploadConfig(System.IO.Stream stream) { + return base.Channel.UploadConfig(stream); + } + + public System.Threading.Tasks.Task UploadConfigAsync(System.IO.Stream stream) { + return base.Channel.UploadConfigAsync(stream); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.FindFiles(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request) { + return base.Channel.FindFiles(request); + } + + public bool FindFiles(long sessionID, Scada.Agent.AppPath appPath, out string[] paths) { + Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest(); + inValue.sessionID = sessionID; + inValue.appPath = appPath; + Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).FindFiles(inValue); + paths = retVal.paths; + return retVal.FindFilesResult; + } + + public System.Threading.Tasks.Task FindFilesAsync(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request) { + return base.Channel.FindFilesAsync(request); + } + + public System.IO.Stream DownloadFile(long sessionID, Scada.Agent.AppPath appPath) { + return base.Channel.DownloadFile(sessionID, appPath); + } + + public System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.AppPath appPath) { + return base.Channel.DownloadFileAsync(sessionID, appPath); + } + + public System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.AppPath appPath, long position) { + return base.Channel.DownloadFileRest(sessionID, appPath, position); } - public System.Threading.Tasks.Task ServiceCommandAsync(long sessionID, Scada.Agent.ServiceCommand command, int service) { - return base.Channel.ServiceCommandAsync(sessionID, command, service); + public System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.AppPath appPath, long position) { + return base.Channel.DownloadFileRestAsync(sessionID, appPath, position); } } } diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap index d1706ae71..273c3ad27 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap @@ -22,10 +22,12 @@ + + + - diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource new file mode 100644 index 000000000..e267aa5ab --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource new file mode 100644 index 000000000..39bcb9491 --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource new file mode 100644 index 000000000..973c46cd5 --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource new file mode 100644 index 000000000..25eb5d8c5 --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd index 334462be5..8bca8f3a3 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd @@ -1,6 +1,8 @@ + + @@ -24,7 +26,8 @@ - + + @@ -45,18 +48,127 @@ - + - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd index 9c3a6f272..2faf25122 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd @@ -1,11 +1,73 @@ - + + + + + + + + + 0 + + + + + + + 1 + + + + + + + 2 + + + + + + + 4 + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item3.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item3.xsd new file mode 100644 index 000000000..04a74a45c --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item3.xsd @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item31.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item31.xsd new file mode 100644 index 000000000..9c6da3168 --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item31.xsd @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs index 76d2606af..60ce65ddb 100644 --- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs +++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs @@ -1,4 +1,5 @@ using Scada.Agent.Ctrl.ServiceReference1; +using System.IO; using System.Windows.Forms; namespace Scada.Agent.Ctrl @@ -13,11 +14,29 @@ public FrmMain() private void button1_Click(object sender, System.EventArgs e) { AgentSvcClient client = new AgentSvcClient(); - double sum = client.Sum(2, 2); - //client.ServiceCommand(0, ServiceCommands.Restart, 0); - client.Close(); - MessageBox.Show(sum.ToString()); + try + { + double sum = client.Sum(2, 2); + MessageBox.Show(sum.ToString()); + + Stream stream = client.DownloadFile(0, AppPath.Base); + if (stream == null) + { + MessageBox.Show("Stream is null."); + } + else + { + byte[] buf = new byte[100]; + int cnt = stream.Read(buf, 0, buf.Length); + string s = System.Text.Encoding.ASCII.GetString(buf, 0, cnt); + MessageBox.Show(s); + } + } + finally + { + client.Close(); + } } } } diff --git a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj index d2cbbfa92..4c5c44cee 100644 --- a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj +++ b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj @@ -77,6 +77,24 @@ Designer + + Designer + + + Designer + + + Reference.svcmap + + + Reference.svcmap + + + Reference.svcmap + + + Reference.svcmap + SettingsSingleFileGenerator Settings.Designer.cs diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs index 50ddac0fd..cbb4fb815 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs @@ -71,7 +71,11 @@ public bool FindFiles(long sessionID, AppPath appPath, out ICollection p [OperationContract] public Stream DownloadFile(long sessionID, AppPath appPath) { - return null; + byte[] buffer = System.Text.Encoding.ASCII.GetBytes("hello"); + MemoryStream stream = new MemoryStream(buffer.Length); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + return stream; } [OperationContract] From 01f1520ca396efa8597e8fb033b362be09b60555 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 21 Mar 2018 15:51:32 +0300 Subject: [PATCH 009/100] ScadaAgent: test wcf streaming --- ScadaAgent/ScadaAgentCtrl/App.config | 4 +- .../ServiceReference1/AgentSvc.wsdl | 16 +++-- .../ServiceReference1/Reference.cs | 66 +++++++++++++++++-- ...iceReference1.FindFilesResponse.datasource | 2 +- ...rence1.GetInstalledAppsResponse.datasource | 2 +- ...rence1.GetServiceStatusResponse.datasource | 2 +- ...Reference1.GetSessionIDResponse.datasource | 2 +- ...Reference1.UploadConfigResponse.datasource | 10 +++ .../ServiceReference1/item.xsd | 25 +++---- ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs | 13 ++++ ScadaAgent/ScadaAgentCtrl/FrmMain.cs | 44 ++++++++++++- .../ScadaAgentCtrl/ScadaAgentCtrl.csproj | 3 + ScadaAgent/ScadaAgentMono/App.config | 11 +++- ScadaAgent/ScadaAgentWcf/AgentSvc.cs | 39 +++++++++-- .../ScadaAgentWcf/ConfigUploadMessage.cs | 18 +++++ ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj | 1 + 16 files changed, 214 insertions(+), 44 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource create mode 100644 ScadaAgent/ScadaAgentWcf/ConfigUploadMessage.cs diff --git a/ScadaAgent/ScadaAgentCtrl/App.config b/ScadaAgent/ScadaAgentCtrl/App.config index 24b813d12..a5a49fcd1 100644 --- a/ScadaAgent/ScadaAgentCtrl/App.config +++ b/ScadaAgent/ScadaAgentCtrl/App.config @@ -6,11 +6,11 @@ - + - diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl index 80a2d3bf4..e183dd99e 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl @@ -51,12 +51,14 @@ - - + + - - + + + + @@ -105,7 +107,7 @@ - + @@ -188,7 +190,9 @@ - + + + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs index 42b956fbb..c56501d5b 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs @@ -60,11 +60,12 @@ public interface AgentSvc { [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")] System.Threading.Tasks.Task DownloadConfigAsync(long sessionID, Scada.Agent.ConfigOptions configOptions); + // CODEGEN: Generating message contract since the operation UploadConfig is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")] - bool UploadConfig(System.IO.Stream stream); + Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse UploadConfig(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")] - System.Threading.Tasks.Task UploadConfigAsync(System.IO.Stream stream); + System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/FindFiles", ReplyAction="http://tempuri.org/AgentSvc/FindFilesResponse")] Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse FindFiles(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request); @@ -191,6 +192,41 @@ public GetInstalledAppsResponse(bool GetInstalledAppsResult, Scada.Agent.ScadaAp } } + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(WrapperName="ConfigUploadMessage", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class ConfigUploadMessage { + + [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")] + public Scada.Agent.ConfigOptions ConfigOptions; + + [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")] + public long SessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public System.IO.Stream Stream; + + public ConfigUploadMessage() { + } + + public ConfigUploadMessage(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + this.ConfigOptions = ConfigOptions; + this.SessionID = SessionID; + this.Stream = Stream; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class UploadConfigResponse { + + public UploadConfigResponse() { + } + } + [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] [System.ServiceModel.MessageContractAttribute(WrapperName="FindFiles", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] @@ -341,12 +377,30 @@ public System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions return base.Channel.DownloadConfigAsync(sessionID, configOptions); } - public bool UploadConfig(System.IO.Stream stream) { - return base.Channel.UploadConfig(stream); + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.UploadConfig(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request) { + return base.Channel.UploadConfig(request); + } + + public void UploadConfig(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage inValue = new Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage(); + inValue.ConfigOptions = ConfigOptions; + inValue.SessionID = SessionID; + inValue.Stream = Stream; + Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).UploadConfig(inValue); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + System.Threading.Tasks.Task Scada.Agent.Ctrl.ServiceReference1.AgentSvc.UploadConfigAsync(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request) { + return base.Channel.UploadConfigAsync(request); } - public System.Threading.Tasks.Task UploadConfigAsync(System.IO.Stream stream) { - return base.Channel.UploadConfigAsync(stream); + public System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage inValue = new Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage(); + inValue.ConfigOptions = ConfigOptions; + inValue.SessionID = SessionID; + inValue.Stream = Stream; + return ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).UploadConfigAsync(inValue); } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource index e267aa5ab..5e7a3f871 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource @@ -6,5 +6,5 @@ cause the file to be unrecognizable by the program. --> - Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse + Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource index 39bcb9491..3185e6821 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource @@ -6,5 +6,5 @@ cause the file to be unrecognizable by the program. --> - Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse + Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource index 973c46cd5..3e6fb6f86 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource @@ -6,5 +6,5 @@ cause the file to be unrecognizable by the program. --> - Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse + Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource index 25eb5d8c5..cf1a366a3 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource @@ -6,5 +6,5 @@ cause the file to be unrecognizable by the program. --> - Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse + Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource new file mode 100644 index 000000000..9f574a896 --- /dev/null +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd index 8bca8f3a3..19189e5e9 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd @@ -110,25 +110,20 @@ - + - - - - - - - - + + + - + @@ -136,7 +131,7 @@ - + @@ -144,14 +139,14 @@ - + - + @@ -159,7 +154,7 @@ - + @@ -167,7 +162,7 @@ - + diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs index 5df316636..be5050661 100644 --- a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs +++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs @@ -29,6 +29,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // button1 @@ -41,11 +42,22 @@ private void InitializeComponent() this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // + // button2 + // + this.button2.Location = new System.Drawing.Point(93, 12); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 1; + this.button2.Text = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // // FrmMain // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.button2); this.Controls.Add(this.button1); this.Name = "FrmMain"; this.Text = "Form1"; @@ -56,6 +68,7 @@ private void InitializeComponent() #endregion private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; } } diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs index 60ce65ddb..0cde240b8 100644 --- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs +++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs @@ -1,4 +1,5 @@ using Scada.Agent.Ctrl.ServiceReference1; +using System; using System.IO; using System.Windows.Forms; @@ -27,10 +28,22 @@ private void button1_Click(object sender, System.EventArgs e) } else { - byte[] buf = new byte[100]; - int cnt = stream.Read(buf, 0, buf.Length); + DateTime t0 = DateTime.UtcNow; + byte[] buf = new byte[1024]; + Stream saver = File.Create(@"D:\file1.txt"); + int cnt; + + while ((cnt = stream.Read(buf, 0, buf.Length)) > 0) + { + saver.Write(buf, 0, cnt); + } + + saver.Close(); + MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms"); + + /*int cnt = stream.Read(buf, 0, buf.Length); string s = System.Text.Encoding.ASCII.GetString(buf, 0, cnt); - MessageBox.Show(s); + MessageBox.Show(s);*/ } } finally @@ -38,5 +51,30 @@ private void button1_Click(object sender, System.EventArgs e) client.Close(); } } + + private void button2_Click(object sender, System.EventArgs e) + { + AgentSvcClient client = new AgentSvcClient(); + Stream stream = null; + + try + { + ConfigOptions configOptions = new ConfigOptions(); + + /*byte[] buffer = System.Text.Encoding.ASCII.GetBytes("I'm Muzzy"); + stream = new MemoryStream(buffer.Length); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0;*/ + + stream = File.Open(@"D:\big.txt", FileMode.Open); + client.UploadConfig(configOptions, 0, stream); + MessageBox.Show("Done"); + } + finally + { + stream?.Close(); + client.Close(); + } + } } } diff --git a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj index 4c5c44cee..0d4179d67 100644 --- a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj +++ b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj @@ -95,6 +95,9 @@ Reference.svcmap + + Reference.svcmap + SettingsSingleFileGenerator Settings.Designer.cs diff --git a/ScadaAgent/ScadaAgentMono/App.config b/ScadaAgent/ScadaAgentMono/App.config index 1ef8518b5..4d16b42f1 100644 --- a/ScadaAgent/ScadaAgentMono/App.config +++ b/ScadaAgent/ScadaAgentMono/App.config @@ -4,11 +4,16 @@ + + + + + - + @@ -19,7 +24,9 @@ - + diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs index cbb4fb815..59a9269d2 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.ServiceModel; @@ -55,10 +56,34 @@ public Stream DownloadConfig(long sessionID, ConfigOptions configOptions) } [OperationContract] - public bool UploadConfig(/*long sessionID, ConfigOptions configOptions,*/ Stream stream) + public void UploadConfig(ConfigUploadMessage configUploadMessage) { - stream = null; - return true; + if (configUploadMessage.Stream == null) + { + System.Console.WriteLine("configUploadMessage.Stream is null"); + } + else + { + /*byte[] buf = new byte[100]; + int cnt = configUploadMessage.Stream.Read(buf, 0, buf.Length); + string s = System.Text.Encoding.ASCII.GetString(buf, 0, cnt); + System.Console.WriteLine(s);*/ + + DateTime t0 = DateTime.UtcNow; + byte[] buf = new byte[1024]; + Stream saver = File.Create("file2.txt"); + int cnt; + + while ((cnt = configUploadMessage.Stream.Read(buf, 0, buf.Length)) > 0) + { + saver.Write(buf, 0, cnt); + } + + saver.Close(); + Console.WriteLine("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms"); + } + + //return true; } [OperationContract] @@ -71,10 +96,12 @@ public bool FindFiles(long sessionID, AppPath appPath, out ICollection p [OperationContract] public Stream DownloadFile(long sessionID, AppPath appPath) { - byte[] buffer = System.Text.Encoding.ASCII.GetBytes("hello"); + /*byte[] buffer = System.Text.Encoding.ASCII.GetBytes("hello"); MemoryStream stream = new MemoryStream(buffer.Length); stream.Write(buffer, 0, buffer.Length); - stream.Position = 0; + stream.Position = 0;*/ + + Stream stream = File.Open("big.txt", FileMode.Open); return stream; } diff --git a/ScadaAgent/ScadaAgentWcf/ConfigUploadMessage.cs b/ScadaAgent/ScadaAgentWcf/ConfigUploadMessage.cs new file mode 100644 index 000000000..7ef33ed4a --- /dev/null +++ b/ScadaAgent/ScadaAgentWcf/ConfigUploadMessage.cs @@ -0,0 +1,18 @@ +using System.IO; +using System.ServiceModel; + +namespace Scada.Agent.Wcf +{ + [MessageContract] + public class ConfigUploadMessage + { + [MessageHeader] + public long SessionID; + + [MessageHeader] + public ConfigOptions ConfigOptions; + + [MessageBodyMember] + public Stream Stream; + } +} diff --git a/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj b/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj index 0184df669..395f4cd24 100644 --- a/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj +++ b/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj @@ -37,6 +37,7 @@ + From 3a9163f79b28623052d42cc32ec4b0352cd0b7fd Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 21 Mar 2018 17:52:38 +0300 Subject: [PATCH 010/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/Settings.cs | 70 +++++++++++++++++++++++++++ ScadaAgent/ScadaAgentCtrl/App.config | 4 +- ScadaAgent/ScadaAgentMono/App.config | 2 +- ScadaAgent/ScadaAgentWcf/AgentSvc.cs | 5 -- 4 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/Settings.cs diff --git a/ScadaAgent/ScadaAgentCore/Settings.cs b/ScadaAgent/ScadaAgentCore/Settings.cs new file mode 100644 index 000000000..162aa6e82 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/Settings.cs @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Agent settings + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Scada.Agent +{ + /// + /// Agent settings + /// Настройки агента + /// + public class Settings + { + /// + /// Agent settings for the system instance + /// Настройки агента для экземплара системы + /// + public class ScadaInstance + { + public string Name { get; set; } + + public string Directory { get; set; } + } + + + /// + /// Конструктор + /// + public Settings() + { + Culture = ""; + Instances = new List(); + } + + + /// + /// Получить или установить культуру агента + /// + public string Culture { get; set; } + + /// + /// Получить настройки экземпляров систем + /// + public List Instances { get; private set; } + } +} diff --git a/ScadaAgent/ScadaAgentCtrl/App.config b/ScadaAgent/ScadaAgentCtrl/App.config index a5a49fcd1..e84d9ebed 100644 --- a/ScadaAgent/ScadaAgentCtrl/App.config +++ b/ScadaAgent/ScadaAgentCtrl/App.config @@ -6,11 +6,11 @@ - + - diff --git a/ScadaAgent/ScadaAgentMono/App.config b/ScadaAgent/ScadaAgentMono/App.config index 4d16b42f1..a93be18a3 100644 --- a/ScadaAgent/ScadaAgentMono/App.config +++ b/ScadaAgent/ScadaAgentMono/App.config @@ -6,7 +6,7 @@ - + diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs index 59a9269d2..415f51209 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs @@ -10,11 +10,6 @@ public class AgentSvc { private static ScadaManager mngr = new ScadaManager(); - [OperationContract] - public double Sum(double a, double b) - { - return mngr.Sum(a, b); - } [OperationContract] public bool GetSessionID(out long sessionID) From 12a42bc65e62a8bcc78c0286a20aefca38a412c8 Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 22 Mar 2018 10:57:28 +0300 Subject: [PATCH 011/100] Create ScadaData.Std and Log.Std --- Log/Log.Std/Log.Std.csproj | 13 ++++ Log/Log.sln | 15 ++++- Log/{ => Log}/ILog.cs | 0 Log/{ => Log}/Log.cs | 0 Log/{ => Log}/Log.csproj | 0 Log/{ => Log}/LogStub.cs | 0 Log/{ => Log}/Properties/AssemblyInfo.cs | 0 ScadaData/ScadaData.Std/ScadaData.Std.csproj | 63 ++++++++++++++++++++ ScadaData/ScadaData.sln | 13 +++- ScadaData/ScadaData/Localization.cs | 21 +++++-- ScadaData/ScadaData/ScadaData.csproj | 5 +- 11 files changed, 118 insertions(+), 12 deletions(-) create mode 100644 Log/Log.Std/Log.Std.csproj rename Log/{ => Log}/ILog.cs (100%) rename Log/{ => Log}/Log.cs (100%) rename Log/{ => Log}/Log.csproj (100%) rename Log/{ => Log}/LogStub.cs (100%) rename Log/{ => Log}/Properties/AssemblyInfo.cs (100%) create mode 100644 ScadaData/ScadaData.Std/ScadaData.Std.csproj diff --git a/Log/Log.Std/Log.Std.csproj b/Log/Log.Std/Log.Std.csproj new file mode 100644 index 000000000..20401feb0 --- /dev/null +++ b/Log/Log.Std/Log.Std.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.0 + + + + + + + + + diff --git a/Log/Log.sln b/Log/Log.sln index 3a0d4a4de..9a2a7bbc3 100644 --- a/Log/Log.sln +++ b/Log/Log.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2005 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Log", "Log.csproj", "{A05EA084-E509-4025-9241-6A5BE5C2B328}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Log", "Log\Log.csproj", "{A05EA084-E509-4025-9241-6A5BE5C2B328}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Log.Std", "Log.Std\Log.Std.csproj", "{8D5B84EB-11D8-4B4E-80A0-E51966863149}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,8 +17,15 @@ Global {A05EA084-E509-4025-9241-6A5BE5C2B328}.Debug|Any CPU.Build.0 = Debug|Any CPU {A05EA084-E509-4025-9241-6A5BE5C2B328}.Release|Any CPU.ActiveCfg = Release|Any CPU {A05EA084-E509-4025-9241-6A5BE5C2B328}.Release|Any CPU.Build.0 = Release|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EA8D43F9-5D59-4AEA-A084-86003618EEA5} + EndGlobalSection EndGlobal diff --git a/Log/ILog.cs b/Log/Log/ILog.cs similarity index 100% rename from Log/ILog.cs rename to Log/Log/ILog.cs diff --git a/Log/Log.cs b/Log/Log/Log.cs similarity index 100% rename from Log/Log.cs rename to Log/Log/Log.cs diff --git a/Log/Log.csproj b/Log/Log/Log.csproj similarity index 100% rename from Log/Log.csproj rename to Log/Log/Log.csproj diff --git a/Log/LogStub.cs b/Log/Log/LogStub.cs similarity index 100% rename from Log/LogStub.cs rename to Log/Log/LogStub.cs diff --git a/Log/Properties/AssemblyInfo.cs b/Log/Log/Properties/AssemblyInfo.cs similarity index 100% rename from Log/Properties/AssemblyInfo.cs rename to Log/Log/Properties/AssemblyInfo.cs diff --git a/ScadaData/ScadaData.Std/ScadaData.Std.csproj b/ScadaData/ScadaData.Std/ScadaData.Std.csproj new file mode 100644 index 000000000..b31093d13 --- /dev/null +++ b/ScadaData/ScadaData.Std/ScadaData.Std.csproj @@ -0,0 +1,63 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll + + + + diff --git a/ScadaData/ScadaData.sln b/ScadaData/ScadaData.sln index ad9d9441a..dbad85f73 100644 --- a/ScadaData/ScadaData.sln +++ b/ScadaData/ScadaData.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2005 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData", "ScadaData\ScadaData.csproj", "{C5DC293F-13CA-435F-A7DB-4BA91639C292}" EndProject @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData.Svc", "ScadaData. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData.Dao", "ScadaData.Dao\ScadaData.Dao.csproj", "{1DDE26A2-1E24-4680-A635-2760B37CAFDB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData.Std", "ScadaData.Std\ScadaData.Std.csproj", "{3C69A20A-6810-445E-AE86-E98AB91C42F4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,8 +34,15 @@ Global {1DDE26A2-1E24-4680-A635-2760B37CAFDB}.Debug|Any CPU.Build.0 = Debug|Any CPU {1DDE26A2-1E24-4680-A635-2760B37CAFDB}.Release|Any CPU.ActiveCfg = Release|Any CPU {1DDE26A2-1E24-4680-A635-2760B37CAFDB}.Release|Any CPU.Build.0 = Release|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ED6A68FA-3866-482A-846C-1C0CED33847A} + EndGlobalSection EndGlobal diff --git a/ScadaData/ScadaData/Localization.cs b/ScadaData/ScadaData/Localization.cs index 0333a64b3..8f687e505 100644 --- a/ScadaData/ScadaData/Localization.cs +++ b/ScadaData/ScadaData/Localization.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,9 @@ * * Author : Mikhail Shiryaev * Created : 2014 - * Modified : 2017 + * Modified : 2018 */ -using Microsoft.Win32; using System; using System.Collections.Generic; using System.Globalization; @@ -166,11 +165,17 @@ private static string ReadCulture() { try { - using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) +#if NETSTANDARD2_0 + return ""; +#else + using (Microsoft.Win32.RegistryKey key = + Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, + Microsoft.Win32.RegistryView.Registry64) .OpenSubKey("Software\\SCADA", false)) { return key.GetValue("Culture").ToString(); } +#endif } catch { @@ -224,9 +229,15 @@ public static bool WriteCulture(string cultureName, out string errMsg) { try { - using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64). +#if !NETSTANDARD2_0 + using (Microsoft.Win32.RegistryKey key = + Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, + Microsoft.Win32.RegistryView.Registry64). CreateSubKey("Software\\SCADA")) + { key.SetValue("Culture", cultureName); + } +#endif errMsg = ""; return true; } diff --git a/ScadaData/ScadaData/ScadaData.csproj b/ScadaData/ScadaData/ScadaData.csproj index c25fad589..0265b9be3 100644 --- a/ScadaData/ScadaData/ScadaData.csproj +++ b/ScadaData/ScadaData/ScadaData.csproj @@ -39,8 +39,9 @@ bin\Release\ScadaData.XML - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll From f9d73509167c0ae777eab211e2567376577556e7 Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 22 Mar 2018 10:58:45 +0300 Subject: [PATCH 012/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/AppDirs.cs | 87 +++++++++++++++++++ .../ScadaAgentCore/ScadaAgentCore.csproj | 9 ++ ScadaAgent/ScadaAgentCore/Settings.cs | 24 +++-- 3 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/AppDirs.cs diff --git a/ScadaAgent/ScadaAgentCore/AppDirs.cs b/ScadaAgent/ScadaAgentCore/AppDirs.cs new file mode 100644 index 000000000..885aa6c8c --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/AppDirs.cs @@ -0,0 +1,87 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : Scheme Editor + * Summary : ScadaAgentCore + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System.IO; + +namespace Scada.Scheme.Editor +{ + /// + /// Application directories + /// Директории приложения + /// + internal class AppDirs + { + /// + /// Конструктор + /// + public AppDirs() + { + ExeDir = ""; + ConfigDir = ""; + LangDir = ""; + LogDir = ""; + TempDir = ""; + } + + + /// + /// Получить директорию исполняемого файла + /// + public string ExeDir { get; protected set; } + + /// + /// Получить директорию конфигурации + /// + public string ConfigDir { get; protected set; } + + /// + /// Получить директорию языковых файлов + /// + public string LangDir { get; protected set; } + + /// + /// Получить директорию журналов + /// + public string LogDir { get; protected set; } + + /// + /// Получить или установить директорию временных файлов + /// + public string TempDir { get; set; } + + + /// + /// Инициализировать директории на основе директории исполняемого файла приложения + /// + public void Init(string exeDir) + { + ExeDir = ScadaUtils.NormalDir(exeDir); + ConfigDir = ExeDir + "Config" + Path.DirectorySeparatorChar; + LangDir = ExeDir + "Lang" + Path.DirectorySeparatorChar; + LogDir = ExeDir + "Log" + Path.DirectorySeparatorChar; + TempDir = ExeDir + "Temp" + Path.DirectorySeparatorChar; + } + } +} diff --git a/ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj b/ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj index 719b9acf7..a6e253d07 100644 --- a/ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj +++ b/ScadaAgent/ScadaAgentCore/ScadaAgentCore.csproj @@ -9,4 +9,13 @@ bin\Release\netstandard2.0\ScadaAgentCore.xml + + + ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll + + + ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll + + + diff --git a/ScadaAgent/ScadaAgentCore/Settings.cs b/ScadaAgent/ScadaAgentCore/Settings.cs index 162aa6e82..05923d7d3 100644 --- a/ScadaAgent/ScadaAgentCore/Settings.cs +++ b/ScadaAgent/ScadaAgentCore/Settings.cs @@ -23,9 +23,7 @@ * Modified : 2018 */ -using System; using System.Collections.Generic; -using System.Text; namespace Scada.Agent { @@ -41,8 +39,22 @@ public class Settings /// public class ScadaInstance { - public string Name { get; set; } + /// + /// Конструктор + /// + public ScadaInstance() + { + Name = ""; + Directory = ""; + } + /// + /// Получить или установить наименование + /// + public string Name { get; set; } + /// + /// Получить или установить директорию + /// public string Directory { get; set; } } @@ -52,16 +64,10 @@ public class ScadaInstance /// public Settings() { - Culture = ""; Instances = new List(); } - /// - /// Получить или установить культуру агента - /// - public string Culture { get; set; } - /// /// Получить настройки экземпляров систем /// From d088d3942c73a402ad2b0bf90bf80f704c4a958f Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 22 Mar 2018 11:12:48 +0300 Subject: [PATCH 013/100] Update references to Log.dll --- ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj | 2 +- ScadaComm/OpenKPs/AddressBook/AddressBook.csproj | 2 +- ScadaComm/OpenKPs/KpEmail/KpEmail.csproj | 5 +++-- ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj | 5 +++-- ScadaComm/OpenKPs/KpModbus/KpModbus.csproj | 2 +- ScadaComm/OpenKPs/KpSms/KpSms.csproj | 2 +- ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj | 5 +++-- ScadaComm/OpenKPs/KpTest/KpTest.csproj | 5 +++-- ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj | 2 +- ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj | 2 +- ScadaComm/ScadaCommMono/ScadaCommMono.csproj | 5 +++-- ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj | 2 +- ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj | 2 +- ScadaServer/OpenModules/ModTest/ModTest.csproj | 2 +- ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj | 5 +++-- ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj | 4 ++-- ScadaServer/ScadaServerMono/ScadaServerMono.csproj | 5 +++-- ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj | 5 +++-- ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj | 6 ++++-- ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj | 5 +++-- ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj | 6 ++++-- ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj | 6 ++++-- ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj | 6 ++++-- ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj | 5 +++-- ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj | 6 ++++-- ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj | 6 ++++-- ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj | 3 ++- .../ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj | 2 +- .../ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj | 5 +++-- ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj | 5 +++-- ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj | 3 ++- 31 files changed, 76 insertions(+), 50 deletions(-) diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj index fb785955b..0d96a038e 100644 --- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj +++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj @@ -65,7 +65,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaComm\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj b/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj index 24d714a29..d19544f38 100644 --- a/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj +++ b/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj @@ -34,7 +34,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj b/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj index ff9fe237e..71a9903f1 100644 --- a/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj +++ b/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj @@ -31,8 +31,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj b/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj index 94c3ea92c..a677fe0bd 100644 --- a/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj +++ b/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj @@ -30,8 +30,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj b/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj index 55b59b71c..c25a48513 100644 --- a/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj +++ b/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj @@ -34,7 +34,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpSms/KpSms.csproj b/ScadaComm/OpenKPs/KpSms/KpSms.csproj index 4c47f3c94..f6b4d3dc6 100644 --- a/ScadaComm/OpenKPs/KpSms/KpSms.csproj +++ b/ScadaComm/OpenKPs/KpSms/KpSms.csproj @@ -38,7 +38,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj b/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj index 745e5f2bb..217553a66 100644 --- a/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj +++ b/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj @@ -30,8 +30,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpTest/KpTest.csproj b/ScadaComm/OpenKPs/KpTest/KpTest.csproj index 0a6d8a2fc..7b2803dac 100644 --- a/ScadaComm/OpenKPs/KpTest/KpTest.csproj +++ b/ScadaComm/OpenKPs/KpTest/KpTest.csproj @@ -36,8 +36,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj b/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj index 79d47b249..5d9b48b61 100644 --- a/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj +++ b/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj @@ -33,7 +33,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj b/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj index 4d362b076..18d59e0f2 100644 --- a/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj +++ b/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj @@ -58,7 +58,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll ..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/ScadaCommMono/ScadaCommMono.csproj b/ScadaComm/ScadaCommMono/ScadaCommMono.csproj index 65a6350b3..5ad55854e 100644 --- a/ScadaComm/ScadaCommMono/ScadaCommMono.csproj +++ b/ScadaComm/ScadaCommMono/ScadaCommMono.csproj @@ -32,8 +32,9 @@ 4 - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj b/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj index d98272bf5..eeac5dd13 100644 --- a/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj +++ b/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj @@ -53,7 +53,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj b/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj index e288f7c39..6d12958ea 100644 --- a/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj +++ b/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj @@ -32,7 +32,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\..\dll\PostgreSQL\Mono.Security.dll diff --git a/ScadaServer/OpenModules/ModTest/ModTest.csproj b/ScadaServer/OpenModules/ModTest/ModTest.csproj index f83de6ab7..2ce645256 100644 --- a/ScadaServer/OpenModules/ModTest/ModTest.csproj +++ b/ScadaServer/OpenModules/ModTest/ModTest.csproj @@ -33,7 +33,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj b/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj index a885f75c7..e47c0c4d5 100644 --- a/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj +++ b/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj @@ -32,8 +32,9 @@ bin\Release\ScadaServerCommon.XML - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj b/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj index af6f86e25..d0bad3344 100644 --- a/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj +++ b/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj @@ -69,7 +69,7 @@ prompt false false - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\ManagedMinimumRules.ruleset + MinimumRecommendedRules.ruleset app.manifest @@ -80,7 +80,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaServer/ScadaServerMono/ScadaServerMono.csproj b/ScadaServer/ScadaServerMono/ScadaServerMono.csproj index 49d29af24..b19038c0f 100644 --- a/ScadaServer/ScadaServerMono/ScadaServerMono.csproj +++ b/ScadaServer/ScadaServerMono/ScadaServerMono.csproj @@ -32,8 +32,9 @@ 4 - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj b/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj index 39c8530d1..bbbf347e8 100644 --- a/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj +++ b/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj @@ -50,8 +50,9 @@ 4 - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj b/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj index efd0e609b..b5c044f3e 100644 --- a/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj +++ b/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj @@ -22,6 +22,7 @@ + true @@ -41,8 +42,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj b/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj index 715162078..9e2a25052 100644 --- a/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj +++ b/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj @@ -31,8 +31,9 @@ bin\Release\PlgChartCommon.XML - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj b/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj index b8ce44603..f06a5df48 100644 --- a/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj +++ b/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj @@ -22,6 +22,7 @@ + true @@ -41,8 +42,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll diff --git a/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj b/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj index 4e0ef3779..0c8ad825f 100644 --- a/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj +++ b/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj @@ -20,6 +20,7 @@ + true @@ -39,8 +40,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj b/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj index 8e111d888..8b3c89153 100644 --- a/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj +++ b/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj @@ -20,6 +20,7 @@ + true @@ -39,8 +40,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\Report\RepBuilder\bin\Release\RepBuilder.dll diff --git a/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj b/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj index 0f4a370c2..81541d878 100644 --- a/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj +++ b/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj @@ -31,8 +31,9 @@ bin\Release\PlgTableCommon.XML - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj b/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj index cde2641c6..1ade04e25 100644 --- a/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj +++ b/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj @@ -20,6 +20,7 @@ + true @@ -39,8 +40,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj b/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj index 1f4ffd5fa..0eefc2dee 100644 --- a/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj +++ b/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj @@ -22,6 +22,7 @@ + true @@ -41,8 +42,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj b/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj index 2c5876914..7aa2dfca0 100644 --- a/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj +++ b/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj @@ -23,6 +23,7 @@ True + true @@ -44,7 +45,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj index a91d5ee0b..98c1b3456 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj +++ b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj @@ -33,7 +33,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj index 6e95acb40..3f5e26aca 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj +++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj @@ -55,8 +55,9 @@ app.manifest - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj b/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj index cbc219f28..e89c14c1a 100644 --- a/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj +++ b/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj @@ -31,8 +31,9 @@ bin\Release\ScadaWebCommon5.xml - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj b/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj index c49f7f1e0..37508f23f 100644 --- a/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj +++ b/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj @@ -23,6 +23,7 @@ True + true @@ -44,7 +45,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll False From 84892e80724644ba7530b6ac5b0a58ac9bc00241 Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 22 Mar 2018 12:08:20 +0300 Subject: [PATCH 014/100] ScadaAgent: dev 2 --- ScadaAgent/ScadaAgentCore/AppData.cs | 79 ++++++++++++++++++++ ScadaAgent/ScadaAgentCore/AppDirs.cs | 8 +- ScadaAgent/ScadaAgentCore/InstanceManager.cs | 35 +++++++++ ScadaAgent/ScadaAgentCore/ScadaManager.cs | 12 --- ScadaAgent/ScadaAgentWcf/AgentSvc.cs | 3 - 5 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/AppData.cs create mode 100644 ScadaAgent/ScadaAgentCore/InstanceManager.cs delete mode 100644 ScadaAgent/ScadaAgentCore/ScadaManager.cs diff --git a/ScadaAgent/ScadaAgentCore/AppData.cs b/ScadaAgent/ScadaAgentCore/AppData.cs new file mode 100644 index 000000000..5fb5e8ce6 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/AppData.cs @@ -0,0 +1,79 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Common data of the agent + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; +using System.Collections.Generic; +using System.Text; +using Utils; + +namespace Scada.Agent +{ + /// + /// Common data of the agent + /// Общие данные агента + /// + public sealed class AppData + { + private static readonly AppData appDataInstance; // экземпляр объекта AppData + + + /// + /// Статический конструктор + /// + static AppData() + { + appDataInstance = new AppData(); + } + + /// + /// Конструктор, ограничивающий создание объекта из других классов + /// + private AppData() + { + AppDirs = new AppDirs(); + Log = new Log(Log.Formats.Full); + } + + + /// + /// Получить директории приложения + /// + public AppDirs AppDirs { get; private set; } + + /// + /// Получить журнал приложения + /// + public Log Log { get; private set; } + + + /// + /// Получить общие данные агента + /// + public static AppData GetAppData() + { + return appDataInstance; + } + } +} diff --git a/ScadaAgent/ScadaAgentCore/AppDirs.cs b/ScadaAgent/ScadaAgentCore/AppDirs.cs index 885aa6c8c..fee89a51d 100644 --- a/ScadaAgent/ScadaAgentCore/AppDirs.cs +++ b/ScadaAgent/ScadaAgentCore/AppDirs.cs @@ -15,8 +15,8 @@ * * * Product : Rapid SCADA - * Module : Scheme Editor - * Summary : ScadaAgentCore + * Module : ScadaAgentCore + * Summary : Application directories * * Author : Mikhail Shiryaev * Created : 2018 @@ -25,13 +25,13 @@ using System.IO; -namespace Scada.Scheme.Editor +namespace Scada.Agent { /// /// Application directories /// Директории приложения /// - internal class AppDirs + public class AppDirs { /// /// Конструктор diff --git a/ScadaAgent/ScadaAgentCore/InstanceManager.cs b/ScadaAgent/ScadaAgentCore/InstanceManager.cs new file mode 100644 index 000000000..7b5be7b9a --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/InstanceManager.cs @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : System instance manager + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +namespace Scada.Agent +{ + /// + /// System instance manager + /// Менеджер экземпляров систем + /// + public class InstanceManager + { + } +} diff --git a/ScadaAgent/ScadaAgentCore/ScadaManager.cs b/ScadaAgent/ScadaAgentCore/ScadaManager.cs deleted file mode 100644 index a0a14663d..000000000 --- a/ScadaAgent/ScadaAgentCore/ScadaManager.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Scada.Agent -{ - public class ScadaManager - { - public double Sum(double a, double b) - { - return a + b; - } - } -} diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs index 415f51209..7edb00ac2 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs @@ -8,9 +8,6 @@ namespace Scada.Agent.Wcf [ServiceContract] public class AgentSvc { - private static ScadaManager mngr = new ScadaManager(); - - [OperationContract] public bool GetSessionID(out long sessionID) { From 855b618d6b5932a7e648645b07464d215fdf47fa Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 22 Mar 2018 16:03:25 +0300 Subject: [PATCH 015/100] ScadaAgent: dev 3 --- ScadaAgent/ScadaAgentCore/Session.cs | 75 ++++++++++++++ ScadaAgent/ScadaAgentCore/SessionManager.cs | 103 ++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 ScadaAgent/ScadaAgentCore/Session.cs create mode 100644 ScadaAgent/ScadaAgentCore/SessionManager.cs diff --git a/ScadaAgent/ScadaAgentCore/Session.cs b/ScadaAgent/ScadaAgentCore/Session.cs new file mode 100644 index 000000000..e07d7a7f0 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/Session.cs @@ -0,0 +1,75 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Session manager + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; + +namespace Scada.Agent +{ + /// + /// Session of communication with the agent + /// Сессия связи с агентом + /// + public class Session + { + /// + /// Конструктор, ограничивающий создание объекта без параметров + /// + private Session() + { + } + + /// + /// Конструктор + /// + public Session(long sessionID) + { + ID = sessionID; + LoggedOn = false; + Username = ""; + ActivityDT = DateTime.UtcNow; + } + + + /// + /// Получить идентификатор сессии + /// + public long ID { get; private set; } + + /// + /// Получить или установить признак, выполнен ли вход пользователя в систему + /// + public bool LoggedOn { get; set; } + + /// + /// Получить или установить имя пользователя + /// + public string Username { get; set; } + + /// + /// Получить или установить дату и время последней активности (UTC) + /// + public DateTime ActivityDT { get; set; } + } +} diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs new file mode 100644 index 000000000..9cd3eb53a --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs @@ -0,0 +1,103 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Session manager + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System.Collections.Generic; +using System.Text; +using Utils; + +namespace Scada.Agent +{ + /// + /// Session manager + /// Менеджер сессий + /// + public class SessionManager + { + private Dictionary sessions; // список сессий, ключ - ид. сессии + + + /// + /// Конструктор, ограничивающий создание объекта без параметров + /// + private SessionManager() + { + } + + /// + /// Конструктор + /// + public SessionManager(ILog log) + { + sessions = new Dictionary(); + } + + + /// + /// Создать сессию и добавить в список сессий + /// + public Session CreateSession() + { + return null; + } + + /// + /// Получить сессию по идентификатору + /// + public Session GetSession(long sessionID) + { + lock (sessions) + { + return sessions.TryGetValue(sessionID, out Session session) ? session: null; + } + } + + /// + /// Удалить неактивные сессии + /// + public void RemoveInactiveSessions() + { + + } + + /// + /// Получить информацию о сессиях + /// + public string GetInfo() + { + StringBuilder sbInfo = new StringBuilder(); + + lock (sessions) + { + foreach (Session session in sessions.Values) + { + // TODO + sbInfo.Append(session.ID).AppendLine(); + } + } + + return sbInfo.ToString(); + } + } +} From cf4ab6bd7eed7e5b5ed6c3c9c96b56888d2be6a7 Mon Sep 17 00:00:00 2001 From: 2mik Date: Fri, 23 Mar 2018 16:54:46 +0300 Subject: [PATCH 016/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/Session.cs | 23 ++++++++++++ ScadaAgent/ScadaAgentCore/SessionManager.cs | 39 +++++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/ScadaAgent/ScadaAgentCore/Session.cs b/ScadaAgent/ScadaAgentCore/Session.cs index e07d7a7f0..50ea96377 100644 --- a/ScadaAgent/ScadaAgentCore/Session.cs +++ b/ScadaAgent/ScadaAgentCore/Session.cs @@ -24,6 +24,7 @@ */ using System; +using System.Text; namespace Scada.Agent { @@ -46,6 +47,7 @@ private Session() public Session(long sessionID) { ID = sessionID; + IpAddress = ""; LoggedOn = false; Username = ""; ActivityDT = DateTime.UtcNow; @@ -57,6 +59,11 @@ public Session(long sessionID) /// public long ID { get; private set; } + /// + /// Получить IP-адрес подключения + /// + public string IpAddress { get; protected set; } + /// /// Получить или установить признак, выполнен ли вход пользователя в систему /// @@ -71,5 +78,21 @@ public Session(long sessionID) /// Получить или установить дату и время последней активности (UTC) /// public DateTime ActivityDT { get; set; } + + /// + /// Вернуть строковое представление объекта + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("[").Append(ID).Append("] ").Append(IpAddress); + + if (LoggedOn) + sb.Append("; ").Append(Username); + + sb.Append("; ").Append(ActivityDT.ToString("T", Localization.Culture)); + + return sb.ToString(); + } } } diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs index 9cd3eb53a..842aa8860 100644 --- a/ScadaAgent/ScadaAgentCore/SessionManager.cs +++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs @@ -35,7 +35,13 @@ namespace Scada.Agent /// public class SessionManager { + /// + /// Количество попыток получения уникального ид. сессии + /// + private const int GetIDAttemtps = 100; + private Dictionary sessions; // список сессий, ключ - ид. сессии + private ILog log; // журнал приложения /// @@ -50,6 +56,7 @@ private SessionManager() /// public SessionManager(ILog log) { + this.log = log; sessions = new Dictionary(); } @@ -59,7 +66,34 @@ public SessionManager(ILog log) /// public Session CreateSession() { - return null; + lock (sessions) + { + long sessionID = CryptoUtils.GetRandomLong(); + int attempt = 0; + bool duplicated; + + while (duplicated = sessions.ContainsKey(sessionID) && ++attempt <= GetIDAttemtps) + { + sessionID = CryptoUtils.GetRandomLong(); + } + + if (duplicated) + { + log.WriteError(Localization.UseRussian ? + "Не удалось создать сессию" : + "Unable to create session"); + return null; + } + else + { + Session session = new Session(sessionID); + sessions.Add(sessionID, session); + log.WriteAction(string.Format(Localization.UseRussian ? + "Создана сессия с ид. {0}" : + "Session with ID {0} created", sessionID)); + return session; + } + } } /// @@ -92,8 +126,7 @@ public string GetInfo() { foreach (Session session in sessions.Values) { - // TODO - sbInfo.Append(session.ID).AppendLine(); + sbInfo.AppendLine(session.ToString()); } } From ba74e28c3f448d05de615ab86a72825550469e0b Mon Sep 17 00:00:00 2001 From: 2mik Date: Fri, 23 Mar 2018 23:52:46 +0300 Subject: [PATCH 017/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/AppData.cs | 8 ++- ScadaAgent/ScadaAgentCore/Session.cs | 13 ++++- ScadaAgent/ScadaAgentCore/SessionManager.cs | 60 ++++++++++++++++----- ScadaAgent/ScadaAgentWcf/AgentSvc.cs | 30 +++++++++-- 4 files changed, 91 insertions(+), 20 deletions(-) diff --git a/ScadaAgent/ScadaAgentCore/AppData.cs b/ScadaAgent/ScadaAgentCore/AppData.cs index 5fb5e8ce6..24872e283 100644 --- a/ScadaAgent/ScadaAgentCore/AppData.cs +++ b/ScadaAgent/ScadaAgentCore/AppData.cs @@ -54,6 +54,7 @@ private AppData() { AppDirs = new AppDirs(); Log = new Log(Log.Formats.Full); + SessionManager = new SessionManager(Log); } @@ -67,11 +68,16 @@ private AppData() /// public Log Log { get; private set; } + /// + /// Получить менеджер сессий + /// + public SessionManager SessionManager { get; private set; } + /// /// Получить общие данные агента /// - public static AppData GetAppData() + public static AppData GetInstance() { return appDataInstance; } diff --git a/ScadaAgent/ScadaAgentCore/Session.cs b/ScadaAgent/ScadaAgentCore/Session.cs index 50ea96377..f29ce56da 100644 --- a/ScadaAgent/ScadaAgentCore/Session.cs +++ b/ScadaAgent/ScadaAgentCore/Session.cs @@ -62,7 +62,7 @@ public Session(long sessionID) /// /// Получить IP-адрес подключения /// - public string IpAddress { get; protected set; } + public string IpAddress { get; set; } /// /// Получить или установить признак, выполнен ли вход пользователя в систему @@ -77,7 +77,16 @@ public Session(long sessionID) /// /// Получить или установить дату и время последней активности (UTC) /// - public DateTime ActivityDT { get; set; } + public DateTime ActivityDT { get; private set; } + + + /// + /// Зарегистрировать активность + /// + public void RegisterActivity() + { + ActivityDT = DateTime.UtcNow; + } /// /// Вернуть строковое представление объекта diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs index 842aa8860..cd79fc3d2 100644 --- a/ScadaAgent/ScadaAgentCore/SessionManager.cs +++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs @@ -23,6 +23,7 @@ * Modified : 2018 */ +using System; using System.Collections.Generic; using System.Text; using Utils; @@ -35,10 +36,18 @@ namespace Scada.Agent /// public class SessionManager { + /// + /// Макс. количество сессий + /// + private const int MaxSessionCnt = 100; /// /// Количество попыток получения уникального ид. сессии /// private const int GetIDAttemtps = 100; + /// + /// Время жизни сессии, если нет активности + /// + private readonly TimeSpan SessionLifetime = TimeSpan.FromMinutes(1); private Dictionary sessions; // список сессий, ключ - ид. сессии private ILog log; // журнал приложения @@ -68,31 +77,39 @@ public Session CreateSession() { lock (sessions) { - long sessionID = CryptoUtils.GetRandomLong(); - int attempt = 0; - bool duplicated; + long sessionID = 0; + bool sessionOK = false; - while (duplicated = sessions.ContainsKey(sessionID) && ++attempt <= GetIDAttemtps) + if (sessions.Count < MaxSessionCnt) { sessionID = CryptoUtils.GetRandomLong(); - } + int attempt = 0; + bool duplicated; - if (duplicated) - { - log.WriteError(Localization.UseRussian ? - "Не удалось создать сессию" : - "Unable to create session"); - return null; + while (duplicated = sessions.ContainsKey(sessionID) && ++attempt <= GetIDAttemtps) + { + sessionID = CryptoUtils.GetRandomLong(); + } + + sessionOK = !duplicated; } - else + + if (sessionOK) { Session session = new Session(sessionID); sessions.Add(sessionID, session); - log.WriteAction(string.Format(Localization.UseRussian ? - "Создана сессия с ид. {0}" : + log.WriteAction(string.Format(Localization.UseRussian ? + "Создана сессия с ид. {0}" : "Session with ID {0} created", sessionID)); return session; } + else + { + log.WriteError(Localization.UseRussian ? + "Не удалось создать сессию" : + "Unable to create session"); + return null; + } } } @@ -112,7 +129,22 @@ public Session GetSession(long sessionID) /// public void RemoveInactiveSessions() { + DateTime utcNowDT = DateTime.UtcNow; + List keysToRemove = new List(); + + lock (sessions) + { + foreach (KeyValuePair pair in sessions) + { + if (utcNowDT - pair.Value.ActivityDT > SessionLifetime) + keysToRemove.Add(pair.Key); + } + foreach (long key in keysToRemove) + { + sessions.Remove(key); + } + } } /// diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs index 7edb00ac2..312cc0503 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentWcf/AgentSvc.cs @@ -8,11 +8,35 @@ namespace Scada.Agent.Wcf [ServiceContract] public class AgentSvc { + /// + /// Данные приложения + /// + private static AppData appData = AppData.GetInstance(); + /// + /// Менеджер сессий + /// + private static SessionManager sessionManager = appData.SessionManager; + + + /// + /// Создать новую сессию + /// [OperationContract] - public bool GetSessionID(out long sessionID) + public bool CreateSession(out long sessionID) { - sessionID = CryptoUtils.GetRandomLong(); - return true; + Session session = sessionManager.CreateSession(); + + if (session == null) + { + sessionID = 0; + return false; + } + else + { + session.IpAddress = ""; // TODO + sessionID = session.ID; + return true; + } } [OperationContract] From 8ee712453964652a7cb06f02256ef60738dc1af7 Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 27 Mar 2018 16:41:11 +0300 Subject: [PATCH 018/100] ScadaAgent: dev --- ScadaAgent/ScadaAgent.sln | 12 +- ScadaAgent/ScadaAgentCore/AgentLogic.cs | 168 +++++++++++++++ ScadaAgent/ScadaAgentCore/AgentUtils.cs | 39 ++++ ScadaAgent/ScadaAgentCore/AppData.cs | 18 ++ ScadaAgent/ScadaAgentCore/AppDirs.cs | 37 +++- ScadaAgent/ScadaAgentCore/SessionManager.cs | 2 +- ScadaAgent/ScadaAgentMono/App.config | 2 +- ScadaAgent/ScadaAgentMono/Program.cs | 117 +++++------ .../ScadaAgentMono/ScadaAgentMono.csproj | 19 +- ScadaAgent/ScadaAgentNet/AgentManager.cs | 198 ++++++++++++++++++ .../AgentSvc.cs | 25 ++- .../ConfigUploadMessage.cs | 2 +- .../Properties/AssemblyInfo.cs | 6 +- .../ScadaAgentNet.csproj} | 16 +- 14 files changed, 572 insertions(+), 89 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/AgentLogic.cs create mode 100644 ScadaAgent/ScadaAgentCore/AgentUtils.cs create mode 100644 ScadaAgent/ScadaAgentNet/AgentManager.cs rename ScadaAgent/{ScadaAgentWcf => ScadaAgentNet}/AgentSvc.cs (83%) rename ScadaAgent/{ScadaAgentWcf => ScadaAgentNet}/ConfigUploadMessage.cs (92%) rename ScadaAgent/{ScadaAgentWcf => ScadaAgentNet}/Properties/AssemblyInfo.cs (89%) rename ScadaAgent/{ScadaAgentWcf/ScadaAgentWcf.csproj => ScadaAgentNet/ScadaAgentNet.csproj} (72%) diff --git a/ScadaAgent/ScadaAgent.sln b/ScadaAgent/ScadaAgent.sln index cfe724431..575dfcea7 100644 --- a/ScadaAgent/ScadaAgent.sln +++ b/ScadaAgent/ScadaAgent.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27428.2005 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentCore", "ScadaAgentCore\ScadaAgentCore.csproj", "{5163526D-91E4-414D-97FE-090E1E7FDA6B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScadaAgentCore", "ScadaAgentCore\ScadaAgentCore.csproj", "{5163526D-91E4-414D-97FE-090E1E7FDA6B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentMono", "ScadaAgentMono\ScadaAgentMono.csproj", "{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}" EndProject @@ -11,7 +11,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentService", "ScadaA EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentCtrl", "ScadaAgentCtrl\ScadaAgentCtrl.csproj", "{67AEE6A7-0F2E-4273-8253-231E6BF3C943}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentWcf", "ScadaAgentWcf\ScadaAgentWcf.csproj", "{620CFDFB-6484-4EDF-9764-D01C90C1FFA8}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentNet", "ScadaAgentNet\ScadaAgentNet.csproj", "{C377283B-858B-4EFC-A560-E90FF2F26B03}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -35,10 +35,10 @@ Global {67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Debug|Any CPU.Build.0 = Debug|Any CPU {67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Release|Any CPU.ActiveCfg = Release|Any CPU {67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Release|Any CPU.Build.0 = Release|Any CPU - {620CFDFB-6484-4EDF-9764-D01C90C1FFA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {620CFDFB-6484-4EDF-9764-D01C90C1FFA8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {620CFDFB-6484-4EDF-9764-D01C90C1FFA8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {620CFDFB-6484-4EDF-9764-D01C90C1FFA8}.Release|Any CPU.Build.0 = Release|Any CPU + {C377283B-858B-4EFC-A560-E90FF2F26B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C377283B-858B-4EFC-A560-E90FF2F26B03}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C377283B-858B-4EFC-A560-E90FF2F26B03}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C377283B-858B-4EFC-A560-E90FF2F26B03}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ScadaAgent/ScadaAgentCore/AgentLogic.cs b/ScadaAgent/ScadaAgentCore/AgentLogic.cs new file mode 100644 index 000000000..bd95f36dc --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/AgentLogic.cs @@ -0,0 +1,168 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Implementation of the agent main logic + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Utils; + +namespace Scada.Agent +{ + /// + /// Implementation of the agent main logic + /// Реализация основной логики агента + /// + public sealed class AgentLogic + { + /// + /// Время ожидания остановки потока, мс + /// + private const int WaitForStop = 10000; + + private SessionManager sessionManager; // ссылка на менджер сессий + private ILog log; // журнал приложения + private Thread thread; // поток работы сервера + private volatile bool terminated; // необходимо завершить работу потока + + + /// + /// Конструктор, ограничивающий создание объекта без параметров + /// + private AgentLogic() + { + } + + /// + /// Конструктор + /// + public AgentLogic(SessionManager sessionManager, ILog log) + { + this.sessionManager = sessionManager ?? throw new ArgumentNullException("sessionManager"); + this.log = log ?? throw new ArgumentNullException("log"); + thread = null; + terminated = false; + } + + + /// + /// Цикл работы агента (метод вызывается в отдельном потоке) + /// + private void Execute() + { + try + { + while (!terminated) + { + Thread.Sleep(ScadaUtils.ThreadDelay); + } + } + finally + { + + } + } + + + /// + /// Запустить обработку логики + /// + public bool StartProcessing() + { + try + { + if (thread == null) + { + log.WriteAction(Localization.UseRussian ? + "Запуск обработки логики" : + "Start logic processing"); + terminated = false; + thread = new Thread(new ThreadStart(Execute)); + thread.Start(); + } + else + { + log.WriteAction(Localization.UseRussian ? + "Обработка логики уже запущена" : + "Logic processing is already started"); + } + } + catch (Exception ex) + { + log.WriteException(ex, Localization.UseRussian ? + "Ошибка при запуске обработки логики" : + "Error starting logic processing"); + } + finally + { + if (thread == null) + { + //workState = WorkStateNames.Error; + //WriteInfo(); + } + } + + return true; + } + + /// + /// Остановить обработку логики + /// + public void StopProcessing() + { + try + { + if (thread != null) + { + terminated = true; + + if (thread.Join(WaitForStop)) + { + log.WriteAction(Localization.UseRussian ? + "Обработка логики остановлена" : + "Logic processing is stopped"); + } + else + { + thread.Abort(); + log.WriteAction(Localization.UseRussian ? + "Обработка логики прервана" : + "Logic processing is aborted"); + } + + thread = null; + } + } + catch (Exception ex) + { + //workState = WorkStateNames.Error; + //WriteInfo(); + log.WriteException(ex, Localization.UseRussian ? + "Ошибка при остановке обработки логики" : + "Error stopping logic processing"); + } + } + } +} diff --git a/ScadaAgent/ScadaAgentCore/AgentUtils.cs b/ScadaAgent/ScadaAgentCore/AgentUtils.cs new file mode 100644 index 000000000..5d45169d9 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/AgentUtils.cs @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaServerCommon + * Summary : The class contains utility methods for Agent + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +namespace Scada.Agent +{ + /// + /// The class contains utility methods for Agent + /// Класс, содержащий вспомогательные методы для Агента + /// + public static class AgentUtils + { + /// + /// Версия Агента + /// + public const string AppVersion = "5.0.0.0"; + } +} diff --git a/ScadaAgent/ScadaAgentCore/AppData.cs b/ScadaAgent/ScadaAgentCore/AppData.cs index 24872e283..62599d1a0 100644 --- a/ScadaAgent/ScadaAgentCore/AppData.cs +++ b/ScadaAgent/ScadaAgentCore/AppData.cs @@ -36,6 +36,11 @@ namespace Scada.Agent /// public sealed class AppData { + /// + /// Имя файла журнала приложения без директории + /// + private const string LogFileName = "ScadaAgent.log"; + private static readonly AppData appDataInstance; // экземпляр объекта AppData @@ -74,6 +79,19 @@ private AppData() public SessionManager SessionManager { get; private set; } + /// + /// Инициализировать общие данные агента + /// + public void Init(string exeDir) + { + // инициализация директорий приложения + AppDirs.Init(exeDir); + + // настройка журнала приложения + Log.FileName = AppDirs.LogDir + LogFileName; + Log.Encoding = Encoding.UTF8; + } + /// /// Получить общие данные агента /// diff --git a/ScadaAgent/ScadaAgentCore/AppDirs.cs b/ScadaAgent/ScadaAgentCore/AppDirs.cs index fee89a51d..d51693dc4 100644 --- a/ScadaAgent/ScadaAgentCore/AppDirs.cs +++ b/ScadaAgent/ScadaAgentCore/AppDirs.cs @@ -39,6 +39,7 @@ public class AppDirs public AppDirs() { ExeDir = ""; + CmdDir = ""; ConfigDir = ""; LangDir = ""; LogDir = ""; @@ -50,7 +51,13 @@ public AppDirs() /// Получить директорию исполняемого файла /// public string ExeDir { get; protected set; } - + + /// + /// Получить директорию команд + /// + /// Используется консольным приложением + public string CmdDir { get; protected set; } + /// /// Получить директорию конфигурации /// @@ -71,6 +78,25 @@ public AppDirs() /// public string TempDir { get; set; } + /// + /// Проверить существование директорий, исключая необязательную директорию команд + /// + public bool Exist + { + get + { + string[] dirs = GetRequiredDirs(); + + foreach (string dir in dirs) + { + if (!Directory.Exists(dir)) + return false; + } + + return true; + } + } + /// /// Инициализировать директории на основе директории исполняемого файла приложения @@ -78,10 +104,19 @@ public AppDirs() public void Init(string exeDir) { ExeDir = ScadaUtils.NormalDir(exeDir); + CmdDir = ExeDir + "Cmd" + Path.DirectorySeparatorChar; ConfigDir = ExeDir + "Config" + Path.DirectorySeparatorChar; LangDir = ExeDir + "Lang" + Path.DirectorySeparatorChar; LogDir = ExeDir + "Log" + Path.DirectorySeparatorChar; TempDir = ExeDir + "Temp" + Path.DirectorySeparatorChar; } + + /// + /// Получить необходимые директории + /// + public string[] GetRequiredDirs() + { + return new string[] { ConfigDir, ConfigDir, LangDir, LogDir, TempDir }; + } } } diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs index cd79fc3d2..e5a05a57b 100644 --- a/ScadaAgent/ScadaAgentCore/SessionManager.cs +++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs @@ -65,7 +65,7 @@ private SessionManager() /// public SessionManager(ILog log) { - this.log = log; + this.log = log ?? throw new ArgumentNullException("log"); sessions = new Dictionary(); } diff --git a/ScadaAgent/ScadaAgentMono/App.config b/ScadaAgent/ScadaAgentMono/App.config index a93be18a3..9346ff2b4 100644 --- a/ScadaAgent/ScadaAgentMono/App.config +++ b/ScadaAgent/ScadaAgentMono/App.config @@ -26,7 +26,7 @@ + contract="Scada.Agent.Net.AgentSvc" /> diff --git a/ScadaAgent/ScadaAgentMono/Program.cs b/ScadaAgent/ScadaAgentMono/Program.cs index 9911478fc..f4fb07fea 100644 --- a/ScadaAgent/ScadaAgentMono/Program.cs +++ b/ScadaAgent/ScadaAgentMono/Program.cs @@ -1,85 +1,68 @@ -using Scada.Agent.Wcf; +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : Agent Console Application + * Summary : Agent console appliction tested on Mono .NET framework + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using Scada.Agent; +using Scada.Agent.Net; using System; -using System.ServiceModel; +using System.Threading; namespace ScadaAgentMono { + /// + /// Agent console appliction tested on Mono .NET framework + /// Консольное приложение агента, протестированное на Mono .NET framework + /// class Program { - private static ServiceHost agentSvcHost; // хост WCF-службы для взаимодействия с агентом - /// - /// Запустить WCF-службу для взаимодействия с агентом + /// The main entry point for the application + /// Основная точка входа для приложения /// - private static bool StartWcfService(out string serviceUrl) + static void Main(string[] args) { - try - { - agentSvcHost = new ServiceHost(typeof(AgentSvc)); - ServiceBehaviorAttribute behavior = - agentSvcHost.Description.Behaviors.Find(); - behavior.ConcurrencyMode = ConcurrencyMode.Multiple; - behavior.InstanceContextMode = InstanceContextMode.Single; - behavior.UseSynchronizationContext = false; - agentSvcHost.Open(); - serviceUrl = agentSvcHost.BaseAddresses.Count > 0 ? - agentSvcHost.BaseAddresses[0].AbsoluteUri : ""; + // запуск агента + Console.WriteLine("Starting Agent..."); + AgentManager agentManager = new AgentManager(); + agentManager.StartAgent(); - //Log.WriteAction(Localization.UseRussian ? - // "WCF-служба запущена" : - // "WCF service is started"); - Console.WriteLine("WCF service is started"); + Console.WriteLine("Agent is started"); + Console.WriteLine("Press 'x' or create 'agentstop' file to stop Agent"); - return true; - } - catch (Exception ex) - { - //Log.WriteException(ex, Localization.UseRussian ? - // "Ошибка при запуске WCF-службы" : - // "Error starting WCF service"); - Console.WriteLine(ex.ToString()); - serviceUrl = ""; - return false; - } - } + // остановка службы при нажатии 'x' или обнаружении файла остановки + FileListener stopFileListener = new FileListener(AppData.GetInstance().AppDirs.ConfigDir + "serverstop"); - /// - /// Остановить WCF-службу, взаимодействующую с веб-интерфейсом - /// - private static void StopWcfService() - { - if (agentSvcHost != null) + while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.X || stopFileListener.FileFound)) { - try - { - agentSvcHost.Close(); - //Log.WriteAction(Localization.UseRussian ? - // "WCF-служба остановлена" : - // "WCF service is stopped"); - Console.WriteLine("WCF service is stopped"); - } - catch - { - agentSvcHost.Abort(); - //Log.WriteAction(Localization.UseRussian ? - // "WCF-служба прервана" : - // "WCF service is aborted"); - Console.WriteLine("WCF service is aborted"); - } - - agentSvcHost = null; + Thread.Sleep(ScadaUtils.ThreadDelay); } - } - - static void Main(string[] args) - { - if (StartWcfService(out string serviceUrl)) - Console.WriteLine("serviceUrl = " + serviceUrl); - - Console.WriteLine("Press a key to stop service..."); - Console.ReadKey(true); - StopWcfService(); + agentManager.StopAgent(); + stopFileListener.DeleteFile(); + stopFileListener.Abort(); + Console.WriteLine("Agent is stopped"); } } } diff --git a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj index 2f4ea6f06..41463ca9f 100644 --- a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj +++ b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj @@ -32,8 +32,15 @@ 4 + + False + ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll + + + False + ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll + - @@ -43,9 +50,13 @@ - - {620cfdfb-6484-4edf-9764-d01c90c1ffa8} - ScadaAgentWcf + + {5163526d-91e4-414d-97fe-090e1e7fda6b} + ScadaAgentCore + + + {c377283b-858b-4efc-a560-e90ff2f26b03} + ScadaAgentNet diff --git a/ScadaAgent/ScadaAgentNet/AgentManager.cs b/ScadaAgent/ScadaAgentNet/AgentManager.cs new file mode 100644 index 000000000..da21fe757 --- /dev/null +++ b/ScadaAgent/ScadaAgentNet/AgentManager.cs @@ -0,0 +1,198 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentNet + * Summary : Agent manager + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.ServiceModel; +using Utils; + +namespace Scada.Agent.Net +{ + /// + /// Agent manager + /// Менеджер агента + /// + public class AgentManager + { + private ILog log; // журнал приложения + private AgentLogic agentLogic; // объект, реализующий основную логику агента + private ServiceHost agentSvcHost; // хост WCF-службы для взаимодействия с агентом + + + /// + /// Конструктор + /// + public AgentManager() + { + log = new LogStub(); + agentLogic = null; + agentSvcHost = null; + AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; + } + + + /// + /// Вывести информацию о необработанном исключении в журнал + /// + private void OnUnhandledException(object sender, UnhandledExceptionEventArgs args) + { + Exception ex = args.ExceptionObject as Exception; + log.WriteException(ex, string.Format(Localization.UseRussian ? + "Необработанное исключение" : + "Unhandled exception")); + } + + /// + /// Запустить WCF-службу для взаимодействия с агентом + /// + private bool StartWcfService() + { + try + { + agentSvcHost = new ServiceHost(typeof(AgentSvc)); + ServiceBehaviorAttribute behavior = + agentSvcHost.Description.Behaviors.Find(); + behavior.ConcurrencyMode = ConcurrencyMode.Multiple; + behavior.InstanceContextMode = InstanceContextMode.Single; + behavior.UseSynchronizationContext = false; + agentSvcHost.Open(); + string serviceUrl = agentSvcHost.BaseAddresses.Count > 0 ? + agentSvcHost.BaseAddresses[0].AbsoluteUri : ""; + + log.WriteAction(string.Format(Localization.UseRussian ? + "WCF-служба запущена по адресу {0}" : + "WCF service is started at {0}", serviceUrl)); + + return true; + } + catch (Exception ex) + { + log.WriteException(ex, Localization.UseRussian ? + "Ошибка при запуске WCF-службы" : + "Error starting WCF service"); + return false; + } + } + + /// + /// Остановить WCF-службу, взаимодействующую с веб-интерфейсом + /// + private void StopWcfService() + { + if (agentSvcHost != null) + { + try + { + agentSvcHost.Close(); + log.WriteAction(Localization.UseRussian ? + "WCF-служба остановлена" : + "WCF service is stopped"); + } + catch + { + agentSvcHost.Abort(); + log.WriteAction(Localization.UseRussian ? + "WCF-служба прервана" : + "WCF service is aborted"); + } + + agentSvcHost = null; + } + } + + + /// + /// Запустить агента + /// + public void StartAgent() + { + // инициализация общих данных + AppData appData = AppData.GetInstance(); + string exeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + appData.Init(exeDir); + + log = appData.Log; + log.WriteBreak(); + log.WriteAction(string.Format(Localization.UseRussian ? + "Агент {0} запущен" : + "Agent {0} started", AgentUtils.AppVersion)); + + + if (appData.AppDirs.Exist) + { + // локализация + string errMsg; + if (Localization.LoadDictionaries(appData.AppDirs.LangDir, "ScadaData", out errMsg)) + CommonPhrases.Init(); + else + log.WriteError(errMsg); + + // запуск + agentLogic = new AgentLogic(appData.SessionManager, appData.Log); + + if (!(StartWcfService() && agentLogic.StartProcessing())) + { + log.WriteError(Localization.UseRussian ? + "Нормальная работа программы невозможна" : + "Normal program execution is impossible"); + } + } + else + { + string errMsg = string.Format(Localization.UseRussian ? + "Необходимые директории не существуют:{0}{1}{0}" + + "Нормальная работа программы невозможна" : + "The required directories do not exist:{0}{1}{0}" + + "Normal program execution is impossible", + Environment.NewLine, string.Join(Environment.NewLine, appData.AppDirs.GetRequiredDirs())); + + try + { + if (EventLog.SourceExists("ScadaAgent")) + EventLog.WriteEvent("ScadaAgent", new EventInstance(0, 0, EventLogEntryType.Error), errMsg); + } + catch { } + + log.WriteError(errMsg); + } + } + + /// + /// Остановить агента + /// + public void StopAgent() + { + StopWcfService(); + agentLogic?.StopProcessing(); + + log.WriteAction(Localization.UseRussian ? + "Агент остановлен" : + "Agent is stopped"); + log.WriteBreak(); + } + } +} diff --git a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs similarity index 83% rename from ScadaAgent/ScadaAgentWcf/AgentSvc.cs rename to ScadaAgent/ScadaAgentNet/AgentSvc.cs index 312cc0503..4f89f2428 100644 --- a/ScadaAgent/ScadaAgentWcf/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs @@ -2,8 +2,9 @@ using System.Collections.Generic; using System.IO; using System.ServiceModel; +using System.ServiceModel.Channels; -namespace Scada.Agent.Wcf +namespace Scada.Agent.Net { [ServiceContract] public class AgentSvc @@ -18,6 +19,26 @@ public class AgentSvc private static SessionManager sessionManager = appData.SessionManager; + /// + /// Получить IP-адрес текущего подключения + /// + private string GetClientIP() + { + try + { + OperationContext context = OperationContext.Current; + MessageProperties props = context.IncomingMessageProperties; + RemoteEndpointMessageProperty remoteEndPoint = + (RemoteEndpointMessageProperty)props[RemoteEndpointMessageProperty.Name]; + return remoteEndPoint.Address; + } + catch + { + return ""; + } + } + + /// /// Создать новую сессию /// @@ -33,7 +54,7 @@ public bool CreateSession(out long sessionID) } else { - session.IpAddress = ""; // TODO + session.IpAddress = GetClientIP(); sessionID = session.ID; return true; } diff --git a/ScadaAgent/ScadaAgentWcf/ConfigUploadMessage.cs b/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs similarity index 92% rename from ScadaAgent/ScadaAgentWcf/ConfigUploadMessage.cs rename to ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs index 7ef33ed4a..6cdacf577 100644 --- a/ScadaAgent/ScadaAgentWcf/ConfigUploadMessage.cs +++ b/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs @@ -1,7 +1,7 @@ using System.IO; using System.ServiceModel; -namespace Scada.Agent.Wcf +namespace Scada.Agent.Net { [MessageContract] public class ConfigUploadMessage diff --git a/ScadaAgent/ScadaAgentWcf/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentNet/Properties/AssemblyInfo.cs similarity index 89% rename from ScadaAgent/ScadaAgentWcf/Properties/AssemblyInfo.cs rename to ScadaAgent/ScadaAgentNet/Properties/AssemblyInfo.cs index d721a0223..6c31bcc9d 100644 --- a/ScadaAgent/ScadaAgentWcf/Properties/AssemblyInfo.cs +++ b/ScadaAgent/ScadaAgentNet/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("ScadaAgentWcf")] +[assembly: AssemblyTitle("ScadaAgentNet")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScadaAgentWcf")] +[assembly: AssemblyProduct("ScadaAgentNet")] [assembly: AssemblyCopyright("Copyright © 2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,7 +20,7 @@ [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("620cfdfb-6484-4edf-9764-d01c90c1ffa8")] +[assembly: Guid("c377283b-858b-4efc-a560-e90ff2f26b03")] // Version information for an assembly consists of the following four values: // diff --git a/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj b/ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj similarity index 72% rename from ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj rename to ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj index 395f4cd24..f0f05689f 100644 --- a/ScadaAgent/ScadaAgentWcf/ScadaAgentWcf.csproj +++ b/ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj @@ -4,11 +4,11 @@ Debug AnyCPU - {620CFDFB-6484-4EDF-9764-D01C90C1FFA8} + {C377283B-858B-4EFC-A560-E90FF2F26B03} Library Properties - Scada.Agent.Wcf - ScadaAgentWcf + Scada.Agent.Net + ScadaAgentNet v4.6.1 512 @@ -28,14 +28,24 @@ TRACE prompt 4 + bin\Release\ScadaAgentNet.xml + + False + ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll + + + False + ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll + + From 52c01c00c7d029ad57319a408b0e2f3a387eb22f Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 27 Mar 2018 17:00:16 +0300 Subject: [PATCH 019/100] ScadaAgent: dev2 --- ScadaAgent/ScadaAgentCore/AppDirs.cs | 2 +- ScadaAgent/ScadaAgentMono/App.config | 2 +- ScadaAgent/ScadaAgentMono/Program.cs | 7 +++++-- ScadaAgent/ScadaAgentNet/AgentManager.cs | 23 ++++++++++------------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ScadaAgent/ScadaAgentCore/AppDirs.cs b/ScadaAgent/ScadaAgentCore/AppDirs.cs index d51693dc4..ff849b54b 100644 --- a/ScadaAgent/ScadaAgentCore/AppDirs.cs +++ b/ScadaAgent/ScadaAgentCore/AppDirs.cs @@ -116,7 +116,7 @@ public void Init(string exeDir) /// public string[] GetRequiredDirs() { - return new string[] { ConfigDir, ConfigDir, LangDir, LogDir, TempDir }; + return new string[] { ConfigDir, LangDir, LogDir, TempDir }; } } } diff --git a/ScadaAgent/ScadaAgentMono/App.config b/ScadaAgent/ScadaAgentMono/App.config index 9346ff2b4..8d42c9dc2 100644 --- a/ScadaAgent/ScadaAgentMono/App.config +++ b/ScadaAgent/ScadaAgentMono/App.config @@ -18,7 +18,7 @@ - + diff --git a/ScadaAgent/ScadaAgentMono/Program.cs b/ScadaAgent/ScadaAgentMono/Program.cs index f4fb07fea..6f6da7b0e 100644 --- a/ScadaAgent/ScadaAgentMono/Program.cs +++ b/ScadaAgent/ScadaAgentMono/Program.cs @@ -46,9 +46,12 @@ static void Main(string[] args) // запуск агента Console.WriteLine("Starting Agent..."); AgentManager agentManager = new AgentManager(); - agentManager.StartAgent(); - Console.WriteLine("Agent is started"); + if (agentManager.StartAgent()) + Console.WriteLine("Agent is started successfully"); + else + Console.WriteLine("Agent is started with errors"); + Console.WriteLine("Press 'x' or create 'agentstop' file to stop Agent"); // остановка службы при нажатии 'x' или обнаружении файла остановки diff --git a/ScadaAgent/ScadaAgentNet/AgentManager.cs b/ScadaAgent/ScadaAgentNet/AgentManager.cs index da21fe757..72c846e27 100644 --- a/ScadaAgent/ScadaAgentNet/AgentManager.cs +++ b/ScadaAgent/ScadaAgentNet/AgentManager.cs @@ -128,7 +128,7 @@ private void StopWcfService() /// /// Запустить агента /// - public void StartAgent() + public bool StartAgent() { // инициализация общих данных AppData appData = AppData.GetInstance(); @@ -154,30 +154,27 @@ public void StartAgent() // запуск agentLogic = new AgentLogic(appData.SessionManager, appData.Log); - if (!(StartWcfService() && agentLogic.StartProcessing())) + if (StartWcfService() && agentLogic.StartProcessing()) + { + return true; + } + else { log.WriteError(Localization.UseRussian ? "Нормальная работа программы невозможна" : "Normal program execution is impossible"); + return false; } } else { - string errMsg = string.Format(Localization.UseRussian ? + log.WriteError(string.Format(Localization.UseRussian ? "Необходимые директории не существуют:{0}{1}{0}" + "Нормальная работа программы невозможна" : "The required directories do not exist:{0}{1}{0}" + "Normal program execution is impossible", - Environment.NewLine, string.Join(Environment.NewLine, appData.AppDirs.GetRequiredDirs())); - - try - { - if (EventLog.SourceExists("ScadaAgent")) - EventLog.WriteEvent("ScadaAgent", new EventInstance(0, 0, EventLogEntryType.Error), errMsg); - } - catch { } - - log.WriteError(errMsg); + Environment.NewLine, string.Join(Environment.NewLine, appData.AppDirs.GetRequiredDirs()))); + return false; } } From de4eaef9d5f426abe7ed4541334983063cd40234 Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 27 Mar 2018 17:04:53 +0300 Subject: [PATCH 020/100] ScadaAgent: remove unused refs --- ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj b/ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj index f0f05689f..568800ad0 100644 --- a/ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj +++ b/ScadaAgent/ScadaAgentNet/ScadaAgentNet.csproj @@ -40,9 +40,7 @@ ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll - - From b1d4aad325bcea8fc5d86d0cd71c72a6ea46d02a Mon Sep 17 00:00:00 2001 From: 2mik Date: Tue, 27 Mar 2018 19:15:25 +0300 Subject: [PATCH 021/100] ScadaAgent: organize usings --- ScadaAgent/ScadaAgentNet/AgentManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ScadaAgent/ScadaAgentNet/AgentManager.cs b/ScadaAgent/ScadaAgentNet/AgentManager.cs index 72c846e27..c260b6619 100644 --- a/ScadaAgent/ScadaAgentNet/AgentManager.cs +++ b/ScadaAgent/ScadaAgentNet/AgentManager.cs @@ -24,7 +24,6 @@ */ using System; -using System.Diagnostics; using System.IO; using System.Reflection; using System.ServiceModel; From e81a5c2ffcf6d10a33a502bc464749c95c10e70a Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 28 Mar 2018 17:46:31 +0300 Subject: [PATCH 022/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/AgentLogic.cs | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/ScadaAgent/ScadaAgentCore/AgentLogic.cs b/ScadaAgent/ScadaAgentCore/AgentLogic.cs index bd95f36dc..509aab2f9 100644 --- a/ScadaAgent/ScadaAgentCore/AgentLogic.cs +++ b/ScadaAgent/ScadaAgentCore/AgentLogic.cs @@ -41,6 +41,14 @@ public sealed class AgentLogic /// Время ожидания остановки потока, мс /// private const int WaitForStop = 10000; + /// + /// Период обработки сессий + /// + private static readonly TimeSpan SessProcPeriod = TimeSpan.FromSeconds(5); + /// + /// Период записи в файл информации о работе приложения + /// + private static readonly TimeSpan WriteInfoPeriod = TimeSpan.FromSeconds(1); private SessionManager sessionManager; // ссылка на менджер сессий private ILog log; // журнал приложения @@ -74,17 +82,43 @@ private void Execute() { try { + DateTime sessProcDT = DateTime.MinValue; // время обработки сессий + DateTime writeInfoDT = DateTime.MinValue; // время записи информации о работе приложения + while (!terminated) { + DateTime utcNow = DateTime.UtcNow; + + // удаление неактивных сессий + if (utcNow - sessProcDT >= SessProcPeriod) + { + sessProcDT = utcNow; + sessionManager.RemoveInactiveSessions(); + } + + // запись информации о работе приложения + if (utcNow - writeInfoDT >= WriteInfoPeriod) + { + writeInfoDT = utcNow; + WriteInfo(); + } + Thread.Sleep(ScadaUtils.ThreadDelay); } } finally { - + WriteInfo(); } } + /// + /// Записать в файл информацию о работе приложения + /// + private void WriteInfo() + { + } + /// /// Запустить обработку логики From 8d207004760878c29dbedfcb9e22be8a0c2031cc Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 29 Mar 2018 09:34:31 +0300 Subject: [PATCH 023/100] ScadaComm: remove duplicated ConfigFileName --- ScadaComm/ScadaCommCommon/CommUtils.cs | 2 +- ScadaComm/ScadaCommSvc/Manager.cs | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ScadaComm/ScadaCommCommon/CommUtils.cs b/ScadaComm/ScadaCommCommon/CommUtils.cs index 865228fc5..2705169d1 100644 --- a/ScadaComm/ScadaCommCommon/CommUtils.cs +++ b/ScadaComm/ScadaCommCommon/CommUtils.cs @@ -58,7 +58,7 @@ public enum ProtocolLogFormats /// /// Версия Коммуникатора /// - public const string AppVersion = "5.1.0.2"; + public const string AppVersion = "5.1.0.3"; /// /// Формат даты и времени для вывода в журнал линии связи diff --git a/ScadaComm/ScadaCommSvc/Manager.cs b/ScadaComm/ScadaCommSvc/Manager.cs index 03c9354ae..f60e4964b 100644 --- a/ScadaComm/ScadaCommSvc/Manager.cs +++ b/ScadaComm/ScadaCommSvc/Manager.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2006 - * Modified : 2017 + * Modified : 2018 */ using Scada.Data.Models; @@ -42,10 +42,6 @@ namespace Scada.Comm.Svc /// internal sealed class Manager { - /// - /// Имя файла конфигурации - /// - private const string ConfigFileName = "ScadaCommSvcConfig.xml"; /// /// Имя основного Log-файла программы /// @@ -628,7 +624,7 @@ public void StartCommLine(int lineNum) // загрузка линии связи из файла кофигурации string errMsg; Settings.CommLine commLineSett; - if (Settings.LoadCommLine(AppDirs.ConfigDir + ConfigFileName, lineNum, + if (Settings.LoadCommLine(AppDirs.ConfigDir + Settings.DefFileName, lineNum, out commLineSett, out errMsg)) { if (commLineSett == null) From 8e158e15ce9fe59878cca1ee0ebf7c516c6ae273 Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 29 Mar 2018 11:26:11 +0300 Subject: [PATCH 024/100] ScadaAgent: sessions work --- ScadaAgent/ScadaAgentCore/AgentLogic.cs | 147 +++++++++++++++--- ScadaAgent/ScadaAgentCore/AppData.cs | 6 +- ScadaAgent/ScadaAgentCore/Session.cs | 2 +- ScadaAgent/ScadaAgentCore/SessionManager.cs | 32 +++- .../ServiceReference1/AgentSvc.wsdl | 37 ++--- .../ServiceReference1/Reference.cs | 56 +++---- ...ference1.CreateSessionResponse.datasource} | 4 +- ...Reference1.UploadConfigResponse.datasource | 2 +- .../ServiceReference1/item.xsd | 21 +-- ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs | 13 ++ ScadaAgent/ScadaAgentCtrl/FrmMain.cs | 18 ++- .../ScadaAgentCtrl/ScadaAgentCtrl.csproj | 6 +- .../ScadaAgentMono/ScadaAgentMono.csproj | 10 ++ ScadaAgent/ScadaAgentNet/AgentManager.cs | 2 +- 14 files changed, 238 insertions(+), 118 deletions(-) rename ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/{Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource => Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource} (56%) diff --git a/ScadaAgent/ScadaAgentCore/AgentLogic.cs b/ScadaAgent/ScadaAgentCore/AgentLogic.cs index 509aab2f9..42fb86cd2 100644 --- a/ScadaAgent/ScadaAgentCore/AgentLogic.cs +++ b/ScadaAgent/ScadaAgentCore/AgentLogic.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text; using System.Threading; using Utils; @@ -37,6 +38,26 @@ namespace Scada.Agent /// public sealed class AgentLogic { + /// + /// Состояния работы агента + /// + private enum WorkState + { + Undefined = 0, + Normal = 1, + Error = 2, + Terminated = 3 + } + + /// + /// Наименования состояний работы на английском + /// + private static readonly string[] WorkStateNamesEn = { "undefined", "normal", "error", "terminated" }; + /// + /// Наименования состояний работы на русском + /// + private static readonly string[] WorkStateNamesRu = { "не определено", "норма", "ошибка", "завершён" }; + /// /// Время ожидания остановки потока, мс /// @@ -51,9 +72,14 @@ public sealed class AgentLogic private static readonly TimeSpan WriteInfoPeriod = TimeSpan.FromSeconds(1); private SessionManager sessionManager; // ссылка на менджер сессий + private AppDirs appDirs; // директории приложения private ILog log; // журнал приложения private Thread thread; // поток работы сервера private volatile bool terminated; // необходимо завершить работу потока + private string infoFileName; // полное имя файла информации + private DateTime utcStartDT; // дата и время запуска (UTC) + private DateTime startDT; // дата и время запуска + private WorkState workState; // состояние работы /// @@ -66,15 +92,32 @@ private AgentLogic() /// /// Конструктор /// - public AgentLogic(SessionManager sessionManager, ILog log) + public AgentLogic(SessionManager sessionManager, AppDirs appDirs, ILog log) { this.sessionManager = sessionManager ?? throw new ArgumentNullException("sessionManager"); + this.appDirs = appDirs ?? throw new ArgumentNullException("appDirs"); this.log = log ?? throw new ArgumentNullException("log"); + thread = null; terminated = false; + infoFileName = appDirs.LogDir + AppData.InfoFileName; + utcStartDT = startDT = DateTime.MinValue; + workState = WorkState.Undefined; } + /// + /// Подготовить обработку логики + /// + private void PrepareProcessing() + { + terminated = false; + utcStartDT = DateTime.UtcNow; + startDT = utcStartDT.ToLocalTime(); + workState = WorkState.Normal; + WriteInfo(); + } + /// /// Цикл работы агента (метод вызывается в отдельном потоке) /// @@ -87,27 +130,42 @@ private void Execute() while (!terminated) { - DateTime utcNow = DateTime.UtcNow; + try + { + DateTime utcNow = DateTime.UtcNow; + + // удаление неактивных сессий + if (utcNow - sessProcDT >= SessProcPeriod) + { + sessProcDT = utcNow; + sessionManager.RemoveInactiveSessions(); + } + + // запись информации о работе приложения + if (utcNow - writeInfoDT >= WriteInfoPeriod) + { + writeInfoDT = utcNow; + WriteInfo(); + } - // удаление неактивных сессий - if (utcNow - sessProcDT >= SessProcPeriod) + Thread.Sleep(ScadaUtils.ThreadDelay); + } + catch (ThreadAbortException) { - sessProcDT = utcNow; - sessionManager.RemoveInactiveSessions(); } - - // запись информации о работе приложения - if (utcNow - writeInfoDT >= WriteInfoPeriod) + catch (Exception ex) { - writeInfoDT = utcNow; - WriteInfo(); + log.WriteException(ex, Localization.UseRussian ? + "Ошибка в цикле работы агента" : + "Error in the agent work cycle"); + Thread.Sleep(ScadaUtils.ThreadDelay); } - - Thread.Sleep(ScadaUtils.ThreadDelay); } } finally { + sessionManager.RemoveAllSessions(); + workState = WorkState.Terminated; WriteInfo(); } } @@ -117,6 +175,59 @@ private void Execute() /// private void WriteInfo() { + try + { + // формирование информации + StringBuilder sbInfo = new StringBuilder(); + TimeSpan workSpan = DateTime.UtcNow - utcStartDT; + string workSpanStr = workSpan.Days > 0 ? + workSpan.ToString(@"d\.hh\:mm\:ss") : + workSpan.ToString(@"hh\:mm\:ss"); + + if (Localization.UseRussian) + { + sbInfo + .AppendLine("Агент") + .AppendLine("-----") + .Append("Запуск : ").AppendLine(startDT.ToLocalizedString()) + .Append("Время работы : ").AppendLine(workSpanStr) + .Append("Состояние : ").AppendLine(WorkStateNamesRu[(int)workState]) + .Append("Версия : ").AppendLine(AgentUtils.AppVersion) + .AppendLine() + .AppendLine("Активные сессии") + .AppendLine("---------------"); + } + else + { + sbInfo + .AppendLine("Agent") + .AppendLine("-----") + .Append("Started : ").AppendLine(startDT.ToLocalizedString()) + .Append("Execution time : ").AppendLine(workSpanStr) + .Append("State : ").AppendLine(WorkStateNamesEn[(int)workState]) + .Append("Version : ").AppendLine(AgentUtils.AppVersion) + .AppendLine() + .AppendLine("Active Sessions") + .AppendLine("---------------"); + } + + sbInfo.Append(sessionManager.GetInfo()); + + // запись в файл + using (StreamWriter writer = new StreamWriter(infoFileName, false, Encoding.UTF8)) + { + writer.Write(sbInfo.ToString()); + } + } + catch (ThreadAbortException) + { + } + catch (Exception ex) + { + log.WriteException(ex, Localization.UseRussian ? + "Ошибка при записи в файл информации о работе приложения" : + "Error writing application information to the file"); + } } @@ -132,7 +243,7 @@ public bool StartProcessing() log.WriteAction(Localization.UseRussian ? "Запуск обработки логики" : "Start logic processing"); - terminated = false; + PrepareProcessing(); thread = new Thread(new ThreadStart(Execute)); thread.Start(); } @@ -153,8 +264,8 @@ public bool StartProcessing() { if (thread == null) { - //workState = WorkStateNames.Error; - //WriteInfo(); + workState = WorkState.Error; + WriteInfo(); } } @@ -191,8 +302,8 @@ public void StopProcessing() } catch (Exception ex) { - //workState = WorkStateNames.Error; - //WriteInfo(); + workState = WorkState.Error; + WriteInfo(); log.WriteException(ex, Localization.UseRussian ? "Ошибка при остановке обработки логики" : "Error stopping logic processing"); diff --git a/ScadaAgent/ScadaAgentCore/AppData.cs b/ScadaAgent/ScadaAgentCore/AppData.cs index 62599d1a0..e59322141 100644 --- a/ScadaAgent/ScadaAgentCore/AppData.cs +++ b/ScadaAgent/ScadaAgentCore/AppData.cs @@ -23,8 +23,6 @@ * Modified : 2018 */ -using System; -using System.Collections.Generic; using System.Text; using Utils; @@ -40,6 +38,10 @@ public sealed class AppData /// Имя файла журнала приложения без директории /// private const string LogFileName = "ScadaAgent.log"; + /// + /// Имя файла информации о работе приложения + /// + public const string InfoFileName = "ScadaAgent.txt"; private static readonly AppData appDataInstance; // экземпляр объекта AppData diff --git a/ScadaAgent/ScadaAgentCore/Session.cs b/ScadaAgent/ScadaAgentCore/Session.cs index f29ce56da..08f120e5a 100644 --- a/ScadaAgent/ScadaAgentCore/Session.cs +++ b/ScadaAgent/ScadaAgentCore/Session.cs @@ -99,7 +99,7 @@ public override string ToString() if (LoggedOn) sb.Append("; ").Append(Username); - sb.Append("; ").Append(ActivityDT.ToString("T", Localization.Culture)); + sb.Append("; ").Append(ActivityDT.ToLocalTime().ToString("T", Localization.Culture)); return sb.ToString(); } diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs index e5a05a57b..cb0166d04 100644 --- a/ScadaAgent/ScadaAgentCore/SessionManager.cs +++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs @@ -147,22 +147,42 @@ public void RemoveInactiveSessions() } } + /// + /// Удалить все сессии + /// + public void RemoveAllSessions() + { + lock (sessions) + { + sessions.Clear(); + } + } + /// /// Получить информацию о сессиях /// public string GetInfo() { - StringBuilder sbInfo = new StringBuilder(); - lock (sessions) { - foreach (Session session in sessions.Values) + if (sessions.Count > 0) { - sbInfo.AppendLine(session.ToString()); + StringBuilder sbInfo = new StringBuilder(); + + foreach (Session session in sessions.Values) + { + sbInfo.AppendLine(session.ToString()); + } + + return sbInfo.ToString(); + } + else + { + return Localization.UseRussian ? + "Нет" : + "No"; } } - - return sbInfo.ToString(); } } } diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl index e183dd99e..9e754b73b 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl @@ -9,17 +9,11 @@ - - + + - - - - - - - - + + @@ -78,13 +72,9 @@ - - - - - - - + + + @@ -125,17 +115,8 @@ - - - - - - - - - - - + + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs index c56501d5b..283bbd0f5 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs @@ -15,18 +15,12 @@ namespace Scada.Agent.Ctrl.ServiceReference1 { [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.AgentSvc")] public interface AgentSvc { - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Sum", ReplyAction="http://tempuri.org/AgentSvc/SumResponse")] - double Sum(double a, double b); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Sum", ReplyAction="http://tempuri.org/AgentSvc/SumResponse")] - System.Threading.Tasks.Task SumAsync(double a, double b); - - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetSessionID", ReplyAction="http://tempuri.org/AgentSvc/GetSessionIDResponse")] - Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse GetSessionID(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request); + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")] + Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse CreateSession(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request); // CODEGEN: Generating message contract since the operation has multiple return values. - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetSessionID", ReplyAction="http://tempuri.org/AgentSvc/GetSessionIDResponse")] - System.Threading.Tasks.Task GetSessionIDAsync(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request); + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")] + System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName); @@ -89,29 +83,29 @@ public interface AgentSvc { [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.MessageContractAttribute(WrapperName="GetSessionID", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] - public partial class GetSessionIDRequest { + [System.ServiceModel.MessageContractAttribute(WrapperName="CreateSession", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class CreateSessionRequest { - public GetSessionIDRequest() { + public CreateSessionRequest() { } } [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.MessageContractAttribute(WrapperName="GetSessionIDResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] - public partial class GetSessionIDResponse { + [System.ServiceModel.MessageContractAttribute(WrapperName="CreateSessionResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class CreateSessionResponse { [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] - public bool GetSessionIDResult; + public bool CreateSessionResult; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] public long sessionID; - public GetSessionIDResponse() { + public CreateSessionResponse() { } - public GetSessionIDResponse(bool GetSessionIDResult, long sessionID) { - this.GetSessionIDResult = GetSessionIDResult; + public CreateSessionResponse(bool CreateSessionResult, long sessionID) { + this.CreateSessionResult = CreateSessionResult; this.sessionID = sessionID; } } @@ -294,28 +288,20 @@ public AgentSvcClient(System.ServiceModel.Channels.Binding binding, System.Servi base(binding, remoteAddress) { } - public double Sum(double a, double b) { - return base.Channel.Sum(a, b); - } - - public System.Threading.Tasks.Task SumAsync(double a, double b) { - return base.Channel.SumAsync(a, b); - } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetSessionID(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request) { - return base.Channel.GetSessionID(request); + Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.CreateSession(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request) { + return base.Channel.CreateSession(request); } - public bool GetSessionID(out long sessionID) { - Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest(); - Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetSessionID(inValue); + public bool CreateSession(out long sessionID) { + Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest(); + Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).CreateSession(inValue); sessionID = retVal.sessionID; - return retVal.GetSessionIDResult; + return retVal.CreateSessionResult; } - public System.Threading.Tasks.Task GetSessionIDAsync(Scada.Agent.Ctrl.ServiceReference1.GetSessionIDRequest request) { - return base.Channel.GetSessionIDAsync(request); + public System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request) { + return base.Channel.CreateSessionAsync(request); } public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName) { diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource similarity index 56% rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource index cf1a366a3..a883dac74 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource @@ -5,6 +5,6 @@ Renaming the file extension or editing the content of this file may cause the file to be unrecognizable by the program. --> - - Scada.Agent.Ctrl.ServiceReference1.GetSessionIDResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + + Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource index 9f574a896..158d4e2eb 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource @@ -6,5 +6,5 @@ cause the file to be unrecognizable by the program. --> - Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse + Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd index 19189e5e9..adb24c255 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd @@ -3,30 +3,15 @@ - - - - - - - - - - - - - - - - + - + - + diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs index be5050661..92a15e5c8 100644 --- a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs +++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs @@ -30,6 +30,7 @@ private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // button1 @@ -52,11 +53,22 @@ private void InitializeComponent() this.button2.UseVisualStyleBackColor = true; this.button2.Click += new System.EventHandler(this.button2_Click); // + // button3 + // + this.button3.Location = new System.Drawing.Point(174, 12); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(75, 23); + this.button3.TabIndex = 2; + this.button3.Text = "button3"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // // FrmMain // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.button1); this.Name = "FrmMain"; @@ -69,6 +81,7 @@ private void InitializeComponent() private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; } } diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs index 0cde240b8..85d7390d6 100644 --- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs +++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs @@ -18,9 +18,6 @@ private void button1_Click(object sender, System.EventArgs e) try { - double sum = client.Sum(2, 2); - MessageBox.Show(sum.ToString()); - Stream stream = client.DownloadFile(0, AppPath.Base); if (stream == null) { @@ -76,5 +73,20 @@ private void button2_Click(object sender, System.EventArgs e) client.Close(); } } + + private void button3_Click(object sender, EventArgs e) + { + AgentSvcClient client = new AgentSvcClient(); + + try + { + client.CreateSession(out long sessionID); + MessageBox.Show("Session ID = " + sessionID); + } + finally + { + client.Close(); + } + } } } diff --git a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj index 0d4179d67..3383e4079 100644 --- a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj +++ b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj @@ -83,6 +83,9 @@ Designer + + Reference.svcmap + Reference.svcmap @@ -92,9 +95,6 @@ Reference.svcmap - - Reference.svcmap - Reference.svcmap diff --git a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj index 41463ca9f..12e3a63f2 100644 --- a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj +++ b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj @@ -59,5 +59,15 @@ ScadaAgentNet + + + Lang\ScadaData.en-GB.xml + PreserveNewest + + + Lang\ScadaData.ru-RU.xml + PreserveNewest + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentNet/AgentManager.cs b/ScadaAgent/ScadaAgentNet/AgentManager.cs index c260b6619..55afde258 100644 --- a/ScadaAgent/ScadaAgentNet/AgentManager.cs +++ b/ScadaAgent/ScadaAgentNet/AgentManager.cs @@ -151,7 +151,7 @@ public bool StartAgent() log.WriteError(errMsg); // запуск - agentLogic = new AgentLogic(appData.SessionManager, appData.Log); + agentLogic = new AgentLogic(appData.SessionManager, appData.AppDirs, appData.Log); if (StartWcfService() && agentLogic.StartProcessing()) { From c47279311a7f456dc5c99885d439a7b7747cdf5b Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 29 Mar 2018 16:18:04 +0300 Subject: [PATCH 025/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/InstanceManager.cs | 7 ++ ScadaAgent/ScadaAgentCore/ScadaInstance.cs | 15 +++ ScadaAgent/ScadaAgentNet/AgentSvc.cs | 99 ++++++++++++++++++- .../ScadaAgentNet/ConfigUploadMessage.cs | 40 +++++++- 4 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/ScadaInstance.cs diff --git a/ScadaAgent/ScadaAgentCore/InstanceManager.cs b/ScadaAgent/ScadaAgentCore/InstanceManager.cs index 7b5be7b9a..f21073cb2 100644 --- a/ScadaAgent/ScadaAgentCore/InstanceManager.cs +++ b/ScadaAgent/ScadaAgentCore/InstanceManager.cs @@ -31,5 +31,12 @@ namespace Scada.Agent /// public class InstanceManager { + /// + /// Получить экземпляр системы по наименованию + /// + public ScadaInstance GetScadaInstance(string name) + { + return null; + } } } diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs new file mode 100644 index 000000000..0b20a7d56 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Scada.Agent +{ + public class ScadaInstance + { + public bool ValidateUser(string username, string encryptedPassword, out string errMsg) + { + errMsg = ""; + return true; + } + } +} diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs index 4f89f2428..f6de75121 100644 --- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs @@ -1,22 +1,56 @@ -using System; +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentNet + * Summary : WCF service for interacting with the agent + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; using System.Collections.Generic; using System.IO; using System.ServiceModel; using System.ServiceModel.Channels; +using Utils; namespace Scada.Agent.Net { + /// + /// WCF service for interacting with the agent + /// WCF-сервис для взаимодействия с агентом + /// [ServiceContract] public class AgentSvc { /// /// Данные приложения /// - private static AppData appData = AppData.GetInstance(); + private static readonly AppData AppData = AppData.GetInstance(); + /// + /// Журнал приложения + /// + private static readonly ILog Log = AppData.Log; /// /// Менеджер сессий /// - private static SessionManager sessionManager = appData.SessionManager; + private static readonly SessionManager SessionManager = AppData.SessionManager; /// @@ -38,6 +72,27 @@ private string GetClientIP() } } + /// + /// Попытаться получить сессию по идентификатору + /// + private bool TryGetSession(long sessionID, out Session session) + { + session = SessionManager.GetSession(sessionID); + + if (session == null) + { + Log.WriteError(string.Format(Localization.UseRussian ? + "Сессия с ид. {0} не найдена" : + "Session with ID {0} not found")); + return false; + } + else + { + session.RegisterActivity(); + return true; + } + } + /// /// Создать новую сессию @@ -45,7 +100,7 @@ private string GetClientIP() [OperationContract] public bool CreateSession(out long sessionID) { - Session session = sessionManager.CreateSession(); + Session session = SessionManager.CreateSession(); if (session == null) { @@ -60,18 +115,34 @@ public bool CreateSession(out long sessionID) } } + /// + /// Войти в систему + /// [OperationContract] public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName) { - return true; + if (TryGetSession(sessionID, out Session session)) + { + return true; + } + else + { + return false; + } } + /// + /// Управлять службой + /// [OperationContract] public bool ControlService(long sessionID, ScadaApps service, ServiceCommand command) { return true; } + /// + /// Получить статус службы + /// [OperationContract] public bool GetServiceStatus(long sessionID, ScadaApps service, out bool isRunning) { @@ -79,6 +150,9 @@ public bool GetServiceStatus(long sessionID, ScadaApps service, out bool isRunni return true; } + /// + /// Получить установленные приложения экземпляра системы + /// [OperationContract] public bool GetInstalledApps(long sessionID, out ScadaApps installedApps) { @@ -86,12 +160,18 @@ public bool GetInstalledApps(long sessionID, out ScadaApps installedApps) return true; } + /// + /// Скачать конфигурацию + /// [OperationContract] public Stream DownloadConfig(long sessionID, ConfigOptions configOptions) { return null; } + /// + /// Загрузить конфигурацию + /// [OperationContract] public void UploadConfig(ConfigUploadMessage configUploadMessage) { @@ -123,6 +203,9 @@ public void UploadConfig(ConfigUploadMessage configUploadMessage) //return true; } + /// + /// Найти файлы + /// [OperationContract] public bool FindFiles(long sessionID, AppPath appPath, out ICollection paths) { @@ -130,6 +213,9 @@ public bool FindFiles(long sessionID, AppPath appPath, out ICollection p return true; } + /// + /// Скачать файл + /// [OperationContract] public Stream DownloadFile(long sessionID, AppPath appPath) { @@ -142,6 +228,9 @@ public Stream DownloadFile(long sessionID, AppPath appPath) return stream; } + /// + /// Скачать часть файла с заданной позиции + /// [OperationContract] public Stream DownloadFileRest(long sessionID, AppPath appPath, long position) { diff --git a/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs b/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs index 6cdacf577..9150665da 100644 --- a/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs +++ b/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs @@ -1,17 +1,55 @@ -using System.IO; +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentNet + * Summary : Message for uploading the configuration + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System.IO; using System.ServiceModel; namespace Scada.Agent.Net { + /// + /// Message for uploading the configuration + /// Сообщение для загрузки конфигурации + /// [MessageContract] public class ConfigUploadMessage { + /// + /// Идентификатор сессии + /// [MessageHeader] public long SessionID; + /// + /// Параметры передачи конфигурации + /// [MessageHeader] public ConfigOptions ConfigOptions; + /// + /// Поток данных конфигурации + /// [MessageBodyMember] public Stream Stream; } From 32cdfee96da6d797423a361afe71c49e2929ce0a Mon Sep 17 00:00:00 2001 From: 2mik Date: Fri, 30 Mar 2018 17:32:27 +0300 Subject: [PATCH 026/100] ScadaAgent: dev --- ScadaAgent/ScadaAgentCore/AppData.cs | 26 +++ ScadaAgent/ScadaAgentCore/AppPath.cs | 2 +- ScadaAgent/ScadaAgentCore/InstanceManager.cs | 31 +++- ScadaAgent/ScadaAgentCore/ScadaInstance.cs | 81 ++++++++- .../ScadaAgentCore/ScadaInstanceSettings.cs | 54 ++++++ ScadaAgent/ScadaAgentCore/Session.cs | 28 +++- ScadaAgent/ScadaAgentCore/Settings.cs | 82 ++++++--- .../Config/ScadaAgentConfig.xml | 6 + .../ScadaAgentMono/ScadaAgentMono.csproj | 1 + ScadaAgent/ScadaAgentNet/AgentManager.cs | 27 ++- ScadaAgent/ScadaAgentNet/AgentSvc.cs | 155 ++++++++++++++---- 11 files changed, 421 insertions(+), 72 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/ScadaInstanceSettings.cs create mode 100644 ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml diff --git a/ScadaAgent/ScadaAgentCore/AppData.cs b/ScadaAgent/ScadaAgentCore/AppData.cs index e59322141..4a837170e 100644 --- a/ScadaAgent/ScadaAgentCore/AppData.cs +++ b/ScadaAgent/ScadaAgentCore/AppData.cs @@ -44,6 +44,7 @@ public sealed class AppData public const string InfoFileName = "ScadaAgent.txt"; private static readonly AppData appDataInstance; // экземпляр объекта AppData + private int tempFileNameCntr; // счётчик временных файлов /// @@ -59,9 +60,13 @@ static AppData() /// private AppData() { + tempFileNameCntr = 0; + AppDirs = new AppDirs(); + Settings = new Settings(); Log = new Log(Log.Formats.Full); SessionManager = new SessionManager(Log); + InstanceManager = new InstanceManager(Settings, Log); } @@ -70,6 +75,11 @@ private AppData() /// public AppDirs AppDirs { get; private set; } + /// + /// Получить настройки агента + /// + public Settings Settings { get; private set; } + /// /// Получить журнал приложения /// @@ -80,6 +90,11 @@ private AppData() /// public SessionManager SessionManager { get; private set; } + /// + /// Получить менеджер экземпляров систем + /// + public InstanceManager InstanceManager { get; private set; } + /// /// Инициализировать общие данные агента @@ -94,6 +109,17 @@ public void Init(string exeDir) Log.Encoding = Encoding.UTF8; } + /// + /// Получить имя временного файла + /// + public string GetTempFileName(string prefix = "", string extension = "") + { + return + (string.IsNullOrEmpty(prefix) ? "temp" : prefix) + + "-" + (++tempFileNameCntr) + + "." + (string.IsNullOrEmpty(extension) ? "tmp" : extension); + } + /// /// Получить общие данные агента /// diff --git a/ScadaAgent/ScadaAgentCore/AppPath.cs b/ScadaAgent/ScadaAgentCore/AppPath.cs index 237c7de7d..64d0240b8 100644 --- a/ScadaAgent/ScadaAgentCore/AppPath.cs +++ b/ScadaAgent/ScadaAgentCore/AppPath.cs @@ -34,7 +34,7 @@ public class AppPath /// /// Путь базы конфигурации /// - public static AppPath Base = new AppPath(ScadaApps.None, AppFolder.Config, ""); + public static readonly AppPath Base = new AppPath(ScadaApps.None, AppFolder.Config, ""); /// diff --git a/ScadaAgent/ScadaAgentCore/InstanceManager.cs b/ScadaAgent/ScadaAgentCore/InstanceManager.cs index f21073cb2..b0e82745a 100644 --- a/ScadaAgent/ScadaAgentCore/InstanceManager.cs +++ b/ScadaAgent/ScadaAgentCore/InstanceManager.cs @@ -23,6 +23,10 @@ * Modified : 2018 */ +using System; +using System.Collections.Concurrent; +using Utils; + namespace Scada.Agent { /// @@ -31,12 +35,37 @@ namespace Scada.Agent /// public class InstanceManager { + private Settings settings; // настройки агента + private ILog log; // журнал приложения + private ConcurrentDictionary locks; // объекты для блокировки экземпларов систем + + + /// + /// Конструктор, ограничивающий создание объекта без параметров + /// + private InstanceManager() + { + } + + /// + /// Конструктор + /// + public InstanceManager(Settings settings, ILog log) + { + this.settings = settings ?? throw new ArgumentNullException("settings"); + this.log = log ?? throw new ArgumentNullException("log"); + locks = new ConcurrentDictionary(); + } + + /// /// Получить экземпляр системы по наименованию /// public ScadaInstance GetScadaInstance(string name) { - return null; + object syncRoot = locks.GetOrAdd(name, (key) => { return new object(); }); + ScadaInstance scadaInstance = new ScadaInstance(name, syncRoot); + return scadaInstance; } } } diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs index 0b20a7d56..c3891ba5d 100644 --- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs +++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs @@ -1,15 +1,90 @@ -using System; -using System.Collections.Generic; -using System.Text; +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Object for manipulating a system instance + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; namespace Scada.Agent { + /// + /// Object for manipulating a system instance + /// Объект для манипуляций с экземпляром системы + /// public class ScadaInstance { + /// + /// Конструктор, ограничивающий создание объекта без параметров + /// + private ScadaInstance() + { + } + + /// + /// Конструктор + /// + public ScadaInstance(string name, object syncRoot) + { + Name = name ?? throw new ArgumentNullException("name"); + SyncRoot = syncRoot ?? throw new ArgumentNullException("syncRoot"); + } + + + /// + /// Получить наименование + /// + public string Name { get; private set; } + + /// + /// Получить или установить объект для синхронизации доступа к экземпляру системы + /// + public object SyncRoot { get; private set; } + + + /// + /// Проверить пароль и права пользователя + /// public bool ValidateUser(string username, string encryptedPassword, out string errMsg) { + // ограничить кол-во попыток errMsg = ""; return true; } + + /// + /// Упаковать конфигурацию в архив + /// + public bool PackConfig(string destFileName, ConfigOptions configOptions) + { + return false; + } + + /// + /// Распаковать архив конфигурации + /// + public bool UnpackConfig(string srcFileName, ConfigOptions configOptions) + { + return false; + } } } diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstanceSettings.cs b/ScadaAgent/ScadaAgentCore/ScadaInstanceSettings.cs new file mode 100644 index 000000000..63dddb88e --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/ScadaInstanceSettings.cs @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Agent settings for the system instance + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +namespace Scada.Agent +{ + /// + /// Agent settings for the system instance + /// Настройки агента для экземплара системы + /// + public class ScadaInstanceSettings + { + /// + /// Конструктор + /// + public ScadaInstanceSettings() + { + Name = ""; + Directory = ""; + } + + + /// + /// Получить или установить наименование + /// + public string Name { get; set; } + + /// + /// Получить или установить директорию + /// + public string Directory { get; set; } + } +} diff --git a/ScadaAgent/ScadaAgentCore/Session.cs b/ScadaAgent/ScadaAgentCore/Session.cs index 08f120e5a..bea1195bb 100644 --- a/ScadaAgent/ScadaAgentCore/Session.cs +++ b/ScadaAgent/ScadaAgentCore/Session.cs @@ -50,6 +50,7 @@ public Session(long sessionID) IpAddress = ""; LoggedOn = false; Username = ""; + ScadaInstance = null; ActivityDT = DateTime.UtcNow; } @@ -65,7 +66,7 @@ public Session(long sessionID) public string IpAddress { get; set; } /// - /// Получить или установить признак, выполнен ли вход пользователя в систему + /// Получить или установить признак, авторизован ли пользователь агента /// public bool LoggedOn { get; set; } @@ -74,6 +75,11 @@ public Session(long sessionID) /// public string Username { get; set; } + /// + /// Получить или установить экземпляр системы + /// + public ScadaInstance ScadaInstance { get; set; } + /// /// Получить или установить дату и время последней активности (UTC) /// @@ -88,6 +94,26 @@ public void RegisterActivity() ActivityDT = DateTime.UtcNow; } + /// + /// Установить данные авторизованного пользователя + /// + public void SetUser(string username, ScadaInstance scadaInstance) + { + LoggedOn = true; + Username = username; + ScadaInstance = scadaInstance; + } + + /// + /// Очистить данные, связанные с пользователем + /// + public void ClearUser() + { + LoggedOn = false; + Username = ""; + ScadaInstance = null; + } + /// /// Вернуть строковое представление объекта /// diff --git a/ScadaAgent/ScadaAgentCore/Settings.cs b/ScadaAgent/ScadaAgentCore/Settings.cs index 05923d7d3..1a980177e 100644 --- a/ScadaAgent/ScadaAgentCore/Settings.cs +++ b/ScadaAgent/ScadaAgentCore/Settings.cs @@ -23,7 +23,10 @@ * Modified : 2018 */ +using System; using System.Collections.Generic; +using System.IO; +using System.Xml; namespace Scada.Agent { @@ -34,29 +37,9 @@ namespace Scada.Agent public class Settings { /// - /// Agent settings for the system instance - /// Настройки агента для экземплара системы + /// Имя файла настроек по умолчанию /// - public class ScadaInstance - { - /// - /// Конструктор - /// - public ScadaInstance() - { - Name = ""; - Directory = ""; - } - - /// - /// Получить или установить наименование - /// - public string Name { get; set; } - /// - /// Получить или установить директорию - /// - public string Directory { get; set; } - } + public const string DefFileName = "ScadaAgentConfig.xml"; /// @@ -64,13 +47,64 @@ public ScadaInstance() /// public Settings() { - Instances = new List(); + Instances = new List(); } /// /// Получить настройки экземпляров систем /// - public List Instances { get; private set; } + public List Instances { get; private set; } + + + /// + /// Установить значения настроек по умолчанию + /// + private void SetToDefault() + { + Instances.Clear(); + } + + + /// + /// Загрузить настройки из файла + /// + public bool Load(string fileName, out string errMsg) + { + // установка значений по умолчанию + SetToDefault(); + + try + { + if (!File.Exists(fileName)) + throw new FileNotFoundException(string.Format(CommonPhrases.NamedFileNotFound, fileName)); + + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(fileName); + XmlElement rootElem = xmlDoc.DocumentElement; + + XmlNode instancesNode = rootElem.SelectSingleNode("Instances"); + if (instancesNode != null) + { + XmlNodeList instanceNodeList = instancesNode.SelectNodes("Instance"); + foreach (XmlElement instanceElem in instanceNodeList) + { + Instances.Add(new ScadaInstanceSettings() + { + Name = instanceElem.GetAttribute("name"), + Directory = instanceElem.GetAttribute("directory") + }); + } + } + + errMsg = ""; + return true; + } + catch (Exception ex) + { + errMsg = CommonPhrases.LoadAppSettingsError + ":" + Environment.NewLine + ex.Message; + return false; + } + } } } diff --git a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml new file mode 100644 index 000000000..4b43785bd --- /dev/null +++ b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj index 12e3a63f2..64f2688e6 100644 --- a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj +++ b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj @@ -68,6 +68,7 @@ Lang\ScadaData.ru-RU.xml PreserveNewest + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentNet/AgentManager.cs b/ScadaAgent/ScadaAgentNet/AgentManager.cs index 55afde258..4b2825e58 100644 --- a/ScadaAgent/ScadaAgentNet/AgentManager.cs +++ b/ScadaAgent/ScadaAgentNet/AgentManager.cs @@ -140,41 +140,40 @@ public bool StartAgent() "Агент {0} запущен" : "Agent {0} started", AgentUtils.AppVersion)); - if (appData.AppDirs.Exist) { // локализация - string errMsg; - if (Localization.LoadDictionaries(appData.AppDirs.LangDir, "ScadaData", out errMsg)) + if (Localization.LoadDictionaries(appData.AppDirs.LangDir, "ScadaData", out string errMsg)) CommonPhrases.Init(); else log.WriteError(errMsg); // запуск + string settingsFileName = appData.AppDirs.ConfigDir + Settings.DefFileName; agentLogic = new AgentLogic(appData.SessionManager, appData.AppDirs, appData.Log); - if (StartWcfService() && agentLogic.StartProcessing()) + if (appData.Settings.Load(settingsFileName, out errMsg) && + StartWcfService() && agentLogic.StartProcessing()) { return true; } - else + else if (!string.IsNullOrEmpty(errMsg)) { - log.WriteError(Localization.UseRussian ? - "Нормальная работа программы невозможна" : - "Normal program execution is impossible"); - return false; + log.WriteError(errMsg); } } else { log.WriteError(string.Format(Localization.UseRussian ? - "Необходимые директории не существуют:{0}{1}{0}" + - "Нормальная работа программы невозможна" : - "The required directories do not exist:{0}{1}{0}" + - "Normal program execution is impossible", + "Необходимые директории не существуют:{0}{1}" : + "The required directories do not exist:{0}{1}", Environment.NewLine, string.Join(Environment.NewLine, appData.AppDirs.GetRequiredDirs()))); - return false; } + + log.WriteError(Localization.UseRussian ? + "Нормальная работа программы невозможна" : + "Normal program execution is impossible"); + return false; } /// diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs index f6de75121..013689c23 100644 --- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs @@ -39,6 +39,11 @@ namespace Scada.Agent.Net [ServiceContract] public class AgentSvc { + /// + /// Размер буфера для приёма файлов + /// + private int ReceiveBufSize = 1024; + /// /// Данные приложения /// @@ -51,6 +56,10 @@ public class AgentSvc /// Менеджер сессий /// private static readonly SessionManager SessionManager = AppData.SessionManager; + /// + /// Менеджер экземпляров систем + /// + private static readonly InstanceManager InstanceManager = AppData.InstanceManager; /// @@ -83,7 +92,7 @@ private bool TryGetSession(long sessionID, out Session session) { Log.WriteError(string.Format(Localization.UseRussian ? "Сессия с ид. {0} не найдена" : - "Session with ID {0} not found")); + "Session with ID {0} not found", sessionID)); return false; } else @@ -93,6 +102,76 @@ private bool TryGetSession(long sessionID, out Session session) } } + /// + /// Попытаться получить экземпляр системы по ид. сессии + /// + private bool TryGetScadaInstance(long sessionID, out ScadaInstance scadaInstance) + { + if (TryGetSession(sessionID, out Session session)) + { + scadaInstance = session.LoggedOn ? session.ScadaInstance : null; + + if (scadaInstance == null) + { + Log.WriteError(string.Format(Localization.UseRussian ? + "Экземпляр системы не определён для сессии с ид. {0}" : + "System instance is not defined for a session with ID {0}", sessionID)); + return false; + } + else + { + return true; + } + } + else + { + scadaInstance = null; + return false; + } + } + + /// + /// Проверить сообщение для загрузки конфигурации + /// + private bool ValidateMessage(ConfigUploadMessage message) + { + return message != null && message.ConfigOptions != null || message.Stream != null; + } + + /// + /// Принять файл + /// + private bool ReceiveFile(Stream srcStream, string destFileName) + { + try + { + DateTime t0 = DateTime.UtcNow; + byte[] buffer = new byte[ReceiveBufSize]; + + using (FileStream destStream = File.Create(destFileName)) + { + int readCnt; + while ((readCnt = srcStream.Read(buffer, 0, ReceiveBufSize)) > 0) + { + destStream.Write(buffer, 0, readCnt); + } + } + + Log.WriteAction(string.Format(Localization.UseRussian ? + "Файл {0} принят успешно за {1} мс" : + "File {0} received successfully in {1} ms", + Path.GetFileName(destFileName), (int)(DateTime.UtcNow - t0).TotalMilliseconds)); + return true; + } + catch (Exception ex) + { + Log.WriteException(ex, Localization.UseRussian ? + "Ошибка при приёме файла" : + "Error receiving file"); + return false; + } + } + /// /// Создать новую сессию @@ -123,12 +202,29 @@ public bool Login(long sessionID, string username, string encryptedPassword, str { if (TryGetSession(sessionID, out Session session)) { - return true; - } - else - { - return false; + session.ClearUser(); + ScadaInstance scadaInstance = InstanceManager.GetScadaInstance(scadaInstanceName); + + if (scadaInstance == null) + { + Log.WriteError(string.Format(Localization.UseRussian ? + "Экземпляр системы с наименованием \"{0}\" не найден" : + "System instance named \"{0}\" not found", scadaInstanceName)); + } + else if (scadaInstance.ValidateUser(username, encryptedPassword, out string errMsg)) + { + session.SetUser(username, scadaInstance); + return true; + } + else + { + Log.WriteError(string.Format(Localization.UseRussian ? + "Пользователь {0} не прошёл проверку - {1}" : + "User {0} failed validation - {1}", username, errMsg)); + } } + + return false; } /// @@ -166,6 +262,18 @@ public bool GetInstalledApps(long sessionID, out ScadaApps installedApps) [OperationContract] public Stream DownloadConfig(long sessionID, ConfigOptions configOptions) { + if (TryGetScadaInstance(sessionID, out ScadaInstance scadaInstance)) + { + lock (scadaInstance.SyncRoot) + { + string tempFileName = AppData.GetTempFileName("download-config", "zip"); + if (scadaInstance.PackConfig(tempFileName, configOptions)) + { + return File.Open(tempFileName, FileMode.Open, FileAccess.Read, FileShare.None); + } + } + } + return null; } @@ -175,32 +283,23 @@ public Stream DownloadConfig(long sessionID, ConfigOptions configOptions) [OperationContract] public void UploadConfig(ConfigUploadMessage configUploadMessage) { - if (configUploadMessage.Stream == null) - { - System.Console.WriteLine("configUploadMessage.Stream is null"); - } - else + if (ValidateMessage(configUploadMessage)) { - /*byte[] buf = new byte[100]; - int cnt = configUploadMessage.Stream.Read(buf, 0, buf.Length); - string s = System.Text.Encoding.ASCII.GetString(buf, 0, cnt); - System.Console.WriteLine(s);*/ - - DateTime t0 = DateTime.UtcNow; - byte[] buf = new byte[1024]; - Stream saver = File.Create("file2.txt"); - int cnt; - - while ((cnt = configUploadMessage.Stream.Read(buf, 0, buf.Length)) > 0) + if (TryGetScadaInstance(configUploadMessage.SessionID, out ScadaInstance scadaInstance)) { - saver.Write(buf, 0, cnt); + string tempFileName = AppData.GetTempFileName("upload-config", "zip"); + if (ReceiveFile(configUploadMessage.Stream, tempFileName)) + { + scadaInstance.UnpackConfig(tempFileName, configUploadMessage.ConfigOptions); + } } - - saver.Close(); - Console.WriteLine("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms"); } - - //return true; + else + { + Log.WriteError(Localization.UseRussian ? + "Загружаемая конфигурация не определена или некорректна" : + "Uploaded configuration is undefined or incorrect"); + } } /// From 1767660f96b6bb31b9ffc0afeb7fbab1c4ef74dd Mon Sep 17 00:00:00 2001 From: 2mik Date: Fri, 30 Mar 2018 17:33:58 +0300 Subject: [PATCH 027/100] ScadaAgent: fix GetTempFileName --- ScadaAgent/ScadaAgentCore/AppData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScadaAgent/ScadaAgentCore/AppData.cs b/ScadaAgent/ScadaAgentCore/AppData.cs index 4a837170e..802cd0bd8 100644 --- a/ScadaAgent/ScadaAgentCore/AppData.cs +++ b/ScadaAgent/ScadaAgentCore/AppData.cs @@ -114,7 +114,7 @@ public void Init(string exeDir) /// public string GetTempFileName(string prefix = "", string extension = "") { - return + return AppDirs.TempDir + (string.IsNullOrEmpty(prefix) ? "temp" : prefix) + "-" + (++tempFileNameCntr) + "." + (string.IsNullOrEmpty(extension) ? "tmp" : extension); From b2b427b6c03e2faa3fb6fddc526e2e6006edc5fc Mon Sep 17 00:00:00 2001 From: 2mik Date: Fri, 30 Mar 2018 17:41:28 +0300 Subject: [PATCH 028/100] ScadaAgent: dev 2 --- ScadaAgent/ScadaAgentCore/AgentLogic.cs | 32 ++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/ScadaAgent/ScadaAgentCore/AgentLogic.cs b/ScadaAgent/ScadaAgentCore/AgentLogic.cs index 42fb86cd2..428795896 100644 --- a/ScadaAgent/ScadaAgentCore/AgentLogic.cs +++ b/ScadaAgent/ScadaAgentCore/AgentLogic.cs @@ -67,6 +67,10 @@ private enum WorkState /// private static readonly TimeSpan SessProcPeriod = TimeSpan.FromSeconds(5); /// + /// Период удаления временных файлов + /// + private static readonly TimeSpan RemoveTempPeriod = TimeSpan.FromMinutes(1); + /// /// Период записи в файл информации о работе приложения /// private static readonly TimeSpan WriteInfoPeriod = TimeSpan.FromSeconds(1); @@ -118,6 +122,22 @@ private void PrepareProcessing() WriteInfo(); } + /// + /// Удалить устаревшие временные файлы + /// + private void RemoveOutdatedTempFiles() + { + // TODO + } + + /// + /// Удалить все временные файлы + /// + private void RemoveAllTempFiles() + { + // TODO + } + /// /// Цикл работы агента (метод вызывается в отдельном потоке) /// @@ -125,7 +145,8 @@ private void Execute() { try { - DateTime sessProcDT = DateTime.MinValue; // время обработки сессий + DateTime sessProcDT = DateTime.MinValue; // время обработки сессий + DateTime remTempDT = DateTime.MinValue; // время удаления временных файлов DateTime writeInfoDT = DateTime.MinValue; // время записи информации о работе приложения while (!terminated) @@ -141,6 +162,13 @@ private void Execute() sessionManager.RemoveInactiveSessions(); } + // удаление устаревших временных файлов + if (utcNow - remTempDT >= RemoveTempPeriod) + { + remTempDT = utcNow; + RemoveOutdatedTempFiles(); + } + // запись информации о работе приложения if (utcNow - writeInfoDT >= WriteInfoPeriod) { @@ -165,6 +193,8 @@ private void Execute() finally { sessionManager.RemoveAllSessions(); + RemoveAllTempFiles(); + workState = WorkState.Terminated; WriteInfo(); } From 2e4ac2d50e6b95bd7b392e7563cee0687addeda1 Mon Sep 17 00:00:00 2001 From: 2mik Date: Fri, 30 Mar 2018 18:52:30 +0300 Subject: [PATCH 029/100] ScadaAgent: dev 3 --- ScadaAgent/ScadaAgentNet/AgentSvc.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs index 013689c23..5c64070a9 100644 --- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs @@ -287,10 +287,13 @@ public void UploadConfig(ConfigUploadMessage configUploadMessage) { if (TryGetScadaInstance(configUploadMessage.SessionID, out ScadaInstance scadaInstance)) { - string tempFileName = AppData.GetTempFileName("upload-config", "zip"); - if (ReceiveFile(configUploadMessage.Stream, tempFileName)) + lock (scadaInstance.SyncRoot) { - scadaInstance.UnpackConfig(tempFileName, configUploadMessage.ConfigOptions); + string tempFileName = AppData.GetTempFileName("upload-config", "zip"); + if (ReceiveFile(configUploadMessage.Stream, tempFileName)) + { + scadaInstance.UnpackConfig(tempFileName, configUploadMessage.ConfigOptions); + } } } } From 81e678225674facc919bf70b90a23307fd7f0faa Mon Sep 17 00:00:00 2001 From: 2mik Date: Sun, 1 Apr 2018 02:10:47 +0300 Subject: [PATCH 030/100] ScadaAgent: refactor definitions --- ScadaAgent/ScadaAgentCore/AgentLogic.cs | 67 +++++++++-- ScadaAgent/ScadaAgentCore/AppFolder.cs | 4 +- ScadaAgent/ScadaAgentCore/ConfigOptions.cs | 11 +- ScadaAgent/ScadaAgentCore/ConfigParts.cs | 67 +++++++++++ .../ScadaAgentCore/{AppPath.cs => RelPath.cs} | 26 ++--- ScadaAgent/ScadaAgentCore/ScadaInstance.cs | 2 +- .../{ScadaApps.cs => ServiceApp.cs} | 25 +---- .../ServiceReference1/AgentSvc.wsdl | 18 +-- .../ServiceReference1/Reference.cs | 106 +++++++++--------- ...eference1.CreateSessionResponse.datasource | 2 +- ...ce1.GetAvailableConfigResponse.datasource} | 4 +- .../ServiceReference1/item.xsd | 18 +-- .../ServiceReference1/item2.xsd | 68 +++++++---- ScadaAgent/ScadaAgentCtrl/FrmMain.cs | 2 +- .../ScadaAgentCtrl/ScadaAgentCtrl.csproj | 2 +- .../ScadaAgentMono/ScadaAgentMono.csproj | 4 +- ScadaAgent/ScadaAgentNet/AgentSvc.cs | 16 +-- 17 files changed, 275 insertions(+), 167 deletions(-) create mode 100644 ScadaAgent/ScadaAgentCore/ConfigParts.cs rename ScadaAgent/ScadaAgentCore/{AppPath.cs => RelPath.cs} (68%) rename ScadaAgent/ScadaAgentCore/{ScadaApps.cs => ServiceApp.cs} (71%) rename ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/{Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource => Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource} (54%) diff --git a/ScadaAgent/ScadaAgentCore/AgentLogic.cs b/ScadaAgent/ScadaAgentCore/AgentLogic.cs index 428795896..4c6e8eebe 100644 --- a/ScadaAgent/ScadaAgentCore/AgentLogic.cs +++ b/ScadaAgent/ScadaAgentCore/AgentLogic.cs @@ -69,7 +69,11 @@ private enum WorkState /// /// Период удаления временных файлов /// - private static readonly TimeSpan RemoveTempPeriod = TimeSpan.FromMinutes(1); + private static readonly TimeSpan DelTempFilePeriod = TimeSpan.FromMinutes(1); + /// + /// Время жизни временных файлов + /// + private static readonly TimeSpan TempFileLifetime = TimeSpan.FromMinutes(10); /// /// Период записи в файл информации о работе приложения /// @@ -125,17 +129,56 @@ private void PrepareProcessing() /// /// Удалить устаревшие временные файлы /// - private void RemoveOutdatedTempFiles() + private void DeleteOutdatedTempFiles() { - // TODO + try + { + DateTime utcNow = DateTime.UtcNow; + DirectoryInfo dirInfo = new DirectoryInfo(appDirs.TempDir); + + foreach (FileInfo fileInfo in dirInfo.EnumerateFiles()) + { + if (utcNow - fileInfo.CreationTimeUtc >= TempFileLifetime) + { + fileInfo.Delete(); + log.WriteAction(string.Format(Localization.UseRussian ? + "Удалён временный файл {0}" : + "Temporary file {0} deleted", fileInfo.Name)); + } + } + } + catch (Exception ex) + { + log.WriteException(ex, Localization.UseRussian ? + "Ошибка при удалении устаревших временных файлов" : + "Error deleting outdated temporary files"); + } } /// /// Удалить все временные файлы /// - private void RemoveAllTempFiles() + private void DeleteAllTempFiles() { - // TODO + try + { + DirectoryInfo dirInfo = new DirectoryInfo(appDirs.TempDir); + + foreach (FileInfo fileInfo in dirInfo.EnumerateFiles()) + { + fileInfo.Delete(); + } + + log.WriteAction(Localization.UseRussian ? + "Удалены все временные файлы" : + "All temporary files deleted"); + } + catch (Exception ex) + { + log.WriteException(ex, Localization.UseRussian ? + "Ошибка при удалении всех временных файлов" : + "Error deleting all temporary files"); + } } /// @@ -145,9 +188,9 @@ private void Execute() { try { - DateTime sessProcDT = DateTime.MinValue; // время обработки сессий - DateTime remTempDT = DateTime.MinValue; // время удаления временных файлов - DateTime writeInfoDT = DateTime.MinValue; // время записи информации о работе приложения + DateTime sessProcDT = DateTime.MinValue; // время обработки сессий + DateTime delTempFileDT = DateTime.MinValue; // время удаления временных файлов + DateTime writeInfoDT = DateTime.MinValue; // время записи информации о работе приложения while (!terminated) { @@ -163,10 +206,10 @@ private void Execute() } // удаление устаревших временных файлов - if (utcNow - remTempDT >= RemoveTempPeriod) + if (utcNow - delTempFileDT >= DelTempFilePeriod) { - remTempDT = utcNow; - RemoveOutdatedTempFiles(); + delTempFileDT = utcNow; + DeleteOutdatedTempFiles(); } // запись информации о работе приложения @@ -193,7 +236,7 @@ private void Execute() finally { sessionManager.RemoveAllSessions(); - RemoveAllTempFiles(); + DeleteAllTempFiles(); workState = WorkState.Terminated; WriteInfo(); diff --git a/ScadaAgent/ScadaAgentCore/AppFolder.cs b/ScadaAgent/ScadaAgentCore/AppFolder.cs index ba2c04210..bd03c3f52 100644 --- a/ScadaAgent/ScadaAgentCore/AppFolder.cs +++ b/ScadaAgent/ScadaAgentCore/AppFolder.cs @@ -32,9 +32,9 @@ namespace Scada.Agent public enum AppFolder { /// - /// Не определена + /// Корневая /// - Undef, + Root, /// /// Конфигурация diff --git a/ScadaAgent/ScadaAgentCore/ConfigOptions.cs b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs index cdd11b5cf..727ec7684 100644 --- a/ScadaAgent/ScadaAgentCore/ConfigOptions.cs +++ b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs @@ -34,18 +34,13 @@ namespace Scada.Agent public class ConfigOptions { /// - /// Получить или установить приложение + /// Получить или установить части конфигурации /// - public ScadaApps ScadaApp { get; set; } - - /// - /// Получить или установить директорию приложения - /// - public AppFolder AppFolder { get; set; } + public ConfigParts ConfigParts { get; set; } /// /// Получить или установить исключаемые пути /// - public ICollection ExcludedPaths { get; private set; } + public ICollection ExcludedPaths { get; private set; } } } diff --git a/ScadaAgent/ScadaAgentCore/ConfigParts.cs b/ScadaAgent/ScadaAgentCore/ConfigParts.cs new file mode 100644 index 000000000..e86520282 --- /dev/null +++ b/ScadaAgent/ScadaAgentCore/ConfigParts.cs @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentCore + * Summary : Parts of the configuration + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; + +namespace Scada.Agent +{ + /// + /// Parts of the configuration + /// Части конфигурации + /// + [Flags] + public enum ConfigParts + { + /// + /// Не задано + /// + None = 0, + + /// + /// База конфигурации + /// + Base = 1, + + /// + /// Сервер + /// + Server = 2, + + /// + /// Коммуникатор + /// + Communicator = 4, + + /// + /// Вебстанция + /// + Webstation = 8, + + /// + /// Вся конфигурация + /// + All = Base | Server | Communicator | Webstation + } +} diff --git a/ScadaAgent/ScadaAgentCore/AppPath.cs b/ScadaAgent/ScadaAgentCore/RelPath.cs similarity index 68% rename from ScadaAgent/ScadaAgentCore/AppPath.cs rename to ScadaAgent/ScadaAgentCore/RelPath.cs index 64d0240b8..89d8bdb9c 100644 --- a/ScadaAgent/ScadaAgentCore/AppPath.cs +++ b/ScadaAgent/ScadaAgentCore/RelPath.cs @@ -16,7 +16,7 @@ * * Product : Rapid SCADA * Module : ScadaAgentCore - * Summary : Path relative to an application + * Summary : Relative path * * Author : Mikhail Shiryaev * Created : 2018 @@ -26,40 +26,34 @@ namespace Scada.Agent { /// - /// Path relative to an application - /// Путь относительно приложения + /// Relative path + /// Относительный путь /// - public class AppPath + public class RelPath { - /// - /// Путь базы конфигурации - /// - public static readonly AppPath Base = new AppPath(ScadaApps.None, AppFolder.Config, ""); - - /// /// Конструктор /// - public AppPath() - : this(ScadaApps.None, AppFolder.Undef, "") + public RelPath() + : this(ConfigParts.None, AppFolder.Root, "") { } /// /// Конструктор /// - public AppPath(ScadaApps scadaApp, AppFolder appFolder, string path) + public RelPath(ConfigParts configPart, AppFolder appFolder, string path) { - ScadaApp = scadaApp; + ConfigPart = configPart; AppFolder = appFolder; Path = path ?? ""; } /// - /// Получить или установить приложение + /// Получить или установить часть конфигурации /// - public ScadaApps ScadaApp { get; set; } + public ConfigParts ConfigPart { get; set; } /// /// Получить или установить папку приложения diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs index c3891ba5d..858a91d32 100644 --- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs +++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs @@ -66,7 +66,7 @@ public ScadaInstance(string name, object syncRoot) /// public bool ValidateUser(string username, string encryptedPassword, out string errMsg) { - // ограничить кол-во попыток + // TODO: реализовать и ограничить кол-во попыток errMsg = ""; return true; } diff --git a/ScadaAgent/ScadaAgentCore/ScadaApps.cs b/ScadaAgent/ScadaAgentCore/ServiceApp.cs similarity index 71% rename from ScadaAgent/ScadaAgentCore/ScadaApps.cs rename to ScadaAgent/ScadaAgentCore/ServiceApp.cs index 828f74f98..c6e39f309 100644 --- a/ScadaAgent/ScadaAgentCore/ScadaApps.cs +++ b/ScadaAgent/ScadaAgentCore/ServiceApp.cs @@ -16,42 +16,29 @@ * * Product : Rapid SCADA * Module : ScadaAgentCore - * Summary : Applications + * Summary : Service applications * * Author : Mikhail Shiryaev * Created : 2018 * Modified : 2018 */ -using System; - namespace Scada.Agent { /// - /// Applications - /// Приложения + /// Service applications + /// Приложения-сервисы /// - [Flags] - public enum ScadaApps + public enum ServiceApp { - /// - /// Не задано - /// - None = 0, - /// /// Сервер /// - Server = 1, + Server, /// /// Коммуникатор /// - Communicator = 2, - - /// - /// Вебстанция - /// - Webstation = 4 + Communicator } } diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl index 9e754b73b..410c95f69 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl @@ -33,11 +33,11 @@ - - + + - - + + @@ -88,9 +88,9 @@ - - - + + + @@ -151,8 +151,8 @@ - - + + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs index 283bbd0f5..df4aec15d 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs @@ -29,10 +29,10 @@ public interface AgentSvc { System.Threading.Tasks.Task LoginAsync(long sessionID, string username, string encryptedPassword, string scadaInstanceName); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")] - bool ControlService(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command); + bool ControlService(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")] - System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command); + System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")] Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse GetServiceStatus(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request); @@ -41,12 +41,12 @@ public interface AgentSvc { [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")] System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request); - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetInstalledApps", ReplyAction="http://tempuri.org/AgentSvc/GetInstalledAppsResponse")] - Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse GetInstalledApps(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request); + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")] + Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse GetAvailableConfig(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request); // CODEGEN: Generating message contract since the operation has multiple return values. - [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetInstalledApps", ReplyAction="http://tempuri.org/AgentSvc/GetInstalledAppsResponse")] - System.Threading.Tasks.Task GetInstalledAppsAsync(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request); + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")] + System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")] System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions configOptions); @@ -69,16 +69,16 @@ public interface AgentSvc { System.Threading.Tasks.Task FindFilesAsync(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")] - System.IO.Stream DownloadFile(long sessionID, Scada.Agent.AppPath appPath); + System.IO.Stream DownloadFile(long sessionID, Scada.Agent.RelPath relPath); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")] - System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.AppPath appPath); + System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.RelPath relPath); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")] - System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.AppPath appPath, long position); + System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.RelPath relPath, long position); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")] - System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.AppPath appPath, long position); + System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.RelPath relPath, long position); } [System.Diagnostics.DebuggerStepThroughAttribute()] @@ -119,14 +119,14 @@ public partial class GetServiceStatusRequest { public long sessionID; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] - public Scada.Agent.ScadaApps service; + public Scada.Agent.ServiceApp serviceApp; public GetServiceStatusRequest() { } - public GetServiceStatusRequest(long sessionID, Scada.Agent.ScadaApps service) { + public GetServiceStatusRequest(long sessionID, Scada.Agent.ServiceApp serviceApp) { this.sessionID = sessionID; - this.service = service; + this.serviceApp = serviceApp; } } @@ -152,37 +152,37 @@ public GetServiceStatusResponse(bool GetServiceStatusResult, bool isRunning) { [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.MessageContractAttribute(WrapperName="GetInstalledApps", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] - public partial class GetInstalledAppsRequest { + [System.ServiceModel.MessageContractAttribute(WrapperName="GetAvailableConfig", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetAvailableConfigRequest { [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] public long sessionID; - public GetInstalledAppsRequest() { + public GetAvailableConfigRequest() { } - public GetInstalledAppsRequest(long sessionID) { + public GetAvailableConfigRequest(long sessionID) { this.sessionID = sessionID; } } [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.MessageContractAttribute(WrapperName="GetInstalledAppsResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] - public partial class GetInstalledAppsResponse { + [System.ServiceModel.MessageContractAttribute(WrapperName="GetAvailableConfigResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetAvailableConfigResponse { [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] - public bool GetInstalledAppsResult; + public bool GetAvailableConfigResult; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] - public Scada.Agent.ScadaApps installedApps; + public Scada.Agent.ConfigParts configParts; - public GetInstalledAppsResponse() { + public GetAvailableConfigResponse() { } - public GetInstalledAppsResponse(bool GetInstalledAppsResult, Scada.Agent.ScadaApps installedApps) { - this.GetInstalledAppsResult = GetInstalledAppsResult; - this.installedApps = installedApps; + public GetAvailableConfigResponse(bool GetAvailableConfigResult, Scada.Agent.ConfigParts configParts) { + this.GetAvailableConfigResult = GetAvailableConfigResult; + this.configParts = configParts; } } @@ -230,14 +230,14 @@ public partial class FindFilesRequest { public long sessionID; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] - public Scada.Agent.AppPath appPath; + public Scada.Agent.RelPath relPath; public FindFilesRequest() { } - public FindFilesRequest(long sessionID, Scada.Agent.AppPath appPath) { + public FindFilesRequest(long sessionID, Scada.Agent.RelPath relPath) { this.sessionID = sessionID; - this.appPath = appPath; + this.relPath = relPath; } } @@ -312,12 +312,12 @@ public System.Threading.Tasks.Task LoginAsync(long sessionID, string usern return base.Channel.LoginAsync(sessionID, username, encryptedPassword, scadaInstanceName); } - public bool ControlService(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command) { - return base.Channel.ControlService(sessionID, service, command); + public bool ControlService(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command) { + return base.Channel.ControlService(sessionID, serviceApp, command); } - public System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ScadaApps service, Scada.Agent.ServiceCommand command) { - return base.Channel.ControlServiceAsync(sessionID, service, command); + public System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command) { + return base.Channel.ControlServiceAsync(sessionID, serviceApp, command); } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] @@ -325,10 +325,10 @@ Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse Scada.Agent.Ctrl.Ser return base.Channel.GetServiceStatus(request); } - public bool GetServiceStatus(long sessionID, Scada.Agent.ScadaApps service, out bool isRunning) { + public bool GetServiceStatus(long sessionID, Scada.Agent.ServiceApp serviceApp, out bool isRunning) { Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest(); inValue.sessionID = sessionID; - inValue.service = service; + inValue.serviceApp = serviceApp; Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetServiceStatus(inValue); isRunning = retVal.isRunning; return retVal.GetServiceStatusResult; @@ -339,20 +339,20 @@ public bool GetServiceStatus(long sessionID, Scada.Agent.ScadaApps service, out } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetInstalledApps(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request) { - return base.Channel.GetInstalledApps(request); + Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetAvailableConfig(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request) { + return base.Channel.GetAvailableConfig(request); } - public bool GetInstalledApps(long sessionID, out Scada.Agent.ScadaApps installedApps) { - Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest(); + public bool GetAvailableConfig(long sessionID, out Scada.Agent.ConfigParts configParts) { + Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest(); inValue.sessionID = sessionID; - Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetInstalledApps(inValue); - installedApps = retVal.installedApps; - return retVal.GetInstalledAppsResult; + Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetAvailableConfig(inValue); + configParts = retVal.configParts; + return retVal.GetAvailableConfigResult; } - public System.Threading.Tasks.Task GetInstalledAppsAsync(Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsRequest request) { - return base.Channel.GetInstalledAppsAsync(request); + public System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request) { + return base.Channel.GetAvailableConfigAsync(request); } public System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions configOptions) { @@ -394,10 +394,10 @@ Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse Scada.Agent.Ctrl.ServiceRef return base.Channel.FindFiles(request); } - public bool FindFiles(long sessionID, Scada.Agent.AppPath appPath, out string[] paths) { + public bool FindFiles(long sessionID, Scada.Agent.RelPath relPath, out string[] paths) { Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest(); inValue.sessionID = sessionID; - inValue.appPath = appPath; + inValue.relPath = relPath; Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).FindFiles(inValue); paths = retVal.paths; return retVal.FindFilesResult; @@ -407,20 +407,20 @@ public bool FindFiles(long sessionID, Scada.Agent.AppPath appPath, out string[] return base.Channel.FindFilesAsync(request); } - public System.IO.Stream DownloadFile(long sessionID, Scada.Agent.AppPath appPath) { - return base.Channel.DownloadFile(sessionID, appPath); + public System.IO.Stream DownloadFile(long sessionID, Scada.Agent.RelPath relPath) { + return base.Channel.DownloadFile(sessionID, relPath); } - public System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.AppPath appPath) { - return base.Channel.DownloadFileAsync(sessionID, appPath); + public System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.RelPath relPath) { + return base.Channel.DownloadFileAsync(sessionID, relPath); } - public System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.AppPath appPath, long position) { - return base.Channel.DownloadFileRest(sessionID, appPath, position); + public System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.RelPath relPath, long position) { + return base.Channel.DownloadFileRest(sessionID, relPath, position); } - public System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.AppPath appPath, long position) { - return base.Channel.DownloadFileRestAsync(sessionID, appPath, position); + public System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.RelPath relPath, long position) { + return base.Channel.DownloadFileRestAsync(sessionID, relPath, position); } } } diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource index a883dac74..3c959ba46 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource @@ -6,5 +6,5 @@ cause the file to be unrecognizable by the program. --> - Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse + Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource similarity index 54% rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource index 3185e6821..0f904b4ce 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse.datasource +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource @@ -5,6 +5,6 @@ Renaming the file extension or editing the content of this file may cause the file to be unrecognizable by the program. --> - - Scada.Agent.Ctrl.ServiceReference1.GetInstalledAppsResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + + Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd index adb24c255..9f1b76b6f 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd @@ -37,7 +37,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -65,18 +65,18 @@ - + - + - - + + @@ -108,7 +108,7 @@ - + @@ -124,7 +124,7 @@ - + @@ -139,7 +139,7 @@ - + diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd index 2faf25122..7e4ff1cb5 100644 --- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd +++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd @@ -1,7 +1,22 @@ - + + + + + + + + + + + + + + + + @@ -12,62 +27,67 @@ - + 1 - + 2 - + 4 + + + + 8 + + + + + + + 15 + + + - - - - - - - - - + - - + + + + + + + + + - + - - - - - - - - \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs index 85d7390d6..e73b83def 100644 --- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs +++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs @@ -18,7 +18,7 @@ private void button1_Click(object sender, System.EventArgs e) try { - Stream stream = client.DownloadFile(0, AppPath.Base); + Stream stream = client.DownloadFile(0, new RelPath()); if (stream == null) { MessageBox.Show("Stream is null."); diff --git a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj index 3383e4079..7dbbf23ab 100644 --- a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj +++ b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj @@ -89,7 +89,7 @@ Reference.svcmap - + Reference.svcmap diff --git a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj index 64f2688e6..135383eac 100644 --- a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj +++ b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj @@ -68,7 +68,9 @@ Lang\ScadaData.ru-RU.xml PreserveNewest - + + PreserveNewest + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs index 5c64070a9..0969f4545 100644 --- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs +++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs @@ -231,7 +231,7 @@ public bool Login(long sessionID, string username, string encryptedPassword, str /// Управлять службой /// [OperationContract] - public bool ControlService(long sessionID, ScadaApps service, ServiceCommand command) + public bool ControlService(long sessionID, ServiceApp serviceApp, ServiceCommand command) { return true; } @@ -240,19 +240,19 @@ public bool ControlService(long sessionID, ScadaApps service, ServiceCommand com /// Получить статус службы /// [OperationContract] - public bool GetServiceStatus(long sessionID, ScadaApps service, out bool isRunning) + public bool GetServiceStatus(long sessionID, ServiceApp serviceApp, out bool isRunning) { isRunning = true; return true; } /// - /// Получить установленные приложения экземпляра системы + /// Получить доступные части конфигурации экземпляра системы /// [OperationContract] - public bool GetInstalledApps(long sessionID, out ScadaApps installedApps) + public bool GetAvailableConfig(long sessionID, out ConfigParts configParts) { - installedApps = ScadaApps.None; + configParts = ConfigParts.All; return true; } @@ -309,7 +309,7 @@ public void UploadConfig(ConfigUploadMessage configUploadMessage) /// Найти файлы /// [OperationContract] - public bool FindFiles(long sessionID, AppPath appPath, out ICollection paths) + public bool FindFiles(long sessionID, RelPath relPath, out ICollection paths) { paths = null; return true; @@ -319,7 +319,7 @@ public bool FindFiles(long sessionID, AppPath appPath, out ICollection p /// Скачать файл /// [OperationContract] - public Stream DownloadFile(long sessionID, AppPath appPath) + public Stream DownloadFile(long sessionID, RelPath relPath) { /*byte[] buffer = System.Text.Encoding.ASCII.GetBytes("hello"); MemoryStream stream = new MemoryStream(buffer.Length); @@ -334,7 +334,7 @@ public Stream DownloadFile(long sessionID, AppPath appPath) /// Скачать часть файла с заданной позиции /// [OperationContract] - public Stream DownloadFileRest(long sessionID, AppPath appPath, long position) + public Stream DownloadFileRest(long sessionID, RelPath relPath, long position) { return null; } From 585bc87863f55371c7350d4572e21d669d1d08cc Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 19 Apr 2018 14:52:45 +0300 Subject: [PATCH 031/100] PlgTable: hidden items are not displayed in reports --- .../version-history/webstation-plugins-history.html | 5 ++++- .../PlgTable/AppCode/Table/HourDataRepBuilder.cs | 13 ++++++++----- ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html index 718fcfb9c..745feeafa 100644 --- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html +++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html @@ -88,7 +88,10 @@

Магазин

- Первоначальная разработка плагина

Таблицы

-
PlgTable 5.0.2.0 (16.03.2018)
+    
PlgTable 5.0.2.1 (В разработке)
+- Скрытые элементы табличных представлений не выводятся в отчёт
+
+PlgTable 5.0.2.0 (16.03.2018)
 - Использование очереди для отправки Ajax-запросов
 - Сокращено на 1 секунду время закрытия диалога отправки команды
 
diff --git a/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs b/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs
index 5703ccd7d..b9d013fc1 100644
--- a/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs
+++ b/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2016
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada.Client;
@@ -203,10 +203,13 @@ protected override void FinalXmlDocProc()
             for (int i = 0, cnt = tableView.Items.Count; i < cnt; i++)
             {
                 viewItem = tableView.Items[i];
-                cnlProps = viewItem.CnlNum > 0 ? dataAccess.GetCnlProps(viewItem.CnlNum) : null;
-                Row newRow = itemRowTemplate.Clone();
-                ExcelProc(newRow);
-                table.AppendRow(newRow);
+                if (!viewItem.Hidden)
+                {
+                    cnlProps = viewItem.CnlNum > 0 ? dataAccess.GetCnlProps(viewItem.CnlNum) : null;
+                    Row newRow = itemRowTemplate.Clone();
+                    ExcelProc(newRow);
+                    table.AppendRow(newRow);
+                }
             }
         }
 
diff --git a/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs b/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs
index cfce67d4e..d22b99261 100644
--- a/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs
+++ b/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs
@@ -34,6 +34,6 @@ public static class TableUtils
         /// 
         /// Версия таблиц
         /// 
-        public const string TableVersion = "5.0.2.0";
+        public const string TableVersion = "5.0.2.1";
     }
 }

From 59756e1fb582c14b966e17997057bb569c1d4709 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 23 Apr 2018 17:39:32 +0300
Subject: [PATCH 032/100] ScadaAgent: dev

---
 ScadaAgent/ScadaAgentCore/InstanceManager.cs    | 13 ++++++++++---
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs      | 11 +++++++++--
 ScadaAgent/ScadaAgentCore/Settings.cs           | 12 +++++++-----
 ScadaAgent/ScadaAgentMono/Program.cs            |  4 +---
 ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj |  2 +-
 5 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/InstanceManager.cs b/ScadaAgent/ScadaAgentCore/InstanceManager.cs
index b0e82745a..5836f7441 100644
--- a/ScadaAgent/ScadaAgentCore/InstanceManager.cs
+++ b/ScadaAgent/ScadaAgentCore/InstanceManager.cs
@@ -63,9 +63,16 @@ public InstanceManager(Settings settings, ILog log)
         /// 
         public ScadaInstance GetScadaInstance(string name)
         {
-            object syncRoot = locks.GetOrAdd(name, (key) => { return new object(); });
-            ScadaInstance scadaInstance = new ScadaInstance(name, syncRoot);
-            return scadaInstance;
+            if (settings.Instances.TryGetValue(name, out ScadaInstanceSettings instanceSettings))
+            {
+                object syncRoot = locks.GetOrAdd(name, (key) => { return new object(); });
+                ScadaInstance scadaInstance = new ScadaInstance(instanceSettings, syncRoot);
+                return scadaInstance;
+            }
+            else
+            {
+                return null;
+            }
         }
     }
 }
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 858a91d32..87b3883fb 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -43,10 +43,12 @@ private ScadaInstance()
         /// 
         /// Конструктор
         /// 
-        public ScadaInstance(string name, object syncRoot)
+        public ScadaInstance(ScadaInstanceSettings settings, object syncRoot)
         {
-            Name = name ?? throw new ArgumentNullException("name");
+            Settings = settings ?? throw new ArgumentNullException("settings");
             SyncRoot = syncRoot ?? throw new ArgumentNullException("syncRoot");
+
+            Name = settings.Name;
         }
 
 
@@ -55,6 +57,11 @@ public ScadaInstance(string name, object syncRoot)
         /// 
         public string Name { get; private set; }
 
+        /// 
+        /// Получить настройки экземпляра системы
+        /// 
+        public ScadaInstanceSettings Settings { get; private set; }
+
         /// 
         /// Получить или установить объект для синхронизации доступа к экземпляру системы
         /// 
diff --git a/ScadaAgent/ScadaAgentCore/Settings.cs b/ScadaAgent/ScadaAgentCore/Settings.cs
index 1a980177e..1af210ffe 100644
--- a/ScadaAgent/ScadaAgentCore/Settings.cs
+++ b/ScadaAgent/ScadaAgentCore/Settings.cs
@@ -47,14 +47,14 @@ public class Settings
         /// 
         public Settings()
         {
-            Instances = new List();
+            Instances = new SortedList();
         }
 
 
         /// 
-        /// Получить настройки экземпляров систем
+        /// Получить настройки экземпляров систем, ключ - наименование экземпляра
         /// 
-        public List Instances { get; private set; }
+        public SortedList Instances { get; private set; }
 
 
         /// 
@@ -89,11 +89,13 @@ public bool Load(string fileName, out string errMsg)
                     XmlNodeList instanceNodeList = instancesNode.SelectNodes("Instance");
                     foreach (XmlElement instanceElem in instanceNodeList)
                     {
-                        Instances.Add(new ScadaInstanceSettings()
+                        ScadaInstanceSettings instanceSettings = new ScadaInstanceSettings()
                         {
                             Name = instanceElem.GetAttribute("name"),
                             Directory = instanceElem.GetAttribute("directory")
-                        });
+                        };
+
+                        Instances[instanceSettings.Name] = instanceSettings;
                     }
                 }
 
diff --git a/ScadaAgent/ScadaAgentMono/Program.cs b/ScadaAgent/ScadaAgentMono/Program.cs
index 6f6da7b0e..119a1f28d 100644
--- a/ScadaAgent/ScadaAgentMono/Program.cs
+++ b/ScadaAgent/ScadaAgentMono/Program.cs
@@ -23,13 +23,11 @@
  * Modified : 2018
  */
 
-using Scada;
-using Scada.Agent;
 using Scada.Agent.Net;
 using System;
 using System.Threading;
 
-namespace ScadaAgentMono
+namespace Scada.Agent.Mono
 {
     /// 
     /// Agent console appliction tested on Mono .NET framework
diff --git a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj
index 135383eac..4a4e61c12 100644
--- a/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj
+++ b/ScadaAgent/ScadaAgentMono/ScadaAgentMono.csproj
@@ -6,7 +6,7 @@
     AnyCPU
     {45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}
     Exe
-    ScadaAgentMono
+    Scada.Agent.Mono
     ScadaAgentMono
     v4.6.1
     512

From 4ae9de4bd634621e9e9f6fc88795cbe59192ac1c Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 24 Apr 2018 15:58:57 +0300
Subject: [PATCH 033/100] ScadaAgent: dev

---
 ScadaAgent/ScadaAgentCore/ConfigOptions.cs    | 10 ++
 ScadaAgent/ScadaAgentCore/InstanceManager.cs  |  2 +-
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs    | 95 ++++++++++++++++++-
 ScadaAgent/ScadaAgentCore/Settings.cs         |  2 +-
 ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs | 16 ++--
 ScadaAgent/ScadaAgentCtrl/FrmMain.cs          | 47 +++++----
 6 files changed, 139 insertions(+), 33 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/ConfigOptions.cs b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs
index 727ec7684..3333c8b47 100644
--- a/ScadaAgent/ScadaAgentCore/ConfigOptions.cs
+++ b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs
@@ -33,6 +33,16 @@ namespace Scada.Agent
     /// 
     public class ConfigOptions
     {
+        /// 
+        /// Конструктор
+        /// 
+        public ConfigOptions()
+        {
+            ConfigParts = ConfigParts.All;
+            ExcludedPaths = new List();
+        }
+
+
         /// 
         /// Получить или установить части конфигурации
         /// 
diff --git a/ScadaAgent/ScadaAgentCore/InstanceManager.cs b/ScadaAgent/ScadaAgentCore/InstanceManager.cs
index 5836f7441..b5861fce1 100644
--- a/ScadaAgent/ScadaAgentCore/InstanceManager.cs
+++ b/ScadaAgent/ScadaAgentCore/InstanceManager.cs
@@ -66,7 +66,7 @@ public ScadaInstance GetScadaInstance(string name)
             if (settings.Instances.TryGetValue(name, out ScadaInstanceSettings instanceSettings))
             {
                 object syncRoot = locks.GetOrAdd(name, (key) => { return new object(); });
-                ScadaInstance scadaInstance = new ScadaInstance(instanceSettings, syncRoot);
+                ScadaInstance scadaInstance = new ScadaInstance(instanceSettings, syncRoot, log);
                 return scadaInstance;
             }
             else
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 87b3883fb..7e4fa367b 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -24,6 +24,9 @@
  */
 
 using System;
+using System.IO;
+using System.IO.Compression;
+using Utils;
 
 namespace Scada.Agent
 {
@@ -33,6 +36,9 @@ namespace Scada.Agent
     /// 
     public class ScadaInstance
     {
+        private ILog log; // журнал приложения
+
+
         /// 
         /// Конструктор, ограничивающий создание объекта без параметров
         /// 
@@ -43,11 +49,11 @@ private ScadaInstance()
         /// 
         /// Конструктор
         /// 
-        public ScadaInstance(ScadaInstanceSettings settings, object syncRoot)
+        public ScadaInstance(ScadaInstanceSettings settings, object syncRoot, ILog log)
         {
             Settings = settings ?? throw new ArgumentNullException("settings");
             SyncRoot = syncRoot ?? throw new ArgumentNullException("syncRoot");
-
+            this.log = log ?? throw new ArgumentNullException("log");
             Name = settings.Name;
         }
 
@@ -68,6 +74,66 @@ public ScadaInstance(ScadaInstanceSettings settings, object syncRoot)
         public object SyncRoot { get; private set; }
 
 
+        /// 
+        /// Получить директорию части конфигурации
+        /// 
+        private string GetConfigPartDir(ConfigParts configPart)
+        {
+            switch (configPart)
+            {
+                case ConfigParts.Base:
+                    return Settings.Directory + "BaseDAT" + Path.DirectorySeparatorChar;
+                case ConfigParts.Server:
+                    return Settings.Directory + "ScadaServer" + Path.DirectorySeparatorChar;
+                case ConfigParts.Communicator:
+                    return Settings.Directory + "ScadaComm" + Path.DirectorySeparatorChar;
+                case ConfigParts.Webstation:
+                    return Settings.Directory + "ScadaWeb" + Path.DirectorySeparatorChar;
+                default:
+                    return "";
+            }
+        }
+
+        /// 
+        /// Упаковать директорию
+        /// 
+        private void PackDir(ZipArchive zipArchive, string srcDir, bool recursively, string entryPrefix)
+        {
+            srcDir = ScadaUtils.NormalDir(srcDir);
+            int srcDirLen = srcDir.Length;
+            DirectoryInfo srcDirInfo = new DirectoryInfo(srcDir);
+            FileInfo[] fileInfoArr = srcDirInfo.GetFiles("*.*", 
+                recursively ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
+
+            foreach (FileInfo fileInfo in fileInfoArr)
+            {
+                if (!fileInfo.Extension.Equals(".bak", StringComparison.OrdinalIgnoreCase))
+                {
+                    string entryName = fileInfo.FullName.Substring(srcDirLen).Replace('\\', '/');
+                    zipArchive.CreateEntryFromFile(fileInfo.FullName, entryPrefix + entryName,
+                        CompressionLevel.Fastest);
+                }
+            }
+        }
+
+        /// 
+        /// Упаковать базу конфигурации
+        /// 
+        private void PackBase(ZipArchive zipArchive)
+        {
+            PackDir(zipArchive, Settings.Directory + "BaseDAT", false, "BaseDAT/");
+        }
+
+        /// 
+        /// Упаковать конфигурацию сервера
+        /// 
+        private void PackServerConfig(ZipArchive zipArchive)
+        {
+            PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaServer", "Config"), true, 
+                "ScadaServer/Config/");
+        }
+
+
         /// 
         /// Проверить пароль и права пользователя
         /// 
@@ -83,7 +149,30 @@ public bool ValidateUser(string username, string encryptedPassword, out string e
         /// 
         public bool PackConfig(string destFileName, ConfigOptions configOptions)
         {
-            return false;
+            try
+            {
+                using (FileStream fileStream = 
+                    new FileStream(destFileName, FileMode.Create, FileAccess.Write, FileShare.None))
+                {
+                    ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create);
+
+                    if (configOptions.ConfigParts.HasFlag(ConfigParts.Base))
+                        PackBase(zipArchive);
+
+                    if (configOptions.ConfigParts.HasFlag(ConfigParts.Server))
+                        PackServerConfig(zipArchive);
+
+                    return true;
+                }
+
+            }
+            catch (Exception ex)
+            {
+                log.WriteException(ex, Localization.UseRussian ? 
+                    "Ошибка при упаковке конфигурации в архив" :
+                    "Error packing configuration into archive");
+                return false;
+            }
         }
 
         /// 
diff --git a/ScadaAgent/ScadaAgentCore/Settings.cs b/ScadaAgent/ScadaAgentCore/Settings.cs
index 1af210ffe..179c2068c 100644
--- a/ScadaAgent/ScadaAgentCore/Settings.cs
+++ b/ScadaAgent/ScadaAgentCore/Settings.cs
@@ -92,7 +92,7 @@ public bool Load(string fileName, out string errMsg)
                         ScadaInstanceSettings instanceSettings = new ScadaInstanceSettings()
                         {
                             Name = instanceElem.GetAttribute("name"),
-                            Directory = instanceElem.GetAttribute("directory")
+                            Directory = ScadaUtils.NormalDir(instanceElem.GetAttribute("directory"))
                         };
 
                         Instances[instanceSettings.Name] = instanceSettings;
diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs
index 92a15e5c8..efbdeb042 100644
--- a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs
+++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs
@@ -37,29 +37,29 @@ private void InitializeComponent()
             // 
             this.button1.Location = new System.Drawing.Point(12, 12);
             this.button1.Name = "button1";
-            this.button1.Size = new System.Drawing.Size(75, 23);
+            this.button1.Size = new System.Drawing.Size(100, 23);
             this.button1.TabIndex = 0;
-            this.button1.Text = "button1";
+            this.button1.Text = "Create Session";
             this.button1.UseVisualStyleBackColor = true;
             this.button1.Click += new System.EventHandler(this.button1_Click);
             // 
             // button2
             // 
-            this.button2.Location = new System.Drawing.Point(93, 12);
+            this.button2.Location = new System.Drawing.Point(118, 12);
             this.button2.Name = "button2";
-            this.button2.Size = new System.Drawing.Size(75, 23);
+            this.button2.Size = new System.Drawing.Size(100, 23);
             this.button2.TabIndex = 1;
-            this.button2.Text = "button2";
+            this.button2.Text = "Download";
             this.button2.UseVisualStyleBackColor = true;
             this.button2.Click += new System.EventHandler(this.button2_Click);
             // 
             // button3
             // 
-            this.button3.Location = new System.Drawing.Point(174, 12);
+            this.button3.Location = new System.Drawing.Point(224, 12);
             this.button3.Name = "button3";
-            this.button3.Size = new System.Drawing.Size(75, 23);
+            this.button3.Size = new System.Drawing.Size(100, 23);
             this.button3.TabIndex = 2;
-            this.button3.Text = "button3";
+            this.button3.Text = "Upload";
             this.button3.UseVisualStyleBackColor = true;
             this.button3.Click += new System.EventHandler(this.button3_Click);
             // 
diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
index e73b83def..179a4d5ef 100644
--- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
+++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
@@ -7,18 +7,40 @@ namespace Scada.Agent.Ctrl
 {
     public partial class FrmMain : Form
     {
+        private long sessionID = 0;
+
+
         public FrmMain()
         {
             InitializeComponent();
         }
 
+
         private void button1_Click(object sender, System.EventArgs e)
         {
             AgentSvcClient client = new AgentSvcClient();
 
             try
             {
-                Stream stream = client.DownloadFile(0, new RelPath());
+                client.CreateSession(out sessionID);
+                client.Login(sessionID, "admin", "", "Default");
+                MessageBox.Show("Session ID = " + sessionID);
+            }
+            finally
+            {
+                client.Close();
+            }
+        }
+
+        private void button2_Click(object sender, System.EventArgs e)
+        {
+            AgentSvcClient client = new AgentSvcClient();
+
+            try
+            {
+                //Stream stream = client.DownloadFile(sessionID, new RelPath());
+                Stream stream = client.DownloadConfig(sessionID, new ConfigOptions());
+
                 if (stream == null)
                 {
                     MessageBox.Show("Stream is null.");
@@ -27,7 +49,7 @@ private void button1_Click(object sender, System.EventArgs e)
                 {
                     DateTime t0 = DateTime.UtcNow;
                     byte[] buf = new byte[1024];
-                    Stream saver = File.Create(@"D:\file1.txt");
+                    Stream saver = File.Create(@"C:\SCADA\file1.txt");
                     int cnt;
 
                     while ((cnt = stream.Read(buf, 0, buf.Length)) > 0)
@@ -49,7 +71,7 @@ private void button1_Click(object sender, System.EventArgs e)
             }
         }
 
-        private void button2_Click(object sender, System.EventArgs e)
+        private void button3_Click(object sender, EventArgs e)
         {
             AgentSvcClient client = new AgentSvcClient();
             Stream stream = null;
@@ -63,8 +85,8 @@ private void button2_Click(object sender, System.EventArgs e)
                 stream.Write(buffer, 0, buffer.Length);
                 stream.Position = 0;*/
 
-                stream = File.Open(@"D:\big.txt", FileMode.Open);
-                client.UploadConfig(configOptions, 0, stream);
+                stream = File.Open(@"C:\SCADA\big.txt", FileMode.Open);
+                client.UploadConfig(configOptions, sessionID, stream);
                 MessageBox.Show("Done");
             }
             finally
@@ -73,20 +95,5 @@ private void button2_Click(object sender, System.EventArgs e)
                 client.Close();
             }
         }
-
-        private void button3_Click(object sender, EventArgs e)
-        {
-            AgentSvcClient client = new AgentSvcClient();
-
-            try
-            {
-                client.CreateSession(out long sessionID);
-                MessageBox.Show("Session ID = " + sessionID);
-            }
-            finally
-            {
-                client.Close();
-            }
-        }
     }
 }

From ae8e76ab24ab60b48f0a250a77e7e12095749d9e Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 24 Apr 2018 17:20:45 +0300
Subject: [PATCH 034/100] LangPack: fix es-LA

---
 LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml    | 4 ++--
 LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml     | 2 +-
 LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml    | 2 +-
 LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml        | 2 +-
 LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml       | 2 +-
 LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml          | 2 +-
 LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml         | 2 +-
 LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml      | 2 +-
 LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml      | 2 +-
 .../v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml   | 2 +-
 .../ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml        | 2 +-
 LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml    | 2 +-
 .../v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml    | 2 +-
 13 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml
index 4122b75d2..55fd3e006 100644
--- a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     El archivo de base de datos de la configuración en el formato de SDF {0} no encontrado.
@@ -12,7 +12,7 @@
     El archivo de la importación es indefinido.
     El archivo de la importación no existe.
     Importar configuracion de Base de Datos
-    Importar tabla de configuracion Base de Datos; "{0}"Importar tabla de configuracion Base de Datos; "{0}"
     Archivo de Origen: 
     Error al Importar carga de tabla
     Columnas de la tabla de la Origen
diff --git a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml
index c50ac008d..12fe3cc3c 100644
--- a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Información
diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml
index 8c204b177..237a776aa 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Error al cargar agenda de direcciones
diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml
index a3a80a700..908d88af3 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Email - Dispositivo {0} Configuracion
diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml
index d78ab7ec5..ef075a93b 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     MODBUS. Editor de la plantilla del dispositivo
diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml
index a5bfdfb43..de2c41e66 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     0} configuraciones del dispositivo {
diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml
index 63cd6b548..4528fde49 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     SNMP - {0} configuraciones del dispositivo
diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml
index 365ba687d..df847aea9 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Importación de líneas y dispositivos de comunicación
diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml
index b6e9742b2..1659e43d9 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Información
diff --git a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml
index 0ea99d03e..171c5d36b 100644
--- a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Información
diff --git a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml
index 3f2c743c2..901ef3ef6 100644
--- a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     SCADA-Scheme Editor
diff --git a/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml
index b2d3dea40..4575ea8c0 100644
--- a/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Información
diff --git a/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml
index 6f7630a4e..19482da3d 100644
--- a/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml
@@ -1,4 +1,4 @@
-
+
 
   
     Información

From b52fb2869b61a9896e973c98d9ea647dba52c1b9 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 24 Apr 2018 17:34:53 +0300
Subject: [PATCH 035/100] ScadaAgent: dev2

---
 ScadaAgent/ScadaAgentCore/ConfigParts.cs      | 13 ++--
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs    | 62 ++++++++-----------
 .../ServiceReference1/item2.xsd               | 15 +++--
 3 files changed, 46 insertions(+), 44 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/ConfigParts.cs b/ScadaAgent/ScadaAgentCore/ConfigParts.cs
index e86520282..38adc58ff 100644
--- a/ScadaAgent/ScadaAgentCore/ConfigParts.cs
+++ b/ScadaAgent/ScadaAgentCore/ConfigParts.cs
@@ -44,24 +44,29 @@ public enum ConfigParts
         /// 
         Base = 1,
 
+        /// 
+        /// Интерфейс
+        /// 
+        Interface = 2,
+
         /// 
         /// Сервер
         /// 
-        Server = 2,
+        Server = 4,
 
         /// 
         /// Коммуникатор
         /// 
-        Communicator = 4,
+        Communicator = 8,
 
         /// 
         /// Вебстанция
         /// 
-        Webstation = 8,
+        Webstation = 16,
 
         /// 
         /// Вся конфигурация
         /// 
-        All = Base | Server | Communicator | Webstation
+        All = Base | Interface | Server | Communicator | Webstation
     }
 }
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 7e4fa367b..9c5c376cf 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -24,6 +24,7 @@
  */
 
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.IO.Compression;
 using Utils;
@@ -75,23 +76,12 @@ public ScadaInstance(ScadaInstanceSettings settings, object syncRoot, ILog log)
 
 
         /// 
-        /// Получить директорию части конфигурации
+        /// ???
         /// 
-        private string GetConfigPartDir(ConfigParts configPart)
+        private void MakeAbsolutePath(ICollection relPaths, out List dirs, out List fileNames)
         {
-            switch (configPart)
-            {
-                case ConfigParts.Base:
-                    return Settings.Directory + "BaseDAT" + Path.DirectorySeparatorChar;
-                case ConfigParts.Server:
-                    return Settings.Directory + "ScadaServer" + Path.DirectorySeparatorChar;
-                case ConfigParts.Communicator:
-                    return Settings.Directory + "ScadaComm" + Path.DirectorySeparatorChar;
-                case ConfigParts.Webstation:
-                    return Settings.Directory + "ScadaWeb" + Path.DirectorySeparatorChar;
-                default:
-                    return "";
-            }
+            dirs = null;
+            fileNames = null;
         }
 
         /// 
@@ -116,23 +106,6 @@ private void PackDir(ZipArchive zipArchive, string srcDir, bool recursively, str
             }
         }
 
-        /// 
-        /// Упаковать базу конфигурации
-        /// 
-        private void PackBase(ZipArchive zipArchive)
-        {
-            PackDir(zipArchive, Settings.Directory + "BaseDAT", false, "BaseDAT/");
-        }
-
-        /// 
-        /// Упаковать конфигурацию сервера
-        /// 
-        private void PackServerConfig(ZipArchive zipArchive)
-        {
-            PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaServer", "Config"), true, 
-                "ScadaServer/Config/");
-        }
-
 
         /// 
         /// Проверить пароль и права пользователя
@@ -155,12 +128,29 @@ public bool PackConfig(string destFileName, ConfigOptions configOptions)
                     new FileStream(destFileName, FileMode.Create, FileAccess.Write, FileShare.None))
                 {
                     ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create);
+                    ConfigParts configParts = configOptions.ConfigParts;
+
+                    if (configParts.HasFlag(ConfigParts.Base))
+                        PackDir(zipArchive, Settings.Directory + "BaseDAT", false, "BaseDAT/");
+
+                    if (configParts.HasFlag(ConfigParts.Interface))
+                        PackDir(zipArchive, Settings.Directory + "Interface", true, "Interface/");
+
+                    if (configParts.HasFlag(ConfigParts.Server))
+                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaServer", "Config"), true,
+                            "ScadaServer/Config/");
 
-                    if (configOptions.ConfigParts.HasFlag(ConfigParts.Base))
-                        PackBase(zipArchive);
+                    if (configParts.HasFlag(ConfigParts.Communicator))
+                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaComm", "Config"), true,
+                            "ScadaComm/Config/");
 
-                    if (configOptions.ConfigParts.HasFlag(ConfigParts.Server))
-                        PackServerConfig(zipArchive);
+                    if (configParts.HasFlag(ConfigParts.Webstation))
+                    {
+                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaWeb", "config"), true, 
+                            "ScadaWeb/config/");
+                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaWeb", "storage"), true,
+                            "ScadaWeb/storage/");
+                    }
 
                     return true;
                 }
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd
index 7e4ff1cb5..7afd7a233 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd	
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd	
@@ -34,31 +34,38 @@
               
             
           
-          
+          
             
               
                 2
               
             
           
-          
+          
             
               
                 4
               
             
           
-          
+          
             
               
                 8
               
             
           
+          
+            
+              
+                16
+              
+            
+          
           
             
               
-                15
+                31
               
             
           

From f52628fe4c6769204c921053e78f2fbc1c43d404 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Wed, 25 Apr 2018 19:24:50 +0300
Subject: [PATCH 036/100] ScadaAgent: pach/unpack config

---
 ScadaAgent/ScadaAgentCore/RelPath.cs          |   2 +-
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs    | 369 ++++++++++++++++--
 ScadaAgent/ScadaAgentCtrl/FrmMain.cs          |   7 +-
 .../Config/ScadaAgentConfig.xml               |   2 +-
 4 files changed, 335 insertions(+), 45 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/RelPath.cs b/ScadaAgent/ScadaAgentCore/RelPath.cs
index 89d8bdb9c..4c53a7dca 100644
--- a/ScadaAgent/ScadaAgentCore/RelPath.cs
+++ b/ScadaAgent/ScadaAgentCore/RelPath.cs
@@ -42,7 +42,7 @@ public RelPath()
         /// 
         /// Конструктор
         /// 
-        public RelPath(ConfigParts configPart, AppFolder appFolder, string path)
+        public RelPath(ConfigParts configPart, AppFolder appFolder, string path = "")
         {
             ConfigPart = configPart;
             AppFolder = appFolder;
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 9c5c376cf..f059a901f 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -37,6 +37,66 @@ namespace Scada.Agent
     /// 
     public class ScadaInstance
     {
+        /// 
+        /// Список путей
+        /// 
+        private class PathList
+        {
+            /// 
+            /// Конструктор
+            /// 
+            public PathList()
+            {
+                Dirs = new List();
+                Files = new List();
+            }
+
+            /// 
+            /// Получить абсолютные пути директорий
+            /// 
+            public List Dirs { get; private set; }
+            /// 
+            /// Получить абсолютные пути файлов
+            /// 
+            public List Files { get; private set; }
+        }
+
+        /// 
+        /// Справочник путей, сгруппированных по частям конфигурации и папкам приложения
+        /// 
+        private class PathDict : Dictionary>
+        {
+            /// 
+            /// Получить или создать список путей
+            /// 
+            public PathList GetOrAdd(ConfigParts configPart, AppFolder appFolder)
+            {
+                Dictionary subDict;
+                PathList pathList;
+
+                if (TryGetValue(configPart, out subDict))
+                {
+                    if (subDict.TryGetValue(appFolder, out pathList))
+                        return pathList;
+                }
+                else
+                {
+                    subDict = new Dictionary();
+                    this[configPart] = subDict;
+                }
+
+                pathList = new PathList();
+                subDict[appFolder] = pathList;
+                return pathList;
+            }
+        }
+
+        /// 
+        /// Все части конфигурации в виде массива
+        /// 
+        private static ConfigParts[] AllConfigParts = { ConfigParts.Base, ConfigParts.Interface,
+            ConfigParts.Server, ConfigParts.Communicator, ConfigParts.Webstation };
+
         private ILog log; // журнал приложения
 
 
@@ -76,36 +136,230 @@ public ScadaInstance(ScadaInstanceSettings settings, object syncRoot, ILog log)
 
 
         /// 
-        /// ???
+        /// Получить относительные пути конфигурации, соответствующие заданным частям
         /// 
-        private void MakeAbsolutePath(ICollection relPaths, out List dirs, out List fileNames)
+        private List GetConfigPaths(ConfigParts configParts)
         {
-            dirs = null;
-            fileNames = null;
+            List configPaths = new List();
+
+            if (configParts.HasFlag(ConfigParts.Base))
+                configPaths.Add(new RelPath(ConfigParts.Base, AppFolder.Root));
+
+            if (configParts.HasFlag(ConfigParts.Interface))
+                configPaths.Add(new RelPath(ConfigParts.Interface, AppFolder.Root));
+
+            if (configParts.HasFlag(ConfigParts.Server))
+                configPaths.Add(new RelPath(ConfigParts.Server, AppFolder.Config));
+
+            if (configParts.HasFlag(ConfigParts.Communicator))
+                configPaths.Add(new RelPath(ConfigParts.Communicator, AppFolder.Config));
+
+            if (configParts.HasFlag(ConfigParts.Webstation))
+            {
+                configPaths.Add(new RelPath(ConfigParts.Webstation, AppFolder.Config));
+                configPaths.Add(new RelPath(ConfigParts.Webstation, AppFolder.Storage));
+            }
+
+            return configPaths;
+        }
+
+        /// 
+        /// Получить директорию части конфигурации
+        /// 
+        private string GetConfigPartDir(ConfigParts configPart, char? directorySeparator)
+        {
+            switch (configPart)
+            {
+                case ConfigParts.Base:
+                    return "BaseDAT" + directorySeparator;
+                case ConfigParts.Interface:
+                    return "Interface" + directorySeparator;
+                case ConfigParts.Server:
+                    return "ScadaServer" + directorySeparator;
+                case ConfigParts.Communicator:
+                    return "ScadaComm" + directorySeparator;
+                case ConfigParts.Webstation:
+                    return "ScadaWeb" + directorySeparator;
+                default:
+                    throw new ArgumentException("Incorrect configuration part.");
+            }
+        }
+
+        /// 
+        /// Получить директорию папки приложения
+        /// 
+        private string GetAppFolderDir(AppFolder appFolder, char? directorySeparator, bool lowerCase = false)
+        {
+            string dir;
+
+            switch (appFolder)
+            {
+                case AppFolder.Config:
+                    dir = "Config" + directorySeparator;
+                    break;
+                case AppFolder.Log:
+                    dir = "Log" + directorySeparator;
+                    break;
+                case AppFolder.Storage:
+                    dir = "Storage" + directorySeparator;
+                    break;
+                default:
+                    dir = "";
+                    break;
+            }
+
+            return lowerCase ? dir.ToLowerInvariant() : dir;
+        }
+
+        /// 
+        /// Получить директорию папки приложения
+        /// 
+        private string GetAppFolderDir(ConfigParts configPart, AppFolder appFolder, char directorySeparator)
+        {
+            return GetConfigPartDir(configPart, directorySeparator) +
+                GetAppFolderDir(appFolder, directorySeparator, configPart == ConfigParts.Webstation);
+        }
+
+        /// 
+        /// Получить абсолютный путь из относительного
+        /// 
+        private string GetAbsPath(RelPath relPath)
+        {
+            return Path.Combine(Settings.Directory, 
+                GetConfigPartDir(relPath.ConfigPart, null), 
+                GetAppFolderDir(relPath.AppFolder, null, relPath.ConfigPart == ConfigParts.Webstation), 
+                relPath.Path);
+        }
+
+        /// 
+        /// Разделить исключаемые пути по группам
+        /// 
+        private PathDict SeparatePaths(ICollection relPaths)
+        {
+            PathDict pathDict = new PathDict();
+
+            foreach (RelPath relPath in relPaths)
+            {
+                PathList pathList = pathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder);
+                string absPath = GetAbsPath(relPath);
+                char lastPathSym = absPath[absPath.Length - 1];
+
+                if (lastPathSym == Path.DirectorySeparatorChar || lastPathSym == Path.AltDirectorySeparatorChar)
+                    pathList.Dirs.Add(absPath);
+                else
+                    pathList.Files.Add(absPath);
+            }
+
+            return pathDict;
         }
 
         /// 
         /// Упаковать директорию
         /// 
-        private void PackDir(ZipArchive zipArchive, string srcDir, bool recursively, string entryPrefix)
+        private void PackDir(ZipArchive zipArchive, string srcDir, string entryPrefix, PathList excludedPaths)
         {
             srcDir = ScadaUtils.NormalDir(srcDir);
-            int srcDirLen = srcDir.Length;
-            DirectoryInfo srcDirInfo = new DirectoryInfo(srcDir);
-            FileInfo[] fileInfoArr = srcDirInfo.GetFiles("*.*", 
-                recursively ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
 
-            foreach (FileInfo fileInfo in fileInfoArr)
+            if (!excludedPaths.Dirs.Contains(srcDir))
+            {
+                DirectoryInfo srcDirInfo = new DirectoryInfo(srcDir);
+
+                // упаковка поддиректорий
+                DirectoryInfo[] dirInfoArr = srcDirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
+
+                foreach (DirectoryInfo dirInfo in dirInfoArr)
+                {
+                    PackDir(zipArchive, dirInfo.FullName, entryPrefix + dirInfo.Name + "/", excludedPaths);
+                }
+
+                // упаковка файлов
+                FileInfo[] fileInfoArr = srcDirInfo.GetFiles("*", SearchOption.TopDirectoryOnly);
+                int srcDirLen = srcDir.Length;
+
+                foreach (FileInfo fileInfo in fileInfoArr)
+                {
+                    if (!excludedPaths.Files.Contains(fileInfo.FullName) &&
+                        !fileInfo.Extension.Equals(".bak", StringComparison.OrdinalIgnoreCase))
+                    {
+                        string entryName = fileInfo.FullName.Substring(srcDirLen).Replace('\\', '/');
+                        zipArchive.CreateEntryFromFile(fileInfo.FullName, entryPrefix + entryName,
+                            CompressionLevel.Fastest);
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Упаковать директорию
+        /// 
+        private void PackDir(ZipArchive zipArchive, RelPath relPath, PathDict excludedPathDict)
+        {
+            PackDir(zipArchive, 
+                GetAbsPath(relPath),
+                GetAppFolderDir(relPath.ConfigPart, relPath.AppFolder, '/'), 
+                excludedPathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder));
+        }
+
+        /// 
+        /// Очистить директорию
+        /// 
+        private void ClearDir(string dir, PathList excludedPaths, out bool dirEmpty)
+        {
+            if (excludedPaths.Dirs.Contains(dir))
             {
-                if (!fileInfo.Extension.Equals(".bak", StringComparison.OrdinalIgnoreCase))
+                dirEmpty = false;
+            }
+            else
+            {
+                DirectoryInfo dirInfo = new DirectoryInfo(dir);
+
+                // очистка поддиректорий
+                DirectoryInfo[] subdirInfoArr = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
+
+                foreach (DirectoryInfo subdirInfo in subdirInfoArr)
                 {
-                    string entryName = fileInfo.FullName.Substring(srcDirLen).Replace('\\', '/');
-                    zipArchive.CreateEntryFromFile(fileInfo.FullName, entryPrefix + entryName,
-                        CompressionLevel.Fastest);
+                    ClearDir(subdirInfo.FullName, excludedPaths, out bool subdirEmpty);
+                    if (subdirEmpty)
+                        subdirInfo.Delete();
+                }
+
+                // удаление файлов
+                FileInfo[] fileInfoArr = dirInfo.GetFiles("*", SearchOption.TopDirectoryOnly);
+                dirEmpty = true;
+
+                foreach (FileInfo fileInfo in fileInfoArr)
+                {
+                    if (excludedPaths.Files.Contains(fileInfo.FullName))
+                        dirEmpty = false;
+                    else
+                        fileInfo.Delete();
                 }
             }
         }
 
+        /// 
+        /// Очистить директорию
+        /// 
+        private void ClearDir(RelPath relPath, PathDict excludedPathDict)
+        {
+            ClearDir(GetAbsPath(relPath), excludedPathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder), 
+                out bool dirEmpty);
+        }
+
+        /// 
+        /// Проверить, что строка начинается хотя бы с одного из заданных значений
+        /// 
+        private bool StartsWith(string s, ICollection values, StringComparison comparisonType)
+        {
+            foreach (string val in values)
+            {
+                if (s.StartsWith(val, comparisonType))
+                    return true;
+            }
+
+            return false;
+        }
+
 
         /// 
         /// Проверить пароль и права пользователя
@@ -124,37 +378,22 @@ public bool PackConfig(string destFileName, ConfigOptions configOptions)
         {
             try
             {
+                List configPaths = GetConfigPaths(configOptions.ConfigParts);
+                PathDict pathDict = SeparatePaths(configOptions.ExcludedPaths);
+
                 using (FileStream fileStream = 
                     new FileStream(destFileName, FileMode.Create, FileAccess.Write, FileShare.None))
                 {
-                    ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create);
-                    ConfigParts configParts = configOptions.ConfigParts;
-
-                    if (configParts.HasFlag(ConfigParts.Base))
-                        PackDir(zipArchive, Settings.Directory + "BaseDAT", false, "BaseDAT/");
-
-                    if (configParts.HasFlag(ConfigParts.Interface))
-                        PackDir(zipArchive, Settings.Directory + "Interface", true, "Interface/");
-
-                    if (configParts.HasFlag(ConfigParts.Server))
-                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaServer", "Config"), true,
-                            "ScadaServer/Config/");
-
-                    if (configParts.HasFlag(ConfigParts.Communicator))
-                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaComm", "Config"), true,
-                            "ScadaComm/Config/");
-
-                    if (configParts.HasFlag(ConfigParts.Webstation))
+                    using (ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create))
                     {
-                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaWeb", "config"), true, 
-                            "ScadaWeb/config/");
-                        PackDir(zipArchive, Path.Combine(Settings.Directory, "ScadaWeb", "storage"), true,
-                            "ScadaWeb/storage/");
-                    }
+                        foreach (RelPath relPath in configPaths)
+                        {
+                            PackDir(zipArchive, relPath, pathDict);
+                        }
 
-                    return true;
+                        return true;
+                    }
                 }
-
             }
             catch (Exception ex)
             {
@@ -170,7 +409,57 @@ public bool PackConfig(string destFileName, ConfigOptions configOptions)
         /// 
         public bool UnpackConfig(string srcFileName, ConfigOptions configOptions)
         {
-            return false;
+            try
+            {
+                // удаление существующей конфигурации
+                List configPaths = GetConfigPaths(configOptions.ConfigParts);
+                PathDict pathDict = SeparatePaths(configOptions.ExcludedPaths);
+
+                foreach (RelPath relPath in configPaths)
+                {
+                    ClearDir(relPath, pathDict);
+                }
+
+                // определение допустимых директорий для распаковки
+                ConfigParts configParts = configOptions.ConfigParts;
+                List allowedEntries = new List(AllConfigParts.Length);
+
+                foreach (ConfigParts configPart in AllConfigParts)
+                {
+                    if (configParts.HasFlag(configPart))
+                        allowedEntries.Add(GetConfigPartDir(configPart, '/'));
+                }
+
+                // распаковка новой конфигурации
+                using (FileStream fileStream =
+                    new FileStream(srcFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
+                {
+                    using (ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read))
+                    {
+                        string instanceDir = Settings.Directory;
+
+                        foreach (ZipArchiveEntry entry in zipArchive.Entries)
+                        {
+                            if (StartsWith(entry.FullName, allowedEntries, StringComparison.Ordinal))
+                            {
+                                string relPath = entry.FullName.Replace('/', Path.DirectorySeparatorChar);
+                                string destFileName = instanceDir + relPath;
+                                Directory.CreateDirectory(Path.GetDirectoryName(destFileName));
+                                entry.ExtractToFile(destFileName, true);
+                            }
+                        }
+
+                        return true;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                log.WriteException(ex, Localization.UseRussian ?
+                    "Ошибка при распаковке конфигурации из архива" :
+                    "Error unpacking configuration from archive");
+                return false;
+            }
         }
     }
 }
diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
index 179a4d5ef..07f16f60e 100644
--- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
+++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
@@ -49,7 +49,7 @@ private void button2_Click(object sender, System.EventArgs e)
                 {
                     DateTime t0 = DateTime.UtcNow;
                     byte[] buf = new byte[1024];
-                    Stream saver = File.Create(@"C:\SCADA\file1.txt");
+                    Stream saver = File.Create(@"C:\SCADA\config.zip");
                     int cnt;
 
                     while ((cnt = stream.Read(buf, 0, buf.Length)) > 0)
@@ -78,6 +78,7 @@ private void button3_Click(object sender, EventArgs e)
 
             try
             {
+                DateTime t0 = DateTime.UtcNow;
                 ConfigOptions configOptions = new ConfigOptions();
 
                 /*byte[] buffer = System.Text.Encoding.ASCII.GetBytes("I'm Muzzy");
@@ -85,9 +86,9 @@ private void button3_Click(object sender, EventArgs e)
                 stream.Write(buffer, 0, buffer.Length);
                 stream.Position = 0;*/
 
-                stream = File.Open(@"C:\SCADA\big.txt", FileMode.Open);
+                stream = File.Open(@"C:\SCADA\config.zip", FileMode.Open);
                 client.UploadConfig(configOptions, sessionID, stream);
-                MessageBox.Show("Done");
+                MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms");
             }
             finally
             {
diff --git a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
index 4b43785bd..aeae44626 100644
--- a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
+++ b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
@@ -1,6 +1,6 @@
 
 
   
-    
+    
   
 
\ No newline at end of file

From e1680a794e3239bd65c5d81ac726564da32a02f6 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Thu, 26 Apr 2018 11:45:31 +0300
Subject: [PATCH 037/100] ScadaAgent: work with files

---
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs | 93 +++++++++++++++++++---
 ScadaAgent/ScadaAgentNet/AgentSvc.cs       | 65 +++++++++++----
 2 files changed, 133 insertions(+), 25 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index f059a901f..8967ec1c5 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -220,17 +220,6 @@ private string GetAppFolderDir(ConfigParts configPart, AppFolder appFolder, char
                 GetAppFolderDir(appFolder, directorySeparator, configPart == ConfigParts.Webstation);
         }
 
-        /// 
-        /// Получить абсолютный путь из относительного
-        /// 
-        private string GetAbsPath(RelPath relPath)
-        {
-            return Path.Combine(Settings.Directory, 
-                GetConfigPartDir(relPath.ConfigPart, null), 
-                GetAppFolderDir(relPath.AppFolder, null, relPath.ConfigPart == ConfigParts.Webstation), 
-                relPath.Path);
-        }
-
         /// 
         /// Разделить исключаемые пути по группам
         /// 
@@ -371,6 +360,47 @@ public bool ValidateUser(string username, string encryptedPassword, out string e
             return true;
         }
 
+        /// 
+        /// Получить абсолютный путь из относительного
+        /// 
+        public string GetAbsPath(RelPath relPath)
+        {
+            return Path.Combine(Settings.Directory,
+                GetConfigPartDir(relPath.ConfigPart, null),
+                GetAppFolderDir(relPath.AppFolder, null, relPath.ConfigPart == ConfigParts.Webstation),
+                relPath.Path);
+        }
+
+        /// 
+        /// Получить доступные части конфигурации
+        /// 
+        public bool GetAvailableConfig(out ConfigParts configParts)
+        {
+            try
+            {
+                configParts = ConfigParts.None;
+
+                foreach (ConfigParts configPart in AllConfigParts)
+                {
+                    string configPartDir = Settings.Directory + 
+                        GetConfigPartDir(configPart, Path.DirectorySeparatorChar);
+
+                    if (Directory.Exists(configPartDir))
+                        configParts |= configPart;
+                }
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                log.WriteException(ex, Localization.UseRussian ?
+                    "Ошибка при получении доступных частей конфигурации" :
+                    "Error getting available parts of the configuration");
+                configParts = ConfigParts.None;
+                return false;
+            }
+        }
+
         /// 
         /// Упаковать конфигурацию в архив
         /// 
@@ -461,5 +491,46 @@ public bool UnpackConfig(string srcFileName, ConfigOptions configOptions)
                 return false;
             }
         }
+
+        /// 
+        /// Обзор директории
+        /// 
+        public bool Browse(RelPath relPath, out ICollection directories, out ICollection files)
+        {
+            try
+            {
+                string absPath = GetAbsPath(relPath);
+                DirectoryInfo dirInfo = new DirectoryInfo(absPath);
+
+                // получение поддиректорий
+                directories = new List();
+                DirectoryInfo[] subdirInfoArr = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
+
+                foreach (DirectoryInfo subdirInfo in subdirInfoArr)
+                {
+                    directories.Add(subdirInfo.Name);
+                }
+
+                // получение файлов
+                files = new List();
+                FileInfo[] fileInfoArr = dirInfo.GetFiles("*", SearchOption.TopDirectoryOnly);
+
+                foreach (FileInfo fileInfo in fileInfoArr)
+                {
+                    files.Add(fileInfo.Name);
+                }
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                log.WriteException(ex, Localization.UseRussian ?
+                   "Ошибка при обзоре директории" :
+                   "Error browsing directory");
+                directories = null;
+                files = null;
+                return false;
+            }
+        }
     }
 }
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index 0969f4545..1279a0b84 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -252,8 +252,15 @@ public bool GetServiceStatus(long sessionID, ServiceApp serviceApp, out bool isR
         [OperationContract]
         public bool GetAvailableConfig(long sessionID, out ConfigParts configParts)
         {
-            configParts = ConfigParts.All;
-            return true;
+            if (TryGetScadaInstance(sessionID, out ScadaInstance scadaInstance))
+            {
+                return scadaInstance.GetAvailableConfig(out configParts);
+            }
+            else
+            {
+                configParts = ConfigParts.None;
+                return false;
+            }
         }
 
         /// 
@@ -306,13 +313,22 @@ public void UploadConfig(ConfigUploadMessage configUploadMessage)
         }
 
         /// 
-        /// Найти файлы
+        /// Обзор директории
         /// 
         [OperationContract]
-        public bool FindFiles(long sessionID, RelPath relPath, out ICollection paths)
+        public bool Browse(long sessionID, RelPath relPath, 
+            out ICollection directories, out ICollection files)
         {
-            paths = null;
-            return true;
+            if (TryGetScadaInstance(sessionID, out ScadaInstance scadaInstance))
+            {
+                return scadaInstance.Browse(relPath, out directories, out files);
+            }
+            else
+            {
+                directories = null;
+                files = null;
+                return false;
+            }
         }
 
         /// 
@@ -321,13 +337,7 @@ public bool FindFiles(long sessionID, RelPath relPath, out ICollection p
         [OperationContract]
         public Stream DownloadFile(long sessionID, RelPath relPath)
         {
-            /*byte[] buffer = System.Text.Encoding.ASCII.GetBytes("hello");
-            MemoryStream stream = new MemoryStream(buffer.Length);
-            stream.Write(buffer, 0, buffer.Length);
-            stream.Position = 0;*/
-
-            Stream stream = File.Open("big.txt", FileMode.Open);
-            return stream;
+            return DownloadFileRest(sessionID, relPath, 0);
         }
 
         /// 
@@ -336,7 +346,34 @@ public Stream DownloadFile(long sessionID, RelPath relPath)
         [OperationContract]
         public Stream DownloadFileRest(long sessionID, RelPath relPath, long position)
         {
-            return null;
+            if (TryGetScadaInstance(sessionID, out ScadaInstance scadaInstance))
+            {
+                try
+                {
+                    string path = scadaInstance.GetAbsPath(relPath);
+                    Stream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
+
+                    if (position > 0)
+                        stream.Position = position;
+
+                    return stream;
+                }
+                catch (FileNotFoundException)
+                {
+                    return null;
+                }
+                catch (Exception ex)
+                {
+                    Log.WriteException(ex, Localization.UseRussian ?
+                        "Ошибка при открытии файла" :
+                        "Error opening file");
+                    return null;
+                }
+            }
+            else
+            {
+                return null;
+            }
         }
     }
 }

From e6474a66d791c96ae17926d2353a8de3b4edce79 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Thu, 26 Apr 2018 15:10:19 +0300
Subject: [PATCH 038/100] ScadaAgent: control services

---
 ScadaAgent/ScadaAgentCore/AgentUtils.cs    |  13 ++
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs | 132 +++++++++++++++++++++
 ScadaAgent/ScadaAgentCore/ServiceApp.cs    |   2 +-
 ScadaAgent/ScadaAgentCore/ServiceStatus.cs |  54 +++++++++
 ScadaAgent/ScadaAgentNet/AgentSvc.cs       |  22 +++-
 5 files changed, 218 insertions(+), 5 deletions(-)
 create mode 100644 ScadaAgent/ScadaAgentCore/ServiceStatus.cs

diff --git a/ScadaAgent/ScadaAgentCore/AgentUtils.cs b/ScadaAgent/ScadaAgentCore/AgentUtils.cs
index 5d45169d9..4564ae456 100644
--- a/ScadaAgent/ScadaAgentCore/AgentUtils.cs
+++ b/ScadaAgent/ScadaAgentCore/AgentUtils.cs
@@ -23,6 +23,8 @@
  * Modified : 2018
  */
 
+using System.Runtime.InteropServices;
+
 namespace Scada.Agent
 {
     /// 
@@ -35,5 +37,16 @@ public static class AgentUtils
         /// Версия Агента
         /// 
         public const string AppVersion = "5.0.0.0";
+
+        /// 
+        /// Проверить, что программное обеспечение работает под управлением Windows
+        /// 
+        public static bool IsWindows
+        {
+            get
+            {
+                return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+            }
+        }
     }
 }
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 8967ec1c5..17a5e4cb0 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -25,8 +25,10 @@
 
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 using System.IO.Compression;
+using System.Text;
 using Utils;
 
 namespace Scada.Agent
@@ -135,6 +137,56 @@ public ScadaInstance(ScadaInstanceSettings settings, object syncRoot, ILog log)
         public object SyncRoot { get; private set; }
 
 
+        /// 
+        /// Получить директорию сервиса
+        /// 
+        private string GetServiceDir(ServiceApp serviceApp, char? directorySeparator)
+        {
+            switch (serviceApp)
+            {
+                case ServiceApp.Server:
+                    return GetConfigPartDir(ConfigParts.Server, directorySeparator);
+                case ServiceApp.Communicator:
+                    return GetConfigPartDir(ConfigParts.Communicator, directorySeparator);
+                default:
+                    throw new ArgumentException("Unknown service.");
+            }
+        }
+
+        /// 
+        /// Получить имя файла статуса сервиса
+        /// 
+        private string GetServiceStatusFile(ServiceApp serviceApp)
+        {
+            switch (serviceApp)
+            {
+                case ServiceApp.Server:
+                    return "ScadaServerSvc.txt";
+                case ServiceApp.Communicator:
+                    return "ScadaCommSvc.txt";
+                default:
+                    throw new ArgumentException("Unknown service.");
+            }
+        }
+
+        /// 
+        /// Получить имя файла команды сервиса
+        /// 
+        private string GetServiceBatchFile(ServiceCommand command)
+        {
+            string ext = AgentUtils.IsWindows ? ".bat" : ".sh";
+
+            switch (command)
+            {
+                case ServiceCommand.Start:
+                    return "svc_start" + ext;
+                case ServiceCommand.Stop:
+                    return "svc_stop" + ext;
+                default: // ServiceCommand.Restart
+                    return "svc_restart" + ext;
+            }
+        }
+
         /// 
         /// Получить относительные пути конфигурации, соответствующие заданным частям
         /// 
@@ -360,6 +412,86 @@ public bool ValidateUser(string username, string encryptedPassword, out string e
             return true;
         }
 
+        /// 
+        /// Управлять службой
+        /// 
+        public bool ControlService(ServiceApp serviceApp, ServiceCommand command)
+        {
+            try
+            {
+                string batchFileName = Path.Combine(Settings.Directory,
+                    GetServiceDir(serviceApp, null), GetServiceBatchFile(command));
+                Process.Start(batchFileName);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                log.WriteException(ex, Localization.UseRussian ?
+                   "Ошибка при управлении службой" :
+                   "Error controlling service");
+                return false;
+            }
+        }
+
+        /// 
+        /// Получить статус службы
+        /// 
+        public bool GetServiceStatus(ServiceApp serviceApp, out ServiceStatus status)
+        {
+            try
+            {
+                status = ServiceStatus.Undefined;
+                string statusFileName = Path.Combine(Settings.Directory, 
+                    GetServiceDir(serviceApp, null), GetAppFolderDir(AppFolder.Log, null),
+                    GetServiceStatusFile(serviceApp));
+
+                if (File.Exists(statusFileName))
+                {
+                    string[] lines = File.ReadAllLines(statusFileName, Encoding.UTF8);
+
+                    foreach (string line in lines)
+                    {
+                        if (line.StartsWith("State", StringComparison.Ordinal) ||
+                            line.StartsWith("Состояние", StringComparison.Ordinal))
+                        {
+                            int colonInd = line.IndexOf(':');
+
+                            if (colonInd > 0)
+                            {
+                                string statusStr = line.Substring(colonInd + 1).Trim();
+
+                                if (statusStr.Equals("normal", StringComparison.OrdinalIgnoreCase) ||
+                                    statusStr.Equals("норма", StringComparison.OrdinalIgnoreCase))
+                                {
+                                    status = ServiceStatus.Normal;
+                                }
+                                else if (statusStr.Equals("stopped", StringComparison.OrdinalIgnoreCase) ||
+                                    statusStr.Equals("остановлен", StringComparison.OrdinalIgnoreCase))
+                                {
+                                    status = ServiceStatus.Stopped;
+                                }
+                                else if (statusStr.Equals("error", StringComparison.OrdinalIgnoreCase) ||
+                                    statusStr.Equals("ошибка", StringComparison.OrdinalIgnoreCase))
+                                {
+                                    status = ServiceStatus.Error;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                log.WriteException(ex, Localization.UseRussian ?
+                   "Ошибка при получении статуса службы" :
+                   "Error getting service status");
+                status = ServiceStatus.Undefined;
+                return false;
+            }
+        }
+
         /// 
         /// Получить абсолютный путь из относительного
         /// 
diff --git a/ScadaAgent/ScadaAgentCore/ServiceApp.cs b/ScadaAgent/ScadaAgentCore/ServiceApp.cs
index c6e39f309..911c4c7e8 100644
--- a/ScadaAgent/ScadaAgentCore/ServiceApp.cs
+++ b/ScadaAgent/ScadaAgentCore/ServiceApp.cs
@@ -27,7 +27,7 @@ namespace Scada.Agent
 {
     /// 
     /// Service applications
-    /// Приложения-сервисы
+    /// Приложения-службы
     /// 
     public enum ServiceApp
     {
diff --git a/ScadaAgent/ScadaAgentCore/ServiceStatus.cs b/ScadaAgent/ScadaAgentCore/ServiceStatus.cs
new file mode 100644
index 000000000..437e9f04f
--- /dev/null
+++ b/ScadaAgent/ScadaAgentCore/ServiceStatus.cs
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : ScadaAgentCore
+ * Summary  : Service statuses
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+namespace Scada.Agent
+{
+    /// 
+    /// Service statuses
+    /// Статусы службы
+    /// 
+    public enum ServiceStatus
+    {
+        /// 
+        /// Не определён
+        /// 
+        Undefined,
+
+        /// 
+        /// Норма
+        /// 
+        Normal,
+
+        /// 
+        /// Остановлен
+        /// 
+        Stopped,
+
+        /// 
+        /// Ошибка
+        /// 
+        Error
+    }
+}
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index 1279a0b84..a4382cd60 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -233,17 +233,31 @@ public bool Login(long sessionID, string username, string encryptedPassword, str
         [OperationContract]
         public bool ControlService(long sessionID, ServiceApp serviceApp, ServiceCommand command)
         {
-            return true;
+            if (TryGetScadaInstance(sessionID, out ScadaInstance scadaInstance))
+            {
+                return scadaInstance.ControlService(serviceApp, command);
+            }
+            else
+            {
+                return false;
+            }
         }
 
         /// 
         /// Получить статус службы
         /// 
         [OperationContract]
-        public bool GetServiceStatus(long sessionID, ServiceApp serviceApp, out bool isRunning)
+        public bool GetServiceStatus(long sessionID, ServiceApp serviceApp, out ServiceStatus status)
         {
-            isRunning = true;
-            return true;
+            if (TryGetScadaInstance(sessionID, out ScadaInstance scadaInstance))
+            {
+                return scadaInstance.GetServiceStatus(serviceApp, out status);
+            }
+            else
+            {
+                status = ServiceStatus.Undefined;
+                return false;
+            }
         }
 
         /// 

From 539ffe274763dae59bb7da2cb17470abae4da762 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Thu, 26 Apr 2018 16:43:37 +0300
Subject: [PATCH 039/100] ScadaAgent: dev

---
 ScadaAgent/ScadaAgentCore/CryptoUtils.cs      |  19 +++
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs    |   2 +-
 .../ServiceReference1/AgentSvc.wsdl           |  18 +--
 .../ServiceReference1/Reference.cs            | 138 +++++++++++++-----
 ...rviceReference1.BrowseResponse.datasource} |   4 +-
 ...ServiceReference1.LoginResponse.datasource |  10 ++
 .../ServiceReference1/item.xsd                |  32 ++--
 .../ServiceReference1/item2.xsd               |   9 ++
 ScadaAgent/ScadaAgentCtrl/FrmMain.cs          |   6 +-
 .../ScadaAgentCtrl/ScadaAgentCtrl.csproj      |   7 +-
 ScadaAgent/ScadaAgentNet/AgentSvc.cs          |  24 ++-
 11 files changed, 199 insertions(+), 70 deletions(-)
 rename ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/{Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource => Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource} (56%)
 create mode 100644 ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource

diff --git a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
index 686321b88..2aa8b10ac 100644
--- a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
+++ b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
@@ -39,6 +39,7 @@ public static class CryptoUtils
         /// 
         private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
 
+
         /// 
         /// Получить случайное 64-битное целое
         /// 
@@ -48,5 +49,23 @@ public static long GetRandomLong()
             Rng.GetBytes(randomArr);
             return BitConverter.ToInt64(randomArr, 0);
         }
+
+        /// 
+        /// Зашифровать пароль
+        /// 
+        public static string EncryptPassword(string password)
+        {
+            // TODO
+            return password;
+        }
+
+        /// 
+        /// Дешифровать пароль
+        /// 
+        public static string DecryptPassword(string encryptedPassword)
+        {
+            // TODO
+            return encryptedPassword;
+        }
     }
 }
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 17a5e4cb0..dbc7333b4 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -405,7 +405,7 @@ private bool StartsWith(string s, ICollection values, StringComparison c
         /// 
         /// Проверить пароль и права пользователя
         /// 
-        public bool ValidateUser(string username, string encryptedPassword, out string errMsg)
+        public bool ValidateUser(string username, string password, out string errMsg)
         {
             // TODO: реализовать и ограничить кол-во попыток
             errMsg = "";
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl
index 410c95f69..cee4e852c 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl	
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl	
@@ -53,11 +53,11 @@
     
   
   
-  
-    
+  
+    
   
-  
-    
+  
+    
   
   
     
@@ -100,9 +100,9 @@
       
       
     
-    
-      
-      
+    
+      
+      
     
     
       
@@ -180,8 +180,8 @@
         
       
     
-    
-      
+    
+      
       
         
       
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs
index df4aec15d..64168ad01 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs	
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs	
@@ -23,10 +23,11 @@ public interface AgentSvc {
         System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")]
-        bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName);
+        Scada.Agent.Ctrl.ServiceReference1.LoginResponse Login(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request);
         
+        // CODEGEN: Generating message contract since the operation has multiple return values.
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")]
-        System.Threading.Tasks.Task LoginAsync(long sessionID, string username, string encryptedPassword, string scadaInstanceName);
+        System.Threading.Tasks.Task LoginAsync(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")]
         bool ControlService(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command);
@@ -61,12 +62,12 @@ public interface AgentSvc {
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")]
         System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request);
         
-        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/FindFiles", ReplyAction="http://tempuri.org/AgentSvc/FindFilesResponse")]
-        Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse FindFiles(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request);
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")]
+        Scada.Agent.Ctrl.ServiceReference1.BrowseResponse Browse(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request);
         
         // CODEGEN: Generating message contract since the operation has multiple return values.
-        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/FindFiles", ReplyAction="http://tempuri.org/AgentSvc/FindFilesResponse")]
-        System.Threading.Tasks.Task FindFilesAsync(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request);
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")]
+        System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")]
         System.IO.Stream DownloadFile(long sessionID, Scada.Agent.RelPath relPath);
@@ -110,6 +111,54 @@ public CreateSessionResponse(bool CreateSessionResult, long sessionID) {
         }
     }
     
+    [System.Diagnostics.DebuggerStepThroughAttribute()]
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+    [System.ServiceModel.MessageContractAttribute(WrapperName="Login", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
+    public partial class LoginRequest {
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)]
+        public long sessionID;
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)]
+        public string username;
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=2)]
+        public string encryptedPassword;
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=3)]
+        public string scadaInstanceName;
+        
+        public LoginRequest() {
+        }
+        
+        public LoginRequest(long sessionID, string username, string encryptedPassword, string scadaInstanceName) {
+            this.sessionID = sessionID;
+            this.username = username;
+            this.encryptedPassword = encryptedPassword;
+            this.scadaInstanceName = scadaInstanceName;
+        }
+    }
+    
+    [System.Diagnostics.DebuggerStepThroughAttribute()]
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+    [System.ServiceModel.MessageContractAttribute(WrapperName="LoginResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
+    public partial class LoginResponse {
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)]
+        public bool LoginResult;
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)]
+        public string errMsg;
+        
+        public LoginResponse() {
+        }
+        
+        public LoginResponse(bool LoginResult, string errMsg) {
+            this.LoginResult = LoginResult;
+            this.errMsg = errMsg;
+        }
+    }
+    
     [System.Diagnostics.DebuggerStepThroughAttribute()]
     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
     [System.ServiceModel.MessageContractAttribute(WrapperName="GetServiceStatus", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
@@ -139,14 +188,14 @@ public partial class GetServiceStatusResponse {
         public bool GetServiceStatusResult;
         
         [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)]
-        public bool isRunning;
+        public Scada.Agent.ServiceStatus status;
         
         public GetServiceStatusResponse() {
         }
         
-        public GetServiceStatusResponse(bool GetServiceStatusResult, bool isRunning) {
+        public GetServiceStatusResponse(bool GetServiceStatusResult, Scada.Agent.ServiceStatus status) {
             this.GetServiceStatusResult = GetServiceStatusResult;
-            this.isRunning = isRunning;
+            this.status = status;
         }
     }
     
@@ -223,8 +272,8 @@ public UploadConfigResponse() {
     
     [System.Diagnostics.DebuggerStepThroughAttribute()]
     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
-    [System.ServiceModel.MessageContractAttribute(WrapperName="FindFiles", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
-    public partial class FindFilesRequest {
+    [System.ServiceModel.MessageContractAttribute(WrapperName="Browse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
+    public partial class BrowseRequest {
         
         [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)]
         public long sessionID;
@@ -232,10 +281,10 @@ public partial class FindFilesRequest {
         [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)]
         public Scada.Agent.RelPath relPath;
         
-        public FindFilesRequest() {
+        public BrowseRequest() {
         }
         
-        public FindFilesRequest(long sessionID, Scada.Agent.RelPath relPath) {
+        public BrowseRequest(long sessionID, Scada.Agent.RelPath relPath) {
             this.sessionID = sessionID;
             this.relPath = relPath;
         }
@@ -243,21 +292,25 @@ public FindFilesRequest(long sessionID, Scada.Agent.RelPath relPath) {
     
     [System.Diagnostics.DebuggerStepThroughAttribute()]
     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
-    [System.ServiceModel.MessageContractAttribute(WrapperName="FindFilesResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
-    public partial class FindFilesResponse {
+    [System.ServiceModel.MessageContractAttribute(WrapperName="BrowseResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
+    public partial class BrowseResponse {
         
         [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)]
-        public bool FindFilesResult;
+        public bool BrowseResult;
         
         [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)]
-        public string[] paths;
+        public string[] directories;
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=2)]
+        public string[] files;
         
-        public FindFilesResponse() {
+        public BrowseResponse() {
         }
         
-        public FindFilesResponse(bool FindFilesResult, string[] paths) {
-            this.FindFilesResult = FindFilesResult;
-            this.paths = paths;
+        public BrowseResponse(bool BrowseResult, string[] directories, string[] files) {
+            this.BrowseResult = BrowseResult;
+            this.directories = directories;
+            this.files = files;
         }
     }
     
@@ -304,12 +357,24 @@ public bool CreateSession(out long sessionID) {
             return base.Channel.CreateSessionAsync(request);
         }
         
-        public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName) {
-            return base.Channel.Login(sessionID, username, encryptedPassword, scadaInstanceName);
+        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+        Scada.Agent.Ctrl.ServiceReference1.LoginResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.Login(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request) {
+            return base.Channel.Login(request);
+        }
+        
+        public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName, out string errMsg) {
+            Scada.Agent.Ctrl.ServiceReference1.LoginRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.LoginRequest();
+            inValue.sessionID = sessionID;
+            inValue.username = username;
+            inValue.encryptedPassword = encryptedPassword;
+            inValue.scadaInstanceName = scadaInstanceName;
+            Scada.Agent.Ctrl.ServiceReference1.LoginResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).Login(inValue);
+            errMsg = retVal.errMsg;
+            return retVal.LoginResult;
         }
         
-        public System.Threading.Tasks.Task LoginAsync(long sessionID, string username, string encryptedPassword, string scadaInstanceName) {
-            return base.Channel.LoginAsync(sessionID, username, encryptedPassword, scadaInstanceName);
+        public System.Threading.Tasks.Task LoginAsync(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request) {
+            return base.Channel.LoginAsync(request);
         }
         
         public bool ControlService(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command) {
@@ -325,12 +390,12 @@ Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse Scada.Agent.Ctrl.Ser
             return base.Channel.GetServiceStatus(request);
         }
         
-        public bool GetServiceStatus(long sessionID, Scada.Agent.ServiceApp serviceApp, out bool isRunning) {
+        public bool GetServiceStatus(long sessionID, Scada.Agent.ServiceApp serviceApp, out Scada.Agent.ServiceStatus status) {
             Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest();
             inValue.sessionID = sessionID;
             inValue.serviceApp = serviceApp;
             Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetServiceStatus(inValue);
-            isRunning = retVal.isRunning;
+            status = retVal.status;
             return retVal.GetServiceStatusResult;
         }
         
@@ -390,21 +455,22 @@ public void UploadConfig(Scada.Agent.ConfigOptions ConfigOptions, long SessionID
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.FindFiles(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request) {
-            return base.Channel.FindFiles(request);
+        Scada.Agent.Ctrl.ServiceReference1.BrowseResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.Browse(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request) {
+            return base.Channel.Browse(request);
         }
         
-        public bool FindFiles(long sessionID, Scada.Agent.RelPath relPath, out string[] paths) {
-            Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest();
+        public bool Browse(long sessionID, Scada.Agent.RelPath relPath, out string[] directories, out string[] files) {
+            Scada.Agent.Ctrl.ServiceReference1.BrowseRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.BrowseRequest();
             inValue.sessionID = sessionID;
             inValue.relPath = relPath;
-            Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).FindFiles(inValue);
-            paths = retVal.paths;
-            return retVal.FindFilesResult;
+            Scada.Agent.Ctrl.ServiceReference1.BrowseResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).Browse(inValue);
+            directories = retVal.directories;
+            files = retVal.files;
+            return retVal.BrowseResult;
         }
         
-        public System.Threading.Tasks.Task FindFilesAsync(Scada.Agent.Ctrl.ServiceReference1.FindFilesRequest request) {
-            return base.Channel.FindFilesAsync(request);
+        public System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request) {
+            return base.Channel.BrowseAsync(request);
         }
         
         public System.IO.Stream DownloadFile(long sessionID, Scada.Agent.RelPath relPath) {
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource
similarity index 56%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource
rename to ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource
index 5e7a3f871..643e53244 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse.datasource	
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource	
@@ -5,6 +5,6 @@
     Renaming the file extension or editing the content of this file may   
     cause the file to be unrecognizable by the program.
 -->
-
-   Scada.Agent.Ctrl.ServiceReference1.FindFilesResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+
+   Scada.Agent.Ctrl.ServiceReference1.BrowseResponse
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource
new file mode 100644
index 000000000..183f75391
--- /dev/null
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource	
@@ -0,0 +1,10 @@
+
+
+
+   Scada.Agent.Ctrl.ServiceReference1.LoginResponse
+
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd
index 9f1b76b6f..f5e7fda8c 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd	
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd	
@@ -30,6 +30,7 @@
     
       
         
+        
       
     
   
@@ -61,7 +62,7 @@
     
       
         
-        
+        
       
     
   
@@ -76,7 +77,7 @@
     
       
         
-        
+        
       
     
   
@@ -84,39 +85,40 @@
     
       
         
-        
+        
       
     
   
   
     
       
-        
+        
       
     
   
   
     
       
-        
+        
       
     
   
-  
+  
   
-  
+  
     
       
         
-        
+        
       
     
   
-  
+  
     
       
-        
-        
+        
+        
+        
       
     
   
@@ -124,14 +126,14 @@
     
       
         
-        
+        
       
     
   
   
     
       
-        
+        
       
     
   
@@ -139,7 +141,7 @@
     
       
         
-        
+        
         
       
     
@@ -147,7 +149,7 @@
   
     
       
-        
+        
       
     
   
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd
index 7afd7a233..76a301227 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd	
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd	
@@ -16,6 +16,15 @@
     
   
   
+  
+    
+      
+      
+      
+      
+    
+  
+  
   
     
       
diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
index 07f16f60e..2b9480659 100644
--- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
+++ b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
@@ -23,8 +23,12 @@ private void button1_Click(object sender, System.EventArgs e)
             try
             {
                 client.CreateSession(out sessionID);
-                client.Login(sessionID, "admin", "", "Default");
                 MessageBox.Show("Session ID = " + sessionID);
+
+                if (client.Login(sessionID, "admin", "", "Default", out string errMsg))
+                    MessageBox.Show("Login OK");
+                else
+                    MessageBox.Show(errMsg);
             }
             finally
             {
diff --git a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj
index 7dbbf23ab..1f299194c 100644
--- a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj
+++ b/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj
@@ -83,10 +83,10 @@
     
       Designer
     
-    
+    
       Reference.svcmap
     
-    
+    
       Reference.svcmap
     
     
@@ -95,6 +95,9 @@
     
       Reference.svcmap
     
+    
+      Reference.svcmap
+    
     
       Reference.svcmap
     
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index a4382cd60..ccb47174d 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -198,31 +198,47 @@ public bool CreateSession(out long sessionID)
         /// Войти в систему
         /// 
         [OperationContract]
-        public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName)
+        public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName,
+            out string errMsg)
         {
             if (TryGetSession(sessionID, out Session session))
             {
                 session.ClearUser();
                 ScadaInstance scadaInstance = InstanceManager.GetScadaInstance(scadaInstanceName);
+                string password = CryptoUtils.DecryptPassword(encryptedPassword);
 
                 if (scadaInstance == null)
                 {
+                    errMsg = Localization.UseRussian ?
+                       "Экземпляр системы не найден." :
+                       "System instance not found.";
+
                     Log.WriteError(string.Format(Localization.UseRussian ?
                         "Экземпляр системы с наименованием \"{0}\" не найден" :
                         "System instance named \"{0}\" not found", scadaInstanceName));
                 }
-                else if (scadaInstance.ValidateUser(username, encryptedPassword, out string errMsg))
+                else if (scadaInstance.ValidateUser(username, password, out errMsg))
                 {
+                    Log.WriteError(string.Format(Localization.UseRussian ?
+                        "Пользователь {0} подключился к {1}" :
+                        "User {0} connected to {1}", username, scadaInstanceName));
                     session.SetUser(username, scadaInstance);
                     return true;
                 }
                 else
                 {
                     Log.WriteError(string.Format(Localization.UseRussian ?
-                        "Пользователь {0} не прошёл проверку - {1}" :
-                        "User {0} failed validation - {1}", username, errMsg));
+                        "Пользователь {0} не прошёл проверку для подключения к {1} - {2}" :
+                        "User {0} failed validation to connect to {1} - {2}", 
+                        username, scadaInstanceName, errMsg));
                 }
             }
+            else
+            {
+                errMsg = Localization.UseRussian ?
+                    "Сессия не найдена." :
+                    "Session not found.";
+            }
 
             return false;
         }

From 722280aa16d2a058fef13adf29782d1c9e76adc0 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 10:37:55 +0300
Subject: [PATCH 040/100] ScadaAgent: user validation

---
 ScadaAgent/ScadaAgentCore/CryptoUtils.cs    |  4 +-
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs  | 65 +++++++++++++++++++--
 ScadaAgent/ScadaAgentCore/SessionManager.cs |  8 +--
 ScadaAgent/ScadaAgentNet/AgentSvc.cs        | 10 ++--
 4 files changed, 72 insertions(+), 15 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
index 2aa8b10ac..ff41eeb4b 100644
--- a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
+++ b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
@@ -53,7 +53,7 @@ public static long GetRandomLong()
         /// 
         /// Зашифровать пароль
         /// 
-        public static string EncryptPassword(string password)
+        public static string EncryptPassword(string password, long sessionID)
         {
             // TODO
             return password;
@@ -62,7 +62,7 @@ public static string EncryptPassword(string password)
         /// 
         /// Дешифровать пароль
         /// 
-        public static string DecryptPassword(string encryptedPassword)
+        public static string DecryptPassword(string encryptedPassword, long sessionID)
         {
             // TODO
             return encryptedPassword;
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index dbc7333b4..0b03a5819 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -23,8 +23,11 @@
  * Modified : 2018
  */
 
+using Scada.Data.Configuration;
+using Scada.Data.Tables;
 using System;
 using System.Collections.Generic;
+using System.Data;
 using System.Diagnostics;
 using System.IO;
 using System.IO.Compression;
@@ -93,6 +96,10 @@ public PathList GetOrAdd(ConfigParts configPart, AppFolder appFolder)
             }
         }
 
+        /// 
+        /// Макс. количество попыток проверки пользователя
+        /// 
+        private const int MaxValidateUserAttempts = 3;
         /// 
         /// Все части конфигурации в виде массива
         /// 
@@ -100,6 +107,7 @@ public PathList GetOrAdd(ConfigParts configPart, AppFolder appFolder)
             ConfigParts.Server, ConfigParts.Communicator, ConfigParts.Webstation };
 
         private ILog log; // журнал приложения
+        private int validateUserAttemptNum; // номер попытки проверки пользователя
 
 
         /// 
@@ -117,6 +125,7 @@ public ScadaInstance(ScadaInstanceSettings settings, object syncRoot, ILog log)
             Settings = settings ?? throw new ArgumentNullException("settings");
             SyncRoot = syncRoot ?? throw new ArgumentNullException("syncRoot");
             this.log = log ?? throw new ArgumentNullException("log");
+            validateUserAttemptNum = 0;
             Name = settings.Name;
         }
 
@@ -403,13 +412,61 @@ private bool StartsWith(string s, ICollection values, StringComparison c
 
 
         /// 
-        /// Проверить пароль и права пользователя
+        /// Проверить пользователя
         /// 
+        /// Проверяется имя пользователя, пароль и роль
         public bool ValidateUser(string username, string password, out string errMsg)
         {
-            // TODO: реализовать и ограничить кол-во попыток
-            errMsg = "";
-            return true;
+            try
+            {
+                // проверка количества попыток
+                if (validateUserAttemptNum > MaxValidateUserAttempts)
+                {
+                    errMsg = Localization.UseRussian ?
+                        "Превышено количество попыток входа" :
+                        "Number of login attempts exceeded";
+                    return false;
+                }
+
+                if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
+                {
+                    // открытие таблицы пользователей
+                    BaseAdapter baseAdapter = new BaseAdapter();
+                    DataTable userTable = new DataTable();
+                    baseAdapter.FileName = Path.Combine(Settings.Directory,
+                        GetConfigPartDir(ConfigParts.Base, null), "user.dat");
+                    baseAdapter.Fill(userTable, false);
+
+                    // поиск и проверка информации о пользователе
+                    userTable.CaseSensitive = false;
+                    DataRow[] rows = userTable.Select(string.Format("Name = '{0}'", username));
+
+                    if (rows.Length > 0)
+                    {
+                        DataRow row = rows[0];
+                        if ((string)row["Password"] == password && (int)row["RoleID"] == BaseValues.Roles.Admin)
+                        {
+                            validateUserAttemptNum = 0;
+                            errMsg = "";
+                            return true;
+                        }
+                    }
+                }
+
+                validateUserAttemptNum++;
+                errMsg = Localization.UseRussian ?
+                    "Неверное имя пользователя или пароль" :
+                    "Invalid username or password";
+                return false;
+            }
+            catch (Exception ex)
+            {
+                errMsg = Localization.UseRussian ?
+                   "Ошибка при проверке пользователя" :
+                   "Error validating user";
+                log.WriteException(ex, errMsg);
+                return false;
+            }
         }
 
         /// 
diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs
index cb0166d04..e3d71b6c6 100644
--- a/ScadaAgent/ScadaAgentCore/SessionManager.cs
+++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs
@@ -41,9 +41,9 @@ public class SessionManager
         /// 
         private const int MaxSessionCnt = 100;
         /// 
-        /// Количество попыток получения уникального ид. сессии
+        /// Макс. количество попыток получения уникального ид. сессии
         /// 
-        private const int GetIDAttemtps = 100;
+        private const int MaxGetSessionIDAttempts = 100;
         /// 
         /// Время жизни сессии, если нет активности
         /// 
@@ -83,10 +83,10 @@ public Session CreateSession()
                 if (sessions.Count < MaxSessionCnt)
                 {
                     sessionID = CryptoUtils.GetRandomLong();
-                    int attempt = 0;
+                    int attemptNum = 0;
                     bool duplicated;
 
-                    while (duplicated = sessions.ContainsKey(sessionID) && ++attempt <= GetIDAttemtps)
+                    while (duplicated = sessions.ContainsKey(sessionID) && ++attemptNum <= MaxGetSessionIDAttempts)
                     {
                         sessionID = CryptoUtils.GetRandomLong();
                     }
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index ccb47174d..eac519e28 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -205,13 +205,13 @@ public bool Login(long sessionID, string username, string encryptedPassword, str
             {
                 session.ClearUser();
                 ScadaInstance scadaInstance = InstanceManager.GetScadaInstance(scadaInstanceName);
-                string password = CryptoUtils.DecryptPassword(encryptedPassword);
+                string password = CryptoUtils.DecryptPassword(encryptedPassword, sessionID);
 
                 if (scadaInstance == null)
                 {
                     errMsg = Localization.UseRussian ?
-                       "Экземпляр системы не найден." :
-                       "System instance not found.";
+                       "Экземпляр системы не найден" :
+                       "System instance not found";
 
                     Log.WriteError(string.Format(Localization.UseRussian ?
                         "Экземпляр системы с наименованием \"{0}\" не найден" :
@@ -236,8 +236,8 @@ public bool Login(long sessionID, string username, string encryptedPassword, str
             else
             {
                 errMsg = Localization.UseRussian ?
-                    "Сессия не найдена." :
-                    "Session not found.";
+                    "Сессия не найдена" :
+                    "Session not found";
             }
 
             return false;

From 211fb63e2cc9f03439c8172a336744a4c32df642 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 11:09:57 +0300
Subject: [PATCH 041/100] LangPack: fix es-LA

---
 LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml      | 4 ++--
 .../ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml        | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml
index df847aea9..cfe65de70 100644
--- a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml
@@ -234,8 +234,8 @@
     Comportamiento
     Master - SCADA-Communicator envía solicitud a un dispositivo y recibe respuesta.
Slave - SCADA-Communicator espera pasivamente los datos de un dispositivo.
     Selección del dispositivo
-    Por dirección IPDLL determinado
+    Por dirección IP
+	  DLL determinado
     El método de enlazar los datos recibidos a un dispositivo en modo esclavo:
Por dirección IP: la dirección IP remota equivale a un número de llamada del dispositivo.
DLL Determined - algoritmo se implementa en la biblioteca de dispositivos.
     Puerto local de UDP
     Puerto UDP local para conexiones entrantes.
Las conexiones entrantes deben ser permitidas por un firewall.
diff --git a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml
index 901ef3ef6..c8dfbef0b 100644
--- a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml
+++ b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml
@@ -36,7 +36,7 @@
     Seleccionar elemento para editar sus propiedades
     Esquemas (*.sch)|*.sch|Todos los Archivos (*.*)|*.*
     El esquema a sido modificado. Guardar los cambios?
-	Utilice las llaves de flecha para mover el elemento seleccionado.
+	  Utilice las llaves de flecha para mover el elemento seleccionado.
   
   
     Error al cargar el esquema de archivo

From a6056ea1fc5affba8cc98392c286e64dd187548a Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 11:35:23 +0300
Subject: [PATCH 042/100] ScadaData: add ScadaUtils.Crypto

---
 ScadaData/ScadaData.Std/ScadaData.Std.csproj |   1 +
 ScadaData/ScadaData/ScadaData.csproj         |   1 +
 ScadaData/ScadaData/ScadaUtils.Crypto.cs     | 126 +++++++++++++++++++
 ScadaData/ScadaData/ScadaUtils.cs            |  21 +---
 4 files changed, 129 insertions(+), 20 deletions(-)
 create mode 100644 ScadaData/ScadaData/ScadaUtils.Crypto.cs

diff --git a/ScadaData/ScadaData.Std/ScadaData.Std.csproj b/ScadaData/ScadaData.Std/ScadaData.Std.csproj
index b31093d13..8bb6a5ebc 100644
--- a/ScadaData/ScadaData.Std/ScadaData.Std.csproj
+++ b/ScadaData/ScadaData.Std/ScadaData.Std.csproj
@@ -42,6 +42,7 @@
     
     
     
+    
     
     
     
diff --git a/ScadaData/ScadaData/ScadaData.csproj b/ScadaData/ScadaData/ScadaData.csproj
index 0265b9be3..4e7668afa 100644
--- a/ScadaData/ScadaData/ScadaData.csproj
+++ b/ScadaData/ScadaData/ScadaData.csproj
@@ -84,6 +84,7 @@
     
     
     
+    
     
     
     
diff --git a/ScadaData/ScadaData/ScadaUtils.Crypto.cs b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
new file mode 100644
index 000000000..54e4d0031
--- /dev/null
+++ b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : ScadaData
+ * Summary  : The class contains utility methods for the whole system. Cryptographic utilities
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Scada
+{
+    partial class ScadaUtils
+    {
+        /// 
+        /// Генератор криптографически защищённых случайных чисел
+        /// 
+        private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
+
+
+        /// 
+        /// Получить случайное 64-битное целое
+        /// 
+        public static long GetRandomLong()
+        {
+            byte[] randomArr = new byte[8];
+            Rng.GetBytes(randomArr);
+            return BitConverter.ToInt64(randomArr, 0);
+        }
+
+        /// 
+        /// Вычислить хеш-функцию MD5 по массиву байт
+        /// 
+        public static string ComputeHash(byte[] bytes)
+        {
+            return BytesToHex(MD5.Create().ComputeHash(bytes));
+        }
+
+        /// 
+        /// Вычислить хеш-функцию MD5 по строке
+        /// 
+        public static string ComputeHash(string s)
+        {
+            return ComputeHash(Encoding.UTF8.GetBytes(s));
+        }
+
+        /// 
+        /// Зашифровать строку
+        /// 
+        public static string Encrypt(string s, byte[] secretKey, byte[] vector)
+        {
+            RijndaelManaged alg = null;
+
+            try
+            {
+                alg = new RijndaelManaged() { Key = secretKey, IV = vector };
+
+                using (MemoryStream memStream = new MemoryStream())
+                {
+                    using (CryptoStream cryptoStream =
+                        new CryptoStream(memStream, alg.CreateEncryptor(secretKey, vector), CryptoStreamMode.Write))
+                    {
+                        using (StreamWriter writer = new StreamWriter(cryptoStream))
+                            writer.Write(s);
+                    }
+
+                    return BytesToHex(memStream.ToArray());
+                }
+            }
+            finally
+            {
+                alg?.Clear();
+            }
+        }
+
+        /// 
+        /// Дешифровать строку
+        /// 
+        public static string Decrypt(string s, byte[] secretKey, byte[] vector)
+        {
+            if (!HexToBytes(s, out byte[] encryptedData))
+                throw new ArgumentException("String is not hexadecimal.", "s");
+
+            RijndaelManaged alg = null;
+
+            try
+            {
+                alg = new RijndaelManaged() { Key = secretKey, IV = vector };
+
+                using (MemoryStream memStream = new MemoryStream(encryptedData))
+                {
+                    using (CryptoStream cryptoStream =
+                        new CryptoStream(memStream, alg.CreateDecryptor(secretKey, vector), CryptoStreamMode.Read))
+                    {
+                        using (StreamReader reader = new StreamReader(cryptoStream))
+                            return reader.ReadToEnd();
+                    }
+                }
+            }
+            finally
+            {
+                alg?.Clear();
+            }
+        }
+    }
+}
diff --git a/ScadaData/ScadaData/ScadaUtils.cs b/ScadaData/ScadaData/ScadaUtils.cs
index 5020813d7..822987c59 100644
--- a/ScadaData/ScadaData/ScadaUtils.cs
+++ b/ScadaData/ScadaData/ScadaUtils.cs
@@ -26,11 +26,8 @@
 using System;
 using System.Globalization;
 using System.IO;
-using System.Runtime.Serialization;
 using System.Runtime.Serialization.Formatters.Binary;
-using System.Security.Cryptography;
 using System.Text;
-using System.Web;
 
 namespace Scada
 {
@@ -43,7 +40,7 @@ public static partial class ScadaUtils
         /// 
         /// Версия данной библиотеки
         /// 
-        internal const string LibVersion = "5.1.0.0";
+        internal const string LibVersion = "5.1.1.0";
         /// 
         /// Задержка потока для экономии ресурсов, мс
         /// 
@@ -309,22 +306,6 @@ public static bool HexToBytes(string s, out byte[] bytes, bool skipWhiteSpace =
             bytes = new byte[bufLen];
             return HexToBytes(s, 0, bytes, 0, bufLen);
         }
-
-        /// 
-        /// Вычислить хеш-функцию MD5 по массиву байт
-        /// 
-        public static string ComputeHash(byte[] bytes)
-        {
-            return BytesToHex(MD5.Create().ComputeHash(bytes));
-        }
-
-        /// 
-        /// Вычислить хеш-функцию MD5 по строке
-        /// 
-        public static string ComputeHash(string s)
-        {
-            return ComputeHash(Encoding.UTF8.GetBytes(s));
-        }
         
         /// 
         /// Глубокое (полное) клонирование объекта

From 02b82c1989fed36b91cc3443e73d4d4e0ce7b032 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 14:10:55 +0300
Subject: [PATCH 043/100] ScadaData: crypto and hex fixes

---
 ScadaData/ScadaData/CommonPhrases.cs         |  3 ++
 ScadaData/ScadaData/Lang/ScadaData.en-GB.xml |  1 +
 ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml |  1 +
 ScadaData/ScadaData/ScadaUtils.Crypto.cs     | 50 ++++++++++++++++----
 ScadaData/ScadaData/ScadaUtils.cs            | 40 ++++++++++------
 5 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/ScadaData/ScadaData/CommonPhrases.cs b/ScadaData/ScadaData/CommonPhrases.cs
index bc05dabf9..0165004e8 100644
--- a/ScadaData/ScadaData/CommonPhrases.cs
+++ b/ScadaData/ScadaData/CommonPhrases.cs
@@ -64,6 +64,7 @@ static CommonPhrases()
         public static string DateTimeRequired { get; private set; }
         public static string LineLengthLimit { get; private set; }
         public static string NotNumber { get; private set; }
+        public static string NotHexadecimal { get; private set; }
         public static string LoadImageError { get; private set; }
         public static string LoadHyperlinkError { get; private set; }
         public static string IncorrectFileFormat { get; private set; }
@@ -136,6 +137,7 @@ private static void SetToDefault()
             DateTimeRequired = Localization.Dict.GetEmptyPhrase("DateTimeRequired");
             LineLengthLimit = Localization.Dict.GetEmptyPhrase("LineLengthLimit");
             NotNumber = Localization.Dict.GetEmptyPhrase("NotNumber");
+            NotHexadecimal = Localization.Dict.GetEmptyPhrase("NotHexadecimal");
             LoadImageError = Localization.Dict.GetEmptyPhrase("LoadImageError");
             LoadHyperlinkError = Localization.Dict.GetEmptyPhrase("LoadHyperlinkError");
             IncorrectFileFormat = Localization.Dict.GetEmptyPhrase("IncorrectFileFormat");
@@ -212,6 +214,7 @@ public static void Init()
                 DateTimeRequired = dict.GetPhrase("DateTimeRequired", DateTimeRequired);
                 LineLengthLimit = dict.GetPhrase("LineLengthLimit", LineLengthLimit);
                 NotNumber = dict.GetPhrase("NotNumber", NotNumber);
+                NotHexadecimal = dict.GetPhrase("NotHexadecimal", NotHexadecimal);
                 LoadImageError = dict.GetPhrase("LoadImageError", LoadImageError);
                 LoadHyperlinkError = dict.GetPhrase("LoadHyperlinkError", LoadHyperlinkError);
                 NoData = dict.GetPhrase("NoData", NoData);
diff --git a/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml b/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml
index 55afea2c9..c67154112 100644
--- a/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml
+++ b/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml
@@ -27,6 +27,7 @@
     Date and time are required.
     The string length must be {0} symbols or less.
     "{0}" is not a number.
+    String is not hexadecimal.
     Error loading image from file:
{0}
     Error loading hyperlink from file:
{0}
     Incorrect file format.
diff --git a/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml b/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml
index 3393ccd89..c09427ac7 100644
--- a/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml
+++ b/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml
@@ -27,6 +27,7 @@
     Требуется дата и время.
     Длина строки должна быть не более {0} символов.
     "{0}" не является числом.
+    Строка не является 16-ричной записью.
     Ошибка при загрузке изображения из файла:
{0}
     Ошибка при загрузке гиперссылки из файла:
{0}
     Некорректный формат файла.
diff --git a/ScadaData/ScadaData/ScadaUtils.Crypto.cs b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
index 54e4d0031..0740337e7 100644
--- a/ScadaData/ScadaData/ScadaUtils.Crypto.cs
+++ b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
@@ -24,6 +24,7 @@
  */
 
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.Security.Cryptography;
 using System.Text;
@@ -37,6 +38,28 @@ partial class ScadaUtils
         /// 
         private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
 
+        /// 
+        /// Размер секретного ключа, байт
+        /// 
+        public const int SecretKeySize = 32;
+        /// 
+        /// Размер вектора инициализации, байт
+        /// 
+        public const int IVSize = 16;
+
+
+        /// 
+        /// Считать все данные из потока
+        /// 
+        private static byte[] ReadToEnd(Stream inputStream)
+        {
+            using (MemoryStream memStream = new MemoryStream())
+            {
+                inputStream.CopyTo(memStream);
+                return memStream.ToArray();
+            }
+        }
+
 
         /// 
         /// Получить случайное 64-битное целое
@@ -68,6 +91,14 @@ public static string ComputeHash(string s)
         /// Зашифровать строку
         /// 
         public static string Encrypt(string s, byte[] secretKey, byte[] vector)
+        {
+            return BytesToHex(EncryptBytes(Encoding.UTF8.GetBytes(s), secretKey, vector));
+        }
+
+        /// 
+        /// Зашифровать массив байт
+        /// 
+        public static byte[] EncryptBytes(byte[] bytes, byte[] secretKey, byte[] vector)
         {
             RijndaelManaged alg = null;
 
@@ -80,11 +111,10 @@ public static string Encrypt(string s, byte[] secretKey, byte[] vector)
                     using (CryptoStream cryptoStream =
                         new CryptoStream(memStream, alg.CreateEncryptor(secretKey, vector), CryptoStreamMode.Write))
                     {
-                        using (StreamWriter writer = new StreamWriter(cryptoStream))
-                            writer.Write(s);
+                        cryptoStream.Write(bytes, 0, bytes.Length);
                     }
 
-                    return BytesToHex(memStream.ToArray());
+                    return memStream.ToArray();
                 }
             }
             finally
@@ -98,22 +128,26 @@ public static string Encrypt(string s, byte[] secretKey, byte[] vector)
         /// 
         public static string Decrypt(string s, byte[] secretKey, byte[] vector)
         {
-            if (!HexToBytes(s, out byte[] encryptedData))
-                throw new ArgumentException("String is not hexadecimal.", "s");
+            return Encoding.UTF8.GetString(DecryptBytes(HexToBytes(s), secretKey, vector));
+        }
 
+        /// 
+        /// Дешифровать массив байт
+        /// 
+        public static byte[] DecryptBytes(byte[] bytes, byte[] secretKey, byte[] vector)
+        {
             RijndaelManaged alg = null;
 
             try
             {
                 alg = new RijndaelManaged() { Key = secretKey, IV = vector };
 
-                using (MemoryStream memStream = new MemoryStream(encryptedData))
+                using (MemoryStream memStream = new MemoryStream(bytes))
                 {
                     using (CryptoStream cryptoStream =
                         new CryptoStream(memStream, alg.CreateDecryptor(secretKey, vector), CryptoStreamMode.Read))
                     {
-                        using (StreamReader reader = new StreamReader(cryptoStream))
-                            return reader.ReadToEnd();
+                        return ReadToEnd(cryptoStream);
                     }
                 }
             }
diff --git a/ScadaData/ScadaData/ScadaUtils.cs b/ScadaData/ScadaData/ScadaUtils.cs
index 822987c59..2808d3264 100644
--- a/ScadaData/ScadaData/ScadaUtils.cs
+++ b/ScadaData/ScadaData/ScadaUtils.cs
@@ -41,6 +41,15 @@ public static partial class ScadaUtils
         /// Версия данной библиотеки
         /// 
         internal const string LibVersion = "5.1.1.0";
+        /// 
+        /// Формат вещественных чисел с разделителем точкой
+        /// 
+        private static readonly NumberFormatInfo NfiDot;
+        /// 
+        /// Формат вещественных чисел с разделителем запятой
+        /// 
+        private static readonly NumberFormatInfo NfiComma;
+
         /// 
         /// Задержка потока для экономии ресурсов, мс
         /// 
@@ -51,15 +60,15 @@ public static partial class ScadaUtils
         /// Совпадает с началом отсчёта времени в OLE Automation и Delphi
         public static readonly DateTime ScadaEpoch = new DateTime(1899, 12, 30, 0, 0, 0, DateTimeKind.Utc);
 
-        private static NumberFormatInfo nfi; // формат вещественных чисел
-
 
         /// 
         /// Конструктор
         /// 
         static ScadaUtils()
         {
-            nfi = (NumberFormatInfo)CultureInfo.CurrentCulture.NumberFormat.Clone();
+            NfiDot = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
+            NfiComma = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
+            NfiComma.NumberDecimalSeparator = ",";
         }
 
 
@@ -227,11 +236,7 @@ public static double StrToDoubleExc(string s)
         /// Метод работает с разделителями целой части '.' и ','
         public static double ParseDouble(string s)
         {
-            lock (nfi)
-            {
-                nfi.NumberDecimalSeparator = s.Contains(".") ? "." : ",";
-                return double.Parse(s, nfi);
-            }
+            return double.Parse(s, s.Contains(".") ? NfiDot : NfiComma);
         }
 
         /// 
@@ -240,11 +245,7 @@ public static double ParseDouble(string s)
         /// Метод работает с разделителями целой части '.' и ','
         public static bool TryParseDouble(string s, out double result)
         {
-            lock (nfi)
-            {
-                nfi.NumberDecimalSeparator = s.Contains(".") ? "." : ",";
-                return double.TryParse(s, NumberStyles.Float, nfi, out result);
-            }
+            return double.TryParse(s, NumberStyles.Float, s.Contains(".") ? NfiDot : NfiComma, out result);
         }
 
         /// 
@@ -306,7 +307,18 @@ public static bool HexToBytes(string s, out byte[] bytes, bool skipWhiteSpace =
             bytes = new byte[bufLen];
             return HexToBytes(s, 0, bytes, 0, bufLen);
         }
-        
+
+        /// 
+        /// Преобразовать строку 16-ричных чисел в массив байт
+        /// 
+        public static byte[] HexToBytes(string s, bool skipWhiteSpace = false)
+        {
+            if (HexToBytes(s, out byte[] bytes, skipWhiteSpace))
+                return bytes;
+            else
+                throw new ArgumentException(CommonPhrases.NotHexadecimal, "s");
+        }
+
         /// 
         /// Глубокое (полное) клонирование объекта
         /// 

From 61c405d585cb19b76f10633f0c3f8da49b48be4a Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 14:11:13 +0300
Subject: [PATCH 044/100] ScadaAgent: decrypt password

---
 ScadaAgent/ScadaAgentCore/CryptoUtils.cs      | 52 ++++++++++++-------
 ScadaAgent/ScadaAgentCore/SessionManager.cs   |  4 +-
 ScadaAgent/ScadaAgentCore/Settings.cs         | 36 +++++++++++++
 .../Config/ScadaAgentConfig.xml               |  2 +
 ScadaAgent/ScadaAgentNet/AgentSvc.cs          | 31 ++++++-----
 5 files changed, 91 insertions(+), 34 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
index ff41eeb4b..98714b9d9 100644
--- a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
+++ b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
@@ -24,7 +24,7 @@
  */
 
 using System;
-using System.Security.Cryptography;
+using System.Text;
 
 namespace Scada.Agent
 {
@@ -35,37 +35,51 @@ namespace Scada.Agent
     public static class CryptoUtils
     {
         /// 
-        /// Генератор криптографически защищённых случайных чисел
+        /// Зашифровать пароль
         /// 
-        private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
+        public static string EncryptPassword(string password, long sessionID, byte[] secretKey, byte[] vector)
+        {
+            byte[] pwdBuf = Encoding.UTF8.GetBytes(password);
+            byte[] sessBuf = BitConverter.GetBytes(sessionID);
 
+            for (int i = 0, cnt = Math.Min(pwdBuf.Length, sessBuf.Length); i < cnt; i++)
+            {
+                pwdBuf[i] ^= sessBuf[i];
+            }
 
-        /// 
-        /// Получить случайное 64-битное целое
-        /// 
-        public static long GetRandomLong()
-        {
-            byte[] randomArr = new byte[8];
-            Rng.GetBytes(randomArr);
-            return BitConverter.ToInt64(randomArr, 0);
+            return ScadaUtils.BytesToHex(ScadaUtils.EncryptBytes(pwdBuf, secretKey, vector));
         }
 
         /// 
-        /// Зашифровать пароль
+        /// Дешифровать пароль
         /// 
-        public static string EncryptPassword(string password, long sessionID)
+        public static string DecryptPassword(string encryptedPassword, long sessionID, byte[] secretKey, byte[] vector)
         {
-            // TODO
-            return password;
+            byte[] pwdBuf = ScadaUtils.HexToBytes(encryptedPassword);
+            byte[] sessBuf = BitConverter.GetBytes(sessionID);
+
+            for (int i = 0, cnt = Math.Min(pwdBuf.Length, sessBuf.Length); i < cnt; i++)
+            {
+                pwdBuf[i] ^= sessBuf[i];
+            }
+
+            return Encoding.UTF8.GetString(ScadaUtils.DecryptBytes(pwdBuf, secretKey, vector));
         }
 
         /// 
-        /// Дешифровать пароль
+        /// Дешифровать пароль, не вызывая исключений в случае ошибки
         /// 
-        public static string DecryptPassword(string encryptedPassword, long sessionID)
+        public static string SafelyDecryptPassword(string encryptedPassword, long sessionID, 
+            byte[] secretKey, byte[] vector)
         {
-            // TODO
-            return encryptedPassword;
+            try
+            {
+                return DecryptPassword(encryptedPassword, sessionID, secretKey, vector);
+            }
+            catch
+            {
+                return "";
+            }
         }
     }
 }
diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs
index e3d71b6c6..61de83b98 100644
--- a/ScadaAgent/ScadaAgentCore/SessionManager.cs
+++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs
@@ -82,13 +82,13 @@ public Session CreateSession()
 
                 if (sessions.Count < MaxSessionCnt)
                 {
-                    sessionID = CryptoUtils.GetRandomLong();
+                    sessionID = ScadaUtils.GetRandomLong();
                     int attemptNum = 0;
                     bool duplicated;
 
                     while (duplicated = sessions.ContainsKey(sessionID) && ++attemptNum <= MaxGetSessionIDAttempts)
                     {
-                        sessionID = CryptoUtils.GetRandomLong();
+                        sessionID = ScadaUtils.GetRandomLong();
                     }
 
                     sessionOK = !duplicated;
diff --git a/ScadaAgent/ScadaAgentCore/Settings.cs b/ScadaAgent/ScadaAgentCore/Settings.cs
index 179c2068c..e503cb628 100644
--- a/ScadaAgent/ScadaAgentCore/Settings.cs
+++ b/ScadaAgent/ScadaAgentCore/Settings.cs
@@ -48,9 +48,20 @@ public class Settings
         public Settings()
         {
             Instances = new SortedList();
+            SetToDefault();
         }
 
 
+        /// 
+        /// Получить секретный ключ для шифрования паролей
+        /// 
+        public byte[] SecretKey { get; private set; }
+
+        /// 
+        /// Получить вектор инициализации для шифрования паролей
+        /// 
+        public byte[] IV { get; private set; }
+
         /// 
         /// Получить настройки экземпляров систем, ключ - наименование экземпляра
         /// 
@@ -62,6 +73,8 @@ public Settings()
         /// 
         private void SetToDefault()
         {
+            SecretKey = null;
+            IV = null;
             Instances.Clear();
         }
 
@@ -83,6 +96,29 @@ public bool Load(string fileName, out string errMsg)
                 xmlDoc.Load(fileName);
                 XmlElement rootElem = xmlDoc.DocumentElement;
 
+                // загрузка секретного ключа
+                if (ScadaUtils.HexToBytes(rootElem.GetChildAsString("SecretKey"), out byte[] secretKey) &&
+                    secretKey.Length == ScadaUtils.SecretKeySize)
+                {
+                    SecretKey = secretKey;
+                }
+                else
+                {
+                    throw new ScadaException(string.Format(CommonPhrases.IncorrectXmlNodeVal, "SecretKey"));
+                }
+
+                // загрузка вектора инициализации
+                if (ScadaUtils.HexToBytes(rootElem.GetChildAsString("IV"), out byte[] iv) &&
+                    iv.Length == ScadaUtils.IVSize)
+                {
+                    IV = iv;
+                }
+                else
+                {
+                    throw new ScadaException(string.Format(CommonPhrases.IncorrectXmlNodeVal, "IV"));
+                }
+
+                // загрузка настроек экземпляров систем
                 XmlNode instancesNode = rootElem.SelectSingleNode("Instances");
                 if (instancesNode != null)
                 {
diff --git a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
index aeae44626..c38796e7a 100644
--- a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
+++ b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
@@ -1,5 +1,7 @@
 
 
+  5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1
+  A72B989FF1DF5679D9826D671398B6B3
   
     
   
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index eac519e28..fbf3c8490 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -205,7 +205,6 @@ public bool Login(long sessionID, string username, string encryptedPassword, str
             {
                 session.ClearUser();
                 ScadaInstance scadaInstance = InstanceManager.GetScadaInstance(scadaInstanceName);
-                string password = CryptoUtils.DecryptPassword(encryptedPassword, sessionID);
 
                 if (scadaInstance == null)
                 {
@@ -217,20 +216,26 @@ public bool Login(long sessionID, string username, string encryptedPassword, str
                         "Экземпляр системы с наименованием \"{0}\" не найден" :
                         "System instance named \"{0}\" not found", scadaInstanceName));
                 }
-                else if (scadaInstance.ValidateUser(username, password, out errMsg))
-                {
-                    Log.WriteError(string.Format(Localization.UseRussian ?
-                        "Пользователь {0} подключился к {1}" :
-                        "User {0} connected to {1}", username, scadaInstanceName));
-                    session.SetUser(username, scadaInstance);
-                    return true;
-                }
                 else
                 {
-                    Log.WriteError(string.Format(Localization.UseRussian ?
-                        "Пользователь {0} не прошёл проверку для подключения к {1} - {2}" :
-                        "User {0} failed validation to connect to {1} - {2}", 
-                        username, scadaInstanceName, errMsg));
+                    string password = CryptoUtils.SafelyDecryptPassword(encryptedPassword, sessionID,
+                        AppData.Settings.SecretKey, AppData.Settings.IV);
+
+                    if (scadaInstance.ValidateUser(username, password, out errMsg))
+                    {
+                        Log.WriteError(string.Format(Localization.UseRussian ?
+                            "Пользователь {0} подключился к {1}" :
+                            "User {0} connected to {1}", username, scadaInstanceName));
+                        session.SetUser(username, scadaInstance);
+                        return true;
+                    }
+                    else
+                    {
+                        Log.WriteError(string.Format(Localization.UseRussian ?
+                            "Пользователь {0} не прошёл проверку для подключения к {1} - {2}" :
+                            "User {0} failed validation to connect to {1} - {2}",
+                            username, scadaInstanceName, errMsg));
+                    }
                 }
             }
             else

From d7a6143230af6fedcb457fd664020a4432e712c2 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 14:49:30 +0300
Subject: [PATCH 045/100] ScadaData: minor fixes

---
 ScadaData/ScadaData/ScadaUtils.Crypto.cs | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/ScadaData/ScadaData/ScadaUtils.Crypto.cs b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
index 0740337e7..d6f94860a 100644
--- a/ScadaData/ScadaData/ScadaUtils.Crypto.cs
+++ b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
@@ -90,26 +90,26 @@ public static string ComputeHash(string s)
         /// 
         /// Зашифровать строку
         /// 
-        public static string Encrypt(string s, byte[] secretKey, byte[] vector)
+        public static string Encrypt(string s, byte[] secretKey, byte[] iv)
         {
-            return BytesToHex(EncryptBytes(Encoding.UTF8.GetBytes(s), secretKey, vector));
+            return BytesToHex(EncryptBytes(Encoding.UTF8.GetBytes(s), secretKey, iv));
         }
 
         /// 
         /// Зашифровать массив байт
         /// 
-        public static byte[] EncryptBytes(byte[] bytes, byte[] secretKey, byte[] vector)
+        public static byte[] EncryptBytes(byte[] bytes, byte[] secretKey, byte[] iv)
         {
             RijndaelManaged alg = null;
 
             try
             {
-                alg = new RijndaelManaged() { Key = secretKey, IV = vector };
+                alg = new RijndaelManaged() { Key = secretKey, IV = iv };
 
                 using (MemoryStream memStream = new MemoryStream())
                 {
                     using (CryptoStream cryptoStream =
-                        new CryptoStream(memStream, alg.CreateEncryptor(secretKey, vector), CryptoStreamMode.Write))
+                        new CryptoStream(memStream, alg.CreateEncryptor(secretKey, iv), CryptoStreamMode.Write))
                     {
                         cryptoStream.Write(bytes, 0, bytes.Length);
                     }
@@ -126,26 +126,26 @@ public static byte[] EncryptBytes(byte[] bytes, byte[] secretKey, byte[] vector)
         /// 
         /// Дешифровать строку
         /// 
-        public static string Decrypt(string s, byte[] secretKey, byte[] vector)
+        public static string Decrypt(string s, byte[] secretKey, byte[] iv)
         {
-            return Encoding.UTF8.GetString(DecryptBytes(HexToBytes(s), secretKey, vector));
+            return Encoding.UTF8.GetString(DecryptBytes(HexToBytes(s), secretKey, iv));
         }
 
         /// 
         /// Дешифровать массив байт
         /// 
-        public static byte[] DecryptBytes(byte[] bytes, byte[] secretKey, byte[] vector)
+        public static byte[] DecryptBytes(byte[] bytes, byte[] secretKey, byte[] iv)
         {
             RijndaelManaged alg = null;
 
             try
             {
-                alg = new RijndaelManaged() { Key = secretKey, IV = vector };
+                alg = new RijndaelManaged() { Key = secretKey, IV = iv };
 
                 using (MemoryStream memStream = new MemoryStream(bytes))
                 {
                     using (CryptoStream cryptoStream =
-                        new CryptoStream(memStream, alg.CreateDecryptor(secretKey, vector), CryptoStreamMode.Read))
+                        new CryptoStream(memStream, alg.CreateDecryptor(secretKey, iv), CryptoStreamMode.Read))
                     {
                         return ReadToEnd(cryptoStream);
                     }

From 5b46a823c6309efebd2e9342ff9d9a49ee269f1d Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 14:49:49 +0300
Subject: [PATCH 046/100] ScadaAgent: encryption refactor

---
 ScadaAgent/ScadaAgentCore/CryptoUtils.cs      | 38 +++++++++----------
 ScadaAgent/ScadaAgentCore/Settings.cs         | 19 +---------
 .../Config/ScadaAgentConfig.xml               |  1 -
 ScadaAgent/ScadaAgentNet/AgentSvc.cs          |  4 +-
 4 files changed, 22 insertions(+), 40 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
index 98714b9d9..d997fd19b 100644
--- a/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
+++ b/ScadaAgent/ScadaAgentCore/CryptoUtils.cs
@@ -35,46 +35,46 @@ namespace Scada.Agent
     public static class CryptoUtils
     {
         /// 
-        /// Зашифровать пароль
+        /// Создать вектор инициализации на освнове ид. сессии
         /// 
-        public static string EncryptPassword(string password, long sessionID, byte[] secretKey, byte[] vector)
+        private static byte[] CreateIV(long sessionID)
         {
-            byte[] pwdBuf = Encoding.UTF8.GetBytes(password);
+            byte[] iv = new byte[ScadaUtils.IVSize];
             byte[] sessBuf = BitConverter.GetBytes(sessionID);
+            int sessBufLen = sessBuf.Length;
 
-            for (int i = 0, cnt = Math.Min(pwdBuf.Length, sessBuf.Length); i < cnt; i++)
+            for (int i = 0; i < ScadaUtils.IVSize; i++)
             {
-                pwdBuf[i] ^= sessBuf[i];
+                iv[i] = sessBuf[i % sessBufLen];
             }
 
-            return ScadaUtils.BytesToHex(ScadaUtils.EncryptBytes(pwdBuf, secretKey, vector));
+            return iv;
         }
 
         /// 
-        /// Дешифровать пароль
+        /// Зашифровать пароль
         /// 
-        public static string DecryptPassword(string encryptedPassword, long sessionID, byte[] secretKey, byte[] vector)
+        public static string EncryptPassword(string password, long sessionID, byte[] secretKey)
         {
-            byte[] pwdBuf = ScadaUtils.HexToBytes(encryptedPassword);
-            byte[] sessBuf = BitConverter.GetBytes(sessionID);
-
-            for (int i = 0, cnt = Math.Min(pwdBuf.Length, sessBuf.Length); i < cnt; i++)
-            {
-                pwdBuf[i] ^= sessBuf[i];
-            }
+            return ScadaUtils.Encrypt(password, secretKey, CreateIV(sessionID));
+        }
 
-            return Encoding.UTF8.GetString(ScadaUtils.DecryptBytes(pwdBuf, secretKey, vector));
+        /// 
+        /// Дешифровать пароль
+        /// 
+        public static string DecryptPassword(string encryptedPassword, long sessionID, byte[] secretKey)
+        {
+            return ScadaUtils.Decrypt(encryptedPassword, secretKey, CreateIV(sessionID));
         }
 
         /// 
         /// Дешифровать пароль, не вызывая исключений в случае ошибки
         /// 
-        public static string SafelyDecryptPassword(string encryptedPassword, long sessionID, 
-            byte[] secretKey, byte[] vector)
+        public static string SafelyDecryptPassword(string encryptedPassword, long sessionID, byte[] secretKey)
         {
             try
             {
-                return DecryptPassword(encryptedPassword, sessionID, secretKey, vector);
+                return DecryptPassword(encryptedPassword, sessionID, secretKey);
             }
             catch
             {
diff --git a/ScadaAgent/ScadaAgentCore/Settings.cs b/ScadaAgent/ScadaAgentCore/Settings.cs
index e503cb628..bedcef425 100644
--- a/ScadaAgent/ScadaAgentCore/Settings.cs
+++ b/ScadaAgent/ScadaAgentCore/Settings.cs
@@ -47,8 +47,8 @@ public class Settings
         /// 
         public Settings()
         {
+            SecretKey = null;
             Instances = new SortedList();
-            SetToDefault();
         }
 
 
@@ -57,11 +57,6 @@ public Settings()
         /// 
         public byte[] SecretKey { get; private set; }
 
-        /// 
-        /// Получить вектор инициализации для шифрования паролей
-        /// 
-        public byte[] IV { get; private set; }
-
         /// 
         /// Получить настройки экземпляров систем, ключ - наименование экземпляра
         /// 
@@ -74,7 +69,6 @@ public Settings()
         private void SetToDefault()
         {
             SecretKey = null;
-            IV = null;
             Instances.Clear();
         }
 
@@ -107,17 +101,6 @@ public bool Load(string fileName, out string errMsg)
                     throw new ScadaException(string.Format(CommonPhrases.IncorrectXmlNodeVal, "SecretKey"));
                 }
 
-                // загрузка вектора инициализации
-                if (ScadaUtils.HexToBytes(rootElem.GetChildAsString("IV"), out byte[] iv) &&
-                    iv.Length == ScadaUtils.IVSize)
-                {
-                    IV = iv;
-                }
-                else
-                {
-                    throw new ScadaException(string.Format(CommonPhrases.IncorrectXmlNodeVal, "IV"));
-                }
-
                 // загрузка настроек экземпляров систем
                 XmlNode instancesNode = rootElem.SelectSingleNode("Instances");
                 if (instancesNode != null)
diff --git a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
index c38796e7a..e2123f580 100644
--- a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
+++ b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml
@@ -1,7 +1,6 @@
 
 
   5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1
-  A72B989FF1DF5679D9826D671398B6B3
   
     
   
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index fbf3c8490..186b9e242 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -218,8 +218,8 @@ public bool Login(long sessionID, string username, string encryptedPassword, str
                 }
                 else
                 {
-                    string password = CryptoUtils.SafelyDecryptPassword(encryptedPassword, sessionID,
-                        AppData.Settings.SecretKey, AppData.Settings.IV);
+                    string password = CryptoUtils.SafelyDecryptPassword(encryptedPassword, sessionID, 
+                        AppData.Settings.SecretKey);
 
                     if (scadaInstance.ValidateUser(username, password, out errMsg))
                     {

From 18dfd998e0a7eef80b53c3652f10a6d0f2b32b65 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 17:47:39 +0300
Subject: [PATCH 047/100] ScadaAgent: service should work

---
 ScadaAgent/ScadaAgent.sln                     |  12 +-
 ScadaAgent/ScadaAgentMono/Program.cs          |   6 +-
 .../ScadaAgentMono/Properties/AssemblyInfo.cs |  14 +-
 .../ScadaAgentNet/Properties/AssemblyInfo.cs  |  12 +-
 ScadaAgent/ScadaAgentService/Program.cs       |  25 ----
 ScadaAgent/ScadaAgentService/Service1.cs      |  28 ----
 .../App.config                                |   0
 ScadaAgent/ScadaAgentSvc/Program.cs           |  47 +++++++
 .../ProjectInstaller.Designer.cs              |  59 ++++++++
 ScadaAgent/ScadaAgentSvc/ProjectInstaller.cs  |  42 ++++++
 .../ScadaAgentSvc/ProjectInstaller.resx       | 129 ++++++++++++++++++
 .../Properties/AssemblyInfo.cs                |  14 +-
 .../ScadaAgentSvc.csproj}                     |  46 +++++--
 .../SvcMain.Designer.cs}                      |   4 +-
 ScadaAgent/ScadaAgentSvc/SvcMain.cs           |  60 ++++++++
 15 files changed, 403 insertions(+), 95 deletions(-)
 delete mode 100644 ScadaAgent/ScadaAgentService/Program.cs
 delete mode 100644 ScadaAgent/ScadaAgentService/Service1.cs
 rename ScadaAgent/{ScadaAgentService => ScadaAgentSvc}/App.config (100%)
 create mode 100644 ScadaAgent/ScadaAgentSvc/Program.cs
 create mode 100644 ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs
 create mode 100644 ScadaAgent/ScadaAgentSvc/ProjectInstaller.cs
 create mode 100644 ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx
 rename ScadaAgent/{ScadaAgentService => ScadaAgentSvc}/Properties/AssemblyInfo.cs (78%)
 rename ScadaAgent/{ScadaAgentService/ScadaAgentService.csproj => ScadaAgentSvc/ScadaAgentSvc.csproj} (56%)
 rename ScadaAgent/{ScadaAgentService/Service1.Designer.cs => ScadaAgentSvc/SvcMain.Designer.cs} (94%)
 create mode 100644 ScadaAgent/ScadaAgentSvc/SvcMain.cs

diff --git a/ScadaAgent/ScadaAgent.sln b/ScadaAgent/ScadaAgent.sln
index 575dfcea7..d12f42104 100644
--- a/ScadaAgent/ScadaAgent.sln
+++ b/ScadaAgent/ScadaAgent.sln
@@ -7,12 +7,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScadaAgentCore", "ScadaAgen
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentMono", "ScadaAgentMono\ScadaAgentMono.csproj", "{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentService", "ScadaAgentService\ScadaAgentService.csproj", "{593318B1-3CB4-441B-B273-E3F37DF070B5}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentCtrl", "ScadaAgentCtrl\ScadaAgentCtrl.csproj", "{67AEE6A7-0F2E-4273-8253-231E6BF3C943}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentNet", "ScadaAgentNet\ScadaAgentNet.csproj", "{C377283B-858B-4EFC-A560-E90FF2F26B03}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentSvc", "ScadaAgentSvc\ScadaAgentSvc.csproj", "{593318B1-3CB4-441B-B273-E3F37DF070B5}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -27,10 +27,6 @@ Global
 		{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}.Release|Any CPU.Build.0 = Release|Any CPU
-		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Release|Any CPU.Build.0 = Release|Any CPU
 		{67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -39,6 +35,10 @@ Global
 		{C377283B-858B-4EFC-A560-E90FF2F26B03}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{C377283B-858B-4EFC-A560-E90FF2F26B03}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{C377283B-858B-4EFC-A560-E90FF2F26B03}.Release|Any CPU.Build.0 = Release|Any CPU
+		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/ScadaAgent/ScadaAgentMono/Program.cs b/ScadaAgent/ScadaAgentMono/Program.cs
index 119a1f28d..cfc67d4c4 100644
--- a/ScadaAgent/ScadaAgentMono/Program.cs
+++ b/ScadaAgent/ScadaAgentMono/Program.cs
@@ -16,7 +16,7 @@
  * 
  * Product  : Rapid SCADA
  * Module   : Agent Console Application
- * Summary  : Agent console appliction tested on Mono .NET framework
+ * Summary  : Agent console application designed for Mono .NET framework
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2018
@@ -30,8 +30,8 @@
 namespace Scada.Agent.Mono
 {
     /// 
-    /// Agent console appliction tested on Mono .NET framework
-    /// Консольное приложение агента, протестированное на Mono .NET framework
+    /// Agent console application designed for Mono .NET framework
+    /// Консольное приложение агента, предназначенное для Mono .NET framework
     /// 
     class Program
     {
diff --git a/ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs
index 8570f700c..8aac21dee 100644
--- a/ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs
+++ b/ScadaAgent/ScadaAgentMono/Properties/AssemblyInfo.cs
@@ -1,16 +1,16 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
+using Scada.Agent;
+using System.Reflection;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
-[assembly: AssemblyTitle("ScadaAgentMono")]
+[assembly: AssemblyTitle("Agent Service for Mono")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ScadaAgentMono")]
-[assembly: AssemblyCopyright("Copyright ©  2018")]
+[assembly: AssemblyProduct("Rapid SCADA")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion(AgentUtils.AppVersion)]
+[assembly: AssemblyFileVersion(AgentUtils.AppVersion)]
diff --git a/ScadaAgent/ScadaAgentNet/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentNet/Properties/AssemblyInfo.cs
index 6c31bcc9d..2d65e19fe 100644
--- a/ScadaAgent/ScadaAgentNet/Properties/AssemblyInfo.cs
+++ b/ScadaAgent/ScadaAgentNet/Properties/AssemblyInfo.cs
@@ -1,5 +1,5 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
+using Scada.Agent;
+using System.Reflection;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following
@@ -9,8 +9,8 @@
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ScadaAgentNet")]
-[assembly: AssemblyCopyright("Copyright ©  2018")]
+[assembly: AssemblyProduct("Rapid SCADA")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion(AgentUtils.AppVersion)]
+[assembly: AssemblyFileVersion(AgentUtils.AppVersion)]
diff --git a/ScadaAgent/ScadaAgentService/Program.cs b/ScadaAgent/ScadaAgentService/Program.cs
deleted file mode 100644
index 9804aedbd..000000000
--- a/ScadaAgent/ScadaAgentService/Program.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.ServiceProcess;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ScadaAgentService
-{
-    static class Program
-    {
-        /// 
-        /// The main entry point for the application.
-        /// 
-        static void Main()
-        {
-            ServiceBase[] ServicesToRun;
-            ServicesToRun = new ServiceBase[]
-            {
-                new Service1()
-            };
-            ServiceBase.Run(ServicesToRun);
-        }
-    }
-}
diff --git a/ScadaAgent/ScadaAgentService/Service1.cs b/ScadaAgent/ScadaAgentService/Service1.cs
deleted file mode 100644
index 4e12ed44f..000000000
--- a/ScadaAgent/ScadaAgentService/Service1.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Diagnostics;
-using System.Linq;
-using System.ServiceProcess;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ScadaAgentService
-{
-    public partial class Service1 : ServiceBase
-    {
-        public Service1()
-        {
-            InitializeComponent();
-        }
-
-        protected override void OnStart(string[] args)
-        {
-        }
-
-        protected override void OnStop()
-        {
-        }
-    }
-}
diff --git a/ScadaAgent/ScadaAgentService/App.config b/ScadaAgent/ScadaAgentSvc/App.config
similarity index 100%
rename from ScadaAgent/ScadaAgentService/App.config
rename to ScadaAgent/ScadaAgentSvc/App.config
diff --git a/ScadaAgent/ScadaAgentSvc/Program.cs b/ScadaAgent/ScadaAgentSvc/Program.cs
new file mode 100644
index 000000000..ccf52eff1
--- /dev/null
+++ b/ScadaAgent/ScadaAgentSvc/Program.cs
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : Agent Service
+ * Summary  : Agent service for Windows
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using System.ServiceProcess;
+
+namespace Scada.Agent.Svc
+{
+    /// 
+    /// Agent service for Windows
+    /// Служба агента для Windows
+    /// 
+    static class Program
+    {
+        /// 
+        /// The main entry point for the application
+        /// Основная точка входа для приложения
+        /// 
+        static void Main()
+        {
+            ServiceBase[] ServicesToRun;
+            ServicesToRun = new ServiceBase[] { new SvcMain() };
+            ServiceBase.Run(ServicesToRun);
+        }
+    }
+}
diff --git a/ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs
new file mode 100644
index 000000000..39f126c32
--- /dev/null
+++ b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs
@@ -0,0 +1,59 @@
+namespace Scada.Agent.Svc
+{
+    partial class ProjectInstaller
+    {
+        /// 
+        /// Required designer variable.
+        /// 
+        private System.ComponentModel.IContainer components = null;
+
+        ///  
+        /// Clean up any resources being used.
+        /// 
+        /// true if managed resources should be disposed; otherwise, false.
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// 
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// 
+        private void InitializeComponent()
+        {
+            this.serviceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
+            this.serviceInstaller = new System.ServiceProcess.ServiceInstaller();
+            // 
+            // serviceProcessInstaller
+            // 
+            this.serviceProcessInstaller.Password = null;
+            this.serviceProcessInstaller.Username = null;
+            // 
+            // serviceInstaller
+            // 
+            this.serviceInstaller.Description = "Agent provides remote management of Rapid SCADA instances.";
+            this.serviceInstaller.DisplayName = "ScadaAgentService";
+            this.serviceInstaller.ServiceName = "ScadaAgentService";
+            this.serviceInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
+            // 
+            // ProjectInstaller
+            // 
+            this.Installers.AddRange(new System.Configuration.Install.Installer[] {
+            this.serviceProcessInstaller,
+            this.serviceInstaller});
+
+        }
+
+        #endregion
+
+        private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller;
+        private System.ServiceProcess.ServiceInstaller serviceInstaller;
+    }
+}
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentSvc/ProjectInstaller.cs b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.cs
new file mode 100644
index 000000000..0f41a5b6b
--- /dev/null
+++ b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.cs
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : Agent Service
+ * Summary  : Service installer
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using System.ComponentModel;
+
+namespace Scada.Agent.Svc
+{
+    /// 
+    /// Service installer
+    /// Инсталлятор службы
+    /// 
+    [RunInstaller(true)]
+    public partial class ProjectInstaller : System.Configuration.Install.Installer
+    {
+        public ProjectInstaller()
+        {
+            InitializeComponent();
+        }
+    }
+}
diff --git a/ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx
new file mode 100644
index 000000000..2c076de59
--- /dev/null
+++ b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx
@@ -0,0 +1,129 @@
+
+
+  
+  
+    
+    
+      
+        
+          
+            
+              
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+              
+            
+          
+          
+            
+              
+                
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+                
+              
+              
+            
+          
+        
+      
+    
+  
+  
+    text/microsoft-resx
+  
+  
+    2.0
+  
+  
+    System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    17, 17
+  
+  
+    196, 17
+  
+  
+    False
+  
+
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentSvc/Properties/AssemblyInfo.cs
similarity index 78%
rename from ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs
rename to ScadaAgent/ScadaAgentSvc/Properties/AssemblyInfo.cs
index 4622c3ea7..71343ab09 100644
--- a/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs
+++ b/ScadaAgent/ScadaAgentSvc/Properties/AssemblyInfo.cs
@@ -1,16 +1,16 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
+using Scada.Agent;
+using System.Reflection;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
-[assembly: AssemblyTitle("ScadaAgentService")]
+[assembly: AssemblyTitle("Agent Service for Windows")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ScadaAgentService")]
-[assembly: AssemblyCopyright("Copyright ©  2018")]
+[assembly: AssemblyProduct("Rapid SCADA")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion(AgentUtils.AppVersion)]
+[assembly: AssemblyFileVersion(AgentUtils.AppVersion)]
diff --git a/ScadaAgent/ScadaAgentService/ScadaAgentService.csproj b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
similarity index 56%
rename from ScadaAgent/ScadaAgentService/ScadaAgentService.csproj
rename to ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
index 43b2fddfd..2bc1e6217 100644
--- a/ScadaAgent/ScadaAgentService/ScadaAgentService.csproj
+++ b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
@@ -6,7 +6,7 @@
     AnyCPU
     {593318B1-3CB4-441B-B273-E3F37DF070B5}
     WinExe
-    ScadaAgentService
+    Scada.Agent.Svc
     ScadaAgentService
     v4.6.1
     512
@@ -32,22 +32,31 @@
     4
   
   
+    
+      False
+      ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll
+    
+    
+      False
+      ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll
+    
     
-    
-    
-    
-    
-    
-    
+    
+    
     
-    
   
   
-    
+    
       Component
     
-    
-      Service1.cs
+    
+      ProjectInstaller.cs
+    
+    
+      Component
+    
+    
+      SvcMain.cs
     
     
     
@@ -55,5 +64,20 @@
   
     
   
+  
+    
+      {5163526D-91E4-414D-97FE-090E1E7FDA6B}
+      ScadaAgentCore
+    
+    
+      {c377283b-858b-4efc-a560-e90ff2f26b03}
+      ScadaAgentNet
+    
+  
+  
+    
+      ProjectInstaller.cs
+    
+  
   
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentService/Service1.Designer.cs b/ScadaAgent/ScadaAgentSvc/SvcMain.Designer.cs
similarity index 94%
rename from ScadaAgent/ScadaAgentService/Service1.Designer.cs
rename to ScadaAgent/ScadaAgentSvc/SvcMain.Designer.cs
index c2fd74d0b..a0bf3e3ab 100644
--- a/ScadaAgent/ScadaAgentService/Service1.Designer.cs
+++ b/ScadaAgent/ScadaAgentSvc/SvcMain.Designer.cs
@@ -1,6 +1,6 @@
-namespace ScadaAgentService
+namespace Scada.Agent.Svc
 {
-    partial class Service1
+    partial class SvcMain
     {
         ///  
         /// Required designer variable.
diff --git a/ScadaAgent/ScadaAgentSvc/SvcMain.cs b/ScadaAgent/ScadaAgentSvc/SvcMain.cs
new file mode 100644
index 000000000..cd788d361
--- /dev/null
+++ b/ScadaAgent/ScadaAgentSvc/SvcMain.cs
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : Agent Service
+ * Summary  : ScadaAgentSvc service implementation
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada.Agent.Net;
+using System.ServiceProcess;
+
+namespace Scada.Agent.Svc
+{
+    /// 
+    /// ScadaAgentSvc service implementation
+    /// Реализация службы ScadaAgentSvc
+    /// 
+    public partial class SvcMain : ServiceBase
+    {
+        AgentManager agentManager;
+
+        public SvcMain()
+        {
+            InitializeComponent();
+            agentManager = new AgentManager();
+        }
+
+        protected override void OnStart(string[] args)
+        {
+            agentManager.StartAgent();
+        }
+
+        protected override void OnStop()
+        {
+            agentManager.StopAgent();
+        }
+
+        protected override void OnShutdown()
+        {
+            agentManager.StopAgent();
+        }
+    }
+}

From 84a948ea6966791b6828c1f5ef4abea6cbcf72a5 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 27 Apr 2018 17:47:59 +0300
Subject: [PATCH 048/100] ScadaData: fix exception type

---
 ScadaData/ScadaData/ScadaUtils.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ScadaData/ScadaData/ScadaUtils.cs b/ScadaData/ScadaData/ScadaUtils.cs
index 2808d3264..ad06c9964 100644
--- a/ScadaData/ScadaData/ScadaUtils.cs
+++ b/ScadaData/ScadaData/ScadaUtils.cs
@@ -316,7 +316,7 @@ public static byte[] HexToBytes(string s, bool skipWhiteSpace = false)
             if (HexToBytes(s, out byte[] bytes, skipWhiteSpace))
                 return bytes;
             else
-                throw new ArgumentException(CommonPhrases.NotHexadecimal, "s");
+                throw new FormatException(CommonPhrases.NotHexadecimal);
         }
 
         /// 

From df3bbba19d483baafa804dfc463e8d45ce35bd25 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Wed, 2 May 2018 10:49:58 +0300
Subject: [PATCH 049/100] Update building instructions

---
 HowToBuild.txt | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/HowToBuild.txt b/HowToBuild.txt
index 258d090d4..ed17b456c 100644
--- a/HowToBuild.txt
+++ b/HowToBuild.txt
@@ -1,7 +1,6 @@
 How to Build Rapid SCADA
 ------------------------
-Microsoft Visual Studio 2010 Professional or higher is needed. 
-Visual Studio Community 2013 is also acceptable.
+Microsoft Visual Studio 2015 or higher is needed. Visual Studio Community is OK.
 
 1. Download the source code from SCADA and DLL repositories:
    https://github.com/RapidScada/scada
@@ -18,4 +17,6 @@ Visual Studio Community 2013 is also acceptable.
    ScadaWeb,
    ScadaScheme.
 
-3. Enjoy the binaries builded by yourself.
\ No newline at end of file
+   Use the Release configuration so that the links are correct.
+
+3. Enjoy the binaries built by yourself.

From 317dffb696b9106b1f905fa179860ce1e428fd39 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 4 May 2018 18:25:11 +0300
Subject: [PATCH 050/100] ScadaAdmin: remote management

---
 .../AgentSvcRef/AgentSvc.wsdl                 | 216 ++++++++++
 .../AgentSvcRef/Reference.cs                  | 371 ++++++++++++++++++
 .../AgentSvcRef/Reference.svcmap              |  36 ++
 ...daAdmin.AgentSvcRef.ConfigParts.datasource |  10 +
 ...Admin.AgentSvcRef.ServiceStatus.datasource |  10 +
 .../AgentSvcRef/configuration.svcinfo         |  10 +
 .../AgentSvcRef/configuration91.svcinfo       | 201 ++++++++++
 .../Connected Services/AgentSvcRef/item.disco |   4 +
 .../Connected Services/AgentSvcRef/item.xsd   |   9 +
 .../Connected Services/AgentSvcRef/item1.xsd  | 109 +++++
 .../Connected Services/AgentSvcRef/item2.xsd  |   6 +
 .../Connected Services/AgentSvcRef/item3.xsd  | 156 ++++++++
 .../Connected Services/AgentSvcRef/item4.xsd  |  42 ++
 ScadaAdmin/ScadaAdmin/FrmAbout.cs             |   6 +-
 ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs     |  44 ++-
 ScadaAdmin/ScadaAdmin/FrmMain.cs              |  26 +-
 ScadaAdmin/ScadaAdmin/FrmMain.resx            |   2 +-
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |   4 +
 .../Remote/FrmDownloadConfig.Designer.cs      | 230 +++++++++++
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |  19 +
 .../ScadaAdmin/Remote/FrmDownloadConfig.resx  | 151 +++++++
 .../Remote/FrmServerStatus.Designer.cs        |  39 ++
 .../ScadaAdmin/Remote/FrmServerStatus.cs      |  19 +
 .../Remote/FrmUploadConfig.Designer.cs        |  39 ++
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      |  19 +
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |  64 ++-
 ScadaAdmin/ScadaAdmin/app.config              |  14 +-
 .../administrator-history.html                |   5 +-
 28 files changed, 1850 insertions(+), 11 deletions(-)
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/AgentSvc.wsdl
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.svcmap
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ConfigParts.datasource
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ServiceStatus.datasource
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration.svcinfo
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration91.svcinfo
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.disco
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.xsd
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item2.xsd
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item3.xsd
 create mode 100644 ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item4.xsd
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs

diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/AgentSvc.wsdl b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/AgentSvc.wsdl
new file mode 100644
index 000000000..cee4e852c
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/AgentSvc.wsdl	
@@ -0,0 +1,216 @@
+
+
+  
+    
+      
+      
+      
+      
+      
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+    
+  
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+    
+      
+      
+    
+  
+  
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+        
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+    
+      
+      
+        
+      
+      
+        
+      
+    
+  
+  
+    
+      
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs
new file mode 100644
index 000000000..0697a0e48
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs	
@@ -0,0 +1,371 @@
+//------------------------------------------------------------------------------
+// 
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// 
+//------------------------------------------------------------------------------
+
+namespace ScadaAdmin.AgentSvcRef {
+    using System.Runtime.Serialization;
+    using System;
+    
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+    [System.Runtime.Serialization.DataContractAttribute(Name="ServiceApp", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")]
+    public enum ServiceApp : int {
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Server = 0,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Communicator = 1,
+    }
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+    [System.Runtime.Serialization.DataContractAttribute(Name="ServiceCommand", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")]
+    public enum ServiceCommand : int {
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Start = 0,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Stop = 1,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Restart = 2,
+    }
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+    [System.Runtime.Serialization.DataContractAttribute(Name="ServiceStatus", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")]
+    public enum ServiceStatus : int {
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Undefined = 0,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Normal = 1,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Stopped = 2,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Error = 3,
+    }
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+    [System.FlagsAttribute()]
+    [System.Runtime.Serialization.DataContractAttribute(Name="ConfigParts", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")]
+    public enum ConfigParts : int {
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        None = 0,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Base = 1,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Interface = 2,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Server = 4,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Communicator = 8,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Webstation = 16,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        All = 31,
+    }
+    
+    [System.Diagnostics.DebuggerStepThroughAttribute()]
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+    [System.Runtime.Serialization.DataContractAttribute(Name="ConfigOptions", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")]
+    [System.SerializableAttribute()]
+    public partial class ConfigOptions : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
+        
+        [System.NonSerializedAttribute()]
+        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
+        
+        [System.Runtime.Serialization.OptionalFieldAttribute()]
+        private ScadaAdmin.AgentSvcRef.ConfigParts ConfigPartsField;
+        
+        [global::System.ComponentModel.BrowsableAttribute(false)]
+        public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
+            get {
+                return this.extensionDataField;
+            }
+            set {
+                this.extensionDataField = value;
+            }
+        }
+        
+        [System.Runtime.Serialization.DataMemberAttribute()]
+        public ScadaAdmin.AgentSvcRef.ConfigParts ConfigParts {
+            get {
+                return this.ConfigPartsField;
+            }
+            set {
+                if ((this.ConfigPartsField.Equals(value) != true)) {
+                    this.ConfigPartsField = value;
+                    this.RaisePropertyChanged("ConfigParts");
+                }
+            }
+        }
+        
+        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
+        
+        protected void RaisePropertyChanged(string propertyName) {
+            System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
+            if ((propertyChanged != null)) {
+                propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
+            }
+        }
+    }
+    
+    [System.Diagnostics.DebuggerStepThroughAttribute()]
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+    [System.Runtime.Serialization.DataContractAttribute(Name="RelPath", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")]
+    [System.SerializableAttribute()]
+    public partial class RelPath : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
+        
+        [System.NonSerializedAttribute()]
+        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
+        
+        [System.Runtime.Serialization.OptionalFieldAttribute()]
+        private ScadaAdmin.AgentSvcRef.AppFolder AppFolderField;
+        
+        [System.Runtime.Serialization.OptionalFieldAttribute()]
+        private ScadaAdmin.AgentSvcRef.ConfigParts ConfigPartField;
+        
+        [System.Runtime.Serialization.OptionalFieldAttribute()]
+        private string PathField;
+        
+        [global::System.ComponentModel.BrowsableAttribute(false)]
+        public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
+            get {
+                return this.extensionDataField;
+            }
+            set {
+                this.extensionDataField = value;
+            }
+        }
+        
+        [System.Runtime.Serialization.DataMemberAttribute()]
+        public ScadaAdmin.AgentSvcRef.AppFolder AppFolder {
+            get {
+                return this.AppFolderField;
+            }
+            set {
+                if ((this.AppFolderField.Equals(value) != true)) {
+                    this.AppFolderField = value;
+                    this.RaisePropertyChanged("AppFolder");
+                }
+            }
+        }
+        
+        [System.Runtime.Serialization.DataMemberAttribute()]
+        public ScadaAdmin.AgentSvcRef.ConfigParts ConfigPart {
+            get {
+                return this.ConfigPartField;
+            }
+            set {
+                if ((this.ConfigPartField.Equals(value) != true)) {
+                    this.ConfigPartField = value;
+                    this.RaisePropertyChanged("ConfigPart");
+                }
+            }
+        }
+        
+        [System.Runtime.Serialization.DataMemberAttribute()]
+        public string Path {
+            get {
+                return this.PathField;
+            }
+            set {
+                if ((object.ReferenceEquals(this.PathField, value) != true)) {
+                    this.PathField = value;
+                    this.RaisePropertyChanged("Path");
+                }
+            }
+        }
+        
+        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
+        
+        protected void RaisePropertyChanged(string propertyName) {
+            System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
+            if ((propertyChanged != null)) {
+                propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
+            }
+        }
+    }
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+    [System.Runtime.Serialization.DataContractAttribute(Name="AppFolder", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")]
+    public enum AppFolder : int {
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Root = 0,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Config = 1,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Log = 2,
+        
+        [System.Runtime.Serialization.EnumMemberAttribute()]
+        Storage = 3,
+    }
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="AgentSvcRef.AgentSvc")]
+    public interface AgentSvc {
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")]
+        bool CreateSession(out long sessionID);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")]
+        bool Login(out string errMsg, long sessionID, string username, string encryptedPassword, string scadaInstanceName);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")]
+        bool ControlService(long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp, ScadaAdmin.AgentSvcRef.ServiceCommand command);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")]
+        bool GetServiceStatus(out ScadaAdmin.AgentSvcRef.ServiceStatus status, long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")]
+        bool GetAvailableConfig(out ScadaAdmin.AgentSvcRef.ConfigParts configParts, long sessionID);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")]
+        System.IO.Stream DownloadConfig(long sessionID, ScadaAdmin.AgentSvcRef.ConfigOptions configOptions);
+        
+        // CODEGEN: Generating message contract since the operation UploadConfig is neither RPC nor document wrapped.
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")]
+        ScadaAdmin.AgentSvcRef.UploadConfigResponse UploadConfig(ScadaAdmin.AgentSvcRef.ConfigUploadMessage request);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")]
+        bool Browse(out string[] directories, out string[] files, long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")]
+        System.IO.Stream DownloadFile(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath);
+        
+        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")]
+        System.IO.Stream DownloadFileRest(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath, long position);
+    }
+    
+    [System.Diagnostics.DebuggerStepThroughAttribute()]
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+    [System.ServiceModel.MessageContractAttribute(WrapperName="ConfigUploadMessage", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
+    public partial class ConfigUploadMessage {
+        
+        [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")]
+        public ScadaAdmin.AgentSvcRef.ConfigOptions ConfigOptions;
+        
+        [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")]
+        public long SessionID;
+        
+        [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)]
+        public System.IO.Stream Stream;
+        
+        public ConfigUploadMessage() {
+        }
+        
+        public ConfigUploadMessage(ScadaAdmin.AgentSvcRef.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) {
+            this.ConfigOptions = ConfigOptions;
+            this.SessionID = SessionID;
+            this.Stream = Stream;
+        }
+    }
+    
+    [System.Diagnostics.DebuggerStepThroughAttribute()]
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+    [System.ServiceModel.MessageContractAttribute(IsWrapped=false)]
+    public partial class UploadConfigResponse {
+        
+        public UploadConfigResponse() {
+        }
+    }
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+    public interface AgentSvcChannel : ScadaAdmin.AgentSvcRef.AgentSvc, System.ServiceModel.IClientChannel {
+    }
+    
+    [System.Diagnostics.DebuggerStepThroughAttribute()]
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+    public partial class AgentSvcClient : System.ServiceModel.ClientBase, ScadaAdmin.AgentSvcRef.AgentSvc {
+        
+        public AgentSvcClient() {
+        }
+        
+        public AgentSvcClient(string endpointConfigurationName) : 
+                base(endpointConfigurationName) {
+        }
+        
+        public AgentSvcClient(string endpointConfigurationName, string remoteAddress) : 
+                base(endpointConfigurationName, remoteAddress) {
+        }
+        
+        public AgentSvcClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
+                base(endpointConfigurationName, remoteAddress) {
+        }
+        
+        public AgentSvcClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
+                base(binding, remoteAddress) {
+        }
+        
+        public bool CreateSession(out long sessionID) {
+            return base.Channel.CreateSession(out sessionID);
+        }
+        
+        public bool Login(out string errMsg, long sessionID, string username, string encryptedPassword, string scadaInstanceName) {
+            return base.Channel.Login(out errMsg, sessionID, username, encryptedPassword, scadaInstanceName);
+        }
+        
+        public bool ControlService(long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp, ScadaAdmin.AgentSvcRef.ServiceCommand command) {
+            return base.Channel.ControlService(sessionID, serviceApp, command);
+        }
+        
+        public bool GetServiceStatus(out ScadaAdmin.AgentSvcRef.ServiceStatus status, long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp) {
+            return base.Channel.GetServiceStatus(out status, sessionID, serviceApp);
+        }
+        
+        public bool GetAvailableConfig(out ScadaAdmin.AgentSvcRef.ConfigParts configParts, long sessionID) {
+            return base.Channel.GetAvailableConfig(out configParts, sessionID);
+        }
+        
+        public System.IO.Stream DownloadConfig(long sessionID, ScadaAdmin.AgentSvcRef.ConfigOptions configOptions) {
+            return base.Channel.DownloadConfig(sessionID, configOptions);
+        }
+        
+        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+        ScadaAdmin.AgentSvcRef.UploadConfigResponse ScadaAdmin.AgentSvcRef.AgentSvc.UploadConfig(ScadaAdmin.AgentSvcRef.ConfigUploadMessage request) {
+            return base.Channel.UploadConfig(request);
+        }
+        
+        public void UploadConfig(ScadaAdmin.AgentSvcRef.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) {
+            ScadaAdmin.AgentSvcRef.ConfigUploadMessage inValue = new ScadaAdmin.AgentSvcRef.ConfigUploadMessage();
+            inValue.ConfigOptions = ConfigOptions;
+            inValue.SessionID = SessionID;
+            inValue.Stream = Stream;
+            ScadaAdmin.AgentSvcRef.UploadConfigResponse retVal = ((ScadaAdmin.AgentSvcRef.AgentSvc)(this)).UploadConfig(inValue);
+        }
+        
+        public bool Browse(out string[] directories, out string[] files, long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath) {
+            return base.Channel.Browse(out directories, out files, sessionID, relPath);
+        }
+        
+        public System.IO.Stream DownloadFile(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath) {
+            return base.Channel.DownloadFile(sessionID, relPath);
+        }
+        
+        public System.IO.Stream DownloadFileRest(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath, long position) {
+            return base.Channel.DownloadFileRest(sessionID, relPath, position);
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.svcmap b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.svcmap
new file mode 100644
index 000000000..35ec80ed6
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.svcmap	
@@ -0,0 +1,36 @@
+
+
+  
+    false
+    true
+    
+    false
+    false
+    false
+    
+    
+    true
+    Auto
+    true
+    true
+    
+    
+    
+  
+  
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ConfigParts.datasource b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ConfigParts.datasource
new file mode 100644
index 000000000..d0dc511ef
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ConfigParts.datasource	
@@ -0,0 +1,10 @@
+
+
+
+   ScadaAdmin.AgentSvcRef.ConfigParts, Connected Services.AgentSvcRef.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ServiceStatus.datasource b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ServiceStatus.datasource
new file mode 100644
index 000000000..27519ae88
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ServiceStatus.datasource	
@@ -0,0 +1,10 @@
+
+
+
+   ScadaAdmin.AgentSvcRef.ServiceStatus, Connected Services.AgentSvcRef.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration.svcinfo b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration.svcinfo
new file mode 100644
index 000000000..38bb543c7
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration.svcinfo	
@@ -0,0 +1,10 @@
+
+
+  
+  
+    
+  
+  
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration91.svcinfo b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration91.svcinfo
new file mode 100644
index 000000000..8031434d2
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration91.svcinfo	
@@ -0,0 +1,201 @@
+
+
+  
+    
+      
+        
+          BasicHttpBinding_AgentSvc
+        
+        
+          
+        
+        
+          
+        
+        
+          
+        
+        
+          
+        
+        
+          
+        
+        
+          
+        
+        
+          StrongWildcard
+        
+        
+          
+        
+        
+          65536
+        
+        
+          
+        
+        
+          
+        
+        
+          System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement
+        
+        
+          0
+        
+        
+          0
+        
+        
+          0
+        
+        
+          0
+        
+        
+          0
+        
+        
+          System.Text.UTF8Encoding
+        
+        
+          Buffered
+        
+        
+          
+        
+        
+          Text
+        
+        
+          System.ServiceModel.Configuration.BasicHttpSecurityElement
+        
+        
+          None
+        
+        
+          System.ServiceModel.Configuration.HttpTransportSecurityElement
+        
+        
+          None
+        
+        
+          None
+        
+        
+          System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement
+        
+        
+          Never
+        
+        
+          TransportSelected
+        
+        
+          (Collection)
+        
+        
+          
+        
+        
+          System.ServiceModel.Configuration.BasicHttpMessageSecurityElement
+        
+        
+          UserName
+        
+        
+          Default
+        
+      
+    
+  
+  
+    
+      
+        
+          http://localhost:10002/ScadaAgent/ScadaAgentSvc/
+        
+        
+          
+        
+        
+          basicHttpBinding
+        
+        
+          BasicHttpBinding_AgentSvc
+        
+        
+          AgentSvcRef.AgentSvc
+        
+        
+          System.ServiceModel.Configuration.AddressHeaderCollectionElement
+        
+        
+          <Header />
+        
+        
+          System.ServiceModel.Configuration.IdentityElement
+        
+        
+          System.ServiceModel.Configuration.UserPrincipalNameElement
+        
+        
+          
+        
+        
+          System.ServiceModel.Configuration.ServicePrincipalNameElement
+        
+        
+          
+        
+        
+          System.ServiceModel.Configuration.DnsElement
+        
+        
+          
+        
+        
+          System.ServiceModel.Configuration.RsaElement
+        
+        
+          
+        
+        
+          System.ServiceModel.Configuration.CertificateElement
+        
+        
+          
+        
+        
+          System.ServiceModel.Configuration.CertificateReferenceElement
+        
+        
+          My
+        
+        
+          LocalMachine
+        
+        
+          FindBySubjectDistinguishedName
+        
+        
+          
+        
+        
+          False
+        
+        
+          BasicHttpBinding_AgentSvc
+        
+        
+          
+        
+        
+          
+        
+      
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.disco b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.disco
new file mode 100644
index 000000000..c6b1d8ffa
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.disco	
@@ -0,0 +1,4 @@
+
+
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.xsd
new file mode 100644
index 000000000..04a74a45c
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.xsd	
@@ -0,0 +1,9 @@
+
+
+  
+    
+      
+    
+  
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd
new file mode 100644
index 000000000..76a301227
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd	
@@ -0,0 +1,109 @@
+
+
+  
+  
+    
+      
+      
+    
+  
+  
+  
+    
+      
+      
+      
+    
+  
+  
+  
+    
+      
+      
+      
+      
+    
+  
+  
+  
+    
+      
+        
+          
+            
+              
+                0
+              
+            
+          
+          
+            
+              
+                1
+              
+            
+          
+          
+            
+              
+                2
+              
+            
+          
+          
+            
+              
+                4
+              
+            
+          
+          
+            
+              
+                8
+              
+            
+          
+          
+            
+              
+                16
+              
+            
+          
+          
+            
+              
+                31
+              
+            
+          
+        
+      
+    
+  
+  
+  
+    
+      
+    
+  
+  
+  
+    
+      
+      
+      
+    
+  
+  
+  
+    
+      
+      
+      
+      
+    
+  
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item2.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item2.xsd
new file mode 100644
index 000000000..9c6da3168
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item2.xsd	
@@ -0,0 +1,6 @@
+
+
+  
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item3.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item3.xsd
new file mode 100644
index 000000000..f5e7fda8c
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item3.xsd	
@@ -0,0 +1,156 @@
+
+
+  
+  
+  
+  
+    
+      
+    
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+        
+        
+        
+      
+    
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+        
+        
+      
+    
+  
+  
+    
+      
+        
+      
+    
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+      
+    
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+      
+    
+  
+  
+    
+      
+        
+      
+    
+  
+  
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+        
+        
+      
+    
+  
+  
+    
+      
+        
+        
+      
+    
+  
+  
+    
+      
+        
+      
+    
+  
+  
+    
+      
+        
+        
+        
+      
+    
+  
+  
+    
+      
+        
+      
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item4.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item4.xsd
new file mode 100644
index 000000000..d58e7f39c
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item4.xsd	
@@ -0,0 +1,42 @@
+
+
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+    
+  
+  
+  
+    
+      
+      
+      
+    
+  
+  
+  
+    
+      
+    
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/FrmAbout.cs b/ScadaAdmin/ScadaAdmin/FrmAbout.cs
index 85a2cbcac..55f1c24d5 100644
--- a/ScadaAdmin/ScadaAdmin/FrmAbout.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmAbout.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2010
- * Modified : 2017
+ * Modified : 2018
  */
 
 using Scada;
@@ -37,7 +37,7 @@ namespace ScadaAdmin
     /// 
     public partial class FrmAbout : Form
     {
-        private const string Version = "5.0.0.2"; // версия приложения
+        private const string Version = "5.1.0.0"; // версия приложения
         private static FrmAbout frmAbout = null;  // экземпляр формы о программе
         
         private bool inited;    // форма инициализирована
diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs b/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs
index 2a0dcb6d2..d252bc3de 100644
--- a/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs
@@ -100,6 +100,10 @@ private void InitializeComponent()
             this.miExplorerRefresh = new System.Windows.Forms.ToolStripMenuItem();
             this.contextInCnls = new System.Windows.Forms.ContextMenuStrip(this.components);
             this.miInCnlProps = new System.Windows.Forms.ToolStripMenuItem();
+            this.miRemote = new System.Windows.Forms.ToolStripMenuItem();
+            this.miRemoteDownload = new System.Windows.Forms.ToolStripMenuItem();
+            this.miRemoteUpload = new System.Windows.Forms.ToolStripMenuItem();
+            this.miRemoteStatus = new System.Windows.Forms.ToolStripMenuItem();
             this.menuMain.SuspendLayout();
             this.toolMain.SuspendLayout();
             this.statusMain.SuspendLayout();
@@ -116,6 +120,7 @@ private void InitializeComponent()
             this.miEdit,
             this.miView,
             this.miService,
+            this.miRemote,
             this.miSettings,
             this.miWindow,
             this.miHelp});
@@ -364,14 +369,14 @@ private void InitializeComponent()
             // 
             this.miSettingsParams.Image = ((System.Drawing.Image)(resources.GetObject("miSettingsParams.Image")));
             this.miSettingsParams.Name = "miSettingsParams";
-            this.miSettingsParams.Size = new System.Drawing.Size(147, 22);
+            this.miSettingsParams.Size = new System.Drawing.Size(180, 22);
             this.miSettingsParams.Text = "Параметры...";
             this.miSettingsParams.Click += new System.EventHandler(this.miSettingsParams_Click);
             // 
             // miSettingsLanguage
             // 
             this.miSettingsLanguage.Name = "miSettingsLanguage";
-            this.miSettingsLanguage.Size = new System.Drawing.Size(147, 22);
+            this.miSettingsLanguage.Size = new System.Drawing.Size(180, 22);
             this.miSettingsLanguage.Text = "Язык...";
             this.miSettingsLanguage.Click += new System.EventHandler(this.miSettingsLanguage_Click);
             // 
@@ -740,6 +745,37 @@ private void InitializeComponent()
             this.miInCnlProps.Text = "Свойства канала";
             this.miInCnlProps.Click += new System.EventHandler(this.miInCnlProps_Click);
             // 
+            // miRemote
+            // 
+            this.miRemote.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.miRemoteDownload,
+            this.miRemoteUpload,
+            this.miRemoteStatus});
+            this.miRemote.Name = "miRemote";
+            this.miRemote.Size = new System.Drawing.Size(122, 20);
+            this.miRemote.Text = "&Удаленный сервер";
+            // 
+            // miRemoteDownload
+            // 
+            this.miRemoteDownload.Name = "miRemoteDownload";
+            this.miRemoteDownload.Size = new System.Drawing.Size(221, 22);
+            this.miRemoteDownload.Text = "Скачать конфигурацию...";
+            this.miRemoteDownload.Click += new System.EventHandler(this.miRemoteDownload_Click);
+            // 
+            // miRemoteUpload
+            // 
+            this.miRemoteUpload.Name = "miRemoteUpload";
+            this.miRemoteUpload.Size = new System.Drawing.Size(221, 22);
+            this.miRemoteUpload.Text = "Передать конфигурацию...";
+            this.miRemoteUpload.Click += new System.EventHandler(this.miRemoteUpload_Click);
+            // 
+            // miRemoteStatus
+            // 
+            this.miRemoteStatus.Name = "miRemoteStatus";
+            this.miRemoteStatus.Size = new System.Drawing.Size(221, 22);
+            this.miRemoteStatus.Text = "Статус сервера...";
+            this.miRemoteStatus.Click += new System.EventHandler(this.miRemoteStatus_Click);
+            // 
             // FrmMain
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -848,6 +884,10 @@ private void InitializeComponent()
         private System.Windows.Forms.ToolStripButton btnRestartComm;
         private System.Windows.Forms.ToolStripSeparator sepFifth;
         private System.Windows.Forms.ToolStripMenuItem miSettingsLanguage;
+        private System.Windows.Forms.ToolStripMenuItem miRemote;
+        private System.Windows.Forms.ToolStripMenuItem miRemoteDownload;
+        private System.Windows.Forms.ToolStripMenuItem miRemoteUpload;
+        private System.Windows.Forms.ToolStripMenuItem miRemoteStatus;
     }
 }
 
diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.cs b/ScadaAdmin/ScadaAdmin/FrmMain.cs
index 1b9c04f94..79193844e 100644
--- a/ScadaAdmin/ScadaAdmin/FrmMain.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmMain.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,11 +20,12 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2010
- * Modified : 2017
+ * Modified : 2018
  */
 
 using Scada;
 using Scada.UI;
+using ScadaAdmin.Remote;
 using System;
 using System.Collections.Generic;
 using System.Data;
@@ -1027,6 +1028,27 @@ private void miServiceRestart_Click(object sender, EventArgs e)
             }
         }
 
+        private void miRemoteDownload_Click(object sender, EventArgs e)
+        {
+            // открытие формы скачивания конфигурации
+            FrmDownloadConfig frmDownloadConfig = new FrmDownloadConfig();
+            frmDownloadConfig.ShowDialog();
+        }
+
+        private void miRemoteUpload_Click(object sender, EventArgs e)
+        {
+            // открытие формы передачи конфигурации
+            FrmUploadConfig frmUploadConfig = new FrmUploadConfig();
+            frmUploadConfig.ShowDialog();
+        }
+
+        private void miRemoteStatus_Click(object sender, EventArgs e)
+        {
+            // открытие формы статуса сервера
+            FrmServerStatus frmServerStatus = new FrmServerStatus();
+            frmServerStatus.ShowDialog();
+        }
+
         private void miWindowCloseActive_Click(object sender, EventArgs e)
         {
             FrmTable frmTable = winControl.ActiveForm as FrmTable;
diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.resx b/ScadaAdmin/ScadaAdmin/FrmMain.resx
index f7549a9c6..3606e77d4 100644
--- a/ScadaAdmin/ScadaAdmin/FrmMain.resx
+++ b/ScadaAdmin/ScadaAdmin/FrmMain.resx
@@ -400,7 +400,7 @@
         AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
         LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
         ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAY
-        DwAAAk1TRnQBSQFMAgEBBwEAAdgBAwHYAQMBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
+        DwAAAk1TRnQBSQFMAgEBBwEAAeABAwHgAQMBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
         AwABQAMAASADAAEBAQABCAYAAQgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
         AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
         AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index 69e9b5a3e..a0060e7ab 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -239,6 +239,10 @@
     Channel Map...
     Restart SCADA-Server
     Restart SCADA-Communicator
+    &Remote Server
+    Download Configuration...
+    Upload Configuration...
+    Server Status...
     &Settings
     Parameters...
     Language...
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
new file mode 100644
index 000000000..30ac27cdd
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
@@ -0,0 +1,230 @@
+namespace ScadaAdmin.Remote
+{
+    partial class FrmDownloadConfig
+    {
+        /// 
+        /// Required designer variable.
+        /// 
+        private System.ComponentModel.IContainer components = null;
+
+        /// 
+        /// Clean up any resources being used.
+        /// 
+        /// true if managed resources should be disposed; otherwise, false.
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// 
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// 
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmDownloadConfig));
+            this.gbConnection = new System.Windows.Forms.GroupBox();
+            this.comboBox1 = new System.Windows.Forms.ComboBox();
+            this.button1 = new System.Windows.Forms.Button();
+            this.button2 = new System.Windows.Forms.Button();
+            this.button3 = new System.Windows.Forms.Button();
+            this.radioButton1 = new System.Windows.Forms.RadioButton();
+            this.textBox1 = new System.Windows.Forms.TextBox();
+            this.btnBaseSDFFile = new System.Windows.Forms.Button();
+            this.radioButton2 = new System.Windows.Forms.RadioButton();
+            this.button4 = new System.Windows.Forms.Button();
+            this.textBox2 = new System.Windows.Forms.TextBox();
+            this.btnDownload = new System.Windows.Forms.Button();
+            this.btnClose = new System.Windows.Forms.Button();
+            this.gbOptions = new System.Windows.Forms.GroupBox();
+            this.gbConnection.SuspendLayout();
+            this.gbOptions.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // gbConnection
+            // 
+            this.gbConnection.Controls.Add(this.button3);
+            this.gbConnection.Controls.Add(this.button2);
+            this.gbConnection.Controls.Add(this.button1);
+            this.gbConnection.Controls.Add(this.comboBox1);
+            this.gbConnection.Location = new System.Drawing.Point(12, 12);
+            this.gbConnection.Name = "gbConnection";
+            this.gbConnection.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
+            this.gbConnection.Size = new System.Drawing.Size(469, 55);
+            this.gbConnection.TabIndex = 0;
+            this.gbConnection.TabStop = false;
+            this.gbConnection.Text = "Подключение к серверу";
+            // 
+            // comboBox1
+            // 
+            this.comboBox1.FormattingEnabled = true;
+            this.comboBox1.Location = new System.Drawing.Point(13, 20);
+            this.comboBox1.Name = "comboBox1";
+            this.comboBox1.Size = new System.Drawing.Size(200, 21);
+            this.comboBox1.TabIndex = 0;
+            // 
+            // button1
+            // 
+            this.button1.Location = new System.Drawing.Point(219, 19);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(75, 23);
+            this.button1.TabIndex = 1;
+            this.button1.Text = "Создать";
+            this.button1.UseVisualStyleBackColor = true;
+            // 
+            // button2
+            // 
+            this.button2.Location = new System.Drawing.Point(300, 19);
+            this.button2.Name = "button2";
+            this.button2.Size = new System.Drawing.Size(75, 23);
+            this.button2.TabIndex = 2;
+            this.button2.Text = "Настроить";
+            this.button2.UseVisualStyleBackColor = true;
+            // 
+            // button3
+            // 
+            this.button3.Location = new System.Drawing.Point(381, 19);
+            this.button3.Name = "button3";
+            this.button3.Size = new System.Drawing.Size(75, 23);
+            this.button3.TabIndex = 3;
+            this.button3.Text = "Удалить";
+            this.button3.UseVisualStyleBackColor = true;
+            // 
+            // radioButton1
+            // 
+            this.radioButton1.AutoSize = true;
+            this.radioButton1.Location = new System.Drawing.Point(13, 19);
+            this.radioButton1.Name = "radioButton1";
+            this.radioButton1.Size = new System.Drawing.Size(154, 17);
+            this.radioButton1.TabIndex = 0;
+            this.radioButton1.TabStop = true;
+            this.radioButton1.Text = "Сохранить в директорию:";
+            this.radioButton1.UseVisualStyleBackColor = true;
+            // 
+            // textBox1
+            // 
+            this.textBox1.Location = new System.Drawing.Point(13, 43);
+            this.textBox1.Name = "textBox1";
+            this.textBox1.Size = new System.Drawing.Size(417, 20);
+            this.textBox1.TabIndex = 1;
+            // 
+            // btnBaseSDFFile
+            // 
+            this.btnBaseSDFFile.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
+            this.btnBaseSDFFile.Image = ((System.Drawing.Image)(resources.GetObject("btnBaseSDFFile.Image")));
+            this.btnBaseSDFFile.Location = new System.Drawing.Point(436, 43);
+            this.btnBaseSDFFile.Name = "btnBaseSDFFile";
+            this.btnBaseSDFFile.Size = new System.Drawing.Size(20, 20);
+            this.btnBaseSDFFile.TabIndex = 2;
+            this.btnBaseSDFFile.UseVisualStyleBackColor = true;
+            // 
+            // radioButton2
+            // 
+            this.radioButton2.AutoSize = true;
+            this.radioButton2.Location = new System.Drawing.Point(13, 69);
+            this.radioButton2.Name = "radioButton2";
+            this.radioButton2.Size = new System.Drawing.Size(122, 17);
+            this.radioButton2.TabIndex = 3;
+            this.radioButton2.TabStop = true;
+            this.radioButton2.Text = "Сохранить в архив:";
+            this.radioButton2.UseVisualStyleBackColor = true;
+            // 
+            // button4
+            // 
+            this.button4.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
+            this.button4.Image = ((System.Drawing.Image)(resources.GetObject("button4.Image")));
+            this.button4.Location = new System.Drawing.Point(436, 92);
+            this.button4.Name = "button4";
+            this.button4.Size = new System.Drawing.Size(20, 20);
+            this.button4.TabIndex = 5;
+            this.button4.UseVisualStyleBackColor = true;
+            // 
+            // textBox2
+            // 
+            this.textBox2.Location = new System.Drawing.Point(13, 92);
+            this.textBox2.Name = "textBox2";
+            this.textBox2.Size = new System.Drawing.Size(417, 20);
+            this.textBox2.TabIndex = 4;
+            // 
+            // btnDownload
+            // 
+            this.btnDownload.Location = new System.Drawing.Point(325, 204);
+            this.btnDownload.Name = "btnDownload";
+            this.btnDownload.Size = new System.Drawing.Size(75, 23);
+            this.btnDownload.TabIndex = 2;
+            this.btnDownload.Text = "Скачать";
+            this.btnDownload.UseVisualStyleBackColor = true;
+            // 
+            // btnClose
+            // 
+            this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnClose.Location = new System.Drawing.Point(406, 204);
+            this.btnClose.Name = "btnClose";
+            this.btnClose.Size = new System.Drawing.Size(75, 23);
+            this.btnClose.TabIndex = 3;
+            this.btnClose.Text = "Закрыть";
+            this.btnClose.UseVisualStyleBackColor = true;
+            // 
+            // gbOptions
+            // 
+            this.gbOptions.Controls.Add(this.radioButton1);
+            this.gbOptions.Controls.Add(this.textBox1);
+            this.gbOptions.Controls.Add(this.btnBaseSDFFile);
+            this.gbOptions.Controls.Add(this.button4);
+            this.gbOptions.Controls.Add(this.radioButton2);
+            this.gbOptions.Controls.Add(this.textBox2);
+            this.gbOptions.Location = new System.Drawing.Point(12, 73);
+            this.gbOptions.Name = "gbOptions";
+            this.gbOptions.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
+            this.gbOptions.Size = new System.Drawing.Size(469, 125);
+            this.gbOptions.TabIndex = 1;
+            this.gbOptions.TabStop = false;
+            this.gbOptions.Text = "Параметры скачивания";
+            // 
+            // FrmDownloadConfig
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.btnClose;
+            this.ClientSize = new System.Drawing.Size(493, 239);
+            this.Controls.Add(this.gbOptions);
+            this.Controls.Add(this.btnClose);
+            this.Controls.Add(this.btnDownload);
+            this.Controls.Add(this.gbConnection);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+            this.MaximizeBox = false;
+            this.MinimizeBox = false;
+            this.Name = "FrmDownloadConfig";
+            this.ShowInTaskbar = false;
+            this.Text = "Скачивание конфигурации";
+            this.gbConnection.ResumeLayout(false);
+            this.gbOptions.ResumeLayout(false);
+            this.gbOptions.PerformLayout();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.GroupBox gbConnection;
+        private System.Windows.Forms.Button button3;
+        private System.Windows.Forms.Button button2;
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.ComboBox comboBox1;
+        private System.Windows.Forms.RadioButton radioButton1;
+        private System.Windows.Forms.TextBox textBox1;
+        private System.Windows.Forms.Button btnBaseSDFFile;
+        private System.Windows.Forms.RadioButton radioButton2;
+        private System.Windows.Forms.Button button4;
+        private System.Windows.Forms.TextBox textBox2;
+        private System.Windows.Forms.Button btnDownload;
+        private System.Windows.Forms.Button btnClose;
+        private System.Windows.Forms.GroupBox gbOptions;
+    }
+}
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
new file mode 100644
index 000000000..42447bed4
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ScadaAdmin.Remote
+{
+    public partial class FrmDownloadConfig : Form
+    {
+        public FrmDownloadConfig()
+        {
+            InitializeComponent();
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
new file mode 100644
index 000000000..1ecd958e7
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
@@ -0,0 +1,151 @@
+
+
+  
+  
+    
+    
+      
+        
+          
+            
+              
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+              
+            
+          
+          
+            
+              
+                
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+                
+              
+              
+            
+          
+        
+      
+    
+  
+  
+    text/microsoft-resx
+  
+  
+    2.0
+  
+  
+    System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+  
+    
+        R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R
+        fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N
+        VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc
+        iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d
+        gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i
+        Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq
+        LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB
+        AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF
+        FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS
+        BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28
+        tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs=
+
+  
+  
+    
+        R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R
+        fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N
+        VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc
+        iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d
+        gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i
+        Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq
+        LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB
+        AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF
+        FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS
+        BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28
+        tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs=
+
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs
new file mode 100644
index 000000000..91f5b949d
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs
@@ -0,0 +1,39 @@
+namespace ScadaAdmin.Remote
+{
+    partial class FrmServerStatus
+    {
+        /// 
+        /// Required designer variable.
+        /// 
+        private System.ComponentModel.IContainer components = null;
+
+        /// 
+        /// Clean up any resources being used.
+        /// 
+        /// true if managed resources should be disposed; otherwise, false.
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// 
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// 
+        private void InitializeComponent()
+        {
+            this.components = new System.ComponentModel.Container();
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(800, 450);
+            this.Text = "FrmServerStatus";
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
new file mode 100644
index 000000000..abe6dd03a
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ScadaAdmin.Remote
+{
+    public partial class FrmServerStatus : Form
+    {
+        public FrmServerStatus()
+        {
+            InitializeComponent();
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
new file mode 100644
index 000000000..7f2652ce1
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
@@ -0,0 +1,39 @@
+namespace ScadaAdmin.Remote
+{
+    partial class FrmUploadConfig
+    {
+        /// 
+        /// Required designer variable.
+        /// 
+        private System.ComponentModel.IContainer components = null;
+
+        /// 
+        /// Clean up any resources being used.
+        /// 
+        /// true if managed resources should be disposed; otherwise, false.
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// 
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// 
+        private void InitializeComponent()
+        {
+            this.components = new System.ComponentModel.Container();
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(800, 450);
+            this.Text = "FrmUploadConfig";
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
new file mode 100644
index 000000000..c304a78cb
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ScadaAdmin.Remote
+{
+    public partial class FrmUploadConfig : Form
+    {
+        public FrmUploadConfig()
+        {
+            InitializeComponent();
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index 0d96a038e..33eccb712 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -83,6 +83,8 @@
     
     
     
+    
+    
     
     
     
@@ -96,6 +98,11 @@
     
     
     
+    
+      True
+      True
+      Reference.svcmap
+    
     
       Form
     
@@ -183,6 +190,24 @@
     
     
     
+    
+      Form
+    
+    
+      FrmDownloadConfig.cs
+    
+    
+      Form
+    
+    
+      FrmServerStatus.cs
+    
+    
+      Form
+    
+    
+      FrmUploadConfig.cs
+    
     
       FrmAbout.cs
     
@@ -235,8 +260,33 @@
       Resources.resx
       True
     
+    
+      FrmDownloadConfig.cs
+    
     
     
+    
+    
+      Designer
+    
+    
+      Designer
+    
+    
+      Designer
+    
+    
+      Designer
+    
+    
+      Designer
+    
+    
+      Reference.svcmap
+    
+    
+      Reference.svcmap
+    
     
       SettingsSingleFileGenerator
       Settings.Designer.cs
@@ -258,6 +308,13 @@
       Lang\ScadaData.ru-RU.xml
       PreserveNewest
     
+    
+    
+    
+    
+      WCF Proxy Generator
+      Reference.cs
+    
     
     
       Designer
@@ -268,7 +325,12 @@
       Designer
     
   
-  
+  
+    
+  
+  
+    
+  
   
   
 
-   Scada.Agent.Ctrl.ServiceReference1.BrowseResponse
+   Scada.Agent.Ctrl.ServiceReference1.BrowseResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource
index 183f75391..26cdb25a0 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource	
+++ b/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource	
@@ -6,5 +6,5 @@
     cause the file to be unrecognizable by the program.
 -->
 
-   Scada.Agent.Ctrl.ServiceReference1.LoginResponse
+   Scada.Agent.Ctrl.ServiceReference1.LoginResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 
\ No newline at end of file

From 30c5533622c141cff3fcf18bd164e6e05b935246 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 6 May 2018 15:10:14 +0300
Subject: [PATCH 052/100] ScadaScheme: fix get EditorMode exception

---
 .../ru/version-history/webstation-plugins-history.html       | 5 ++++-
 ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs        | 5 +++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
index 745feeafa..a4e5612a5 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
@@ -112,7 +112,10 @@ 

Таблицы

- Возможность отправки бинарных команд с выбором значений из списка

Схемы

-
PlgScheme 5.2.1.0 (16.03.2018)
+    
PlgScheme 5.2.1.1 (В разработке)
+- Исправлена ошибка в методе определения запуска Редактора схем
+
+PlgScheme 5.2.1.0 (16.03.2018)
 - Добавлено свойство ширины рамки для написей и рисунков
 - Возможность отправки команд сразу
 - Использование очереди для отправки Ajax-запросов
diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs
index 271d43aaa..6317dcb64 100644
--- a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs
+++ b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs
@@ -48,8 +48,9 @@ public static class SchemeUtils
         public static bool EditorMode
         {
             get
-            {                
-                return Assembly.GetEntryAssembly().GetName().Name == "ScadaSchemeEditor";
+            {
+                Assembly asm = Assembly.GetEntryAssembly();
+                return asm != null && asm.GetName().Name == "ScadaSchemeEditor";
             }
         }
 

From a780631acf4f6be3449bf98488411ac1b16a617e Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 7 May 2018 10:05:41 +0300
Subject: [PATCH 053/100] ScadaAdmin: change directory structure

---
 ScadaAdmin/ScadaAdmin/AppCode/AppData.cs      | 21 +++--
 ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs      | 81 +++++++++++++++++++
 ScadaAdmin/ScadaAdmin/AppCode/Settings.cs     | 12 +--
 .../ScadaAdmin/Config/ScadaAdminConfig.xml    |  8 ++
 ScadaAdmin/ScadaAdmin/FrmAbout.cs             |  2 +-
 ScadaAdmin/ScadaAdmin/FrmCnlMap.cs            |  6 +-
 ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs        |  6 +-
 ScadaAdmin/ScadaAdmin/FrmImport.cs            |  6 +-
 ScadaAdmin/ScadaAdmin/FrmMain.cs              |  7 +-
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |  4 +
 10 files changed, 124 insertions(+), 29 deletions(-)
 create mode 100644 ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Config/ScadaAdminConfig.xml

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs
index be64f13c6..348ffdc1a 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2010
- * Modified : 2014
+ * Modified : 2018
  */
 
 using System.Data;
@@ -50,18 +50,23 @@ internal static class AppData
         /// 
         static AppData()
         {
-            ExeDir = ScadaUtils.NormalDir(Path.GetDirectoryName(Application.ExecutablePath));
-            ErrLog = new Log(Log.Formats.Full);
-            ErrLog.FileName = ExeDir + ErrFileName;
-            ErrLog.Encoding = Encoding.UTF8;
+            AppDirs = new AppDirs();
+            AppDirs.Init(Path.GetDirectoryName(Application.ExecutablePath));
+
+            ErrLog = new Log(Log.Formats.Full)
+            {
+                FileName = AppDirs.LogDir + ErrFileName,
+                Encoding = Encoding.UTF8
+            };
+
             Conn =  new SqlCeConnection();
         }
 
 
         /// 
-        /// Получить директорию исполняемого файла приложения
+        /// Получить директории приложения
         /// 
-        public static string ExeDir { get; private set; }
+        public static AppDirs AppDirs { get; private set; }
 
         /// 
         /// Получить журнал ошибок приложения
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs
new file mode 100644
index 000000000..800abde43
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Application directories
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada;
+using System.IO;
+
+namespace ScadaAdmin
+{
+    /// 
+    /// Application directories
+    /// Директории приложения
+    /// 
+    public class AppDirs
+    {
+        /// 
+        /// Конструктор
+        /// 
+        public AppDirs()
+        {
+            ExeDir = "";
+            ConfigDir = "";
+            LangDir = "";
+            LogDir = "";
+        }
+
+
+        /// 
+        /// Получить директорию исполняемого файла
+        /// 
+        public string ExeDir { get; protected set; }
+        
+        /// 
+        /// Получить директорию конфигурации
+        /// 
+        public string ConfigDir { get; protected set; }
+        
+        /// 
+        /// Получить директорию языковых файлов
+        /// 
+        public string LangDir { get; protected set; }
+        
+        /// 
+        /// Получить директорию журналов
+        /// 
+        public string LogDir { get; protected set; }
+
+
+        /// 
+        /// Инициализировать директории на основе директории исполняемого файла приложения
+        /// 
+        public void Init(string exeDir)
+        {
+            ExeDir = ScadaUtils.NormalDir(exeDir);
+            ConfigDir = ExeDir + "Config" + Path.DirectorySeparatorChar;
+            LangDir = ExeDir + "Lang" + Path.DirectorySeparatorChar;
+            LogDir = ExeDir + "Log" + Path.DirectorySeparatorChar;
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs b/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs
index 18cf8e529..f92d2b7a4 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2010
- * Modified : 2016
+ * Modified : 2018
  */
 
 using System;
@@ -182,7 +182,7 @@ public bool LoadAppSettings(out string errMsg)
             AppSett.SetToDefault();
 
             // загрузка из файла
-            string fileName = AppData.ExeDir + AppSettingsFileName;
+            string fileName = AppData.AppDirs.ConfigDir + AppSettingsFileName;
 
             try
             {
@@ -258,7 +258,7 @@ public bool SaveAppSettings(out string errMsg)
                     "Автоматически резервировать базу конфигурации", "Automatically backup the configuration database");
 
                 // сохранение в файле
-                xmlDoc.Save(AppData.ExeDir + AppSettingsFileName);
+                xmlDoc.Save(AppData.AppDirs.ConfigDir + AppSettingsFileName);
                 errMsg = "";
                 return true;
             }
@@ -279,7 +279,7 @@ public void LoadFormState()
             FormSt.SetToDefault();
 
             // загрузка из файла
-            string fileName = AppData.ExeDir + FormStateFileName;
+            string fileName = AppData.AppDirs.ConfigDir + FormStateFileName;
 
             if (File.Exists(fileName))
             {
@@ -353,7 +353,7 @@ public bool SaveFormState(out string errMsg)
                 rootElem.AppendParamElem("ExplorerWidth", FormSt.ExplorerWidth);
 
                 // сохранение в файле
-                xmlDoc.Save(AppData.ExeDir + FormStateFileName);
+                xmlDoc.Save(AppData.AppDirs.ConfigDir + FormStateFileName);
                 errMsg = "";
                 return true;
             }
diff --git a/ScadaAdmin/ScadaAdmin/Config/ScadaAdminConfig.xml b/ScadaAdmin/ScadaAdmin/Config/ScadaAdminConfig.xml
new file mode 100644
index 000000000..53cb7c5ad
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Config/ScadaAdminConfig.xml
@@ -0,0 +1,8 @@
+
+
+  
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/FrmAbout.cs b/ScadaAdmin/ScadaAdmin/FrmAbout.cs
index 55f1c24d5..a21366b91 100644
--- a/ScadaAdmin/ScadaAdmin/FrmAbout.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmAbout.cs
@@ -99,7 +99,7 @@ private void Init()
                 // загрузка изображения и гиперссылки из файлов, если они существуют
                 bool imgLoaded;
                 string errMsg;
-                if (ScadaUiUtils.LoadAboutForm(AppData.ExeDir, this, activePictureBox, lblWebsite,
+                if (ScadaUiUtils.LoadAboutForm(AppData.AppDirs.ExeDir, this, activePictureBox, lblWebsite,
                     out imgLoaded, out linkUrl, out errMsg))
                 {
                     if (imgLoaded)
diff --git a/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs b/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs
index c74103c82..cd37beb33 100644
--- a/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2012
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada;
@@ -137,7 +137,7 @@ private void btnCreate_Click(object sender, EventArgs e)
 
             StreamWriter writer = null;
             bool mapCreated = false;
-            string mapFileName = AppData.ExeDir + "ScadaAdminCnlMap.txt";
+            string mapFileName = AppData.AppDirs.LogDir + "ScadaAdminCnlMap.txt";
 
             try
             {
diff --git a/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs b/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs
index e86eb785d..6a88eb910 100644
--- a/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2010
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada;
@@ -356,7 +356,7 @@ private void btnCalc_Click(object sender, EventArgs e)
         private void btnCreate_Click(object sender, EventArgs e)
         {
             // создание каналов
-            string logFileName = AppData.ExeDir + "ScadaAdminCreateCnls.txt";
+            string logFileName = AppData.AppDirs.LogDir + "ScadaAdminCreateCnls.txt";
             bool logCreated;
             string msg;
             
diff --git a/ScadaAdmin/ScadaAdmin/FrmImport.cs b/ScadaAdmin/ScadaAdmin/FrmImport.cs
index 5369211c0..67d8c2b24 100644
--- a/ScadaAdmin/ScadaAdmin/FrmImport.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmImport.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2010
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada;
@@ -151,7 +151,7 @@ private void btnImport_Click(object sender, EventArgs e)
 
             if (AppData.Connected)
             {
-                string logFileName = chkImportLog.Checked ? AppData.ExeDir + "ScadaAdminImport.txt" : "";
+                string logFileName = chkImportLog.Checked ? AppData.AppDirs.LogDir + "ScadaAdminImport.txt" : "";
                 bool importOK;
                 bool logCreated;
                 string msg;
diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.cs b/ScadaAdmin/ScadaAdmin/FrmMain.cs
index 79193844e..e89e67101 100644
--- a/ScadaAdmin/ScadaAdmin/FrmMain.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmMain.cs
@@ -588,15 +588,12 @@ private void PrepareCloseAll(bool showError)
         private void FrmMain_Load(object sender, EventArgs e)
         {
             // локализация приложения
-            string langDir = AppData.ExeDir + "Lang\\";
-            string errMsg;
-
-            if (Localization.LoadDictionaries(langDir, "ScadaData", out errMsg))
+            if (Localization.LoadDictionaries(AppData.AppDirs.LangDir, "ScadaData", out string errMsg))
                 CommonPhrases.Init();
             else
                 ScadaUiUtils.ShowError(errMsg);
 
-            if (Localization.LoadDictionaries(langDir, "ScadaAdmin", out errMsg))
+            if (Localization.LoadDictionaries(AppData.AppDirs.LangDir, "ScadaAdmin", out errMsg))
             {
                 Translator.TranslateForm(this, "ScadaAdmin.FrmMain", null, contextExpolorer, contextInCnls);
                 AppPhrases.Init();
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index 33eccb712..50d8e4099 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -95,6 +95,7 @@
   
   
     
+    
     
     
     
@@ -315,6 +316,9 @@
       WCF Proxy Generator
       Reference.cs
     
+    
+      PreserveNewest
+    
     
     
       Designer

From 66c7c3beec68865e47c5899e36535d548d1e9729 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 7 May 2018 16:58:37 +0300
Subject: [PATCH 054/100] ScadaAdmin: settings of remote servers

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  21 +-
 .../ScadaAdmin/AppCode/ServersSettings.cs     | 350 ++++++++++++++++++
 .../ScadaAdmin/Config/RemoteServers.xml       |  25 ++
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |   4 +
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |  35 +-
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |   4 +
 ScadaAdmin/ScadaAdmin/app.config              |  27 +-
 7 files changed, 450 insertions(+), 16 deletions(-)
 create mode 100644 ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index 6d1b4f31c..a50e3362d 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2014
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada;
@@ -193,6 +193,10 @@ static AppPhrases()
         public static string DeleteRowsConfirm { get; private set; }
         public static string ClearTableConfirm { get; private set; }
 
+        // Словарь ScadaAdmin.ServersSettings
+        public static string LoadServersSettingsError { get; private set; }
+        public static string SaveServersSettingsError { get; private set; }
+
         // Словарь ScadaAdmin.Tables
         public static string UpdateDataError { get; private set; }
         public static string FillSchemaError { get; private set; }
@@ -354,6 +358,9 @@ private static void SetToDefault()
             DeleteRowsConfirm = "Вы уверены, что хотите удалить строки?";
             ClearTableConfirm = "Вы уверены, что хотите очистить таблицу?";
 
+            LoadServersSettingsError = "Ошибка при загрузке настроек взаимодействия с удалёнными серверами";
+            SaveServersSettingsError = "Ошибка при сохранении настроек взаимодействия с удалёнными серверами";
+
             UpdateDataError = "Ошибка при сохранении изменений таблицы в БД";
             FillSchemaError = "Ошибка при получении схемы данных таблицы";
             DataRequired = "Столбец \"{0}\" не может содержать пустых значений.";
@@ -474,7 +481,9 @@ public static void Init()
             }
 
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmImport", out dict))
+            {
                 ArchiveItem = dict.GetPhrase("ArchiveItem", ArchiveItem);
+            }
 
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmInCnlProps", out dict))
             {
@@ -493,7 +502,9 @@ public static void Init()
             }
 
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmLanguage", out dict))
+            {
                 IncorrectLanguage = dict.GetPhrase("IncorrectLanguage", IncorrectLanguage);
+            }
 
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmMain", out dict))
             {
@@ -546,6 +557,12 @@ public static void Init()
                 ClearTableConfirm = dict.GetPhrase("ClearTableConfirm", ClearTableConfirm);
             }
 
+            if (Localization.Dictionaries.TryGetValue("ScadaAdmin.ServersSettings", out dict))
+            {
+                LoadServersSettingsError = dict.GetPhrase("LoadServersSettingsError", LoadServersSettingsError);
+                SaveServersSettingsError = dict.GetPhrase("SaveServersSettingsError", SaveServersSettingsError);
+            }
+
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Tables", out dict))
             {
                 UpdateDataError = dict.GetPhrase("UpdateDataError", UpdateDataError);
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
new file mode 100644
index 000000000..ee00c7d70
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Settings of interaction with remote servers
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+
+namespace ScadaAdmin
+{
+    /// 
+    /// Settings of interaction with remote servers
+    /// Настройки взаимодействия с удалёнными серверами
+    /// 
+    internal class ServersSettings
+    {
+        /// 
+        /// Remote server connection settings
+        /// Настройки подключения к удалённому серверу
+        /// 
+        public class ConnectionSettings
+        {
+            /// 
+            /// Конструктор
+            /// 
+            public ConnectionSettings()
+            {
+                SetToDefault();
+            }
+
+            /// 
+            /// Получить или установить наименование
+            /// 
+            public string Name { get; set; }
+            /// 
+            /// Получить или установить имя компьютера или IP-адрес
+            /// 
+            public string Host { get; set; }
+            /// 
+            /// Получить или установить TCP-порт
+            /// 
+            public int Port { get; set; }
+            /// 
+            /// Получить или установить имя пользователя
+            /// 
+            public string Username { get; set; }
+            /// 
+            /// Получить или установить пароль пользователя
+            /// 
+            public string Password { get; set; }
+            /// 
+            /// Получить или установить наименования экземпляра системы
+            /// 
+            public string ScadaInstance { get; set; }
+            /// 
+            /// Получить или установить секретный ключ
+            /// 
+            public byte[] SecretKey { get; set; }
+
+            /// 
+            /// Установить настройки по умолчанию
+            /// 
+            private void SetToDefault()
+            {
+                Name = "";
+                Host = "";
+                Port = 10002;
+                Username = "admin";
+                Password = "";
+                ScadaInstance = "Default";
+                SecretKey = new byte[0];
+            }
+            /// 
+            /// Загрузить настройки из XML-узла
+            /// 
+            public void LoadFromXml(XmlNode xmlNode)
+            {
+                if (xmlNode == null)
+                    throw new ArgumentNullException("xmlNode");
+
+                Name = xmlNode.GetChildAsString("Name");
+                Host = xmlNode.GetChildAsString("Host");
+                Port = xmlNode.GetChildAsInt("Port", 10002);
+                Username = xmlNode.GetChildAsString("Username", "admin");
+                Password = xmlNode.GetChildAsString("Password");
+                ScadaInstance = xmlNode.GetChildAsString("ScadaInstance");
+                SecretKey = ScadaUtils.HexToBytes(xmlNode.GetChildAsString("SecretKey"));
+            }
+        }
+
+        /// 
+        /// Settings of downloading configuration
+        /// Настройки скачивания конфигурации
+        /// 
+        public class DownloadSettings
+        {
+            /// 
+            /// Конструктор
+            /// 
+            public DownloadSettings()
+            {
+                SetToDefault();
+            }
+
+            /// 
+            /// Получить или установить признак сохранения в директорию
+            /// 
+            public bool SaveToDir { get; set; }
+            /// 
+            /// Получить или установить директорию для сохранения конфигурации
+            /// 
+            public string DestDir { get; set; }
+            /// 
+            /// Получить или установить имя файла архива для сохранения конфигурации
+            /// 
+            public string DestFile { get; set; }
+
+            /// 
+            /// Установить настройки по умолчанию
+            /// 
+            private void SetToDefault()
+            {
+                SaveToDir = true;
+                DestDir = @"C:\SCADA\";
+                DestFile = "";
+            }
+            /// 
+            /// Загрузить настройки из XML-узла
+            /// 
+            public void LoadFromXml(XmlNode xmlNode)
+            {
+                if (xmlNode == null)
+                    throw new ArgumentNullException("xmlNode");
+
+                SaveToDir = xmlNode.GetChildAsBool("SaveToDir", true);
+                DestDir = xmlNode.GetChildAsString("DestDir", @"C:\SCADA\");
+                DestFile = xmlNode.GetChildAsString("DestFile");
+            }
+        }
+
+        /// 
+        /// Settings of uploading configuration
+        /// Настройки передачи конфигурации
+        /// 
+        public class UploadSettings
+        {
+            /// 
+            /// Конструктор
+            /// 
+            public UploadSettings()
+            {
+                SelectedFiles = new List();
+                SetToDefault();
+            }
+
+            /// 
+            /// Получить или установить директорию конфигурации
+            /// 
+            public string SrcDir { get; set; }
+            /// 
+            /// Получить или установить признак передачи всех файлов конфигурации
+            /// 
+            public bool AllFiles { get; set; }
+            /// 
+            /// Получить выбранные для передачи файлы конфигурации
+            /// 
+            public List SelectedFiles { get; private set; }
+
+            /// 
+            /// Установить настройки по умолчанию
+            /// 
+            private void SetToDefault()
+            {
+                SrcDir = @"C:\SCADA\";
+                AllFiles = true;
+                SelectedFiles.Clear();
+            }
+            /// 
+            /// Загрузить настройки из XML-узла
+            /// 
+            public void LoadFromXml(XmlNode xmlNode)
+            {
+                if (xmlNode == null)
+                    throw new ArgumentNullException("xmlNode");
+
+                SelectedFiles.Clear();
+                SrcDir = xmlNode.GetChildAsString("SrcDir", @"C:\SCADA\");
+                AllFiles = xmlNode.GetChildAsBool("AllFiles", true);
+
+                XmlNode selectedFilesNode = xmlNode.SelectSingleNode("SelectedFiles");
+                if (selectedFilesNode != null)
+                {
+                    XmlNodeList pathNodeList = xmlNode.SelectNodes("Path");
+                    foreach (XmlNode pathNode in pathNodeList)
+                    {
+                        SelectedFiles.Add(pathNode.InnerText);
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Settings of interaction with a remote server
+        /// Настройки взаимодействия с удалённым сервером
+        /// 
+        public class ServerSettings
+        {
+            /// 
+            /// Конструктор
+            /// 
+            public ServerSettings()
+            {
+                Connection = new ConnectionSettings();
+                Download = new DownloadSettings();
+                Upload = new UploadSettings();
+            }
+
+            /// 
+            /// Получить настройки подключения к серверу
+            /// 
+            public ConnectionSettings Connection { get; private set; }
+            /// 
+            /// Получить настройки скачивания конфигурации
+            /// 
+            public DownloadSettings Download { get; private set; }
+            /// 
+            /// Получить настройки передачи конфигурации
+            /// 
+            public UploadSettings Upload { get; private set; }
+
+            /// 
+            /// Загрузить настройки из XML-узла
+            /// 
+            public void LoadFromXml(XmlNode xmlNode)
+            {
+                if (xmlNode == null)
+                    throw new ArgumentNullException("xmlNode");
+
+                XmlNode connectionNode = xmlNode.SelectSingleNode("Connection");
+                if (connectionNode != null)
+                    Connection.LoadFromXml(connectionNode);
+
+                XmlNode downloadNode = xmlNode.SelectSingleNode("Download");
+                if (downloadNode != null)
+                    Download.LoadFromXml(downloadNode);
+
+                XmlNode uploadNode = xmlNode.SelectSingleNode("Upload");
+                if (uploadNode != null)
+                    Upload.LoadFromXml(uploadNode);
+            }
+        }
+
+
+        /// 
+        /// Имя файла настроек по умолчанию
+        /// 
+        public const string DefFileName = "RemoteServers.xml";
+
+
+        /// 
+        /// Конструктор
+        /// 
+        public ServersSettings()
+        {
+            Servers = new SortedList();
+        }
+
+
+        /// 
+        /// Получить список настроек взаимодействия с серверами, ключ - наименование подключения
+        /// 
+        public SortedList Servers { get; private set; }
+
+
+        /// 
+        /// Загрузить настройки из файла
+        /// 
+        public bool Load(string fileName, out string errMsg)
+        {
+            // установка значений по умолчанию
+            Servers.Clear();
+
+            try
+            {
+                if (!File.Exists(fileName))
+                    throw new FileNotFoundException(string.Format(CommonPhrases.NamedFileNotFound, fileName));
+
+                XmlDocument xmlDoc = new XmlDocument();
+                xmlDoc.Load(fileName);
+
+                XmlNodeList remoteServerNodeList = xmlDoc.DocumentElement.SelectNodes("RemoteServer");
+                foreach (XmlNode remoteServerNode in remoteServerNodeList)
+                {
+                    ServerSettings serverSettings = new ServerSettings();
+                    serverSettings.LoadFromXml(remoteServerNode);
+                    Servers[serverSettings.Connection.Name] = serverSettings;
+                }
+
+                errMsg = "";
+                return true;
+            }
+            catch (Exception ex)
+            {
+                errMsg = AppPhrases.LoadServersSettingsError + ":" + Environment.NewLine + ex.Message;
+                return false;
+            }
+        }
+
+        /// 
+        /// Сохранить настройки в файле
+        /// 
+        public bool Save(string fileName, out string errMsg)
+        {
+            try
+            {
+                // TODO: implement saving
+                errMsg = "";
+                return true;
+            }
+            catch (Exception ex)
+            {
+                errMsg = AppPhrases.SaveServersSettingsError + ":" + Environment.NewLine + ex.Message;
+                return false;
+            }
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml b/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml
new file mode 100644
index 000000000..9324c9dac
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml
@@ -0,0 +1,25 @@
+
+
+  
+    
+      Test
+      localhost
+      10002
+      admin
+      12345
+      Default
+      5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1
+    
+    
+      true
+      C:\SCADA\
+      
+    
+    
+      C:\SCADA\
+      true
+              
+      
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index a0060e7ab..8de5adcf7 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -351,6 +351,10 @@
     Are you sure you want to delete the rows?
     Are you sure you want to clear the table?
   
+  
+    Error loading settings of interaction with remote servers
+    Error saving settings of interaction with remote servers
+  
   
     Error saving the table changes to the database
     Error getting the data table schema
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index beeb0d0c8..419829748 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -1,4 +1,5 @@
-using ScadaAdmin.AgentSvcRef;
+using Scada;
+using ScadaAdmin.AgentSvcRef;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
@@ -17,6 +18,33 @@ public FrmDownloadConfig()
             InitializeComponent();
         }
 
+
+        /// 
+        /// Создать вектор инициализации на освнове ид. сессии
+        /// 
+        private static byte[] CreateIV(long sessionID)
+        {
+            byte[] iv = new byte[ScadaUtils.IVSize];
+            byte[] sessBuf = BitConverter.GetBytes(sessionID);
+            int sessBufLen = sessBuf.Length;
+
+            for (int i = 0; i < ScadaUtils.IVSize; i++)
+            {
+                iv[i] = sessBuf[i % sessBufLen];
+            }
+
+            return iv;
+        }
+
+        /// 
+        /// Зашифровать пароль
+        /// 
+        private static string EncryptPassword(string password, long sessionID, byte[] secretKey)
+        {
+            return ScadaUtils.Encrypt(password, secretKey, CreateIV(sessionID));
+        }
+
+
         private void FrmDownloadConfig_Load(object sender, EventArgs e)
         {
 
@@ -31,7 +59,10 @@ private void btnDownload_Click(object sender, EventArgs e)
                 client.CreateSession(out long sessionID);
                 MessageBox.Show("Session ID = " + sessionID);
 
-                if (client.Login(out string errMsg, sessionID, "admin", "", "Default"))
+                byte[] secretKey = ScadaUtils.HexToBytes("5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1");
+                string encryptedPassword = EncryptPassword("12345", sessionID, secretKey);
+
+                if (client.Login(out string errMsg, sessionID, "admin", encryptedPassword, "Default"))
                     MessageBox.Show("Login OK");
                 else
                     MessageBox.Show(errMsg);
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index 50d8e4099..5db3ca9c8 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -99,6 +99,7 @@
     
     
     
+    
     
       True
       True
@@ -316,6 +317,9 @@
       WCF Proxy Generator
       Reference.cs
     
+    
+      PreserveNewest
+    
     
       PreserveNewest
     
diff --git a/ScadaAdmin/ScadaAdmin/app.config b/ScadaAdmin/ScadaAdmin/app.config
index 01abd70c0..0bfe10f47 100644
--- a/ScadaAdmin/ScadaAdmin/app.config
+++ b/ScadaAdmin/ScadaAdmin/app.config
@@ -1,15 +1,18 @@
 
 
-	
-  
-   
-    
-   
-  
-  
-   
-  
- 
+  
+    
+  
+  
+    
+      
+        
+      
+    
+    
+      
+    
+  
 

From 3c34dd560943373e860e571f90b35f671255ac10 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 7 May 2018 19:30:52 +0300
Subject: [PATCH 055/100] ScadaAdmin: dev

---
 .../ScadaAdmin/AppCode/ServersSettings.cs     |  66 ++++++++-
 .../Remote/CtrlServerConn.Designer.cs         | 110 +++++++++++++++
 .../ScadaAdmin/Remote/CtrlServerConn.cs       | 127 ++++++++++++++++++
 .../ScadaAdmin/Remote/CtrlServerConn.resx     | 120 +++++++++++++++++
 .../Remote/FrmDownloadConfig.Designer.cs      |  73 ++--------
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |  47 ++++++-
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |   9 ++
 7 files changed, 487 insertions(+), 65 deletions(-)
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.resx

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
index ee00c7d70..d8f805e62 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
@@ -35,7 +35,7 @@ namespace ScadaAdmin
     /// Settings of interaction with remote servers
     /// Настройки взаимодействия с удалёнными серверами
     /// 
-    internal class ServersSettings
+    public class ServersSettings
     {
         /// 
         /// Remote server connection settings
@@ -109,6 +109,22 @@ public void LoadFromXml(XmlNode xmlNode)
                 ScadaInstance = xmlNode.GetChildAsString("ScadaInstance");
                 SecretKey = ScadaUtils.HexToBytes(xmlNode.GetChildAsString("SecretKey"));
             }
+            /// 
+            /// Сохранить настройки в XML-узле
+            /// 
+            public void SaveToXml(XmlElement xmlElem)
+            {
+                if (xmlElem == null)
+                    throw new ArgumentNullException("xmlElem");
+
+                xmlElem.AppendElem("Name", Name);
+                xmlElem.AppendElem("Host", Host);
+                xmlElem.AppendElem("Port", Port);
+                xmlElem.AppendElem("Username", Username);
+                xmlElem.AppendElem("Password", Password);
+                xmlElem.AppendElem("ScadaInstance", ScadaInstance);
+                xmlElem.AppendElem("SecretKey", ScadaUtils.BytesToHex(SecretKey));
+            }
         }
 
         /// 
@@ -159,6 +175,18 @@ public void LoadFromXml(XmlNode xmlNode)
                 DestDir = xmlNode.GetChildAsString("DestDir", @"C:\SCADA\");
                 DestFile = xmlNode.GetChildAsString("DestFile");
             }
+            /// 
+            /// Сохранить настройки в XML-узле
+            /// 
+            public void SaveToXml(XmlElement xmlElem)
+            {
+                if (xmlElem == null)
+                    throw new ArgumentNullException("xmlElem");
+
+                xmlElem.AppendElem("SaveToDir", SaveToDir);
+                xmlElem.AppendElem("DestDir", DestDir);
+                xmlElem.AppendElem("DestFile", DestFile);
+            }
         }
 
         /// 
@@ -220,6 +248,23 @@ public void LoadFromXml(XmlNode xmlNode)
                     }
                 }
             }
+            /// 
+            /// Сохранить настройки в XML-узле
+            /// 
+            public void SaveToXml(XmlElement xmlElem)
+            {
+                if (xmlElem == null)
+                    throw new ArgumentNullException("xmlElem");
+
+                xmlElem.AppendElem("SrcDir", SrcDir);
+                xmlElem.AppendElem("AllFiles", AllFiles);
+
+                XmlElement selectedFilesElem = xmlElem.AppendElem("SelectedFiles");
+                foreach (string path in SelectedFiles)
+                {
+                    selectedFilesElem.AppendElem("Path", path);
+                }
+            }
         }
 
         /// 
@@ -271,6 +316,25 @@ public void LoadFromXml(XmlNode xmlNode)
                 if (uploadNode != null)
                     Upload.LoadFromXml(uploadNode);
             }
+            /// 
+            /// Сохранить настройки в XML-узле
+            /// 
+            public void SaveToXml(XmlElement xmlElem)
+            {
+                if (xmlElem == null)
+                    throw new ArgumentNullException("xmlElem");
+
+                Connection.SaveToXml(xmlElem.AppendElem("Connection"));
+                Download.SaveToXml(xmlElem.AppendElem("Download"));
+                Upload.SaveToXml(xmlElem.AppendElem("Upload"));
+            }
+            /// 
+            /// Получить строковое представление объекта
+            /// 
+            public override string ToString()
+            {
+                return Connection.Name;
+            }
         }
 
 
diff --git a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs
new file mode 100644
index 000000000..d99a29045
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs
@@ -0,0 +1,110 @@
+namespace ScadaAdmin.Remote
+{
+    partial class CtrlServerConn
+    {
+        ///  
+        /// Required designer variable.
+        /// 
+        private System.ComponentModel.IContainer components = null;
+
+        ///  
+        /// Clean up any resources being used.
+        /// 
+        /// true if managed resources should be disposed; otherwise, false.
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        ///  
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// 
+        private void InitializeComponent()
+        {
+            this.gbConnection = new System.Windows.Forms.GroupBox();
+            this.btnRemoveConn = new System.Windows.Forms.Button();
+            this.btnEditConn = new System.Windows.Forms.Button();
+            this.btnCreateConn = new System.Windows.Forms.Button();
+            this.cbConnection = new System.Windows.Forms.ComboBox();
+            this.gbConnection.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // gbConnection
+            // 
+            this.gbConnection.Controls.Add(this.btnRemoveConn);
+            this.gbConnection.Controls.Add(this.btnEditConn);
+            this.gbConnection.Controls.Add(this.btnCreateConn);
+            this.gbConnection.Controls.Add(this.cbConnection);
+            this.gbConnection.Location = new System.Drawing.Point(0, 0);
+            this.gbConnection.Name = "gbConnection";
+            this.gbConnection.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
+            this.gbConnection.Size = new System.Drawing.Size(469, 55);
+            this.gbConnection.TabIndex = 1;
+            this.gbConnection.TabStop = false;
+            this.gbConnection.Text = "Подключение к серверу";
+            // 
+            // btnRemoveConn
+            // 
+            this.btnRemoveConn.Location = new System.Drawing.Point(381, 19);
+            this.btnRemoveConn.Name = "btnRemoveConn";
+            this.btnRemoveConn.Size = new System.Drawing.Size(75, 23);
+            this.btnRemoveConn.TabIndex = 3;
+            this.btnRemoveConn.Text = "Удалить";
+            this.btnRemoveConn.UseVisualStyleBackColor = true;
+            // 
+            // btnEditConn
+            // 
+            this.btnEditConn.Location = new System.Drawing.Point(300, 19);
+            this.btnEditConn.Name = "btnEditConn";
+            this.btnEditConn.Size = new System.Drawing.Size(75, 23);
+            this.btnEditConn.TabIndex = 2;
+            this.btnEditConn.Text = "Настроить";
+            this.btnEditConn.UseVisualStyleBackColor = true;
+            // 
+            // btnCreateConn
+            // 
+            this.btnCreateConn.Location = new System.Drawing.Point(219, 19);
+            this.btnCreateConn.Name = "btnCreateConn";
+            this.btnCreateConn.Size = new System.Drawing.Size(75, 23);
+            this.btnCreateConn.TabIndex = 1;
+            this.btnCreateConn.Text = "Создать";
+            this.btnCreateConn.UseVisualStyleBackColor = true;
+            // 
+            // cbConnection
+            // 
+            this.cbConnection.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cbConnection.FormattingEnabled = true;
+            this.cbConnection.Location = new System.Drawing.Point(13, 20);
+            this.cbConnection.Name = "cbConnection";
+            this.cbConnection.Size = new System.Drawing.Size(200, 21);
+            this.cbConnection.TabIndex = 0;
+            this.cbConnection.SelectedIndexChanged += new System.EventHandler(this.cbConnection_SelectedIndexChanged);
+            // 
+            // CtrlServerConn
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.gbConnection);
+            this.Name = "CtrlServerConn";
+            this.Size = new System.Drawing.Size(469, 55);
+            this.gbConnection.ResumeLayout(false);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.GroupBox gbConnection;
+        private System.Windows.Forms.Button btnRemoveConn;
+        private System.Windows.Forms.Button btnEditConn;
+        private System.Windows.Forms.Button btnCreateConn;
+        private System.Windows.Forms.ComboBox cbConnection;
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs
new file mode 100644
index 000000000..1008aaa68
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Control for selecting a connection to a remote server
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+
+namespace ScadaAdmin.Remote
+{
+    /// 
+    /// Control for selecting a connection to a remote server
+    /// Элемент управления для выбора соединения с удалённым сервером
+    /// 
+    public partial class CtrlServerConn : UserControl
+    {
+        private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами
+
+
+        /// 
+        /// Конструктор
+        /// 
+        public CtrlServerConn()
+        {
+            InitializeComponent();
+            serversSettings = null;
+        }
+
+
+        /// 
+        /// Получить или установить настройки взаимодействия с удалёнными серверами
+        /// 
+        public ServersSettings ServersSettings
+        {
+            get
+            {
+                return serversSettings;
+            }
+            set
+            {
+                serversSettings = value;
+                FillServerList();
+            }
+        }
+
+        /// 
+        /// Получить выбранные настройки
+        /// 
+        public ServersSettings.ServerSettings SelectedSettings
+        {
+            get
+            {
+                return cbConnection.SelectedItem as ServersSettings.ServerSettings;
+            }
+        }
+
+
+        /// 
+        /// Заполнить список серверов
+        /// 
+        private void FillServerList()
+        {
+            try
+            {
+                cbConnection.BeginUpdate();
+                cbConnection.Items.Clear();
+
+                if (serversSettings != null)
+                {
+                    foreach (ServersSettings.ServerSettings serverSettings in serversSettings.Servers.Values)
+                    {
+                        cbConnection.Items.Add(serverSettings);
+                    }
+                }
+
+                if (cbConnection.Items.Count > 0)
+                    cbConnection.SelectedIndex = 0;
+            }
+            finally
+            {
+                cbConnection.EndUpdate();
+            }
+        }
+
+        /// 
+        /// Вызвать событие SelectedSettingsChanged
+        /// 
+        private void OnSelectedSettingsChanged()
+        {
+            SelectedSettingsChanged?.Invoke(this, EventArgs.Empty);
+        }
+
+
+        /// 
+        /// Событие возникающее при изменении выбранного соединения
+        /// 
+        [Category("Property Changed")]
+        public event EventHandler SelectedSettingsChanged;
+
+
+        private void cbConnection_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            OnSelectedSettingsChanged();
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.resx b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.resx
new file mode 100644
index 000000000..1af7de150
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.resx
@@ -0,0 +1,120 @@
+
+
+  
+  
+    
+    
+      
+        
+          
+            
+              
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+              
+            
+          
+          
+            
+              
+                
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+                
+              
+              
+            
+          
+        
+      
+    
+  
+  
+    text/microsoft-resx
+  
+  
+    2.0
+  
+  
+    System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
index 66218a328..90be87304 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
@@ -29,11 +29,6 @@ protected override void Dispose(bool disposing)
         private void InitializeComponent()
         {
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmDownloadConfig));
-            this.gbConnection = new System.Windows.Forms.GroupBox();
-            this.btnRemoveConn = new System.Windows.Forms.Button();
-            this.btnEditConn = new System.Windows.Forms.Button();
-            this.btnCreateConn = new System.Windows.Forms.Button();
-            this.cbConnection = new System.Windows.Forms.ComboBox();
             this.rbSaveToDir = new System.Windows.Forms.RadioButton();
             this.txtDestDir = new System.Windows.Forms.TextBox();
             this.btnBrowseDestDir = new System.Windows.Forms.Button();
@@ -43,59 +38,10 @@ private void InitializeComponent()
             this.btnDownload = new System.Windows.Forms.Button();
             this.btnClose = new System.Windows.Forms.Button();
             this.gbOptions = new System.Windows.Forms.GroupBox();
-            this.gbConnection.SuspendLayout();
+            this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
             this.gbOptions.SuspendLayout();
             this.SuspendLayout();
             // 
-            // gbConnection
-            // 
-            this.gbConnection.Controls.Add(this.btnRemoveConn);
-            this.gbConnection.Controls.Add(this.btnEditConn);
-            this.gbConnection.Controls.Add(this.btnCreateConn);
-            this.gbConnection.Controls.Add(this.cbConnection);
-            this.gbConnection.Location = new System.Drawing.Point(12, 12);
-            this.gbConnection.Name = "gbConnection";
-            this.gbConnection.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
-            this.gbConnection.Size = new System.Drawing.Size(469, 55);
-            this.gbConnection.TabIndex = 0;
-            this.gbConnection.TabStop = false;
-            this.gbConnection.Text = "Подключение к серверу";
-            // 
-            // btnRemoveConn
-            // 
-            this.btnRemoveConn.Location = new System.Drawing.Point(381, 19);
-            this.btnRemoveConn.Name = "btnRemoveConn";
-            this.btnRemoveConn.Size = new System.Drawing.Size(75, 23);
-            this.btnRemoveConn.TabIndex = 3;
-            this.btnRemoveConn.Text = "Удалить";
-            this.btnRemoveConn.UseVisualStyleBackColor = true;
-            // 
-            // btnEditConn
-            // 
-            this.btnEditConn.Location = new System.Drawing.Point(300, 19);
-            this.btnEditConn.Name = "btnEditConn";
-            this.btnEditConn.Size = new System.Drawing.Size(75, 23);
-            this.btnEditConn.TabIndex = 2;
-            this.btnEditConn.Text = "Настроить";
-            this.btnEditConn.UseVisualStyleBackColor = true;
-            // 
-            // btnCreateConn
-            // 
-            this.btnCreateConn.Location = new System.Drawing.Point(219, 19);
-            this.btnCreateConn.Name = "btnCreateConn";
-            this.btnCreateConn.Size = new System.Drawing.Size(75, 23);
-            this.btnCreateConn.TabIndex = 1;
-            this.btnCreateConn.Text = "Создать";
-            this.btnCreateConn.UseVisualStyleBackColor = true;
-            // 
-            // cbConnection
-            // 
-            this.cbConnection.FormattingEnabled = true;
-            this.cbConnection.Location = new System.Drawing.Point(13, 20);
-            this.cbConnection.Name = "cbConnection";
-            this.cbConnection.Size = new System.Drawing.Size(200, 21);
-            this.cbConnection.TabIndex = 0;
-            // 
             // rbSaveToDir
             // 
             this.rbSaveToDir.AutoSize = true;
@@ -190,16 +136,23 @@ private void InitializeComponent()
             this.gbOptions.TabStop = false;
             this.gbOptions.Text = "Параметры скачивания";
             // 
+            // ctrlServerConn
+            // 
+            this.ctrlServerConn.Location = new System.Drawing.Point(12, 12);
+            this.ctrlServerConn.Name = "ctrlServerConn";
+            this.ctrlServerConn.Size = new System.Drawing.Size(469, 55);
+            this.ctrlServerConn.TabIndex = 0;
+            // 
             // FrmDownloadConfig
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.btnClose;
             this.ClientSize = new System.Drawing.Size(493, 239);
+            this.Controls.Add(this.ctrlServerConn);
             this.Controls.Add(this.gbOptions);
             this.Controls.Add(this.btnClose);
             this.Controls.Add(this.btnDownload);
-            this.Controls.Add(this.gbConnection);
             this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
             this.MaximizeBox = false;
             this.MinimizeBox = false;
@@ -208,7 +161,6 @@ private void InitializeComponent()
             this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
             this.Text = "Скачивание конфигурации";
             this.Load += new System.EventHandler(this.FrmDownloadConfig_Load);
-            this.gbConnection.ResumeLayout(false);
             this.gbOptions.ResumeLayout(false);
             this.gbOptions.PerformLayout();
             this.ResumeLayout(false);
@@ -216,12 +168,6 @@ private void InitializeComponent()
         }
 
         #endregion
-
-        private System.Windows.Forms.GroupBox gbConnection;
-        private System.Windows.Forms.Button btnRemoveConn;
-        private System.Windows.Forms.Button btnEditConn;
-        private System.Windows.Forms.Button btnCreateConn;
-        private System.Windows.Forms.ComboBox cbConnection;
         private System.Windows.Forms.RadioButton rbSaveToDir;
         private System.Windows.Forms.TextBox txtDestDir;
         private System.Windows.Forms.Button btnBrowseDestDir;
@@ -231,5 +177,6 @@ private void InitializeComponent()
         private System.Windows.Forms.Button btnDownload;
         private System.Windows.Forms.Button btnClose;
         private System.Windows.Forms.GroupBox gbOptions;
+        private CtrlServerConn ctrlServerConn;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index 419829748..f84fe187d 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -1,4 +1,30 @@
-using Scada;
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Download configuration form
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada;
+using Scada.UI;
 using ScadaAdmin.AgentSvcRef;
 using System;
 using System.Collections.Generic;
@@ -11,11 +37,22 @@
 
 namespace ScadaAdmin.Remote
 {
+    /// 
+    /// Download configuration form
+    /// Форма скачивания конфигурации
+    /// 
     public partial class FrmDownloadConfig : Form
     {
+        private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами
+
+
+        /// 
+        /// Конструктор
+        /// 
         public FrmDownloadConfig()
         {
             InitializeComponent();
+            serversSettings = new ServersSettings();
         }
 
 
@@ -47,7 +84,15 @@ private static string EncryptPassword(string password, long sessionID, byte[] se
 
         private void FrmDownloadConfig_Load(object sender, EventArgs e)
         {
+            // загрузка настроек
+            if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
+            {
+                AppData.ErrLog.WriteError(errMsg);
+                ScadaUiUtils.ShowError(errMsg);
+            }
 
+            // отображение настроек
+            ctrlServerConn.ServersSettings = serversSettings;
         }
 
         private void btnDownload_Click(object sender, EventArgs e)
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index 5db3ca9c8..d8aefeac2 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -192,6 +192,12 @@
     
     
     
+    
+      UserControl
+    
+    
+      CtrlServerConn.cs
+    
     
       Form
     
@@ -262,6 +268,9 @@
       Resources.resx
       True
     
+    
+      CtrlServerConn.cs
+    
     
       FrmDownloadConfig.cs
     

From 2a8f24fecfb1467cd3c5664aa41b31a3d7af358d Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 8 May 2018 10:40:05 +0300
Subject: [PATCH 056/100] ScadaAdmin: remote config

---
 .../ScadaAdmin/AppCode/ServersSettings.cs     |  22 ++-
 .../Remote/FrmDownloadConfig.Designer.cs      |  23 +++
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    | 155 +++++++++++++++++-
 .../ScadaAdmin/Remote/FrmDownloadConfig.resx  |   6 +
 4 files changed, 195 insertions(+), 11 deletions(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
index d8f805e62..b39dfe1ef 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
@@ -172,7 +172,7 @@ public void LoadFromXml(XmlNode xmlNode)
                     throw new ArgumentNullException("xmlNode");
 
                 SaveToDir = xmlNode.GetChildAsBool("SaveToDir", true);
-                DestDir = xmlNode.GetChildAsString("DestDir", @"C:\SCADA\");
+                DestDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("DestDir", @"C:\SCADA\"));
                 DestFile = xmlNode.GetChildAsString("DestFile");
             }
             /// 
@@ -235,7 +235,7 @@ public void LoadFromXml(XmlNode xmlNode)
                     throw new ArgumentNullException("xmlNode");
 
                 SelectedFiles.Clear();
-                SrcDir = xmlNode.GetChildAsString("SrcDir", @"C:\SCADA\");
+                SrcDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("SrcDir", @"C:\SCADA\"));
                 AllFiles = xmlNode.GetChildAsBool("AllFiles", true);
 
                 XmlNode selectedFilesNode = xmlNode.SelectSingleNode("SelectedFiles");
@@ -400,7 +400,23 @@ public bool Save(string fileName, out string errMsg)
         {
             try
             {
-                // TODO: implement saving
+                XmlDocument xmlDoc = new XmlDocument();
+
+                XmlDeclaration xmlDecl = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
+                xmlDoc.AppendChild(xmlDecl);
+
+                XmlElement rootElem = xmlDoc.CreateElement("RemoteServers");
+                xmlDoc.AppendChild(rootElem);
+
+                foreach (ServerSettings serverSettings in Servers.Values)
+                {
+                    serverSettings.SaveToXml(rootElem.AppendElem("RemoteServer"));
+                }
+
+                string bakName = fileName + ".bak";
+                File.Copy(fileName, bakName, true);
+                xmlDoc.Save(fileName);
+
                 errMsg = "";
                 return true;
             }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
index 90be87304..01a631fda 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
@@ -38,6 +38,8 @@ private void InitializeComponent()
             this.btnDownload = new System.Windows.Forms.Button();
             this.btnClose = new System.Windows.Forms.Button();
             this.gbOptions = new System.Windows.Forms.GroupBox();
+            this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
+            this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
             this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
             this.gbOptions.SuspendLayout();
             this.SuspendLayout();
@@ -53,6 +55,7 @@ private void InitializeComponent()
             this.rbSaveToDir.TabStop = true;
             this.rbSaveToDir.Text = "Сохранить в директорию:";
             this.rbSaveToDir.UseVisualStyleBackColor = true;
+            this.rbSaveToDir.CheckedChanged += new System.EventHandler(this.rbSaveToDir_CheckedChanged);
             // 
             // txtDestDir
             // 
@@ -61,6 +64,7 @@ private void InitializeComponent()
             this.txtDestDir.Size = new System.Drawing.Size(417, 20);
             this.txtDestDir.TabIndex = 1;
             this.txtDestDir.Text = "C:\\SCADA\\";
+            this.txtDestDir.TextChanged += new System.EventHandler(this.txtDestDir_TextChanged);
             // 
             // btnBrowseDestDir
             // 
@@ -71,6 +75,7 @@ private void InitializeComponent()
             this.btnBrowseDestDir.Size = new System.Drawing.Size(20, 20);
             this.btnBrowseDestDir.TabIndex = 2;
             this.btnBrowseDestDir.UseVisualStyleBackColor = true;
+            this.btnBrowseDestDir.Click += new System.EventHandler(this.btnBrowseDestDir_Click);
             // 
             // rbSaveToArc
             // 
@@ -82,6 +87,7 @@ private void InitializeComponent()
             this.rbSaveToArc.TabStop = true;
             this.rbSaveToArc.Text = "Сохранить в архив:";
             this.rbSaveToArc.UseVisualStyleBackColor = true;
+            this.rbSaveToArc.CheckedChanged += new System.EventHandler(this.rbSaveToArc_CheckedChanged);
             // 
             // btnSelectDestFile
             // 
@@ -92,6 +98,7 @@ private void InitializeComponent()
             this.btnSelectDestFile.Size = new System.Drawing.Size(20, 20);
             this.btnSelectDestFile.TabIndex = 5;
             this.btnSelectDestFile.UseVisualStyleBackColor = true;
+            this.btnSelectDestFile.Click += new System.EventHandler(this.btnSelectDestFile_Click);
             // 
             // txtDestFile
             // 
@@ -99,6 +106,7 @@ private void InitializeComponent()
             this.txtDestFile.Name = "txtDestFile";
             this.txtDestFile.Size = new System.Drawing.Size(417, 20);
             this.txtDestFile.TabIndex = 4;
+            this.txtDestFile.TextChanged += new System.EventHandler(this.txtDestFile_TextChanged);
             // 
             // btnDownload
             // 
@@ -136,12 +144,25 @@ private void InitializeComponent()
             this.gbOptions.TabStop = false;
             this.gbOptions.Text = "Параметры скачивания";
             // 
+            // openFileDialog
+            // 
+            this.openFileDialog.CheckFileExists = false;
+            this.openFileDialog.DefaultExt = "*.zip";
+            this.openFileDialog.Filter = "Архивы (*.zip)|*.zip|Все файлы (*.*)|*.*";
+            this.openFileDialog.Title = "Выберите файл архива для сохранения конфигурации";
+            // 
+            // folderBrowserDialog
+            // 
+            this.folderBrowserDialog.Description = "Выберите директорию для сохранения конфигурации";
+            // 
             // ctrlServerConn
             // 
             this.ctrlServerConn.Location = new System.Drawing.Point(12, 12);
             this.ctrlServerConn.Name = "ctrlServerConn";
+            this.ctrlServerConn.ServersSettings = null;
             this.ctrlServerConn.Size = new System.Drawing.Size(469, 55);
             this.ctrlServerConn.TabIndex = 0;
+            this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged);
             // 
             // FrmDownloadConfig
             // 
@@ -178,5 +199,7 @@ private void InitializeComponent()
         private System.Windows.Forms.Button btnClose;
         private System.Windows.Forms.GroupBox gbOptions;
         private CtrlServerConn ctrlServerConn;
+        private System.Windows.Forms.OpenFileDialog openFileDialog;
+        private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index f84fe187d..2f6df4459 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -44,6 +44,7 @@ namespace ScadaAdmin.Remote
     public partial class FrmDownloadConfig : Form
     {
         private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами
+        private bool downloadSettingsModified;   // последние выбранные настройки скачивания были изменены
 
 
         /// 
@@ -53,6 +54,7 @@ public FrmDownloadConfig()
         {
             InitializeComponent();
             serversSettings = new ServersSettings();
+            downloadSettingsModified = false;
         }
 
 
@@ -81,21 +83,69 @@ private static string EncryptPassword(string password, long sessionID, byte[] se
             return ScadaUtils.Encrypt(password, secretKey, CreateIV(sessionID));
         }
 
+        /// 
+        /// Отобразить настройки скачивания конфигурации
+        /// 
+        private void ShowDownloadSettings(ServersSettings.DownloadSettings downloadSettings)
+        {
+            if (downloadSettings == null)
+            {
+                gbOptions.Enabled = false;
+                btnDownload.Enabled = false;
+            }
+            else
+            {
+                gbOptions.Enabled = true;
+                btnDownload.Enabled = true;
 
-        private void FrmDownloadConfig_Load(object sender, EventArgs e)
+                if (downloadSettings.SaveToDir)
+                {
+                    rbSaveToDir.Checked = true;
+                    txtDestDir.Enabled = true;
+                    btnBrowseDestDir.Enabled = true;
+                    txtDestFile.Enabled = false;
+                    btnSelectDestFile.Enabled = false;
+                }
+                else
+                {
+                    rbSaveToArc.Checked = true;
+                    txtDestDir.Enabled = false;
+                    btnBrowseDestDir.Enabled = false;
+                    txtDestFile.Enabled = true;
+                    btnSelectDestFile.Enabled = true;
+                }
+
+                txtDestDir.Text = downloadSettings.DestDir;
+                txtDestFile.Text = downloadSettings.DestFile;
+            }
+        }
+
+        /// 
+        /// Применить настройки скачивания конфигурации
+        /// 
+        private void ApplyDownloadSettings(ServersSettings.DownloadSettings downloadSettings)
         {
-            // загрузка настроек
-            if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
+            downloadSettings.SaveToDir = rbSaveToDir.Checked;
+            downloadSettings.DestDir = txtDestDir.Text;
+            downloadSettings.DestFile = txtDestFile.Text;
+        }
+
+        /// 
+        /// Сохранить настройки взаимодействия с удалёнными серверами
+        /// 
+        private void SaveServersSettings()
+        {
+            if (!serversSettings.Save(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
             {
                 AppData.ErrLog.WriteError(errMsg);
                 ScadaUiUtils.ShowError(errMsg);
             }
-
-            // отображение настроек
-            ctrlServerConn.ServersSettings = serversSettings;
         }
 
-        private void btnDownload_Click(object sender, EventArgs e)
+        /// 
+        /// Скачать конфигурацию
+        /// 
+        private void DownloadConfig(ServersSettings.ServerSettings serverSettings)
         {
             AgentSvcClient client = new AgentSvcClient();
 
@@ -112,7 +162,7 @@ private void btnDownload_Click(object sender, EventArgs e)
                 else
                     MessageBox.Show(errMsg);
 
-                Stream stream = client.DownloadConfig(sessionID, 
+                Stream stream = client.DownloadConfig(sessionID,
                     new ConfigOptions() { ConfigParts = ConfigParts.All });
 
                 if (stream == null)
@@ -140,5 +190,94 @@ private void btnDownload_Click(object sender, EventArgs e)
                 client.Close();
             }
         }
+
+
+        private void FrmDownloadConfig_Load(object sender, EventArgs e)
+        {
+            // загрузка настроек
+            if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
+            {
+                AppData.ErrLog.WriteError(errMsg);
+                ScadaUiUtils.ShowError(errMsg);
+            }
+
+            // отображение настроек
+            ctrlServerConn.ServersSettings = serversSettings;
+        }
+
+        private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e)
+        {
+            ShowDownloadSettings(ctrlServerConn.SelectedSettings?.Download);
+            downloadSettingsModified = false;
+        }
+
+        private void rbSaveToDir_CheckedChanged(object sender, EventArgs e)
+        {
+            txtDestDir.Enabled = rbSaveToDir.Checked;
+            btnBrowseDestDir.Enabled = rbSaveToDir.Checked;
+            downloadSettingsModified = true;
+        }
+
+        private void rbSaveToArc_CheckedChanged(object sender, EventArgs e)
+        {
+            txtDestFile.Enabled = rbSaveToArc.Checked;
+            btnSelectDestFile.Enabled = rbSaveToArc.Checked;
+            downloadSettingsModified = true;
+        }
+
+        private void txtDestDir_TextChanged(object sender, EventArgs e)
+        {
+            downloadSettingsModified = true;
+        }
+
+        private void txtDestFile_TextChanged(object sender, EventArgs e)
+        {
+            downloadSettingsModified = true;
+        }
+
+        private void btnBrowseDestDir_Click(object sender, EventArgs e)
+        {
+            // выбор директории для сохранения конфигурации
+            folderBrowserDialog.SelectedPath = txtDestDir.Text.Trim();
+
+            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
+                txtDestDir.Text = ScadaUtils.NormalDir(folderBrowserDialog.SelectedPath);
+
+            txtDestDir.Focus();
+            txtDestDir.DeselectAll();
+        }
+
+        private void btnSelectDestFile_Click(object sender, EventArgs e)
+        {
+            // выбор файла архива для сохранения конфигурации
+            string fileName = txtDestFile.Text.Trim();
+            openFileDialog.FileName = fileName;
+
+            if (fileName != "")
+                openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName);
+
+            if (openFileDialog.ShowDialog() == DialogResult.OK)
+                txtDestFile.Text = openFileDialog.FileName;
+
+            txtDestFile.Focus();
+            txtDestFile.DeselectAll();
+        }
+
+        private void btnDownload_Click(object sender, EventArgs e)
+        {
+            // проверка настроек и скачивание конфигурации
+            ServersSettings.ServerSettings serverSettings = ctrlServerConn.SelectedSettings;
+
+            if (serverSettings != null)
+            {
+                if (downloadSettingsModified)
+                {
+                    ApplyDownloadSettings(serverSettings.Download);
+                    SaveServersSettings();
+                }
+
+                DownloadConfig(serverSettings);
+            }
+        }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
index c1e2ce87e..517bc7808 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
@@ -148,4 +148,10 @@
         tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs=
 
   
+  
+    17, 17
+  
+  
+    150, 17
+  
 
\ No newline at end of file

From 284108d164e91f25073d69610adb3e755473601d Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 8 May 2018 15:56:43 +0300
Subject: [PATCH 057/100] ScadaAgent: minor improvements

---
 ScadaAgent/ScadaAgentCore/SessionManager.cs | 11 +++++++++++
 ScadaAgent/ScadaAgentNet/AgentSvc.cs        | 19 ++++++++++++-------
 2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs
index 61de83b98..00cabbd67 100644
--- a/ScadaAgent/ScadaAgentCore/SessionManager.cs
+++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs
@@ -124,6 +124,17 @@ public Session GetSession(long sessionID)
             }
         }
 
+        /// 
+        /// Удалить заданную сессию
+        /// 
+        public void RemoveSession(long sessionID)
+        {
+            lock (sessions)
+            {
+                sessions.Remove(sessionID);
+            }
+        }
+
         /// 
         /// Удалить неактивные сессии
         /// 
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index 186b9e242..ccae02fa1 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -42,7 +42,7 @@ public class AgentSvc
         /// 
         /// Размер буфера для приёма файлов
         /// 
-        private int ReceiveBufSize = 1024;
+        private const int ReceiveBufSize = 10240;
 
         /// 
         /// Данные приложения
@@ -146,15 +146,10 @@ private bool ReceiveFile(Stream srcStream, string destFileName)
             try
             {
                 DateTime t0 = DateTime.UtcNow;
-                byte[] buffer = new byte[ReceiveBufSize];
 
                 using (FileStream destStream = File.Create(destFileName))
                 {
-                    int readCnt;
-                    while ((readCnt = srcStream.Read(buffer, 0, ReceiveBufSize)) > 0)
-                    {
-                        destStream.Write(buffer, 0, readCnt);
-                    }
+                    srcStream.CopyTo(destStream, ReceiveBufSize);
                 }
 
                 Log.WriteAction(string.Format(Localization.UseRussian ?
@@ -410,5 +405,15 @@ public Stream DownloadFileRest(long sessionID, RelPath relPath, long position)
                 return null;
             }
         }
+        
+        /// 
+        /// Закрыть сессию
+        /// 
+        /// Неактивные сессии также закрываются автоматически по таймауту
+        [OperationContract]
+        public void CloseSession(long sessionID)
+        {
+            SessionManager.RemoveSession(sessionID);
+        }
     }
 }

From c6c96b3e28c29b302dde2135abaaa7fb1e51b960 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 8 May 2018 16:14:20 +0300
Subject: [PATCH 058/100] ScadaAgent: shouldn't remove particular session doe
 to security

---
 ScadaAgent/ScadaAgentCore/SessionManager.cs | 11 -----------
 ScadaAgent/ScadaAgentNet/AgentSvc.cs        | 12 +-----------
 2 files changed, 1 insertion(+), 22 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/SessionManager.cs b/ScadaAgent/ScadaAgentCore/SessionManager.cs
index 00cabbd67..61de83b98 100644
--- a/ScadaAgent/ScadaAgentCore/SessionManager.cs
+++ b/ScadaAgent/ScadaAgentCore/SessionManager.cs
@@ -124,17 +124,6 @@ public Session GetSession(long sessionID)
             }
         }
 
-        /// 
-        /// Удалить заданную сессию
-        /// 
-        public void RemoveSession(long sessionID)
-        {
-            lock (sessions)
-            {
-                sessions.Remove(sessionID);
-            }
-        }
-
         /// 
         /// Удалить неактивные сессии
         /// 
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index ccae02fa1..a5b2e81cf 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -218,7 +218,7 @@ public bool Login(long sessionID, string username, string encryptedPassword, str
 
                     if (scadaInstance.ValidateUser(username, password, out errMsg))
                     {
-                        Log.WriteError(string.Format(Localization.UseRussian ?
+                        Log.WriteAction(string.Format(Localization.UseRussian ?
                             "Пользователь {0} подключился к {1}" :
                             "User {0} connected to {1}", username, scadaInstanceName));
                         session.SetUser(username, scadaInstance);
@@ -405,15 +405,5 @@ public Stream DownloadFileRest(long sessionID, RelPath relPath, long position)
                 return null;
             }
         }
-        
-        /// 
-        /// Закрыть сессию
-        /// 
-        /// Неактивные сессии также закрываются автоматически по таймауту
-        [OperationContract]
-        public void CloseSession(long sessionID)
-        {
-            SessionManager.RemoveSession(sessionID);
-        }
     }
 }

From 49a332441a607e61697e468fabe0d3bfab5352f4 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 8 May 2018 16:47:39 +0300
Subject: [PATCH 059/100] ScadaAdmin: download config

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  37 ++++
 ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs     |  15 +-
 .../ScadaAdmin/AppCode/DownloadUpload.cs      | 190 ++++++++++++++++++
 ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs |  27 +--
 ScadaAdmin/ScadaAdmin/FrmMain.cs              |   2 +
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |  12 ++
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |  88 ++------
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |   1 +
 8 files changed, 282 insertions(+), 90 deletions(-)
 create mode 100644 ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index a50e3362d..0c69abf4b 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -42,6 +42,18 @@ static AppPhrases()
         public static string BaseSDFFileNotFound { get; private set; }
         public static string RefreshRequired { get; private set; }
 
+        // Словарь ScadaAdmin.DownloadUpload
+        public static string DownloadTitle { get; private set; }
+        public static string ConnectionName { get; private set; }
+        public static string SessionCreated { get; private set; }
+        public static string UnableCreateSession { get; private set; }
+        public static string LoggedOn { get; private set; }
+        public static string UnableLogin { get; private set; }
+        public static string DownloadDataEmpty { get; private set; }
+        public static string DownloadCompleted { get; private set; }
+        public static string DownloadSuccessful { get; private set; }
+        public static string DownloadError { get; private set; }
+
         // Словарь ScadaAdmin.ImportExport
         public static string ChooseBaseTableFile { get; private set; }
         public static string ChooseBaseArchiveFile { get; private set; }
@@ -217,6 +229,17 @@ private static void SetToDefault()
             BaseSDFFileNotFound = "Файл базы конфигурации в формате SDF {0} не найден.";
             RefreshRequired = "\r\nОбновите открытые таблицы, чтобы отобразить изменения.";
 
+            DownloadTitle = "{0} Скачивание конфигурации";
+            ConnectionName = "Соединение : {0}";
+            SessionCreated = "Создана сессия {0}";
+            UnableCreateSession = "Не удалось создать сессию";
+            LoggedOn = "Вход в систему выполнен";
+            UnableLogin = "Не удалось войти в систему - {0}";
+            DownloadDataEmpty = "Отсутствуют данные для скачивания";
+            DownloadCompleted = "Скачивание завершено успешно за {0} с";
+            DownloadSuccessful = "Скачивание завершено успешно";
+            DownloadError = "Ошибка при скачивании конфигурации";
+
             ChooseBaseTableFile = "Выберите файл таблицы базы конфигурации";
             ChooseBaseArchiveFile = "Выберите файл архива базы конфигурации";
             BaseTableFileFilter = "Таблицы базы конфигурации|*.dat|Все файлы|*.*";
@@ -385,6 +408,20 @@ public static void Init()
                 RefreshRequired = dict.GetPhrase("RefreshRequired", RefreshRequired);
             }
 
+            if (Localization.Dictionaries.TryGetValue("ScadaAdmin.DownloadUpload", out dict))
+            {
+                DownloadTitle = dict.GetPhrase("DownloadTitle", DownloadTitle);
+                ConnectionName = dict.GetPhrase("ConnectionName", ConnectionName);
+                SessionCreated = dict.GetPhrase("SessionCreated", SessionCreated);
+                UnableCreateSession = dict.GetPhrase("UnableCreateSession", UnableCreateSession);
+                LoggedOn = dict.GetPhrase("LoggedOn", LoggedOn);
+                UnableLogin = dict.GetPhrase("UnableLogin", UnableLogin);
+                DownloadDataEmpty = dict.GetPhrase("DownloadDataEmpty", DownloadDataEmpty);
+                DownloadCompleted = dict.GetPhrase("DownloadCompleted", DownloadCompleted);
+                DownloadSuccessful = dict.GetPhrase("DownloadSuccessful", DownloadSuccessful);
+                DownloadError = dict.GetPhrase("DownloadError", DownloadError);
+            }
+
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.ImportExport", out dict))
             {
                 ChooseBaseTableFile = dict.GetPhrase("ChooseBaseTableFile", ChooseBaseTableFile);
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs
index 305560c7a..7232183fe 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,11 +20,12 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2010
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada;
 using Scada.UI;
+using System.IO;
 using Utils;
 
 namespace ScadaAdmin
@@ -97,5 +98,15 @@ public static bool ValidateStr(string val, int maxLen, out string errMsg)
                 return false;
             }
         }
+
+
+        /// 
+        /// Вывести в файл заголовок с подчёркиванием
+        /// 
+        public static void WriteTitle(StreamWriter writer, string title)
+        {
+            writer.WriteLine(title);
+            writer.WriteLine(new string('-', title.Length));
+        }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
new file mode 100644
index 000000000..d09b0e12e
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Downloading and uploading configuration
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Ionic.Zip;
+using Scada;
+using ScadaAdmin.AgentSvcRef;
+using System;
+using System.IO;
+using System.ServiceModel;
+using System.Text;
+
+namespace ScadaAdmin
+{
+    /// 
+    /// Downloading and uploading configuration
+    /// Скачивание и передача конфигурации
+    /// 
+    internal static class DownloadUpload
+    {
+        /// 
+        /// Создать вектор инициализации на освнове ид. сессии
+        /// 
+        private static byte[] CreateIV(long sessionID)
+        {
+            byte[] iv = new byte[ScadaUtils.IVSize];
+            byte[] sessBuf = BitConverter.GetBytes(sessionID);
+            int sessBufLen = sessBuf.Length;
+
+            for (int i = 0; i < ScadaUtils.IVSize; i++)
+            {
+                iv[i] = sessBuf[i % sessBufLen];
+            }
+
+            return iv;
+        }
+
+        /// 
+        /// Сформировать адрес для подключения к Агенту
+        /// 
+        private static EndpointAddress GetEpAddress(string host, int port)
+        {
+            return new EndpointAddress(
+                string.Format("http://{0}:{1}/ScadaAgent/ScadaAgentSvc/", host, port));
+        }
+
+
+        /// 
+        /// Скачать конфигурацию
+        /// 
+        public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
+            string logFileName, out bool logCreated, out string msg)
+        {
+            if (serverSettings == null)
+                throw new ArgumentNullException("serverSettings");
+            if (logFileName == null)
+                throw new ArgumentNullException("logFileName");
+
+            logCreated = false;
+            StreamWriter writer = null;
+            AgentSvcClient client = null;
+
+            try
+            {
+                DateTime t0 = DateTime.UtcNow;
+                ServersSettings.ConnectionSettings connectionSettings = serverSettings.Connection;
+
+                writer = new StreamWriter(logFileName, false, Encoding.UTF8);
+                logCreated = true;
+
+                AppUtils.WriteTitle(writer,
+                    string.Format(AppPhrases.DownloadTitle, DateTime.Now.ToString("G", Localization.Culture)));
+                writer.WriteLine(AppPhrases.ConnectionName, connectionSettings.Name);
+                writer.WriteLine();
+
+                // настройка соединения
+                client = new AgentSvcClient();
+                client.Endpoint.Address = GetEpAddress(connectionSettings.Host, connectionSettings.Port);
+
+                // создание сессии
+                if (client.CreateSession(out long sessionID))
+                    writer.WriteLine(AppPhrases.SessionCreated, sessionID);
+                else
+                    throw new ScadaException(AppPhrases.UnableCreateSession);
+
+                // вход в систему
+                string encryptedPassword = ScadaUtils.Encrypt(connectionSettings.Password,
+                    connectionSettings.SecretKey, CreateIV(sessionID));
+
+                if (client.Login(out string errMsg, sessionID, connectionSettings.Username, 
+                    encryptedPassword, connectionSettings.ScadaInstance))
+                    writer.WriteLine(AppPhrases.LoggedOn);
+                else
+                    throw new ScadaException(string.Format(AppPhrases.UnableLogin, errMsg));
+
+                // скачивание конфигурации
+                Stream downloadStream = client.DownloadConfig(sessionID,
+                    new ConfigOptions() { ConfigParts = ConfigParts.All });
+
+                if (downloadStream == null)
+                    throw new ScadaException(AppPhrases.DownloadDataEmpty);
+
+                if (serverSettings.Download.SaveToDir)
+                {
+                    // сохранение в директорию
+                    string destDir = serverSettings.Download.DestDir;
+                    Directory.CreateDirectory(destDir);
+                    string tempFileName = destDir + "download-config_" + 
+                        DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".zip";
+
+                    try
+                    {
+                        // сохранение во временный файл, т.к. распаковка из MemoryStream не работает
+                        using (FileStream destStream = File.Create(tempFileName))
+                        {
+                            downloadStream.CopyTo(destStream);
+                        }
+
+                        // распаковка
+                        using (ZipFile zipFile = ZipFile.Read(tempFileName))
+                        {
+                            foreach (ZipEntry zipEntry in zipFile)
+                            {
+                                zipEntry.Extract(destDir, ExtractExistingFileAction.OverwriteSilently);
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        try { File.Delete(tempFileName); }
+                        catch { }
+                    }
+                }
+                else
+                {
+                    // сохранение в файл
+                    string destFile = serverSettings.Download.DestFile;
+                    Directory.CreateDirectory(Path.GetDirectoryName(destFile));
+
+                    using (FileStream destStream = File.Create(destFile))
+                    {
+                        downloadStream.CopyTo(destStream);
+                    }
+                }
+
+                writer.WriteLine(AppPhrases.DownloadCompleted, (int)(DateTime.UtcNow - t0).TotalSeconds);
+                msg = AppPhrases.DownloadSuccessful;
+                return true;
+            }
+            catch (Exception ex)
+            {
+                msg = AppPhrases.DownloadError + ":\r\n" + ex.Message;
+
+                try { writer?.WriteLine(msg); }
+                catch { }
+
+                return false;
+            }
+            finally
+            {
+                try { writer?.Close(); }
+                catch { }
+
+                try { client?.Close(); }
+                catch { }
+            }
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs b/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs
index 392e3cbca..a62c2ea17 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs
@@ -48,21 +48,12 @@ internal static class ImportExport
         private const int ZipDelay = 200;
 
 
-        /// 
-        /// Вывести в журнал заголовок с подчёркиванием
-        /// 
-        private static void WriteTitle(StreamWriter writer, string title)
-        {
-            writer.WriteLine(title);
-            writer.WriteLine(new string('-', title.Length));
-        }
-
         /// 
         /// Вывести в журнал столбцы таблицы
         /// 
         private static void WriteColumns(StreamWriter writer, DataTable dataTable, string subTitle)
         {
-            WriteTitle(writer, subTitle);
+            AppUtils.WriteTitle(writer, subTitle);
             if (dataTable.Columns.Count > 0)
             {
                 foreach (DataColumn column in dataTable.Columns)
@@ -103,7 +94,7 @@ private static void ImportTable(DataTable srcTable, Tables.TableInfo destTableIn
             if (writer != null)
             {
                 writer.WriteLine();
-                WriteTitle(writer, string.Format(AppPhrases.ImportTableTitle, 
+                AppUtils.WriteTitle(writer, string.Format(AppPhrases.ImportTableTitle, 
                     destTableInfo.Name + " (" + destTableInfo.Header + ")"));
                 writer.WriteLine();
                 WriteColumns(writer, srcTable, AppPhrases.SrcTableColumns);
@@ -170,13 +161,13 @@ private static void ImportTable(DataTable srcTable, Tables.TableInfo destTableIn
             // вывод результата и ошибок в журнал импорта
             if (writer != null)
             {
-                WriteTitle(writer, AppPhrases.ImportTableResult);
+                AppUtils.WriteTitle(writer, AppPhrases.ImportTableResult);
                 writer.WriteLine(msg);
 
                 if (errRowCnt > 0)
                 {
                     writer.WriteLine();
-                    WriteTitle(writer, AppPhrases.ImportTableErrors);
+                    AppUtils.WriteTitle(writer, AppPhrases.ImportTableErrors);
 
                     foreach (DataRow row in errRows)
                     {
@@ -216,7 +207,8 @@ public static bool ImportTable(string srcFileName, Tables.TableInfo destTableInf
                     writer = new StreamWriter(logFileName, false, Encoding.UTF8);
                     logCreated = true;
 
-                    WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + AppPhrases.ImportTitle);
+                    AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + 
+                        AppPhrases.ImportTitle);
                     writer.WriteLine(AppPhrases.ImportSource + srcFileName);
                 }
 
@@ -291,7 +283,8 @@ public static bool ImportArchive(string srcFileName, List dest
                     writer = new StreamWriter(logFileName, false, Encoding.UTF8);
                     logCreated = true;
 
-                    WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + AppPhrases.ImportTitle);
+                    AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + 
+                        AppPhrases.ImportTitle);
                     writer.WriteLine(AppPhrases.ImportSource + srcFileName);
                 }
 
@@ -300,7 +293,9 @@ public static bool ImportArchive(string srcFileName, List dest
                     // получение словаря всех файлов архива с именами в нижнем регистре
                     Dictionary zipEntries = new Dictionary(zipFile.Count);
                     foreach (ZipEntry zipEntry in zipFile)
+                    {
                         zipEntries.Add(zipEntry.FileName.ToLowerInvariant(), zipEntry);
+                    }
 
                     // импорт таблиц из тех, которые содержатся в архиве
                     int totalUpdRowCnt = 0;
@@ -349,7 +344,7 @@ public static bool ImportArchive(string srcFileName, List dest
                     if (logCreated)
                     {
                         writer.WriteLine();
-                        WriteTitle(writer, AppPhrases.ImportResult);
+                        AppUtils.WriteTitle(writer, AppPhrases.ImportResult);
                         writer.WriteLine(msg);
                     }
 
diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.cs b/ScadaAdmin/ScadaAdmin/FrmMain.cs
index e89e67101..f5484d798 100644
--- a/ScadaAdmin/ScadaAdmin/FrmMain.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmMain.cs
@@ -553,6 +553,8 @@ private void SetItemsEnabledOnConnect()
             miServiceCreateCnls.Enabled = connected;
             miServiceCloneCnls.Enabled = connected;
             miServiceCnlsMap.Enabled = connected;
+            miRemoteDownload.Enabled = connected;
+            miRemoteUpload.Enabled = connected;
         }
 
         /// 
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index 8de5adcf7..e8ad56c72 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -4,6 +4,18 @@
     The configuration database file in SDF format {0} not found.
     
Update the open tables to display the changes.
   
+  
+    {0} Download Configuration
+    Connection : {0}
+    Session {0} created
+    Unable to create session
+    Logged on
+    Unable to login - {0}
+    No data to download
+    Download completed successfully in {0} sec
+    Download completed successfully
+    Error downloading configuration
+  
   
     Choose a configuration database table file
     Choose a configuration database archive file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index 2f6df4459..2a6724416 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -25,14 +25,9 @@
 
 using Scada;
 using Scada.UI;
-using ScadaAdmin.AgentSvcRef;
 using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
+using System.Diagnostics;
 using System.IO;
-using System.Text;
 using System.Windows.Forms;
 
 namespace ScadaAdmin.Remote
@@ -58,31 +53,6 @@ public FrmDownloadConfig()
         }
 
 
-        /// 
-        /// Создать вектор инициализации на освнове ид. сессии
-        /// 
-        private static byte[] CreateIV(long sessionID)
-        {
-            byte[] iv = new byte[ScadaUtils.IVSize];
-            byte[] sessBuf = BitConverter.GetBytes(sessionID);
-            int sessBufLen = sessBuf.Length;
-
-            for (int i = 0; i < ScadaUtils.IVSize; i++)
-            {
-                iv[i] = sessBuf[i % sessBufLen];
-            }
-
-            return iv;
-        }
-
-        /// 
-        /// Зашифровать пароль
-        /// 
-        private static string EncryptPassword(string password, long sessionID, byte[] secretKey)
-        {
-            return ScadaUtils.Encrypt(password, secretKey, CreateIV(sessionID));
-        }
-
         /// 
         /// Отобразить настройки скачивания конфигурации
         /// 
@@ -136,10 +106,7 @@ private void ApplyDownloadSettings(ServersSettings.DownloadSettings downloadSett
         private void SaveServersSettings()
         {
             if (!serversSettings.Save(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
-            {
-                AppData.ErrLog.WriteError(errMsg);
-                ScadaUiUtils.ShowError(errMsg);
-            }
+                AppUtils.ProcError(errMsg);
         }
 
         /// 
@@ -147,47 +114,24 @@ private void SaveServersSettings()
         /// 
         private void DownloadConfig(ServersSettings.ServerSettings serverSettings)
         {
-            AgentSvcClient client = new AgentSvcClient();
+            // скачивание
+            string logFileName = AppData.AppDirs.LogDir + "ScadaAdminDownload.txt";
+            bool downloadOK = DownloadUpload.DownloadConfig(serverSettings,
+                logFileName, out bool logCreated, out string msg);
 
-            try
+            // отображение сообщения о результате
+            if (downloadOK)
             {
-                client.CreateSession(out long sessionID);
-                MessageBox.Show("Session ID = " + sessionID);
-
-                byte[] secretKey = ScadaUtils.HexToBytes("5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1");
-                string encryptedPassword = EncryptPassword("12345", sessionID, secretKey);
-
-                if (client.Login(out string errMsg, sessionID, "admin", encryptedPassword, "Default"))
-                    MessageBox.Show("Login OK");
-                else
-                    MessageBox.Show(errMsg);
-
-                Stream stream = client.DownloadConfig(sessionID,
-                    new ConfigOptions() { ConfigParts = ConfigParts.All });
-
-                if (stream == null)
-                {
-                    MessageBox.Show("Stream is null.");
-                }
-                else
-                {
-                    DateTime t0 = DateTime.UtcNow;
-                    byte[] buf = new byte[1024];
-                    Stream saver = File.Create(@"C:\SCADA\config.zip");
-                    int cnt;
-
-                    while ((cnt = stream.Read(buf, 0, buf.Length)) > 0)
-                    {
-                        saver.Write(buf, 0, cnt);
-                    }
-
-                    saver.Close();
-                    MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms");
-                }
+                ScadaUiUtils.ShowInfo(msg);
+                // TODO: запуск импорта, если это отмечено в настройках скачивания
             }
-            finally
+            else
             {
-                client.Close();
+                AppUtils.ProcError(msg);
+
+                // отображение журнала в блокноте
+                if (logCreated)
+                    Process.Start(logFileName);
             }
         }
 
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index d8aefeac2..09e857150 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -98,6 +98,7 @@
     
     
     
+    
     
     
     

From 0e6e08fa8d936b0990a32f11d2b0a76118d28c43 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Tue, 8 May 2018 17:55:35 +0300
Subject: [PATCH 060/100] ScadaAdmin: dev

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs     | 5 +----
 ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs | 4 ++--
 ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml | 3 +--
 3 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index 0c69abf4b..68ae28fc6 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -50,7 +50,6 @@ static AppPhrases()
         public static string LoggedOn { get; private set; }
         public static string UnableLogin { get; private set; }
         public static string DownloadDataEmpty { get; private set; }
-        public static string DownloadCompleted { get; private set; }
         public static string DownloadSuccessful { get; private set; }
         public static string DownloadError { get; private set; }
 
@@ -236,8 +235,7 @@ private static void SetToDefault()
             LoggedOn = "Вход в систему выполнен";
             UnableLogin = "Не удалось войти в систему - {0}";
             DownloadDataEmpty = "Отсутствуют данные для скачивания";
-            DownloadCompleted = "Скачивание завершено успешно за {0} с";
-            DownloadSuccessful = "Скачивание завершено успешно";
+            DownloadSuccessful = "Скачивание завершено успешно за {0} с.";
             DownloadError = "Ошибка при скачивании конфигурации";
 
             ChooseBaseTableFile = "Выберите файл таблицы базы конфигурации";
@@ -417,7 +415,6 @@ public static void Init()
                 LoggedOn = dict.GetPhrase("LoggedOn", LoggedOn);
                 UnableLogin = dict.GetPhrase("UnableLogin", UnableLogin);
                 DownloadDataEmpty = dict.GetPhrase("DownloadDataEmpty", DownloadDataEmpty);
-                DownloadCompleted = dict.GetPhrase("DownloadCompleted", DownloadCompleted);
                 DownloadSuccessful = dict.GetPhrase("DownloadSuccessful", DownloadSuccessful);
                 DownloadError = dict.GetPhrase("DownloadError", DownloadError);
             }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index d09b0e12e..d6fddb07b 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -164,8 +164,8 @@ public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
                     }
                 }
 
-                writer.WriteLine(AppPhrases.DownloadCompleted, (int)(DateTime.UtcNow - t0).TotalSeconds);
-                msg = AppPhrases.DownloadSuccessful;
+                msg = string.Format(AppPhrases.DownloadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds);
+                writer.WriteLine(msg);
                 return true;
             }
             catch (Exception ex)
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index e8ad56c72..b4b76dce0 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -12,8 +12,7 @@
     Logged on
     Unable to login - {0}
     No data to download
-    Download completed successfully in {0} sec
-    Download completed successfully
+    Download completed successfully in {0} sec.
     Error downloading configuration
   
   

From 37f22b7e39f4dd0b41b33ada3f75da8187e2f33a Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Thu, 10 May 2018 18:32:23 +0300
Subject: [PATCH 061/100] ScadaAdmin: import all tables

---
 ScadaAdmin/ScadaAdmin/AppCode/AppData.cs      |  10 +-
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  40 ++--
 ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs | 165 +++++++++++++----
 .../ScadaAdmin/AppCode/ServersSettings.cs     |   9 +-
 ScadaAdmin/ScadaAdmin/AppCode/Tables.cs       |  13 +-
 ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs   |  31 ++--
 ScadaAdmin/ScadaAdmin/FrmImport.cs            | 172 ++++++++++++++----
 ScadaAdmin/ScadaAdmin/FrmImport.resx          |   3 +
 ScadaAdmin/ScadaAdmin/FrmMain.cs              |   8 +-
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |  35 +++-
 .../Remote/FrmDownloadConfig.Designer.cs      |  30 ++-
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |  39 +++-
 12 files changed, 423 insertions(+), 132 deletions(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs
index 348ffdc1a..de7173b2e 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs
@@ -59,6 +59,7 @@ static AppData()
                 Encoding = Encoding.UTF8
             };
 
+            Settings = new Settings();
             Conn =  new SqlCeConnection();
         }
 
@@ -74,6 +75,11 @@ static AppData()
         public static Log ErrLog { get; private set; }
 
 
+        /// 
+        /// Получить настройки приложения
+        /// 
+        public static Settings Settings { get; private set; }
+
         /// 
         /// Получить соединение с БД
         /// 
@@ -94,11 +100,13 @@ public static bool Connected
         /// 
         /// Соединиться с БД, используя заданную в файле Web.Config строку связи
         /// 
-        public static void Connect(string baseSdfFileName)
+        public static void Connect()
         {
             if (Conn.State != ConnectionState.Closed)
                 Disconnect();
 
+            string baseSdfFileName = Settings.AppSett.BaseSDFFile;
+
             if (!File.Exists(baseSdfFileName))
                 throw new FileNotFoundException(string.Format(AppPhrases.BaseSDFFileNotFound, baseSdfFileName));
 
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index 68ae28fc6..4aef9580c 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -55,11 +55,11 @@ static AppPhrases()
 
         // Словарь ScadaAdmin.ImportExport
         public static string ChooseBaseTableFile { get; private set; }
-        public static string ChooseBaseArchiveFile { get; private set; }
+        public static string ChooseArchiveFile { get; private set; }
         public static string BaseTableFileFilter { get; private set; }
-        public static string BaseArchiveFileFilter { get; private set; }
-        public static string ImportFileUndefied { get; private set; }
+        public static string ArchiveFileFilter { get; private set; }
         public static string ImportFileNotExist { get; private set; }
+        public static string ImportDirNotExist { get; private set; }
         public static string ImportTitle { get; private set; }
         public static string ImportTableTitle { get; private set; }
         public static string ImportSource { get; private set; }
@@ -76,6 +76,7 @@ static AppPhrases()
         public static string ImportTableResult { get; private set; }
         public static string ImportTableErrors { get; private set; }
         public static string ImportTableError { get; private set; }
+        public static string ImportAllTablesError { get; private set; }
         public static string ImportArchiveError { get; private set; }
         public static string ExportFileUndefied { get; private set; }
         public static string ExportDirUndefied { get; private set; }
@@ -142,6 +143,7 @@ static AppPhrases()
         public static string FillKPGridError { get; private set; }
 
         // Словарь ScadaAdmin.FrmImport
+        public static string AllTablesItem { get; private set; }
         public static string ArchiveItem { get; private set; }
 
         // Словарь ScadaAdmin.FrmInCnlProps
@@ -223,6 +225,9 @@ static AppPhrases()
         public static string GetInCnlNumsError { get; private set; }
         public static string GetCtrlCnlNumsError { get; private set; }
 
+        // Словарь ScadaAdmin.Remote
+        public static string ChooseConfigDir { get; private set; }
+
         private static void SetToDefault()
         {
             BaseSDFFileNotFound = "Файл базы конфигурации в формате SDF {0} не найден.";
@@ -239,14 +244,14 @@ private static void SetToDefault()
             DownloadError = "Ошибка при скачивании конфигурации";
 
             ChooseBaseTableFile = "Выберите файл таблицы базы конфигурации";
-            ChooseBaseArchiveFile = "Выберите файл архива базы конфигурации";
-            BaseTableFileFilter = "Таблицы базы конфигурации|*.dat|Все файлы|*.*";
-            BaseArchiveFileFilter = "Архив базы конфигурации|*.zip|Все файлы|*.*";
-            ImportFileUndefied = "Импортируемый файл не определён.";
+            ChooseArchiveFile = "Выберите файл архива конфигурации";
+            BaseTableFileFilter = "Таблицы базы конфигурации (*.dat)|*.dat|Все файлы (*.*)|*.*";
+            ArchiveFileFilter = "Архив конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*";
             ImportFileNotExist = "Импортируемый файл не существует.";
+            ImportDirNotExist = "Импортируемая директория не существует.";
             ImportTitle = "Импорт базы конфигурации";
             ImportTableTitle = "Импорт таблицы базы конфигурации \"{0}\"";
-            ImportSource = "Исходный файл : ";
+            ImportSource = "Исходный файл или директория : ";
             LoadTableError = "Ошибка при загрузке импортируемой таблицы";
             SrcTableColumns = "Поля исходной таблицы";
             DestTableColumns = "Поля таблицы, в которую производится импорт";
@@ -261,6 +266,8 @@ private static void SetToDefault()
             ImportTableResult = "Результат импорта таблицы";
             ImportTableErrors = "Ошибки импорта таблицы";
             ImportTableError = "Ошибка при импорте таблицы базы конфигурации";
+            ImportAllTablesError = "Ошибка при импорте всех таблиц базы конфигурации";
+            ImportArchiveError = "Ошибка при импорте базы конфигурации из архива";
             ExportFileUndefied = "Файл экспорта не определён.";
             ExportDirUndefied = "Директория экспорта не определена.";
             ExportDirNotExists = "Директория экспорта не существует.";
@@ -323,6 +330,7 @@ private static void SetToDefault()
             FillKPFilterError = "Ошибка при заполнении фильтра КП";
             FillKPGridError = "Ошибка при заполнении таблицы выбора КП";
 
+            AllTablesItem = "Все таблицы";
             ArchiveItem = "Таблицы из архива";
 
             ShowInCnlPropsError = "Ошибка при отображении свойств входного канала";
@@ -395,6 +403,8 @@ private static void SetToDefault()
             GetCtrlCnlNameError = "Ошибка при получении наименования канала управления";
             GetInCnlNumsError = "Ошибка при получении номеров входных каналов";
             GetCtrlCnlNumsError = "Ошибка при получении номеров каналов управления";
+
+            ChooseConfigDir = "Выберите директорию конфигурации";
         }
 
         public static void Init()
@@ -422,11 +432,11 @@ public static void Init()
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.ImportExport", out dict))
             {
                 ChooseBaseTableFile = dict.GetPhrase("ChooseBaseTableFile", ChooseBaseTableFile);
-                ChooseBaseArchiveFile = dict.GetPhrase("ChooseBaseArchiveFile", ChooseBaseArchiveFile);
+                ChooseArchiveFile = dict.GetPhrase("ChooseArchiveFile", ChooseArchiveFile);
                 BaseTableFileFilter = dict.GetPhrase("BaseTableFileFilter", BaseTableFileFilter);
-                BaseArchiveFileFilter = dict.GetPhrase("BaseArchiveFileFilter", BaseArchiveFileFilter);
-                ImportFileUndefied = dict.GetPhrase("ImportFileUndefied", ImportFileUndefied);
+                ArchiveFileFilter = dict.GetPhrase("ArchiveFileFilter", ArchiveFileFilter);
                 ImportFileNotExist = dict.GetPhrase("ImportFileNotExist", ImportFileNotExist);
+                ImportDirNotExist = dict.GetPhrase("ImportDirNotExist", ImportDirNotExist);
                 ImportTitle = dict.GetPhrase("ImportTitle", ImportTitle);
                 ImportTableTitle = dict.GetPhrase("ImportTableTitle", ImportTableTitle);
                 ImportSource = dict.GetPhrase("ImportSource", ImportSource);
@@ -443,6 +453,8 @@ public static void Init()
                 ImportTableResult = dict.GetPhrase("ImportTableResult", ImportTableResult);
                 ImportTableErrors = dict.GetPhrase("ImportTableErrors", ImportTableErrors);
                 ImportTableError = dict.GetPhrase("ImportError", ImportTableError);
+                ImportAllTablesError = dict.GetPhrase("ImportAllTablesError", ImportAllTablesError);
+                ImportArchiveError = dict.GetPhrase("ImportArchiveError", ImportArchiveError);
                 ExportFileUndefied = dict.GetPhrase("ExportFileUndefied", ExportFileUndefied);
                 ExportDirUndefied = dict.GetPhrase("ExportDirUndefied", ExportDirUndefied);
                 ExportDirNotExists = dict.GetPhrase("ExportDirNotExists", ExportDirNotExists);
@@ -516,6 +528,7 @@ public static void Init()
 
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmImport", out dict))
             {
+                AllTablesItem = dict.GetPhrase("AllTablesItem", AllTablesItem);
                 ArchiveItem = dict.GetPhrase("ArchiveItem", ArchiveItem);
             }
 
@@ -613,6 +626,11 @@ public static void Init()
                 GetInCnlNumsError = dict.GetPhrase("GetInCnlNumsError", GetInCnlNumsError);
                 GetCtrlCnlNumsError = dict.GetPhrase("GetCtrlCnlNumsError", GetCtrlCnlNumsError);
             }
+
+            if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Remote", out dict))
+            {
+                ChooseConfigDir = dict.GetPhrase("ChooseConfigDir", ChooseConfigDir);
+            }
         }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs b/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs
index a62c2ea17..a10887312 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs
@@ -109,7 +109,8 @@ private static void ImportTable(DataTable srcTable, Tables.TableInfo destTableIn
 
                 if (tryToUpdate)
                 {
-                    int newID = (int)srcRow[idColName] + shiftID;
+                    object curID = srcRow[idColName];
+                    object newID = curID is int ? (int)curID + shiftID : curID;
                     int rowInd = destTable.DefaultView.Find(newID); // таблица отсортирована по ключу
                     if (rowInd >= 0)
                         destRow = destTable.DefaultView[rowInd].Row;
@@ -187,30 +188,30 @@ public static bool ImportTable(string srcFileName, Tables.TableInfo destTableInf
             int minID, int maxID, int newMinID, string logFileName, out bool logCreated, out string msg)
         {
             // проверка аргументов метода
-            if (string.IsNullOrWhiteSpace(srcFileName))
-                throw new ArgumentException(AppPhrases.ImportFileUndefied);
-
-            if (!File.Exists(srcFileName))
-                throw new FileNotFoundException(AppPhrases.ImportFileNotExist);
+            if (srcFileName == null)
+                throw new ArgumentNullException("srcFileName");
 
             if (destTableInfo == null)
                 throw new ArgumentNullException("destTableInfo");
 
+            if (logFileName == null)
+                throw new ArgumentNullException("logFileName");
+
             logCreated = false;
             StreamWriter writer = null;
 
             try
             {
                 // создание журнала импорта и вывод параметров импорта
-                if (!string.IsNullOrEmpty(logFileName))
-                {
-                    writer = new StreamWriter(logFileName, false, Encoding.UTF8);
-                    logCreated = true;
+                writer = new StreamWriter(logFileName, false, Encoding.UTF8);
+                logCreated = true;
+                AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + 
+                    AppPhrases.ImportTitle);
+                writer.WriteLine(AppPhrases.ImportSource + srcFileName);
 
-                    AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + 
-                        AppPhrases.ImportTitle);
-                    writer.WriteLine(AppPhrases.ImportSource + srcFileName);
-                }
+                // проверка существования импортируемого файла
+                if (!File.Exists(srcFileName))
+                    throw new FileNotFoundException(AppPhrases.ImportFileNotExist);
 
                 // загрузка импортируемой таблицы в формате DAT
                 BaseAdapter baseAdapter = new BaseAdapter();
@@ -257,44 +258,143 @@ public static bool ImportTable(string srcFileName, Tables.TableInfo destTableInf
         }
 
         /// 
-        /// Импортировать архив базы конфигурации (патч)
+        /// Импортировать все таблицы базы конфигурации из заданной директории
         /// 
-        public static bool ImportArchive(string srcFileName, List destTableInfoList,
+        public static bool ImportAllTables(string srcDir, List destTableInfoList,
             string logFileName, out bool logCreated, out string msg)
         {
             // проверка аргументов метода
-            if (string.IsNullOrWhiteSpace(srcFileName))
-                throw new ArgumentException(AppPhrases.ImportFileUndefied);
-
-            if (!File.Exists(srcFileName))
-                throw new FileNotFoundException(AppPhrases.ImportFileNotExist);
+            if (srcDir == null)
+                throw new ArgumentNullException("srcDir");
 
             if (destTableInfoList == null)
                 throw new ArgumentNullException("destTableInfoList");
 
+            if (logFileName == null)
+                throw new ArgumentNullException("logFileName");
+
             logCreated = false;
             StreamWriter writer = null;
 
             try
             {
                 // создание журнала импорта и вывод параметров импорта
-                if (!string.IsNullOrEmpty(logFileName))
+                writer = new StreamWriter(logFileName, false, Encoding.UTF8);
+                logCreated = true;
+                AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " +
+                    AppPhrases.ImportTitle);
+                writer.WriteLine(AppPhrases.ImportSource + srcDir);
+
+                // проверка существования импортируемой директории
+                if (!Directory.Exists(srcDir))
+                    throw new DirectoryNotFoundException(AppPhrases.ImportDirNotExist);
+
+                // импорт таблиц, файлы которых существуют в заданной директории
+                int totalUpdRowCnt = 0;
+                int totalErrRowCnt = 0;
+                int updRowCnt;
+                int errRowCnt;
+                srcDir = ScadaUtils.NormalDir(srcDir);
+
+                foreach (Tables.TableInfo destTableInfo in destTableInfoList)
                 {
-                    writer = new StreamWriter(logFileName, false, Encoding.UTF8);
-                    logCreated = true;
+                    string srcFileName = srcDir + destTableInfo.FileName;
+
+                    if (File.Exists(srcFileName))
+                    {
+                        // загрузка импортируемой таблицы в формате DAT
+                        BaseAdapter baseAdapter = new BaseAdapter();
+                        DataTable srcTable = new DataTable();
+                        baseAdapter.FileName = srcFileName;
+
+                        try
+                        {
+                            baseAdapter.Fill(srcTable, true);
+                        }
+                        catch (Exception ex)
+                        {
+                            throw new Exception(AppPhrases.LoadTableError + ":\r\n" + ex.Message);
+                        }
 
-                    AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + 
-                        AppPhrases.ImportTitle);
-                    writer.WriteLine(AppPhrases.ImportSource + srcFileName);
+                        // импорт таблицы
+                        string s;
+                        ImportTable(srcTable, destTableInfo, 0, writer, out updRowCnt, out errRowCnt, out s);
+                        totalUpdRowCnt += updRowCnt;
+                        totalErrRowCnt += errRowCnt;
+                    }
                 }
 
+                msg = totalErrRowCnt == 0 ? string.Format(AppPhrases.ImportCompleted, totalUpdRowCnt) :
+                    string.Format(AppPhrases.ImportCompletedWithErr, totalUpdRowCnt, totalErrRowCnt);
+
+                // вывод результата в журнал импорта
+                writer.WriteLine();
+                AppUtils.WriteTitle(writer, AppPhrases.ImportResult);
+                writer.WriteLine(msg);
+
+                if (totalUpdRowCnt > 0)
+                    msg += AppPhrases.RefreshRequired;
+                return totalErrRowCnt == 0;
+            }
+            catch (Exception ex)
+            {
+                msg = AppPhrases.ImportAllTablesError + ":\r\n" + ex.Message;
+                try { if (logCreated) writer.WriteLine(msg); }
+                catch { }
+                return false;
+            }
+            finally
+            {
+                try { writer.Close(); }
+                catch { }
+            }
+        }
+
+        /// 
+        /// Импортировать архив базы конфигурации (патч)
+        /// 
+        public static bool ImportArchive(string srcFileName, List destTableInfoList,
+            string logFileName, out bool logCreated, out string msg)
+        {
+            // проверка аргументов метода
+            if (srcFileName == null)
+                throw new ArgumentNullException("srcFileName");
+
+            if (destTableInfoList == null)
+                throw new ArgumentNullException("destTableInfoList");
+
+            if (logFileName == null)
+                throw new ArgumentNullException("logFileName");
+
+            logCreated = false;
+            StreamWriter writer = null;
+
+            try
+            {
+                // создание журнала импорта и вывод параметров импорта
+                writer = new StreamWriter(logFileName, false, Encoding.UTF8);
+                logCreated = true;
+                AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + 
+                    AppPhrases.ImportTitle);
+                writer.WriteLine(AppPhrases.ImportSource + srcFileName);
+
+                // проверка существования импортируемого файла
+                if (!File.Exists(srcFileName))
+                    throw new FileNotFoundException(AppPhrases.ImportFileNotExist);
+
                 using (ZipFile zipFile = ZipFile.Read(srcFileName))
                 {
                     // получение словаря всех файлов архива с именами в нижнем регистре
                     Dictionary zipEntries = new Dictionary(zipFile.Count);
                     foreach (ZipEntry zipEntry in zipFile)
                     {
-                        zipEntries.Add(zipEntry.FileName.ToLowerInvariant(), zipEntry);
+                        string fileName = zipEntry.FileName.ToLowerInvariant();
+                        if (fileName.StartsWith("basedat/", StringComparison.Ordinal) ||
+                            fileName.StartsWith("basedat\\", StringComparison.Ordinal))
+                        {
+                            fileName = fileName.Substring("basedat/".Length);
+                            zipEntries.Add(fileName, zipEntry);
+                        }
                     }
 
                     // импорт таблиц из тех, которые содержатся в архиве
@@ -341,12 +441,9 @@ public static bool ImportArchive(string srcFileName, List dest
                         string.Format(AppPhrases.ImportCompletedWithErr, totalUpdRowCnt, totalErrRowCnt);
 
                     // вывод результата в журнал импорта
-                    if (logCreated)
-                    {
-                        writer.WriteLine();
-                        AppUtils.WriteTitle(writer, AppPhrases.ImportResult);
-                        writer.WriteLine(msg);
-                    }
+                    writer.WriteLine();
+                    AppUtils.WriteTitle(writer, AppPhrases.ImportResult);
+                    writer.WriteLine(msg);
 
                     if (totalUpdRowCnt > 0)
                         msg += AppPhrases.RefreshRequired;
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
index b39dfe1ef..d68259457 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
@@ -153,6 +153,10 @@ public DownloadSettings()
             /// Получить или установить имя файла архива для сохранения конфигурации
             /// 
             public string DestFile { get; set; }
+            /// 
+            /// Получить или установить признак запуска импорта базы конфигурации после скачивания
+            /// 
+            public bool ImportBase { get; set; }
 
             /// 
             /// Установить настройки по умолчанию
@@ -162,6 +166,7 @@ private void SetToDefault()
                 SaveToDir = true;
                 DestDir = @"C:\SCADA\";
                 DestFile = "";
+                ImportBase = true;
             }
             /// 
             /// Загрузить настройки из XML-узла
@@ -173,7 +178,8 @@ public void LoadFromXml(XmlNode xmlNode)
 
                 SaveToDir = xmlNode.GetChildAsBool("SaveToDir", true);
                 DestDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("DestDir", @"C:\SCADA\"));
-                DestFile = xmlNode.GetChildAsString("DestFile");
+                DestFile = xmlNode.GetChildAsString("DestFile", @"C:\SCADA\config.zip");
+                ImportBase = xmlNode.GetChildAsBool("ImportBase", true);
             }
             /// 
             /// Сохранить настройки в XML-узле
@@ -186,6 +192,7 @@ public void SaveToXml(XmlElement xmlElem)
                 xmlElem.AppendElem("SaveToDir", SaveToDir);
                 xmlElem.AppendElem("DestDir", DestDir);
                 xmlElem.AppendElem("DestFile", DestFile);
+                xmlElem.AppendElem("ImportBase", ImportBase);
             }
         }
 
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs b/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs
index 678f6b4be..d516b81bb 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs
@@ -48,12 +48,14 @@ public class TableInfo
             /// 
             /// Конструктор
             /// 
-            public TableInfo(string name, string header, GetTableDelegate getTable, string idColName)
+            public TableInfo(string name, string header, GetTableDelegate getTable, string idColName, 
+                bool hasIntID = true)
             {
                 Name = name;
                 Header = header;
                 GetTable = getTable;
                 IDColName = idColName;
+                HasIntID = !string.IsNullOrEmpty(idColName) && hasIntID;
             }
 
             /// 
@@ -82,6 +84,10 @@ public string FileName
             /// Получить наименование столбца идентификатора, если он числовой и определяется одним столбцом
             /// 
             public string IDColName { get; private set; }
+            /// 
+            /// Таблица имеет целочисленный идентификатор
+            /// 
+            public bool HasIntID { get; private set; }
 
             /// 
             /// Получить строковое представление объекта
@@ -135,7 +141,7 @@ static Tables()
             TableInfoList.Add(new TableInfo("Unit", CommonPhrases.UnitTable, GetUnitTable, "UnitID"));
             TableInfoList.Add(new TableInfo("CmdVal", CommonPhrases.CmdValTable, GetCmdValTable, "CmdValID"));
             TableInfoList.Add(new TableInfo("Format", CommonPhrases.FormatTable, GetFormatTable, "FormatID"));
-            TableInfoList.Add(new TableInfo("Formula", CommonPhrases.FormulaTable, GetFormulaTable, ""));
+            TableInfoList.Add(new TableInfo("Formula", CommonPhrases.FormulaTable, GetFormulaTable, "Name", false));
         }
 
 
@@ -745,8 +751,7 @@ public static void FillTableSchema(DataTable dataTable)
             {
                 if (dataTable != null)
                 {
-                    string tableName = dataTable.TableName == "User" ? "[User]" : dataTable.TableName;
-                    string sql = "select * from " + tableName;
+                    string sql = "select * from [" + dataTable.TableName + "]";
                     SqlCeDataAdapter adapter = new SqlCeDataAdapter(sql, AppData.Conn);
                     adapter.ContinueUpdateOnError = true;
                     adapter.FillSchema(dataTable, SchemaType.Source);
diff --git a/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs b/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs
index a17d59384..6b8ee85dc 100644
--- a/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs
@@ -47,7 +47,8 @@ private void InitializeComponent()
             this.lblFinalID = new System.Windows.Forms.Label();
             this.lblStartID = new System.Windows.Forms.Label();
             this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
-            this.chkImportLog = new System.Windows.Forms.CheckBox();
+            this.lblDirectory = new System.Windows.Forms.Label();
+            this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
             this.gbIDs.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.numNewStartID)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.numFinalID)).BeginInit();
@@ -56,7 +57,7 @@ private void InitializeComponent()
             // 
             // btnImport
             // 
-            this.btnImport.Location = new System.Drawing.Point(152, 188);
+            this.btnImport.Location = new System.Drawing.Point(152, 162);
             this.btnImport.Name = "btnImport";
             this.btnImport.Size = new System.Drawing.Size(75, 23);
             this.btnImport.TabIndex = 7;
@@ -67,7 +68,7 @@ private void InitializeComponent()
             // btnClose
             // 
             this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.btnClose.Location = new System.Drawing.Point(233, 188);
+            this.btnClose.Location = new System.Drawing.Point(233, 162);
             this.btnClose.Name = "btnClose";
             this.btnClose.Size = new System.Drawing.Size(75, 23);
             this.btnClose.TabIndex = 8;
@@ -242,17 +243,14 @@ private void InitializeComponent()
             this.openFileDialog.Filter = "Таблицы базы конфигурации|*.dat|Все файлы|*.*";
             this.openFileDialog.Title = "Выберите файл таблицы базы конфигурации";
             // 
-            // chkImportLog
+            // lblDirectory
             // 
-            this.chkImportLog.AutoSize = true;
-            this.chkImportLog.Checked = true;
-            this.chkImportLog.CheckState = System.Windows.Forms.CheckState.Checked;
-            this.chkImportLog.Location = new System.Drawing.Point(25, 164);
-            this.chkImportLog.Name = "chkImportLog";
-            this.chkImportLog.Size = new System.Drawing.Size(169, 17);
-            this.chkImportLog.TabIndex = 6;
-            this.chkImportLog.Text = "Записать в журнал импорта";
-            this.chkImportLog.UseVisualStyleBackColor = true;
+            this.lblDirectory.AutoSize = true;
+            this.lblDirectory.Location = new System.Drawing.Point(51, 49);
+            this.lblDirectory.Name = "lblDirectory";
+            this.lblDirectory.Size = new System.Drawing.Size(69, 13);
+            this.lblDirectory.TabIndex = 9;
+            this.lblDirectory.Text = "Директория";
             // 
             // FrmImport
             // 
@@ -260,8 +258,8 @@ private void InitializeComponent()
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.btnClose;
-            this.ClientSize = new System.Drawing.Size(320, 223);
-            this.Controls.Add(this.chkImportLog);
+            this.ClientSize = new System.Drawing.Size(320, 197);
+            this.Controls.Add(this.lblDirectory);
             this.Controls.Add(this.gbIDs);
             this.Controls.Add(this.btnImport);
             this.Controls.Add(this.btnClose);
@@ -308,6 +306,7 @@ private void InitializeComponent()
         private System.Windows.Forms.CheckBox chkNewStartID;
         private System.Windows.Forms.CheckBox chkFinalID;
         private System.Windows.Forms.OpenFileDialog openFileDialog;
-        private System.Windows.Forms.CheckBox chkImportLog;
+        private System.Windows.Forms.Label lblDirectory;
+        private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/FrmImport.cs b/ScadaAdmin/ScadaAdmin/FrmImport.cs
index 67d8c2b24..ea902c99b 100644
--- a/ScadaAdmin/ScadaAdmin/FrmImport.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmImport.cs
@@ -39,9 +39,32 @@ namespace ScadaAdmin
     public partial class FrmImport : Form
     {
         /// 
-        /// Имя файла архива базы конфигурации
+        /// Элемент выпадающего списка для иморта всех таблиц
         /// 
-        public const string BaseDATArcFileName = "BaseDAT.zip";
+        private class ImportAllTablesItem
+        {
+            public override string ToString()
+            {
+                return AppPhrases.AllTablesItem;
+            }
+        }
+
+        /// 
+        /// Элемент выпадающего списка для иморта из архива
+        /// 
+        private class ImportArchiveItem
+        {
+            public override string ToString()
+            {
+                return AppPhrases.ArchiveItem;
+            }
+        }
+
+        /// 
+        /// Выбранный элемент при открытии формы
+        /// 
+        public enum SelectedItem { Table, AllTables, Archive };
+
 
         /// 
         /// Конструктор
@@ -50,20 +73,32 @@ public FrmImport()
         {
             InitializeComponent();
 
+            DefaultSelection = SelectedItem.Table;
             DefaultTableName = "";
-            DefaultDirectory = "";
+            DefaultArcFileName = "";
+            DefaultBaseDATDir = "";
         }
 
 
+        /// 
+        /// Выбранный элемент по умолчанию
+        /// 
+        public SelectedItem DefaultSelection { get; set; }
+
         /// 
         /// Получить или установить имя таблицы, выбранной по умолчанию
         /// 
         public string DefaultTableName { get; set; }
 
+        /// 
+        /// Получить или установить имя файла архива конфигурации по умолчанию
+        /// 
+        public string DefaultArcFileName { get; set; }
+
         /// 
         /// Получить или установить директорию по умолчанию
         /// 
-        public string DefaultDirectory { get; set; }
+        public string DefaultBaseDATDir { get; set; }
 
 
         private void FrmImport_Load(object sender, EventArgs e)
@@ -71,62 +106,109 @@ private void FrmImport_Load(object sender, EventArgs e)
             // перевод формы
             Translator.TranslateForm(this, "ScadaAdmin.FrmImport");
 
+            // настройка элементов управления
+            lblDirectory.Left = lblFileName.Left;
+
+            // определение имени файла архива по умолчанию
+            if (string.IsNullOrEmpty(DefaultArcFileName) && !string.IsNullOrEmpty(DefaultBaseDATDir))
+                DefaultArcFileName = Path.GetFullPath(DefaultBaseDATDir + @"..\config.zip");
+
             // заполнение выпадающего списка таблиц
-            int selInd = 0;
+            int tableInd = 0;
 
             foreach (Tables.TableInfo tableInfo in Tables.TableInfoList)
             {
                 int ind = cbTable.Items.Add(tableInfo);
                 if (tableInfo.Name == DefaultTableName)
-                    selInd = ind;
+                    tableInd = ind;
             }
 
-            cbTable.Items.Add(AppPhrases.ArchiveItem);
+            int allTablesInd = cbTable.Items.Add(new ImportAllTablesItem());
+            int archiveInd = cbTable.Items.Add(new ImportArchiveItem());
 
-            if (cbTable.Items.Count > 0)
-                cbTable.SelectedIndex = selInd;
+            // выбор элемента списка
+            switch (DefaultSelection)
+            {
+                case SelectedItem.AllTables:
+                    cbTable.SelectedIndex = allTablesInd;
+                    break;
+                case SelectedItem.Archive:
+                    cbTable.SelectedIndex = archiveInd;
+                    break;
+                default: // SelectedItem.Table
+                    cbTable.SelectedIndex = tableInd;
+                    break;
+            }
         }
 
         private void cbTable_SelectedIndexChanged(object sender, EventArgs e)
         {
             // установка имени файла таблицы
-            Tables.TableInfo tableInfo = cbTable.SelectedItem as Tables.TableInfo;
+            object selItem = cbTable.SelectedItem;
             
-            if (tableInfo == null)
+            if (selItem is ImportAllTablesItem)
             {
-                txtFileName.Text = DefaultDirectory + BaseDATArcFileName;
+                lblFileName.Visible = false;
+                lblDirectory.Visible = true;
+                txtFileName.Text = DefaultBaseDATDir;
                 gbIDs.Enabled = false;
             }
-            else
+            else if (selItem is ImportArchiveItem)
+            {
+                lblFileName.Visible = true;
+                lblDirectory.Visible = false;
+                txtFileName.Text = DefaultArcFileName;
+                gbIDs.Enabled = false;
+            }
+            else if (selItem is Tables.TableInfo tableInfo)
             {
-                txtFileName.Text = DefaultDirectory + tableInfo.FileName;
-                gbIDs.Enabled = tableInfo.IDColName != "";
+                lblFileName.Visible = true;
+                lblDirectory.Visible = false;
+                txtFileName.Text = DefaultBaseDATDir + tableInfo.FileName;
+                gbIDs.Enabled = tableInfo.HasIntID;
             }
         }
 
         private void btnBrowse_Click(object sender, EventArgs e)
         {
-            // настройка диалога открытия файла
-            string fileName = txtFileName.Text.Trim();
-            if (fileName.EndsWith("zip", StringComparison.OrdinalIgnoreCase))
+            if (lblFileName.Visible)
             {
-                openFileDialog.Title = AppPhrases.ChooseBaseArchiveFile;
-                openFileDialog.Filter = AppPhrases.BaseArchiveFileFilter;
+                // выбор импортируемого файла
+                if (cbTable.SelectedItem is ImportArchiveItem)
+                {
+                    openFileDialog.Title = AppPhrases.ChooseArchiveFile;
+                    openFileDialog.Filter = AppPhrases.ArchiveFileFilter;
+                }
+                else
+                {
+                    openFileDialog.Title = AppPhrases.ChooseBaseTableFile;
+                    openFileDialog.Filter = AppPhrases.BaseTableFileFilter;
+                }
+
+                string fileName = txtFileName.Text.Trim();
+                openFileDialog.FileName = fileName;
+
+                if (fileName != "")
+                    openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName);
+
+                if (openFileDialog.ShowDialog() == DialogResult.OK)
+                    txtFileName.Text = openFileDialog.FileName;
+
+                txtFileName.Focus();
+                txtFileName.DeselectAll();
             }
             else
             {
-                openFileDialog.Title = AppPhrases.ChooseBaseTableFile;
-                openFileDialog.Filter = AppPhrases.BaseTableFileFilter;
-            }
+                // выбор директории
+                folderBrowserDialog.SelectedPath = txtFileName.Text.Trim();
+                folderBrowserDialog.Description = CommonPhrases.ChooseBaseDATDir;
+
+                if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
+                    txtFileName.Text = ScadaUtils.NormalDir(folderBrowserDialog.SelectedPath);
 
-            // выбор файла таблицы
-            openFileDialog.FileName = fileName;
-            if (fileName != "")
-                openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName);
-            if (openFileDialog.ShowDialog() == DialogResult.OK)
-                txtFileName.Text = openFileDialog.FileName;
-            txtFileName.Focus();
-            txtFileName.DeselectAll();
+                txtFileName.Focus();
+                txtFileName.DeselectAll();
+            }
         }
 
         private void chkStartID_CheckedChanged(object sender, EventArgs e)
@@ -147,16 +229,21 @@ private void chkNewStartID_CheckedChanged(object sender, EventArgs e)
         private void btnImport_Click(object sender, EventArgs e)
         {
             // импорт выбранной таблицы из формата DAT
-            Tables.TableInfo tableInfo = cbTable.SelectedItem as Tables.TableInfo;
-
             if (AppData.Connected)
             {
-                string logFileName = chkImportLog.Checked ? AppData.AppDirs.LogDir + "ScadaAdminImport.txt" : "";
+                object selItem = cbTable.SelectedItem;
+                string logFileName = AppData.AppDirs.LogDir + "ScadaAdminImport.txt";
                 bool importOK;
                 bool logCreated;
                 string msg;
 
-                if (tableInfo == null)
+                if (selItem is ImportAllTablesItem)
+                {
+                    // импорт всех таблиц из директории
+                    importOK = ImportExport.ImportAllTables(txtFileName.Text, Tables.TableInfoList,
+                        logFileName, out logCreated, out msg);
+                }
+                else if (selItem is ImportArchiveItem)
                 {
                     // импорт архива
                     importOK = ImportExport.ImportArchive(txtFileName.Text, Tables.TableInfoList, 
@@ -165,22 +252,27 @@ private void btnImport_Click(object sender, EventArgs e)
                 else
                 {
                     // импорт таблицы
-                    int minID = gbIDs.Enabled && chkStartID.Checked ? Convert.ToInt32(numStartID.Value) : 1;
+                    Tables.TableInfo tableInfo = (Tables.TableInfo)selItem;
+                    int minID = gbIDs.Enabled && chkStartID.Checked ? Convert.ToInt32(numStartID.Value) : 0;
                     int maxID = gbIDs.Enabled && chkFinalID.Checked ? Convert.ToInt32(numFinalID.Value) : int.MaxValue;
                     int newMinID = gbIDs.Enabled && chkNewStartID.Checked ? Convert.ToInt32(numNewStartID.Value) : 0;
                     importOK = ImportExport.ImportTable(txtFileName.Text, tableInfo, minID, maxID, newMinID,
                         logFileName, out logCreated, out msg);
                 }
 
-                // отображение сообщения о результате импорта
+                // отображение сообщения о результате
                 if (importOK)
+                {
                     ScadaUiUtils.ShowInfo(msg);
+                }
                 else
+                {
                     AppUtils.ProcError(msg);
 
-                // отображение журанала в блокноте
-                if (logCreated)
-                    Process.Start(logFileName);
+                    // отображение журнала в блокноте
+                    if (logCreated)
+                        Process.Start(logFileName);
+                }
             }
         }
     }
diff --git a/ScadaAdmin/ScadaAdmin/FrmImport.resx b/ScadaAdmin/ScadaAdmin/FrmImport.resx
index 724c152b0..545dc9e09 100644
--- a/ScadaAdmin/ScadaAdmin/FrmImport.resx
+++ b/ScadaAdmin/ScadaAdmin/FrmImport.resx
@@ -136,4 +136,7 @@
   
     17, 17
   
+  
+    150, 17
+  
 
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.cs b/ScadaAdmin/ScadaAdmin/FrmMain.cs
index f5484d798..c25cbf1d7 100644
--- a/ScadaAdmin/ScadaAdmin/FrmMain.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmMain.cs
@@ -117,6 +117,7 @@ public FrmMain()
 
             allNodes = new List();
             preventDblClick = false;
+            settings = AppData.Settings;
             frmReplace = null;
         }
 
@@ -394,7 +395,7 @@ private bool Connect(bool expandTree)
                 // соединение с БД
                 if (connectNeeded)
                 {
-                    AppData.Connect(settings.AppSett.BaseSDFFile);
+                    AppData.Connect();
 
                     nodDB.ImageKey = nodDB.SelectedImageKey = "db.gif";
                     nodSystem.Expand();
@@ -619,7 +620,6 @@ private void FrmMain_Load(object sender, EventArgs e)
             SetItemsEnabledOnWindowAction();
 
             // загрузка состояния формы
-            settings = new Settings();
             settings.LoadFormState();
             if (settings.FormSt.IsEmpty)
             {
@@ -852,9 +852,11 @@ private void miDbImport_Click(object sender, EventArgs e)
             // создание и отоборажение формы импорта таблицы
             FrmImport frmImport = new FrmImport();
             FrmTable frmTable = winControl.ActiveForm as FrmTable;
+
             if (frmTable != null && frmTable.Table != null)
                 frmImport.DefaultTableName = frmTable.Table.TableName;
-            frmImport.DefaultDirectory = settings.AppSett.BaseDATDir;
+
+            frmImport.DefaultBaseDATDir = settings.AppSett.BaseDATDir;
             frmImport.ShowDialog();
         }
 
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index b4b76dce0..1154b3205 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -17,14 +17,14 @@
   
   
     Choose a configuration database table file
-    Choose a configuration database archive file
-    Configuration Database Tables|*.dat|All Files|*.*
-    Configuration Database Archive|*.zip|All Files|*.*
-    Import file is undefined.
+    Choose a configuration archive file
+    Configuration Database Tables (*.dat)|*.dat|All Files (*.*)|*.*
+    Configuration Archive (*.zip)|*.zip|All Files (*.*)|*.*
     Import file does not exist.
+    Import directory does not exist.
     Import Configuration Database
     Import Configuration Database Table "{0}"
-    Source file : 
+    Source file or directory : 
     Error loading imported table
     Columns of the Source Table
     Columns of the Destination Table
@@ -37,7 +37,9 @@
     Import Result
     Import Table Result
     Import Table Errors
-    Error import the configuration database table
+    Error import the configuration database table
+    Error import all tables of the configuration database
+    Error import the configuration database from archive
     Export file is undefined.
     Export directory is undefined.
     Export directory does not exist.
@@ -166,13 +168,14 @@
     Import from File
     Table
     File
+    Directory
     Identifiers
     Start
     Final
     New start
-    Write to import log
     Import
     Close
+    All tables
     Tables from archive
   
   
@@ -514,4 +517,22 @@
     Role
     Description
   
+  
+    Choose a configuration directory
+  
+  
+    Connection to server
+    Create
+    Edit
+    Remove
+  
+  
+    Download Configuration
+    Download options
+    Save to directory:
+    Save to archive:
+    Import the configuration database to SDF format after downloading
+    Download
+    Close
+  
 
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
index 01a631fda..0da413096 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
@@ -38,6 +38,7 @@ private void InitializeComponent()
             this.btnDownload = new System.Windows.Forms.Button();
             this.btnClose = new System.Windows.Forms.Button();
             this.gbOptions = new System.Windows.Forms.GroupBox();
+            this.chkImportBase = new System.Windows.Forms.CheckBox();
             this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
             this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
             this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
@@ -64,7 +65,7 @@ private void InitializeComponent()
             this.txtDestDir.Size = new System.Drawing.Size(417, 20);
             this.txtDestDir.TabIndex = 1;
             this.txtDestDir.Text = "C:\\SCADA\\";
-            this.txtDestDir.TextChanged += new System.EventHandler(this.txtDestDir_TextChanged);
+            this.txtDestDir.TextChanged += new System.EventHandler(this.downloadControl_Changed);
             // 
             // btnBrowseDestDir
             // 
@@ -106,11 +107,11 @@ private void InitializeComponent()
             this.txtDestFile.Name = "txtDestFile";
             this.txtDestFile.Size = new System.Drawing.Size(417, 20);
             this.txtDestFile.TabIndex = 4;
-            this.txtDestFile.TextChanged += new System.EventHandler(this.txtDestFile_TextChanged);
+            this.txtDestFile.TextChanged += new System.EventHandler(this.downloadControl_Changed);
             // 
             // btnDownload
             // 
-            this.btnDownload.Location = new System.Drawing.Point(325, 204);
+            this.btnDownload.Location = new System.Drawing.Point(325, 232);
             this.btnDownload.Name = "btnDownload";
             this.btnDownload.Size = new System.Drawing.Size(75, 23);
             this.btnDownload.TabIndex = 2;
@@ -121,7 +122,7 @@ private void InitializeComponent()
             // btnClose
             // 
             this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.btnClose.Location = new System.Drawing.Point(406, 204);
+            this.btnClose.Location = new System.Drawing.Point(406, 232);
             this.btnClose.Name = "btnClose";
             this.btnClose.Size = new System.Drawing.Size(75, 23);
             this.btnClose.TabIndex = 3;
@@ -130,6 +131,7 @@ private void InitializeComponent()
             // 
             // gbOptions
             // 
+            this.gbOptions.Controls.Add(this.chkImportBase);
             this.gbOptions.Controls.Add(this.rbSaveToDir);
             this.gbOptions.Controls.Add(this.txtDestDir);
             this.gbOptions.Controls.Add(this.btnBrowseDestDir);
@@ -139,21 +141,32 @@ private void InitializeComponent()
             this.gbOptions.Location = new System.Drawing.Point(12, 73);
             this.gbOptions.Name = "gbOptions";
             this.gbOptions.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
-            this.gbOptions.Size = new System.Drawing.Size(469, 125);
+            this.gbOptions.Size = new System.Drawing.Size(469, 153);
             this.gbOptions.TabIndex = 1;
             this.gbOptions.TabStop = false;
             this.gbOptions.Text = "Параметры скачивания";
             // 
+            // chkImportBase
+            // 
+            this.chkImportBase.AutoSize = true;
+            this.chkImportBase.Location = new System.Drawing.Point(13, 123);
+            this.chkImportBase.Name = "chkImportBase";
+            this.chkImportBase.Size = new System.Drawing.Size(339, 17);
+            this.chkImportBase.TabIndex = 6;
+            this.chkImportBase.Text = "Импорт базы конфигурации в формат SDF после скачивания";
+            this.chkImportBase.UseVisualStyleBackColor = true;
+            this.chkImportBase.CheckedChanged += new System.EventHandler(this.downloadControl_Changed);
+            // 
             // openFileDialog
             // 
             this.openFileDialog.CheckFileExists = false;
             this.openFileDialog.DefaultExt = "*.zip";
-            this.openFileDialog.Filter = "Архивы (*.zip)|*.zip|Все файлы (*.*)|*.*";
+            this.openFileDialog.Filter = "Архивы конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*";
             this.openFileDialog.Title = "Выберите файл архива для сохранения конфигурации";
             // 
             // folderBrowserDialog
             // 
-            this.folderBrowserDialog.Description = "Выберите директорию для сохранения конфигурации";
+            this.folderBrowserDialog.Description = "Выберите директорию конфигурации";
             // 
             // ctrlServerConn
             // 
@@ -169,7 +182,7 @@ private void InitializeComponent()
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.btnClose;
-            this.ClientSize = new System.Drawing.Size(493, 239);
+            this.ClientSize = new System.Drawing.Size(493, 267);
             this.Controls.Add(this.ctrlServerConn);
             this.Controls.Add(this.gbOptions);
             this.Controls.Add(this.btnClose);
@@ -201,5 +214,6 @@ private void InitializeComponent()
         private CtrlServerConn ctrlServerConn;
         private System.Windows.Forms.OpenFileDialog openFileDialog;
         private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
+        private System.Windows.Forms.CheckBox chkImportBase;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index 2a6724416..bf6ac767e 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -61,6 +61,9 @@ private void ShowDownloadSettings(ServersSettings.DownloadSettings downloadSetti
             if (downloadSettings == null)
             {
                 gbOptions.Enabled = false;
+                rbSaveToDir.Checked = true;
+                txtDestDir.Text = txtDestFile.Text = "";
+                chkImportBase.Checked = false;
                 btnDownload.Enabled = false;
             }
             else
@@ -87,6 +90,7 @@ private void ShowDownloadSettings(ServersSettings.DownloadSettings downloadSetti
 
                 txtDestDir.Text = downloadSettings.DestDir;
                 txtDestFile.Text = downloadSettings.DestFile;
+                chkImportBase.Checked = downloadSettings.ImportBase;
             }
         }
 
@@ -98,6 +102,7 @@ private void ApplyDownloadSettings(ServersSettings.DownloadSettings downloadSett
             downloadSettings.SaveToDir = rbSaveToDir.Checked;
             downloadSettings.DestDir = txtDestDir.Text;
             downloadSettings.DestFile = txtDestFile.Text;
+            downloadSettings.ImportBase = chkImportBase.Checked;
         }
 
         /// 
@@ -123,7 +128,25 @@ private void DownloadConfig(ServersSettings.ServerSettings serverSettings)
             if (downloadOK)
             {
                 ScadaUiUtils.ShowInfo(msg);
-                // TODO: запуск импорта, если это отмечено в настройках скачивания
+
+                // запуск импорта
+                ServersSettings.DownloadSettings downloadSettings = serverSettings.Download;
+                if (downloadSettings.ImportBase)
+                {
+                    FrmImport frmImport = new FrmImport();
+                    if (downloadSettings.SaveToDir)
+                    {
+                        frmImport.DefaultSelection = FrmImport.SelectedItem.AllTables;
+                        frmImport.DefaultBaseDATDir = Path.Combine(downloadSettings.DestDir, "BaseDAT");
+                    }
+                    else
+                    {
+                        frmImport.DefaultSelection = FrmImport.SelectedItem.Archive;
+                        frmImport.DefaultArcFileName = downloadSettings.DestFile;
+                        frmImport.DefaultBaseDATDir = AppData.Settings.AppSett.BaseDATDir;
+                    }
+                    frmImport.ShowDialog();
+                }
             }
             else
             {
@@ -138,6 +161,13 @@ private void DownloadConfig(ServersSettings.ServerSettings serverSettings)
 
         private void FrmDownloadConfig_Load(object sender, EventArgs e)
         {
+            // перевод формы
+            Translator.TranslateForm(this, "ScadaAdmin.Remote.CtrlServerConn");
+            Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmDownloadConfig");
+            openFileDialog.Title = AppPhrases.ChooseArchiveFile;
+            openFileDialog.Filter = AppPhrases.ArchiveFileFilter;
+            folderBrowserDialog.Description = AppPhrases.ChooseConfigDir;
+
             // загрузка настроек
             if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
             {
@@ -169,12 +199,7 @@ private void rbSaveToArc_CheckedChanged(object sender, EventArgs e)
             downloadSettingsModified = true;
         }
 
-        private void txtDestDir_TextChanged(object sender, EventArgs e)
-        {
-            downloadSettingsModified = true;
-        }
-
-        private void txtDestFile_TextChanged(object sender, EventArgs e)
+        private void downloadControl_Changed(object sender, EventArgs e)
         {
             downloadSettingsModified = true;
         }

From 0f79c477f19b8e3f1508f0abaf95798b9b1b8902 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Thu, 10 May 2018 20:34:25 +0300
Subject: [PATCH 062/100] ScadaAdmin: validate download settings

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   | 13 ++++++++++
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |  2 ++
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    | 24 ++++++++++++++++++-
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index 4aef9580c..18e806235 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -228,6 +228,10 @@ static AppPhrases()
         // Словарь ScadaAdmin.Remote
         public static string ChooseConfigDir { get; private set; }
 
+        // Словарь ScadaAdmin.FrmDownloadConfig
+        public static string DestDirRequired { get; private set; }
+        public static string DestFileRequired { get; private set; }
+
         private static void SetToDefault()
         {
             BaseSDFFileNotFound = "Файл базы конфигурации в формате SDF {0} не найден.";
@@ -405,6 +409,9 @@ private static void SetToDefault()
             GetCtrlCnlNumsError = "Ошибка при получении номеров каналов управления";
 
             ChooseConfigDir = "Выберите директорию конфигурации";
+
+            DestDirRequired = "Укажите директорию.";
+            DestFileRequired = "Укажите файл архива.";
         }
 
         public static void Init()
@@ -631,6 +638,12 @@ public static void Init()
             {
                 ChooseConfigDir = dict.GetPhrase("ChooseConfigDir", ChooseConfigDir);
             }
+
+            if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Remote.FrmDownloadConfig", out dict))
+            {
+                DestDirRequired = dict.GetPhrase("DestDirRequired", DestDirRequired);
+                DestFileRequired = dict.GetPhrase("DestFileRequired", DestFileRequired);
+            }
         }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index 1154b3205..5b696a649 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -534,5 +534,7 @@
     Import the configuration database to SDF format after downloading
     Download
     Close
+    Directory is required.
+    Archive file name is required.
   
 
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index bf6ac767e..265d2e2b1 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -94,6 +94,28 @@ private void ShowDownloadSettings(ServersSettings.DownloadSettings downloadSetti
             }
         }
 
+        /// 
+        /// Проверить настройки скачивания конфигурации
+        /// 
+        private bool ValidateDownloadSettings()
+        {
+            if (rbSaveToDir.Checked)
+            {
+                if (string.IsNullOrWhiteSpace(txtDestDir.Text))
+                {
+                    ScadaUiUtils.ShowError(AppPhrases.DestDirRequired);
+                    return false;
+                }
+            }
+            else if (string.IsNullOrWhiteSpace(txtDestFile.Text))
+            {
+                ScadaUiUtils.ShowError(AppPhrases.DestFileRequired);
+                return false;
+            }
+
+            return true;
+        }
+
         /// 
         /// Применить настройки скачивания конфигурации
         /// 
@@ -237,7 +259,7 @@ private void btnDownload_Click(object sender, EventArgs e)
             // проверка настроек и скачивание конфигурации
             ServersSettings.ServerSettings serverSettings = ctrlServerConn.SelectedSettings;
 
-            if (serverSettings != null)
+            if (serverSettings != null && ValidateDownloadSettings())
             {
                 if (downloadSettingsModified)
                 {

From 2163a4e2590df1da22e8ac2d930332c4635cb1fc Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 11 May 2018 12:02:00 +0300
Subject: [PATCH 063/100] ScadaAdmin: upload config

---
 .../ScadaAdmin/AppCode/DownloadUpload.cs      |  44 +++
 .../ScadaAdmin/AppCode/ServersSettings.cs     |   9 +-
 .../Remote/FrmUploadConfig.Designer.cs        | 152 +++++++++-
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      | 268 +++++++++++++++++-
 .../ScadaAdmin/Remote/FrmUploadConfig.resx    | 142 ++++++++++
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |   3 +
 6 files changed, 601 insertions(+), 17 deletions(-)
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index d6fddb07b..846468835 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -27,6 +27,7 @@
 using Scada;
 using ScadaAdmin.AgentSvcRef;
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.ServiceModel;
 using System.Text;
@@ -186,5 +187,48 @@ public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
                 catch { }
             }
         }
+
+        /// 
+        /// Передать конфигурацию
+        /// 
+        public static bool UploadConfig(ServersSettings.ConnectionSettings connectionSettings,
+            List fileNames, ConfigParts configParts, string logFileName, out bool logCreated, out string msg)
+        {
+            if (connectionSettings == null)
+                throw new ArgumentNullException("connectionSettings");
+            if (fileNames == null)
+                throw new ArgumentNullException("fileNames");
+            if (logFileName == null)
+                throw new ArgumentNullException("logFileName");
+
+            logCreated = false;
+            StreamWriter writer = null;
+            AgentSvcClient client = null;
+
+            try
+            {
+
+                // передача конфигурации
+                ConfigOptions configOptions = new ConfigOptions() { ConfigParts = configParts };
+                long sessionID = 0;
+                client.UploadConfig(configOptions, sessionID, null);
+
+            }
+            catch (Exception ex)
+            {
+
+            }
+            finally
+            {
+                try { writer?.Close(); }
+                catch { }
+
+                try { client?.Close(); }
+                catch { }
+            }
+
+            msg = "!!!";
+            return true;
+        }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
index d68259457..a43e11933 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
@@ -216,10 +216,6 @@ public UploadSettings()
             /// 
             public string SrcDir { get; set; }
             /// 
-            /// Получить или установить признак передачи всех файлов конфигурации
-            /// 
-            public bool AllFiles { get; set; }
-            /// 
             /// Получить выбранные для передачи файлы конфигурации
             /// 
             public List SelectedFiles { get; private set; }
@@ -230,7 +226,6 @@ public UploadSettings()
             private void SetToDefault()
             {
                 SrcDir = @"C:\SCADA\";
-                AllFiles = true;
                 SelectedFiles.Clear();
             }
             /// 
@@ -241,10 +236,9 @@ public void LoadFromXml(XmlNode xmlNode)
                 if (xmlNode == null)
                     throw new ArgumentNullException("xmlNode");
 
-                SelectedFiles.Clear();
                 SrcDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("SrcDir", @"C:\SCADA\"));
-                AllFiles = xmlNode.GetChildAsBool("AllFiles", true);
 
+                SelectedFiles.Clear();
                 XmlNode selectedFilesNode = xmlNode.SelectSingleNode("SelectedFiles");
                 if (selectedFilesNode != null)
                 {
@@ -264,7 +258,6 @@ public void SaveToXml(XmlElement xmlElem)
                     throw new ArgumentNullException("xmlElem");
 
                 xmlElem.AppendElem("SrcDir", SrcDir);
-                xmlElem.AppendElem("AllFiles", AllFiles);
 
                 XmlElement selectedFilesElem = xmlElem.AppendElem("SelectedFiles");
                 foreach (string path in SelectedFiles)
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
index 7f2652ce1..88d90b80c 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
@@ -28,12 +28,158 @@ protected override void Dispose(bool disposing)
         /// 
         private void InitializeComponent()
         {
-            this.components = new System.ComponentModel.Container();
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmUploadConfig));
+            System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("BaseDAT\\");
+            System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("C:\\SCADA\\", new System.Windows.Forms.TreeNode[] {
+            treeNode3});
+            this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
+            this.gbOptions = new System.Windows.Forms.GroupBox();
+            this.btnClose = new System.Windows.Forms.Button();
+            this.btnUpload = new System.Windows.Forms.Button();
+            this.lblSrcDir = new System.Windows.Forms.Label();
+            this.txtSrcDir = new System.Windows.Forms.TextBox();
+            this.btnBrowseSrcDir = new System.Windows.Forms.Button();
+            this.lblFiles = new System.Windows.Forms.Label();
+            this.tvFiles = new System.Windows.Forms.TreeView();
+            this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
+            this.gbOptions.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // ctrlServerConn
+            // 
+            this.ctrlServerConn.Location = new System.Drawing.Point(12, 12);
+            this.ctrlServerConn.Name = "ctrlServerConn";
+            this.ctrlServerConn.ServersSettings = null;
+            this.ctrlServerConn.Size = new System.Drawing.Size(469, 55);
+            this.ctrlServerConn.TabIndex = 0;
+            this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged);
+            // 
+            // gbOptions
+            // 
+            this.gbOptions.Controls.Add(this.tvFiles);
+            this.gbOptions.Controls.Add(this.lblFiles);
+            this.gbOptions.Controls.Add(this.txtSrcDir);
+            this.gbOptions.Controls.Add(this.btnBrowseSrcDir);
+            this.gbOptions.Controls.Add(this.lblSrcDir);
+            this.gbOptions.Location = new System.Drawing.Point(12, 73);
+            this.gbOptions.Name = "gbOptions";
+            this.gbOptions.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
+            this.gbOptions.Size = new System.Drawing.Size(469, 334);
+            this.gbOptions.TabIndex = 1;
+            this.gbOptions.TabStop = false;
+            this.gbOptions.Text = "Параметры передачи";
+            // 
+            // btnClose
+            // 
+            this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnClose.Location = new System.Drawing.Point(406, 413);
+            this.btnClose.Name = "btnClose";
+            this.btnClose.Size = new System.Drawing.Size(75, 23);
+            this.btnClose.TabIndex = 5;
+            this.btnClose.Text = "Закрыть";
+            this.btnClose.UseVisualStyleBackColor = true;
+            // 
+            // btnUpload
+            // 
+            this.btnUpload.Location = new System.Drawing.Point(325, 413);
+            this.btnUpload.Name = "btnUpload";
+            this.btnUpload.Size = new System.Drawing.Size(75, 23);
+            this.btnUpload.TabIndex = 4;
+            this.btnUpload.Text = "Передать";
+            this.btnUpload.UseVisualStyleBackColor = true;
+            this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
+            // 
+            // lblSrcDir
+            // 
+            this.lblSrcDir.AutoSize = true;
+            this.lblSrcDir.Location = new System.Drawing.Point(10, 16);
+            this.lblSrcDir.Name = "lblSrcDir";
+            this.lblSrcDir.Size = new System.Drawing.Size(144, 13);
+            this.lblSrcDir.TabIndex = 0;
+            this.lblSrcDir.Text = "Директория конфигурации";
+            // 
+            // txtSrcDir
+            // 
+            this.txtSrcDir.Location = new System.Drawing.Point(13, 32);
+            this.txtSrcDir.Name = "txtSrcDir";
+            this.txtSrcDir.ReadOnly = true;
+            this.txtSrcDir.Size = new System.Drawing.Size(417, 20);
+            this.txtSrcDir.TabIndex = 3;
+            this.txtSrcDir.Text = "C:\\SCADA\\";
+            // 
+            // btnBrowseSrcDir
+            // 
+            this.btnBrowseSrcDir.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
+            this.btnBrowseSrcDir.Image = ((System.Drawing.Image)(resources.GetObject("btnBrowseSrcDir.Image")));
+            this.btnBrowseSrcDir.Location = new System.Drawing.Point(436, 32);
+            this.btnBrowseSrcDir.Name = "btnBrowseSrcDir";
+            this.btnBrowseSrcDir.Size = new System.Drawing.Size(20, 20);
+            this.btnBrowseSrcDir.TabIndex = 4;
+            this.btnBrowseSrcDir.UseVisualStyleBackColor = true;
+            this.btnBrowseSrcDir.Click += new System.EventHandler(this.btnBrowseSrcDir_Click);
+            // 
+            // lblFiles
+            // 
+            this.lblFiles.AutoSize = true;
+            this.lblFiles.Location = new System.Drawing.Point(10, 55);
+            this.lblFiles.Name = "lblFiles";
+            this.lblFiles.Size = new System.Drawing.Size(115, 13);
+            this.lblFiles.TabIndex = 5;
+            this.lblFiles.Text = "Файлы для передачи";
+            // 
+            // tvFiles
+            // 
+            this.tvFiles.CheckBoxes = true;
+            this.tvFiles.Location = new System.Drawing.Point(13, 71);
+            this.tvFiles.Name = "tvFiles";
+            treeNode3.Name = "Node1";
+            treeNode3.Text = "BaseDAT\\";
+            treeNode4.Name = "Node0";
+            treeNode4.Text = "C:\\SCADA\\";
+            this.tvFiles.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
+            treeNode4});
+            this.tvFiles.Size = new System.Drawing.Size(443, 250);
+            this.tvFiles.TabIndex = 6;
+            // 
+            // folderBrowserDialog
+            // 
+            this.folderBrowserDialog.Description = "Выберите директорию конфигурации";
+            // 
+            // FrmUploadConfig
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(800, 450);
-            this.Text = "FrmUploadConfig";
+            this.CancelButton = this.btnClose;
+            this.ClientSize = new System.Drawing.Size(493, 448);
+            this.Controls.Add(this.btnClose);
+            this.Controls.Add(this.btnUpload);
+            this.Controls.Add(this.gbOptions);
+            this.Controls.Add(this.ctrlServerConn);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+            this.MaximizeBox = false;
+            this.MinimizeBox = false;
+            this.Name = "FrmUploadConfig";
+            this.ShowInTaskbar = false;
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+            this.Text = "Передача конфигурации";
+            this.Load += new System.EventHandler(this.FrmUploadConfig_Load);
+            this.gbOptions.ResumeLayout(false);
+            this.gbOptions.PerformLayout();
+            this.ResumeLayout(false);
+
         }
 
         #endregion
+
+        private CtrlServerConn ctrlServerConn;
+        private System.Windows.Forms.GroupBox gbOptions;
+        private System.Windows.Forms.Button btnClose;
+        private System.Windows.Forms.Button btnUpload;
+        private System.Windows.Forms.Label lblSrcDir;
+        private System.Windows.Forms.TextBox txtSrcDir;
+        private System.Windows.Forms.Button btnBrowseSrcDir;
+        private System.Windows.Forms.Label lblFiles;
+        private System.Windows.Forms.TreeView tvFiles;
+        private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
index c304a78cb..8cede4234 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -1,19 +1,275 @@
-using System;
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Upload configuration form
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada;
+using Scada.UI;
+using ScadaAdmin.AgentSvcRef;
+using System;
 using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
+using System.Diagnostics;
+using System.IO;
 using System.Windows.Forms;
 
 namespace ScadaAdmin.Remote
 {
+    /// 
+    /// Upload configuration form
+    /// Форма передачи конфигурации
+    /// 
     public partial class FrmUploadConfig : Form
     {
+        private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами
+        private bool uploadSettingsModified;     // последние выбранные настройки передачи были изменены
+
+
+        /// 
+        /// Конструктор
+        /// 
         public FrmUploadConfig()
         {
             InitializeComponent();
+            serversSettings = new ServersSettings();
+            uploadSettingsModified = false;
+        }
+
+
+        /// 
+        /// Отобразить настройки передачи конфигурации
+        /// 
+        private void ShowUploadSettings(ServersSettings.UploadSettings uploadSettings)
+        {
+            if (uploadSettings == null)
+            {
+                gbOptions.Enabled = false;
+                txtSrcDir.Text = "";
+                tvFiles.Nodes.Clear();
+                btnUpload.Enabled = false;
+            }
+            else
+            {
+                gbOptions.Enabled = true;
+                txtSrcDir.Text = uploadSettings.SrcDir;
+                FillTreeView(uploadSettings);
+                btnUpload.Enabled = true;
+            }
+        }
+
+        /// 
+        /// Заполнить дерево выбранных файлов
+        /// 
+        private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
+        {
+            try
+            {
+                tvFiles.BeginUpdate();
+                tvFiles.Nodes.Clear();
+
+                string srcDir = ScadaUtils.NormalDir(uploadSettings.SrcDir);
+                TreeNode rootNode = tvFiles.Nodes.Add(srcDir);
+
+                // добавление узла базы конфигурации
+                AddDirToTreeView(rootNode, srcDir + "BaseDAT\\");
+
+                // добавление узла интерфейса
+                AddDirToTreeView(rootNode, srcDir + "Interface\\");
+
+                // добавление узла Коммуникатора
+                string commDir = srcDir + "ScadaComm\\";
+                if (Directory.Exists(commDir))
+                {
+                    TreeNode commNode = rootNode.Nodes.Add("ScadaComm\\");
+                    AddDirToTreeView(commNode, commDir + "Config\\");
+                }
+
+                // добавление узла Сервера
+                string serverDir = srcDir + "ScadaServer\\";
+                if (Directory.Exists(serverDir))
+                {
+                    TreeNode serverNode = rootNode.Nodes.Add("ScadaServer\\");
+                    AddDirToTreeView(serverNode, serverDir + "Config\\");
+                }
+
+                // добавление узла Вебстанции
+                string webDir = srcDir + "ScadaWeb\\";
+                if (Directory.Exists(webDir))
+                {
+                    TreeNode serverNode = rootNode.Nodes.Add("ScadaWeb\\");
+                    AddDirToTreeView(serverNode, webDir + "config\\");
+                    AddDirToTreeView(serverNode, webDir + "storage\\");
+                }
+
+                rootNode.Expand();
+            }
+            finally
+            {
+                tvFiles.EndUpdate();
+            }
+        }
+        
+        /// 
+        /// Добавить директорию в дерево
+        /// 
+        private void AddDirToTreeView(TreeNode parentNode, string dir)
+        {
+            AddDirToTreeView(parentNode, new DirectoryInfo(dir));
+        }
+
+        /// 
+        /// Добавить директорию в дерево
+        /// 
+        private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo)
+        {
+            if (dirInfo.Exists)
+            {
+                TreeNode dirNode = parentNode.Nodes.Add(dirInfo.Name + "\\");
+
+                // добавление поддиректорий
+                DirectoryInfo[] subdirInfoArr = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
+
+                foreach (DirectoryInfo subdirInfo in subdirInfoArr)
+                {
+                    AddDirToTreeView(dirNode, subdirInfo);
+                }
+
+                // добавление файлов
+                FileInfo[] fileInfoArr = dirInfo.GetFiles("*", SearchOption.TopDirectoryOnly);
+
+                foreach (FileInfo fileInfo in fileInfoArr)
+                {
+                    if (fileInfo.Extension != ".bak")
+                        dirNode.Nodes.Add(fileInfo.Name);
+                }
+            }
+        }
+
+        /// 
+        /// Проверить настройки передачи конфигурации
+        /// 
+        private bool ValidateUploadSettings()
+        {
+            return true;
+        }
+
+        /// 
+        /// Применить настройки передачи конфигурации
+        /// 
+        private void ApplyUploadSettings(ServersSettings.UploadSettings uploadSettings)
+        {
+            uploadSettings.SrcDir = txtSrcDir.Text;
+        }
+
+        /// 
+        /// Сохранить настройки взаимодействия с удалёнными серверами
+        /// 
+        private void SaveServersSettings()
+        {
+            if (!serversSettings.Save(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
+                AppUtils.ProcError(errMsg);
+        }
+
+        /// 
+        /// Извлечь параметры передачи конфигурации
+        /// 
+        public void RetrieveUploadOptions(out List fileNames, out ConfigParts configParts)
+        {
+            fileNames = new List();
+            configParts = ConfigParts.All;
+        }
+
+        /// 
+        /// Передать конфигурацию
+        /// 
+        private void UploadConfig(ServersSettings.ConnectionSettings connectionSettings,
+            List fileNames, ConfigParts configParts)
+        {
+            // передача
+            string logFileName = AppData.AppDirs.LogDir + "ScadaAdminUpload.txt";
+            bool uploadOK = DownloadUpload.UploadConfig(connectionSettings,
+                fileNames, configParts, logFileName, out bool logCreated, out string msg);
+
+            // отображение сообщения о результате
+            if (uploadOK)
+            {
+                ScadaUiUtils.ShowInfo(msg);
+            }
+            else
+            {
+                AppUtils.ProcError(msg);
+
+                // отображение журнала в блокноте
+                if (logCreated)
+                    Process.Start(logFileName);
+            }
+        }
+
+
+        private void FrmUploadConfig_Load(object sender, EventArgs e)
+        {
+            // перевод формы
+            Translator.TranslateForm(this, "ScadaAdmin.Remote.CtrlServerConn");
+            Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmUploadConfig");
+            folderBrowserDialog.Description = AppPhrases.ChooseConfigDir;
+
+            // загрузка настроек
+            if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
+            {
+                AppData.ErrLog.WriteError(errMsg);
+                ScadaUiUtils.ShowError(errMsg);
+            }
+
+            // отображение настроек
+            ctrlServerConn.ServersSettings = serversSettings;
+        }
+
+        private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e)
+        {
+            ShowUploadSettings(ctrlServerConn.SelectedSettings?.Upload);
+            uploadSettingsModified = false;
+        }
+
+        private void btnBrowseSrcDir_Click(object sender, EventArgs e)
+        {
+
+        }
+
+        private void btnUpload_Click(object sender, EventArgs e)
+        {
+            // проверка настроек и передача конфигурации
+            ServersSettings.ServerSettings serverSettings = ctrlServerConn.SelectedSettings;
+
+            if (serverSettings != null && ValidateUploadSettings())
+            {
+                if (uploadSettingsModified)
+                {
+                    ApplyUploadSettings(serverSettings.Upload);
+                    SaveServersSettings();
+                }
+
+                RetrieveUploadOptions(out List fileNames, out ConfigParts configParts);
+                UploadConfig(serverSettings.Connection, fileNames, configParts);
+            }
         }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
new file mode 100644
index 000000000..0507ec929
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
@@ -0,0 +1,142 @@
+
+
+  
+  
+    
+    
+      
+        
+          
+            
+              
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+              
+            
+          
+          
+            
+              
+                
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+                
+              
+              
+            
+          
+        
+      
+    
+  
+  
+    text/microsoft-resx
+  
+  
+    2.0
+  
+  
+    System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+  
+    
+        R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R
+        fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N
+        VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc
+        iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d
+        gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i
+        Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq
+        LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB
+        AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF
+        FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS
+        BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28
+        tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs=
+
+  
+  
+    17, 17
+  
+  
+    52
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index 09e857150..0d1d8285b 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -275,6 +275,9 @@
     
       FrmDownloadConfig.cs
     
+    
+      FrmUploadConfig.cs
+    
     
     
     

From 8eb93aba91f3c316697adf4d9bf633f6c15b8834 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 11 May 2018 13:32:54 +0300
Subject: [PATCH 064/100] ScadaAdmin: dev

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  3 +
 .../ScadaAdmin/AppCode/DownloadUpload.cs      | 84 +++++++++++++------
 2 files changed, 62 insertions(+), 25 deletions(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index 18e806235..a7b86824a 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -52,6 +52,9 @@ static AppPhrases()
         public static string DownloadDataEmpty { get; private set; }
         public static string DownloadSuccessful { get; private set; }
         public static string DownloadError { get; private set; }
+        public static string UploadTitle { get; private set; }
+        public static string UploadSuccessful { get; private set; }
+        public static string UploadError { get; private set; }
 
         // Словарь ScadaAdmin.ImportExport
         public static string ChooseBaseTableFile { get; private set; }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index 846468835..fb0505561 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -66,6 +66,33 @@ private static EndpointAddress GetEpAddress(string host, int port)
                 string.Format("http://{0}:{1}/ScadaAgent/ScadaAgentSvc/", host, port));
         }
 
+        /// 
+        /// Соединиться с Агентом
+        /// 
+        private static void Connect(ServersSettings.ConnectionSettings connectionSettings, 
+            StreamWriter writer, out AgentSvcClient client, out long sessionID)
+        {
+            // настройка соединения
+            client = new AgentSvcClient();
+            client.Endpoint.Address = GetEpAddress(connectionSettings.Host, connectionSettings.Port);
+
+            // создание сессии
+            if (client.CreateSession(out sessionID))
+                writer.WriteLine(AppPhrases.SessionCreated, sessionID);
+            else
+                throw new ScadaException(AppPhrases.UnableCreateSession);
+
+            // вход в систему
+            string encryptedPassword = ScadaUtils.Encrypt(connectionSettings.Password,
+                connectionSettings.SecretKey, CreateIV(sessionID));
+
+            if (client.Login(out string errMsg, sessionID, connectionSettings.Username,
+                encryptedPassword, connectionSettings.ScadaInstance))
+                writer.WriteLine(AppPhrases.LoggedOn);
+            else
+                throw new ScadaException(string.Format(AppPhrases.UnableLogin, errMsg));
+        }
+
 
         /// 
         /// Скачать конфигурацию
@@ -85,35 +112,16 @@ public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
             try
             {
                 DateTime t0 = DateTime.UtcNow;
-                ServersSettings.ConnectionSettings connectionSettings = serverSettings.Connection;
-
                 writer = new StreamWriter(logFileName, false, Encoding.UTF8);
                 logCreated = true;
 
                 AppUtils.WriteTitle(writer,
                     string.Format(AppPhrases.DownloadTitle, DateTime.Now.ToString("G", Localization.Culture)));
-                writer.WriteLine(AppPhrases.ConnectionName, connectionSettings.Name);
+                writer.WriteLine(AppPhrases.ConnectionName, serverSettings.Connection.Name);
                 writer.WriteLine();
 
-                // настройка соединения
-                client = new AgentSvcClient();
-                client.Endpoint.Address = GetEpAddress(connectionSettings.Host, connectionSettings.Port);
-
-                // создание сессии
-                if (client.CreateSession(out long sessionID))
-                    writer.WriteLine(AppPhrases.SessionCreated, sessionID);
-                else
-                    throw new ScadaException(AppPhrases.UnableCreateSession);
-
-                // вход в систему
-                string encryptedPassword = ScadaUtils.Encrypt(connectionSettings.Password,
-                    connectionSettings.SecretKey, CreateIV(sessionID));
-
-                if (client.Login(out string errMsg, sessionID, connectionSettings.Username, 
-                    encryptedPassword, connectionSettings.ScadaInstance))
-                    writer.WriteLine(AppPhrases.LoggedOn);
-                else
-                    throw new ScadaException(string.Format(AppPhrases.UnableLogin, errMsg));
+                // соединение с Агентом
+                Connect(serverSettings.Connection, writer, out client, out long sessionID);
 
                 // скачивание конфигурации
                 Stream downloadStream = client.DownloadConfig(sessionID,
@@ -207,16 +215,42 @@ public static bool UploadConfig(ServersSettings.ConnectionSettings connectionSet
 
             try
             {
+                DateTime t0 = DateTime.UtcNow;
+
+                writer = new StreamWriter(logFileName, false, Encoding.UTF8);
+                logCreated = true;
+
+                AppUtils.WriteTitle(writer,
+                    string.Format(AppPhrases.UploadTitle, DateTime.Now.ToString("G", Localization.Culture)));
+                writer.WriteLine(AppPhrases.ConnectionName, connectionSettings.Name);
+                writer.WriteLine();
+
+                // соединение с Агентом
+                Connect(connectionSettings, writer, out client, out long sessionID);
+
+                // архивирование конфигурации
+                MemoryStream outStream = new MemoryStream(); // поток закрывается автоматически с помощью WCF
+
+                using (ZipFile zipFile = new ZipFile())
+                {
+                    zipFile.Save(outStream);
+                }
 
                 // передача конфигурации
-                ConfigOptions configOptions = new ConfigOptions() { ConfigParts = configParts };
-                long sessionID = 0;
-                client.UploadConfig(configOptions, sessionID, null);
+                client.UploadConfig(new ConfigOptions() { ConfigParts = configParts }, sessionID, outStream);
 
+                msg = string.Format(AppPhrases.UploadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds);
+                writer.WriteLine(msg);
+                return true;
             }
             catch (Exception ex)
             {
+                msg = AppPhrases.UploadError + ":\r\n" + ex.Message;
 
+                try { writer?.WriteLine(msg); }
+                catch { }
+
+                return false;
             }
             finally
             {

From 2b276ca8143c7b25a5aea33c1f2c1f96ee09fd46 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 11 May 2018 20:22:54 +0300
Subject: [PATCH 065/100] ScadaAgent: fixes

---
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs    |  2 +-
 ScadaAgent/ScadaAgentNet/AgentSvc.cs          |  2 +-
 ScadaAgent/ScadaAgentSvc/App.config           | 34 +++++++++++++++++--
 .../ProjectInstaller.Designer.cs              |  1 +
 .../ScadaAgentSvc/ProjectInstaller.resx       |  4 +--
 ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj |  2 +-
 6 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 0b03a5819..2a935b708 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -601,7 +601,7 @@ public bool PackConfig(string destFileName, ConfigOptions configOptions)
                 PathDict pathDict = SeparatePaths(configOptions.ExcludedPaths);
 
                 using (FileStream fileStream = 
-                    new FileStream(destFileName, FileMode.Create, FileAccess.Write, FileShare.None))
+                    new FileStream(destFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
                 {
                     using (ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create))
                     {
diff --git a/ScadaAgent/ScadaAgentNet/AgentSvc.cs b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
index a5b2e81cf..b174893b7 100644
--- a/ScadaAgent/ScadaAgentNet/AgentSvc.cs
+++ b/ScadaAgent/ScadaAgentNet/AgentSvc.cs
@@ -306,7 +306,7 @@ public Stream DownloadConfig(long sessionID, ConfigOptions configOptions)
                     string tempFileName = AppData.GetTempFileName("download-config", "zip");
                     if (scadaInstance.PackConfig(tempFileName, configOptions))
                     {
-                        return File.Open(tempFileName, FileMode.Open, FileAccess.Read, FileShare.None);
+                        return File.Open(tempFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                     }
                 }
             }
diff --git a/ScadaAgent/ScadaAgentSvc/App.config b/ScadaAgent/ScadaAgentSvc/App.config
index 731f6de6c..8f1107fe3 100644
--- a/ScadaAgent/ScadaAgentSvc/App.config
+++ b/ScadaAgent/ScadaAgentSvc/App.config
@@ -1,6 +1,34 @@
 
 
-     
-        
-    
+  
+    
+  
+  
+    
+      
+        
+      
+    
+    
+      
+        
+          
+          
+        
+      
+    
+    
+      
+        
+          
+            
+          
+        
+        
+        
+      
+    
+  
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs
index 39f126c32..f78eb79e8 100644
--- a/ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs
+++ b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.Designer.cs
@@ -33,6 +33,7 @@ private void InitializeComponent()
             // 
             // serviceProcessInstaller
             // 
+            this.serviceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
             this.serviceProcessInstaller.Password = null;
             this.serviceProcessInstaller.Username = null;
             // 
diff --git a/ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx
index 2c076de59..a16e6a92c 100644
--- a/ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx
+++ b/ScadaAgent/ScadaAgentSvc/ProjectInstaller.resx
@@ -118,10 +118,10 @@
     System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
   
   
-    17, 17
+    148, 17
   
   
-    196, 17
+    17, 17
   
   
     False
diff --git a/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
index 2bc1e6217..3a321fe38 100644
--- a/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
+++ b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
@@ -7,7 +7,7 @@
     {593318B1-3CB4-441B-B273-E3F37DF070B5}
     WinExe
     Scada.Agent.Svc
-    ScadaAgentService
+    ScadaAgentSvc
     v4.6.1
     512
     true

From 89f692730a75a655df743f0084040dca4bd93b21 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 11 May 2018 22:43:01 +0300
Subject: [PATCH 066/100] ScadaAdmin: minor changes

---
 ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index fb0505561..16dd4f58d 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -233,6 +233,7 @@ public static bool UploadConfig(ServersSettings.ConnectionSettings connectionSet
 
                 using (ZipFile zipFile = new ZipFile())
                 {
+                    //zipFile.AddFile
                     zipFile.Save(outStream);
                 }
 

From 7da39ffb7d4ee49446a493f63371d4f97b1fd4a7 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sat, 12 May 2018 12:12:42 +0300
Subject: [PATCH 067/100] ScadaAdmin: dev

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |   1 +
 .../ScadaAdmin/AppCode/DownloadUpload.cs      | 204 +++++++++++++++++-
 .../ScadaAdmin/AppCode/ServersSettings.cs     |  34 ++-
 .../AgentSvcRef/Reference.cs                  |  16 ++
 .../Connected Services/AgentSvcRef/item1.xsd  |   7 +
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      |   6 +-
 ScadaAgent/ScadaAgentCore/ConfigOptions.cs    |   2 +-
 7 files changed, 259 insertions(+), 11 deletions(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index a7b86824a..0feae67bc 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -53,6 +53,7 @@ static AppPhrases()
         public static string DownloadSuccessful { get; private set; }
         public static string DownloadError { get; private set; }
         public static string UploadTitle { get; private set; }
+        public static string NoConfigInSrc { get; private set; }
         public static string UploadSuccessful { get; private set; }
         public static string UploadError { get; private set; }
 
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index 16dd4f58d..28a7bbe75 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -40,6 +40,29 @@ namespace ScadaAdmin
     /// 
     internal static class DownloadUpload
     {
+        /// 
+        /// Исключаемые пути файлов, специфичные для экземпляра системы
+        /// 
+        private static readonly RelPath[] ExcludedPaths;
+
+
+        /// 
+        /// Статический конструктор
+        /// 
+        static DownloadUpload()
+        {
+            ExcludedPaths = new RelPath[]
+            {
+                new RelPath() { ConfigPart = ConfigParts.Communicator, AppFolder = AppFolder.Config, Path = "*_Reg.xml" },
+                new RelPath() { ConfigPart = ConfigParts.Communicator, AppFolder = AppFolder.Config, Path = "CompCode.txt" },
+                new RelPath() { ConfigPart = ConfigParts.Server, AppFolder = AppFolder.Config, Path = "*_Reg.xml" },
+                new RelPath() { ConfigPart = ConfigParts.Server, AppFolder = AppFolder.Config, Path = "CompCode.txt" },
+                new RelPath() { ConfigPart = ConfigParts.Webstation, AppFolder = AppFolder.Config, Path = "*_Reg.xml" },
+                new RelPath() { ConfigPart = ConfigParts.Webstation, AppFolder = AppFolder.Storage, Path = "" },
+            };
+        }
+
+
         /// 
         /// Создать вектор инициализации на освнове ид. сессии
         /// 
@@ -93,6 +116,74 @@ private static void Connect(ServersSettings.ConnectionSettings connectionSetting
                 throw new ScadaException(string.Format(AppPhrases.UnableLogin, errMsg));
         }
 
+        /// 
+        /// Упаковать конфигурацию во временный файл
+        /// 
+        private static void PackConfig(string srcDir, List selectedFiles,
+            out string outFileName, out ConfigParts configParts)
+        {
+            srcDir = ScadaUtils.NormalDir(srcDir);
+            outFileName = srcDir + "upload-config_" +
+                DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".zip";
+            configParts = ConfigParts.None;
+
+            using (ZipFile zipFile = new ZipFile(outFileName))
+            {
+                foreach (string relPath in selectedFiles)
+                {
+                    string path = srcDir + relPath;
+                    configParts = configParts | GetConfigPart(relPath);
+
+                    if (Directory.Exists(path)) // путь является директорией
+                    {
+
+                    }
+                    else if (File.Exists(path))
+                    {
+                        string dirInArc = Path.GetDirectoryName(relPath).Replace('\\', '/');
+                        zipFile.AddFile(path, dirInArc);
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Получить часть конфигурации, которая соответствует пути
+        /// 
+        private static ConfigParts GetConfigPart(string relPath)
+        {
+            if (relPath.StartsWith("BaseDAT", StringComparison.Ordinal))
+                return ConfigParts.Base;
+            else if (relPath.StartsWith("Interface", StringComparison.Ordinal))
+                return ConfigParts.Interface;
+            else if (relPath.StartsWith("ScadaComm", StringComparison.Ordinal))
+                return ConfigParts.Communicator;
+            else if (relPath.StartsWith("ScadaServer", StringComparison.Ordinal))
+                return ConfigParts.Server;
+            else if (relPath.StartsWith("ScadaWeb", StringComparison.Ordinal))
+                return ConfigParts.Webstation;
+            else
+                return ConfigParts.None;
+        }
+
+        /// 
+        /// Получить части конфигурации, которые содержатся в архиве
+        /// 
+        private static ConfigParts GetConfigParts(string arcFileName)
+        {
+            ConfigParts configParts = ConfigParts.None;
+
+            using (ZipFile zipFile = new ZipFile(arcFileName))
+            {
+                foreach (ZipEntry zipEntry in zipFile.Entries)
+                {
+                    configParts = configParts | GetConfigPart(zipEntry.FileName);
+                }
+            }
+
+            return configParts;
+        }
+
 
         /// 
         /// Скачать конфигурацию
@@ -196,14 +287,106 @@ public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
             }
         }
 
+        /// 
+        /// Передать конфигурацию
+        /// 
+        public static bool UploadConfig(ServersSettings.ServerSettings serverSettings,
+            string logFileName, out bool logCreated, out string msg)
+        {
+            if (serverSettings == null)
+                throw new ArgumentNullException("serverSettings");
+            if (logFileName == null)
+                throw new ArgumentNullException("logFileName");
+
+            logCreated = false;
+            StreamWriter writer = null;
+            AgentSvcClient client = null;
+
+            try
+            {
+                DateTime t0 = DateTime.UtcNow;
+
+                writer = new StreamWriter(logFileName, false, Encoding.UTF8);
+                logCreated = true;
+
+                AppUtils.WriteTitle(writer,
+                    string.Format(AppPhrases.UploadTitle, DateTime.Now.ToString("G", Localization.Culture)));
+                writer.WriteLine(AppPhrases.ConnectionName, serverSettings.Connection.Name);
+                writer.WriteLine();
+
+                // соединение с Агентом
+                Connect(serverSettings.Connection, writer, out client, out long sessionID);
+
+                // подготовка конфигурации для передачи
+                ServersSettings.UploadSettings uploadSettings = serverSettings.Upload;
+                ConfigOptions configOptions = new ConfigOptions();
+                string outFileName;
+                bool deleteOutFile;
+
+                if (uploadSettings.GetFromDir)
+                {
+                    PackConfig(uploadSettings.SrcDir, uploadSettings.SelectedFiles, 
+                        out outFileName, out ConfigParts configParts);
+                    configOptions.ConfigParts = configParts;
+                    deleteOutFile = true;
+                }
+                else
+                {
+                    outFileName = uploadSettings.SrcFile;
+                    configOptions.ConfigParts = GetConfigParts(outFileName);
+                    deleteOutFile = false;
+                }
+
+                if (configOptions.ConfigParts == ConfigParts.None)
+                    throw new ScadaException(AppPhrases.NoConfigInSrc);
+
+                if (!uploadSettings.ClearSpecificFiles)
+                    configOptions.ExcludedPaths = ExcludedPaths;
+
+                // передача конфигурации
+                using (Stream outStream = File.Open(outFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
+                {
+                    client.UploadConfig(configOptions, sessionID, outStream);
+                }
+
+                // удаление временного файла
+                if (deleteOutFile)
+                    File.Delete(outFileName);
+
+                msg = string.Format(AppPhrases.UploadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds);
+                writer.WriteLine(msg);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                msg = AppPhrases.UploadError + ":\r\n" + ex.Message;
+
+                try { writer?.WriteLine(msg); }
+                catch { }
+
+                return false;
+            }
+            finally
+            {
+                try { writer?.Close(); }
+                catch { }
+
+                try { client?.Close(); }
+                catch { }
+            }
+        }
+
         /// 
         /// Передать конфигурацию
         /// 
         public static bool UploadConfig(ServersSettings.ConnectionSettings connectionSettings,
-            List fileNames, ConfigParts configParts, string logFileName, out bool logCreated, out string msg)
+            string rootDir, List fileNames, ConfigParts configParts, string logFileName, 
+            out bool logCreated, out string msg)
         {
             if (connectionSettings == null)
                 throw new ArgumentNullException("connectionSettings");
+            if (rootDir == null)
+                throw new ArgumentNullException("rootDir");
             if (fileNames == null)
                 throw new ArgumentNullException("fileNames");
             if (logFileName == null)
@@ -233,7 +416,21 @@ public static bool UploadConfig(ServersSettings.ConnectionSettings connectionSet
 
                 using (ZipFile zipFile = new ZipFile())
                 {
-                    //zipFile.AddFile
+                    rootDir = ScadaUtils.NormalDir(rootDir);
+                    int rootDirLen = rootDir.Length;
+
+                    foreach (string fileName in fileNames)
+                    {
+                        if (!File.Exists(fileName))
+                            throw new FileNotFoundException(string.Format(CommonPhrases.NamedFileNotFound, fileName));
+
+                        //if (!fileName.StartsWith(rootDir, StringComparison.Ordinal))
+                        //    throw new ScadaException(AppPhrases.FileOutsideRoot);
+
+                        string pathInArc = fileName.Substring(rootDirLen).Replace('\\', '/');
+                        zipFile.AddFile(fileName, pathInArc);
+                    }
+
                     zipFile.Save(outStream);
                 }
 
@@ -261,9 +458,6 @@ public static bool UploadConfig(ServersSettings.ConnectionSettings connectionSet
                 try { client?.Close(); }
                 catch { }
             }
-
-            msg = "!!!";
-            return true;
         }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
index a43e11933..b4be304e7 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
@@ -154,6 +154,10 @@ public DownloadSettings()
             /// 
             public string DestFile { get; set; }
             /// 
+            /// Получить или установить признак скачивания файлов, специфичных для экземпляра системы
+            /// 
+            public bool IncludeSpecificFiles { get; set; }
+            /// 
             /// Получить или установить признак запуска импорта базы конфигурации после скачивания
             /// 
             public bool ImportBase { get; set; }
@@ -164,8 +168,9 @@ public DownloadSettings()
             private void SetToDefault()
             {
                 SaveToDir = true;
-                DestDir = @"C:\SCADA\";
+                DestDir = "";
                 DestFile = "";
+                IncludeSpecificFiles = true;
                 ImportBase = true;
             }
             /// 
@@ -179,6 +184,7 @@ public void LoadFromXml(XmlNode xmlNode)
                 SaveToDir = xmlNode.GetChildAsBool("SaveToDir", true);
                 DestDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("DestDir", @"C:\SCADA\"));
                 DestFile = xmlNode.GetChildAsString("DestFile", @"C:\SCADA\config.zip");
+                IncludeSpecificFiles = xmlNode.GetChildAsBool("IncludeSpecificFiles", true);
                 ImportBase = xmlNode.GetChildAsBool("ImportBase", true);
             }
             /// 
@@ -192,6 +198,7 @@ public void SaveToXml(XmlElement xmlElem)
                 xmlElem.AppendElem("SaveToDir", SaveToDir);
                 xmlElem.AppendElem("DestDir", DestDir);
                 xmlElem.AppendElem("DestFile", DestFile);
+                xmlElem.AppendElem("IncludeSpecificFiles", IncludeSpecificFiles);
                 xmlElem.AppendElem("ImportBase", ImportBase);
             }
         }
@@ -211,6 +218,10 @@ public UploadSettings()
                 SetToDefault();
             }
 
+            /// 
+            /// Получить или установить признак передачи из директории
+            /// 
+            public bool GetFromDir { get; set; }
             /// 
             /// Получить или установить директорию конфигурации
             /// 
@@ -219,14 +230,25 @@ public UploadSettings()
             /// Получить выбранные для передачи файлы конфигурации
             /// 
             public List SelectedFiles { get; private set; }
+            /// 
+            /// Получить или установить имя файла архива для передачи
+            /// 
+            public string SrcFile { get; set; }
+            /// 
+            /// Получить или установить признак очистки файлов, специфичных для экземпляра системы
+            /// 
+            public bool ClearSpecificFiles { get; set; }
 
             /// 
             /// Установить настройки по умолчанию
             /// 
             private void SetToDefault()
             {
-                SrcDir = @"C:\SCADA\";
+                GetFromDir = true;
+                SrcDir = "";
                 SelectedFiles.Clear();
+                SrcFile = "";
+                ClearSpecificFiles = true;
             }
             /// 
             /// Загрузить настройки из XML-узла
@@ -236,6 +258,7 @@ public void LoadFromXml(XmlNode xmlNode)
                 if (xmlNode == null)
                     throw new ArgumentNullException("xmlNode");
 
+                GetFromDir = xmlNode.GetChildAsBool("GetFromDir", true);
                 SrcDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("SrcDir", @"C:\SCADA\"));
 
                 SelectedFiles.Clear();
@@ -248,6 +271,9 @@ public void LoadFromXml(XmlNode xmlNode)
                         SelectedFiles.Add(pathNode.InnerText);
                     }
                 }
+
+                SrcFile = xmlNode.GetChildAsString("SrcFile", @"C:\SCADA\config.zip");
+                ClearSpecificFiles = xmlNode.GetChildAsBool("ClearSpecificFiles", true);
             }
             /// 
             /// Сохранить настройки в XML-узле
@@ -257,6 +283,7 @@ public void SaveToXml(XmlElement xmlElem)
                 if (xmlElem == null)
                     throw new ArgumentNullException("xmlElem");
 
+                xmlElem.AppendElem("GetFromDir", GetFromDir);
                 xmlElem.AppendElem("SrcDir", SrcDir);
 
                 XmlElement selectedFilesElem = xmlElem.AppendElem("SelectedFiles");
@@ -264,6 +291,9 @@ public void SaveToXml(XmlElement xmlElem)
                 {
                     selectedFilesElem.AppendElem("Path", path);
                 }
+
+                xmlElem.AppendElem("SrcFile", SrcFile);
+                xmlElem.AppendElem("ClearSpecificFiles", ClearSpecificFiles);
             }
         }
 
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs
index 0697a0e48..269e3df39 100644
--- a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs	
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs	
@@ -94,6 +94,9 @@ public partial class ConfigOptions : object, System.Runtime.Serialization.IExten
         [System.Runtime.Serialization.OptionalFieldAttribute()]
         private ScadaAdmin.AgentSvcRef.ConfigParts ConfigPartsField;
         
+        [System.Runtime.Serialization.OptionalFieldAttribute()]
+        private ScadaAdmin.AgentSvcRef.RelPath[] ExcludedPathsField;
+        
         [global::System.ComponentModel.BrowsableAttribute(false)]
         public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
             get {
@@ -117,6 +120,19 @@ public ScadaAdmin.AgentSvcRef.ConfigParts ConfigParts {
             }
         }
         
+        [System.Runtime.Serialization.DataMemberAttribute()]
+        public ScadaAdmin.AgentSvcRef.RelPath[] ExcludedPaths {
+            get {
+                return this.ExcludedPathsField;
+            }
+            set {
+                if ((object.ReferenceEquals(this.ExcludedPathsField, value) != true)) {
+                    this.ExcludedPathsField = value;
+                    this.RaisePropertyChanged("ExcludedPaths");
+                }
+            }
+        }
+        
         public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
         
         protected void RaisePropertyChanged(string propertyName) {
diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd
index 76a301227..e13908491 100644
--- a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd	
+++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd	
@@ -86,9 +86,16 @@
   
     
       
+      
     
   
   
+  
+    
+      
+    
+  
+  
   
     
       
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
index 8cede4234..ca7ae3e81 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -202,12 +202,12 @@ public void RetrieveUploadOptions(out List fileNames, out ConfigParts co
         /// Передать конфигурацию
         /// 
         private void UploadConfig(ServersSettings.ConnectionSettings connectionSettings,
-            List fileNames, ConfigParts configParts)
+            string rootDir, List fileNames, ConfigParts configParts)
         {
             // передача
             string logFileName = AppData.AppDirs.LogDir + "ScadaAdminUpload.txt";
             bool uploadOK = DownloadUpload.UploadConfig(connectionSettings,
-                fileNames, configParts, logFileName, out bool logCreated, out string msg);
+                rootDir, fileNames, configParts, logFileName, out bool logCreated, out string msg);
 
             // отображение сообщения о результате
             if (uploadOK)
@@ -268,7 +268,7 @@ private void btnUpload_Click(object sender, EventArgs e)
                 }
 
                 RetrieveUploadOptions(out List fileNames, out ConfigParts configParts);
-                UploadConfig(serverSettings.Connection, fileNames, configParts);
+                UploadConfig(serverSettings.Connection, serverSettings.Upload.SrcDir, fileNames, configParts);
             }
         }
     }
diff --git a/ScadaAgent/ScadaAgentCore/ConfigOptions.cs b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs
index 3333c8b47..2dfea8fbe 100644
--- a/ScadaAgent/ScadaAgentCore/ConfigOptions.cs
+++ b/ScadaAgent/ScadaAgentCore/ConfigOptions.cs
@@ -51,6 +51,6 @@ public ConfigOptions()
         /// 
         /// Получить или установить исключаемые пути
         /// 
-        public ICollection ExcludedPaths { get; private set; }
+        public ICollection ExcludedPaths { get; set; }
     }
 }

From d4059ed45a0fb38c38d09a1ab6c52741fb6237e8 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sat, 12 May 2018 19:13:46 +0300
Subject: [PATCH 068/100] ScadaAdmin & ScadaAgent

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  23 ++
 .../ScadaAdmin/AppCode/DownloadUpload.cs      | 126 ++++-------
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |  10 +
 .../Remote/FrmDownloadConfig.Designer.cs      |  35 +--
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |  43 ++--
 .../ScadaAdmin/Remote/FrmDownloadConfig.resx  |   4 +-
 .../Remote/FrmUploadConfig.Designer.cs        | 204 ++++++++++++------
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      |  85 +++++++-
 .../ScadaAdmin/Remote/FrmUploadConfig.resx    |  18 ++
 ScadaAgent/ScadaAgentCore/RelPath.cs          |  11 +
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs    |  49 +++--
 11 files changed, 386 insertions(+), 222 deletions(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index 0feae67bc..36c8dbc45 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -54,6 +54,11 @@ static AppPhrases()
         public static string DownloadError { get; private set; }
         public static string UploadTitle { get; private set; }
         public static string NoConfigInSrc { get; private set; }
+        public static string ConfigUploaded { get; private set; }
+        public static string ServerRestarted { get; private set; }
+        public static string UnableRestartServer { get; private set; }
+        public static string CommRestarted { get; private set; }
+        public static string UnableRestartComm { get; private set; }
         public static string UploadSuccessful { get; private set; }
         public static string UploadError { get; private set; }
 
@@ -250,6 +255,15 @@ private static void SetToDefault()
             DownloadDataEmpty = "Отсутствуют данные для скачивания";
             DownloadSuccessful = "Скачивание завершено успешно за {0} с.";
             DownloadError = "Ошибка при скачивании конфигурации";
+            UploadTitle = "{0} Передача конфигурации";
+            NoConfigInSrc = "Конфигурация отсутствует в заданном источнике.";
+            ConfigUploaded = "Конфигурация передана";
+            ServerRestarted = "Служба Сервера перезапущена";
+            UnableRestartServer = "Не удалось перезапустить службу Сервера";
+            CommRestarted = "Служба Коммуникатора перезапущена";
+            UnableRestartComm = "Не удалось перезапустить службу Коммуникатора";
+            UploadSuccessful = "Передача завершена успешно за {0} с.";
+            UploadError = "Ошибка при передаче конфигурации";
 
             ChooseBaseTableFile = "Выберите файл таблицы базы конфигурации";
             ChooseArchiveFile = "Выберите файл архива конфигурации";
@@ -438,6 +452,15 @@ public static void Init()
                 DownloadDataEmpty = dict.GetPhrase("DownloadDataEmpty", DownloadDataEmpty);
                 DownloadSuccessful = dict.GetPhrase("DownloadSuccessful", DownloadSuccessful);
                 DownloadError = dict.GetPhrase("DownloadError", DownloadError);
+                UploadTitle = dict.GetPhrase("UploadTitle", UploadTitle);
+                NoConfigInSrc = dict.GetPhrase("NoConfigInSrc", NoConfigInSrc);
+                ConfigUploaded = dict.GetPhrase("ConfigUploaded", ConfigUploaded);
+                ServerRestarted = dict.GetPhrase("ServerRestarted", ServerRestarted);
+                UnableRestartServer = dict.GetPhrase("UnableRestartServer", UnableRestartServer);
+                CommRestarted = dict.GetPhrase("CommRestarted", CommRestarted);
+                UnableRestartComm = dict.GetPhrase("UnableRestartComm", UnableRestartComm);
+                UploadSuccessful = dict.GetPhrase("UploadSuccessful", UploadSuccessful);
+                UploadError = dict.GetPhrase("UploadError", UploadError);
             }
 
             if (Localization.Dictionaries.TryGetValue("ScadaAdmin.ImportExport", out dict))
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index 28a7bbe75..6517113f2 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -123,6 +123,7 @@ private static void PackConfig(string srcDir, List selectedFiles,
             out string outFileName, out ConfigParts configParts)
         {
             srcDir = ScadaUtils.NormalDir(srcDir);
+            int srcDirLen = srcDir.Length;
             outFileName = srcDir + "upload-config_" +
                 DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".zip";
             configParts = ConfigParts.None;
@@ -136,7 +137,16 @@ private static void PackConfig(string srcDir, List selectedFiles,
 
                     if (Directory.Exists(path)) // путь является директорией
                     {
-
+                        string[] filesInDir = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
+                        foreach (string fileName in filesInDir)
+                        {
+                            if (Path.GetExtension(fileName) != ".bak")
+                            {
+                                string dirInArc = Path.GetDirectoryName(fileName.Substring(srcDirLen))
+                                    .Replace('\\', '/');
+                                zipFile.AddFile(path, dirInArc);
+                            }
+                        }
                     }
                     else if (File.Exists(path))
                     {
@@ -215,16 +225,21 @@ public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
                 Connect(serverSettings.Connection, writer, out client, out long sessionID);
 
                 // скачивание конфигурации
-                Stream downloadStream = client.DownloadConfig(sessionID,
-                    new ConfigOptions() { ConfigParts = ConfigParts.All });
+                ServersSettings.DownloadSettings downloadSettings = serverSettings.Download;
+                ConfigOptions configOptions = new ConfigOptions() { ConfigParts = ConfigParts.All };
+
+                if (!downloadSettings.IncludeSpecificFiles)
+                    configOptions.ExcludedPaths = ExcludedPaths;
+
+                Stream downloadStream = client.DownloadConfig(sessionID, configOptions);
 
                 if (downloadStream == null)
                     throw new ScadaException(AppPhrases.DownloadDataEmpty);
 
-                if (serverSettings.Download.SaveToDir)
+                if (downloadSettings.SaveToDir)
                 {
                     // сохранение в директорию
-                    string destDir = serverSettings.Download.DestDir;
+                    string destDir = downloadSettings.DestDir;
                     Directory.CreateDirectory(destDir);
                     string tempFileName = destDir + "download-config_" + 
                         DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".zip";
@@ -255,7 +270,7 @@ public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
                 else
                 {
                     // сохранение в файл
-                    string destFile = serverSettings.Download.DestFile;
+                    string destFile = downloadSettings.DestFile;
                     Directory.CreateDirectory(Path.GetDirectoryName(destFile));
 
                     using (FileStream destStream = File.Create(destFile))
@@ -320,20 +335,21 @@ public static bool UploadConfig(ServersSettings.ServerSettings serverSettings,
                 // подготовка конфигурации для передачи
                 ServersSettings.UploadSettings uploadSettings = serverSettings.Upload;
                 ConfigOptions configOptions = new ConfigOptions();
+                ConfigParts configParts;
                 string outFileName;
                 bool deleteOutFile;
 
                 if (uploadSettings.GetFromDir)
                 {
                     PackConfig(uploadSettings.SrcDir, uploadSettings.SelectedFiles, 
-                        out outFileName, out ConfigParts configParts);
+                        out outFileName, out configParts);
                     configOptions.ConfigParts = configParts;
                     deleteOutFile = true;
                 }
                 else
                 {
                     outFileName = uploadSettings.SrcFile;
-                    configOptions.ConfigParts = GetConfigParts(outFileName);
+                    configOptions.ConfigParts = configParts = GetConfigParts(outFileName);
                     deleteOutFile = false;
                 }
 
@@ -347,95 +363,29 @@ public static bool UploadConfig(ServersSettings.ServerSettings serverSettings,
                 using (Stream outStream = File.Open(outFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                 {
                     client.UploadConfig(configOptions, sessionID, outStream);
+                    writer.WriteLine(AppPhrases.ConfigUploaded);
                 }
 
                 // удаление временного файла
                 if (deleteOutFile)
                     File.Delete(outFileName);
 
-                msg = string.Format(AppPhrases.UploadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds);
-                writer.WriteLine(msg);
-                return true;
-            }
-            catch (Exception ex)
-            {
-                msg = AppPhrases.UploadError + ":\r\n" + ex.Message;
-
-                try { writer?.WriteLine(msg); }
-                catch { }
-
-                return false;
-            }
-            finally
-            {
-                try { writer?.Close(); }
-                catch { }
-
-                try { client?.Close(); }
-                catch { }
-            }
-        }
-
-        /// 
-        /// Передать конфигурацию
-        /// 
-        public static bool UploadConfig(ServersSettings.ConnectionSettings connectionSettings,
-            string rootDir, List fileNames, ConfigParts configParts, string logFileName, 
-            out bool logCreated, out string msg)
-        {
-            if (connectionSettings == null)
-                throw new ArgumentNullException("connectionSettings");
-            if (rootDir == null)
-                throw new ArgumentNullException("rootDir");
-            if (fileNames == null)
-                throw new ArgumentNullException("fileNames");
-            if (logFileName == null)
-                throw new ArgumentNullException("logFileName");
-
-            logCreated = false;
-            StreamWriter writer = null;
-            AgentSvcClient client = null;
-
-            try
-            {
-                DateTime t0 = DateTime.UtcNow;
-
-                writer = new StreamWriter(logFileName, false, Encoding.UTF8);
-                logCreated = true;
-
-                AppUtils.WriteTitle(writer,
-                    string.Format(AppPhrases.UploadTitle, DateTime.Now.ToString("G", Localization.Culture)));
-                writer.WriteLine(AppPhrases.ConnectionName, connectionSettings.Name);
-                writer.WriteLine();
-
-                // соединение с Агентом
-                Connect(connectionSettings, writer, out client, out long sessionID);
-
-                // архивирование конфигурации
-                MemoryStream outStream = new MemoryStream(); // поток закрывается автоматически с помощью WCF
-
-                using (ZipFile zipFile = new ZipFile())
+                // перезапуск служб на удалённом сервере
+                if (configParts.HasFlag(ConfigParts.Base) || configParts.HasFlag(ConfigParts.Server))
                 {
-                    rootDir = ScadaUtils.NormalDir(rootDir);
-                    int rootDirLen = rootDir.Length;
-
-                    foreach (string fileName in fileNames)
-                    {
-                        if (!File.Exists(fileName))
-                            throw new FileNotFoundException(string.Format(CommonPhrases.NamedFileNotFound, fileName));
-
-                        //if (!fileName.StartsWith(rootDir, StringComparison.Ordinal))
-                        //    throw new ScadaException(AppPhrases.FileOutsideRoot);
-
-                        string pathInArc = fileName.Substring(rootDirLen).Replace('\\', '/');
-                        zipFile.AddFile(fileName, pathInArc);
-                    }
-
-                    zipFile.Save(outStream);
+                    if (client.ControlService(sessionID, ServiceApp.Server, ServiceCommand.Restart))
+                        writer.WriteLine(AppPhrases.ServerRestarted);
+                    else
+                        writer.WriteLine(AppPhrases.UnableRestartServer);
                 }
 
-                // передача конфигурации
-                client.UploadConfig(new ConfigOptions() { ConfigParts = configParts }, sessionID, outStream);
+                if (configParts.HasFlag(ConfigParts.Base) || configParts.HasFlag(ConfigParts.Communicator))
+                {
+                    if (client.ControlService(sessionID, ServiceApp.Communicator, ServiceCommand.Restart))
+                        writer.WriteLine(AppPhrases.CommRestarted);
+                    else
+                        writer.WriteLine(AppPhrases.UnableRestartComm);
+                }
 
                 msg = string.Format(AppPhrases.UploadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds);
                 writer.WriteLine(msg);
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index 5b696a649..a59f151b8 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -14,6 +14,15 @@
     No data to download
     Download completed successfully in {0} sec.
     Error downloading configuration
+    {0} Upload Configuration
+    Configuration is missing in the specified source.
+    Configuration uploaded
+    The Server service restarted
+    Unable to restart the Server service
+    The Communicator service restarted
+    Unable to restart the Communicator service
+    Upload completed successfully in {0} sec.
+    Error uploading configuration
   
   
     Choose a configuration database table file
@@ -531,6 +540,7 @@
     Download options
     Save to directory:
     Save to archive:
+    Including server specific files such as registration keys
     Import the configuration database to SDF format after downloading
     Download
     Close
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
index 0da413096..bfcfc40a2 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs
@@ -38,6 +38,7 @@ private void InitializeComponent()
             this.btnDownload = new System.Windows.Forms.Button();
             this.btnClose = new System.Windows.Forms.Button();
             this.gbOptions = new System.Windows.Forms.GroupBox();
+            this.chkIncludeSpecificFiles = new System.Windows.Forms.CheckBox();
             this.chkImportBase = new System.Windows.Forms.CheckBox();
             this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
             this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
@@ -48,15 +49,13 @@ private void InitializeComponent()
             // rbSaveToDir
             // 
             this.rbSaveToDir.AutoSize = true;
-            this.rbSaveToDir.Checked = true;
             this.rbSaveToDir.Location = new System.Drawing.Point(13, 19);
             this.rbSaveToDir.Name = "rbSaveToDir";
             this.rbSaveToDir.Size = new System.Drawing.Size(154, 17);
             this.rbSaveToDir.TabIndex = 0;
-            this.rbSaveToDir.TabStop = true;
             this.rbSaveToDir.Text = "Сохранить в директорию:";
             this.rbSaveToDir.UseVisualStyleBackColor = true;
-            this.rbSaveToDir.CheckedChanged += new System.EventHandler(this.rbSaveToDir_CheckedChanged);
+            this.rbSaveToDir.CheckedChanged += new System.EventHandler(this.rbSave_CheckedChanged);
             // 
             // txtDestDir
             // 
@@ -85,10 +84,9 @@ private void InitializeComponent()
             this.rbSaveToArc.Name = "rbSaveToArc";
             this.rbSaveToArc.Size = new System.Drawing.Size(122, 17);
             this.rbSaveToArc.TabIndex = 3;
-            this.rbSaveToArc.TabStop = true;
             this.rbSaveToArc.Text = "Сохранить в архив:";
             this.rbSaveToArc.UseVisualStyleBackColor = true;
-            this.rbSaveToArc.CheckedChanged += new System.EventHandler(this.rbSaveToArc_CheckedChanged);
+            this.rbSaveToArc.CheckedChanged += new System.EventHandler(this.rbSave_CheckedChanged);
             // 
             // btnSelectDestFile
             // 
@@ -111,7 +109,7 @@ private void InitializeComponent()
             // 
             // btnDownload
             // 
-            this.btnDownload.Location = new System.Drawing.Point(325, 232);
+            this.btnDownload.Location = new System.Drawing.Point(325, 255);
             this.btnDownload.Name = "btnDownload";
             this.btnDownload.Size = new System.Drawing.Size(75, 23);
             this.btnDownload.TabIndex = 2;
@@ -122,7 +120,7 @@ private void InitializeComponent()
             // btnClose
             // 
             this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.btnClose.Location = new System.Drawing.Point(406, 232);
+            this.btnClose.Location = new System.Drawing.Point(406, 255);
             this.btnClose.Name = "btnClose";
             this.btnClose.Size = new System.Drawing.Size(75, 23);
             this.btnClose.TabIndex = 3;
@@ -131,6 +129,7 @@ private void InitializeComponent()
             // 
             // gbOptions
             // 
+            this.gbOptions.Controls.Add(this.chkIncludeSpecificFiles);
             this.gbOptions.Controls.Add(this.chkImportBase);
             this.gbOptions.Controls.Add(this.rbSaveToDir);
             this.gbOptions.Controls.Add(this.txtDestDir);
@@ -141,18 +140,29 @@ private void InitializeComponent()
             this.gbOptions.Location = new System.Drawing.Point(12, 73);
             this.gbOptions.Name = "gbOptions";
             this.gbOptions.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
-            this.gbOptions.Size = new System.Drawing.Size(469, 153);
+            this.gbOptions.Size = new System.Drawing.Size(469, 176);
             this.gbOptions.TabIndex = 1;
             this.gbOptions.TabStop = false;
             this.gbOptions.Text = "Параметры скачивания";
             // 
+            // chkIncludeSpecificFiles
+            // 
+            this.chkIncludeSpecificFiles.AutoSize = true;
+            this.chkIncludeSpecificFiles.Location = new System.Drawing.Point(13, 123);
+            this.chkIncludeSpecificFiles.Name = "chkIncludeSpecificFiles";
+            this.chkIncludeSpecificFiles.Size = new System.Drawing.Size(441, 17);
+            this.chkIncludeSpecificFiles.TabIndex = 6;
+            this.chkIncludeSpecificFiles.Text = "Включая файлы специфичные для сервера, в том числе, регистрационные ключи";
+            this.chkIncludeSpecificFiles.UseVisualStyleBackColor = true;
+            this.chkIncludeSpecificFiles.CheckedChanged += new System.EventHandler(this.downloadControl_Changed);
+            // 
             // chkImportBase
             // 
             this.chkImportBase.AutoSize = true;
-            this.chkImportBase.Location = new System.Drawing.Point(13, 123);
+            this.chkImportBase.Location = new System.Drawing.Point(13, 146);
             this.chkImportBase.Name = "chkImportBase";
             this.chkImportBase.Size = new System.Drawing.Size(339, 17);
-            this.chkImportBase.TabIndex = 6;
+            this.chkImportBase.TabIndex = 7;
             this.chkImportBase.Text = "Импорт базы конфигурации в формат SDF после скачивания";
             this.chkImportBase.UseVisualStyleBackColor = true;
             this.chkImportBase.CheckedChanged += new System.EventHandler(this.downloadControl_Changed);
@@ -162,7 +172,7 @@ private void InitializeComponent()
             this.openFileDialog.CheckFileExists = false;
             this.openFileDialog.DefaultExt = "*.zip";
             this.openFileDialog.Filter = "Архивы конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*";
-            this.openFileDialog.Title = "Выберите файл архива для сохранения конфигурации";
+            this.openFileDialog.Title = "Выберите файл архива конфигурации";
             // 
             // folderBrowserDialog
             // 
@@ -182,7 +192,7 @@ private void InitializeComponent()
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.btnClose;
-            this.ClientSize = new System.Drawing.Size(493, 267);
+            this.ClientSize = new System.Drawing.Size(493, 290);
             this.Controls.Add(this.ctrlServerConn);
             this.Controls.Add(this.gbOptions);
             this.Controls.Add(this.btnClose);
@@ -215,5 +225,6 @@ private void InitializeComponent()
         private System.Windows.Forms.OpenFileDialog openFileDialog;
         private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
         private System.Windows.Forms.CheckBox chkImportBase;
+        private System.Windows.Forms.CheckBox chkIncludeSpecificFiles;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index 265d2e2b1..5baaf41c1 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -63,34 +63,23 @@ private void ShowDownloadSettings(ServersSettings.DownloadSettings downloadSetti
                 gbOptions.Enabled = false;
                 rbSaveToDir.Checked = true;
                 txtDestDir.Text = txtDestFile.Text = "";
+                chkIncludeSpecificFiles.Checked = false;
                 chkImportBase.Checked = false;
                 btnDownload.Enabled = false;
             }
             else
             {
                 gbOptions.Enabled = true;
+                txtDestDir.Text = downloadSettings.DestDir;
+                txtDestFile.Text = downloadSettings.DestFile;
+                chkIncludeSpecificFiles.Checked = downloadSettings.IncludeSpecificFiles;
+                chkImportBase.Checked = downloadSettings.ImportBase;
                 btnDownload.Enabled = true;
 
                 if (downloadSettings.SaveToDir)
-                {
                     rbSaveToDir.Checked = true;
-                    txtDestDir.Enabled = true;
-                    btnBrowseDestDir.Enabled = true;
-                    txtDestFile.Enabled = false;
-                    btnSelectDestFile.Enabled = false;
-                }
                 else
-                {
                     rbSaveToArc.Checked = true;
-                    txtDestDir.Enabled = false;
-                    btnBrowseDestDir.Enabled = false;
-                    txtDestFile.Enabled = true;
-                    btnSelectDestFile.Enabled = true;
-                }
-
-                txtDestDir.Text = downloadSettings.DestDir;
-                txtDestFile.Text = downloadSettings.DestFile;
-                chkImportBase.Checked = downloadSettings.ImportBase;
             }
         }
 
@@ -124,6 +113,7 @@ private void ApplyDownloadSettings(ServersSettings.DownloadSettings downloadSett
             downloadSettings.SaveToDir = rbSaveToDir.Checked;
             downloadSettings.DestDir = txtDestDir.Text;
             downloadSettings.DestFile = txtDestFile.Text;
+            downloadSettings.IncludeSpecificFiles = chkIncludeSpecificFiles.Checked;
             downloadSettings.ImportBase = chkImportBase.Checked;
         }
 
@@ -207,18 +197,17 @@ private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e)
             downloadSettingsModified = false;
         }
 
-        private void rbSaveToDir_CheckedChanged(object sender, EventArgs e)
+        private void rbSave_CheckedChanged(object sender, EventArgs e)
         {
-            txtDestDir.Enabled = rbSaveToDir.Checked;
-            btnBrowseDestDir.Enabled = rbSaveToDir.Checked;
-            downloadSettingsModified = true;
-        }
-
-        private void rbSaveToArc_CheckedChanged(object sender, EventArgs e)
-        {
-            txtDestFile.Enabled = rbSaveToArc.Checked;
-            btnSelectDestFile.Enabled = rbSaveToArc.Checked;
-            downloadSettingsModified = true;
+            if (((RadioButton)sender).Checked) // чтобы исключить двойное срабатывание
+            {
+                bool saveToDir = rbSaveToDir.Checked;
+                txtDestDir.Enabled = saveToDir;
+                btnBrowseDestDir.Enabled = saveToDir;
+                txtDestFile.Enabled = !saveToDir;
+                btnSelectDestFile.Enabled = !saveToDir;
+                downloadSettingsModified = true;
+            }
         }
 
         private void downloadControl_Changed(object sender, EventArgs e)
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
index 517bc7808..51627ba7d 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx
@@ -149,9 +149,9 @@
 
   
   
-    17, 17
+    180, 17
   
   
-    150, 17
+    17, 17
   
 
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
index 88d90b80c..73b05c7cf 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
@@ -29,128 +29,189 @@ protected override void Dispose(bool disposing)
         private void InitializeComponent()
         {
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmUploadConfig));
-            System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("BaseDAT\\");
-            System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("C:\\SCADA\\", new System.Windows.Forms.TreeNode[] {
-            treeNode3});
-            this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
+            System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("BaseDAT\\");
+            System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("C:\\SCADA\\", new System.Windows.Forms.TreeNode[] {
+            treeNode1});
             this.gbOptions = new System.Windows.Forms.GroupBox();
-            this.btnClose = new System.Windows.Forms.Button();
-            this.btnUpload = new System.Windows.Forms.Button();
-            this.lblSrcDir = new System.Windows.Forms.Label();
+            this.chkClearSpecificFiles = new System.Windows.Forms.CheckBox();
+            this.btnSelectSrcFile = new System.Windows.Forms.Button();
+            this.txtSrcFile = new System.Windows.Forms.TextBox();
+            this.rbGetFromArc = new System.Windows.Forms.RadioButton();
+            this.rbGetFromDir = new System.Windows.Forms.RadioButton();
+            this.tvFiles = new System.Windows.Forms.TreeView();
+            this.lblFiles = new System.Windows.Forms.Label();
             this.txtSrcDir = new System.Windows.Forms.TextBox();
             this.btnBrowseSrcDir = new System.Windows.Forms.Button();
-            this.lblFiles = new System.Windows.Forms.Label();
-            this.tvFiles = new System.Windows.Forms.TreeView();
+            this.btnClose = new System.Windows.Forms.Button();
+            this.btnUpload = new System.Windows.Forms.Button();
             this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
+            this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
+            this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
             this.gbOptions.SuspendLayout();
             this.SuspendLayout();
             // 
-            // ctrlServerConn
-            // 
-            this.ctrlServerConn.Location = new System.Drawing.Point(12, 12);
-            this.ctrlServerConn.Name = "ctrlServerConn";
-            this.ctrlServerConn.ServersSettings = null;
-            this.ctrlServerConn.Size = new System.Drawing.Size(469, 55);
-            this.ctrlServerConn.TabIndex = 0;
-            this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged);
-            // 
             // gbOptions
             // 
+            this.gbOptions.Controls.Add(this.chkClearSpecificFiles);
+            this.gbOptions.Controls.Add(this.btnSelectSrcFile);
+            this.gbOptions.Controls.Add(this.txtSrcFile);
+            this.gbOptions.Controls.Add(this.rbGetFromArc);
+            this.gbOptions.Controls.Add(this.rbGetFromDir);
             this.gbOptions.Controls.Add(this.tvFiles);
             this.gbOptions.Controls.Add(this.lblFiles);
             this.gbOptions.Controls.Add(this.txtSrcDir);
             this.gbOptions.Controls.Add(this.btnBrowseSrcDir);
-            this.gbOptions.Controls.Add(this.lblSrcDir);
             this.gbOptions.Location = new System.Drawing.Point(12, 73);
             this.gbOptions.Name = "gbOptions";
             this.gbOptions.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
-            this.gbOptions.Size = new System.Drawing.Size(469, 334);
+            this.gbOptions.Size = new System.Drawing.Size(469, 408);
             this.gbOptions.TabIndex = 1;
             this.gbOptions.TabStop = false;
             this.gbOptions.Text = "Параметры передачи";
             // 
-            // btnClose
+            // chkClearSpecificFiles
+            // 
+            this.chkClearSpecificFiles.AutoSize = true;
+            this.chkClearSpecificFiles.Location = new System.Drawing.Point(13, 378);
+            this.chkClearSpecificFiles.Name = "chkClearSpecificFiles";
+            this.chkClearSpecificFiles.Size = new System.Drawing.Size(444, 17);
+            this.chkClearSpecificFiles.TabIndex = 8;
+            this.chkClearSpecificFiles.Text = "Очистить файлы специфичные для сервера, в том числе, регистрационные ключи";
+            this.chkClearSpecificFiles.UseVisualStyleBackColor = true;
+            this.chkClearSpecificFiles.CheckedChanged += new System.EventHandler(this.uploadControl_Changed);
+            // 
+            // btnSelectSrcFile
+            // 
+            this.btnSelectSrcFile.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
+            this.btnSelectSrcFile.Image = ((System.Drawing.Image)(resources.GetObject("btnSelectSrcFile.Image")));
+            this.btnSelectSrcFile.Location = new System.Drawing.Point(436, 347);
+            this.btnSelectSrcFile.Name = "btnSelectSrcFile";
+            this.btnSelectSrcFile.Size = new System.Drawing.Size(20, 20);
+            this.btnSelectSrcFile.TabIndex = 7;
+            this.btnSelectSrcFile.UseVisualStyleBackColor = true;
+            this.btnSelectSrcFile.Click += new System.EventHandler(this.btnSelectSrcFile_Click);
+            // 
+            // txtSrcFile
+            // 
+            this.txtSrcFile.Location = new System.Drawing.Point(13, 347);
+            this.txtSrcFile.Name = "txtSrcFile";
+            this.txtSrcFile.Size = new System.Drawing.Size(417, 20);
+            this.txtSrcFile.TabIndex = 6;
+            this.txtSrcFile.TextChanged += new System.EventHandler(this.uploadControl_Changed);
+            // 
+            // rbGetFromArc
+            // 
+            this.rbGetFromArc.AutoSize = true;
+            this.rbGetFromArc.Location = new System.Drawing.Point(13, 324);
+            this.rbGetFromArc.Name = "rbGetFromArc";
+            this.rbGetFromArc.Size = new System.Drawing.Size(170, 17);
+            this.rbGetFromArc.TabIndex = 5;
+            this.rbGetFromArc.Text = "Файл архива конфигурации:";
+            this.rbGetFromArc.UseVisualStyleBackColor = true;
+            this.rbGetFromArc.CheckedChanged += new System.EventHandler(this.rbGet_CheckedChanged);
+            // 
+            // rbGetFromDir
+            // 
+            this.rbGetFromDir.AutoSize = true;
+            this.rbGetFromDir.Location = new System.Drawing.Point(13, 19);
+            this.rbGetFromDir.Name = "rbGetFromDir";
+            this.rbGetFromDir.Size = new System.Drawing.Size(165, 17);
+            this.rbGetFromDir.TabIndex = 0;
+            this.rbGetFromDir.Text = "Директория конфигурации:";
+            this.rbGetFromDir.UseVisualStyleBackColor = true;
+            this.rbGetFromDir.CheckedChanged += new System.EventHandler(this.rbGet_CheckedChanged);
             // 
-            this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.btnClose.Location = new System.Drawing.Point(406, 413);
-            this.btnClose.Name = "btnClose";
-            this.btnClose.Size = new System.Drawing.Size(75, 23);
-            this.btnClose.TabIndex = 5;
-            this.btnClose.Text = "Закрыть";
-            this.btnClose.UseVisualStyleBackColor = true;
-            // 
-            // btnUpload
+            // tvFiles
             // 
-            this.btnUpload.Location = new System.Drawing.Point(325, 413);
-            this.btnUpload.Name = "btnUpload";
-            this.btnUpload.Size = new System.Drawing.Size(75, 23);
-            this.btnUpload.TabIndex = 4;
-            this.btnUpload.Text = "Передать";
-            this.btnUpload.UseVisualStyleBackColor = true;
-            this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
+            this.tvFiles.CheckBoxes = true;
+            this.tvFiles.Location = new System.Drawing.Point(13, 81);
+            this.tvFiles.Name = "tvFiles";
+            treeNode1.Name = "Node1";
+            treeNode1.Text = "BaseDAT\\";
+            treeNode2.Name = "Node0";
+            treeNode2.Text = "C:\\SCADA\\";
+            this.tvFiles.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
+            treeNode2});
+            this.tvFiles.Size = new System.Drawing.Size(443, 237);
+            this.tvFiles.TabIndex = 4;
+            this.tvFiles.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.tvFiles_AfterCheck);
             // 
-            // lblSrcDir
+            // lblFiles
             // 
-            this.lblSrcDir.AutoSize = true;
-            this.lblSrcDir.Location = new System.Drawing.Point(10, 16);
-            this.lblSrcDir.Name = "lblSrcDir";
-            this.lblSrcDir.Size = new System.Drawing.Size(144, 13);
-            this.lblSrcDir.TabIndex = 0;
-            this.lblSrcDir.Text = "Директория конфигурации";
+            this.lblFiles.AutoSize = true;
+            this.lblFiles.Location = new System.Drawing.Point(10, 65);
+            this.lblFiles.Name = "lblFiles";
+            this.lblFiles.Size = new System.Drawing.Size(115, 13);
+            this.lblFiles.TabIndex = 3;
+            this.lblFiles.Text = "Файлы для передачи";
             // 
             // txtSrcDir
             // 
-            this.txtSrcDir.Location = new System.Drawing.Point(13, 32);
+            this.txtSrcDir.Location = new System.Drawing.Point(13, 42);
             this.txtSrcDir.Name = "txtSrcDir";
             this.txtSrcDir.ReadOnly = true;
             this.txtSrcDir.Size = new System.Drawing.Size(417, 20);
-            this.txtSrcDir.TabIndex = 3;
+            this.txtSrcDir.TabIndex = 1;
             this.txtSrcDir.Text = "C:\\SCADA\\";
+            this.txtSrcDir.TextChanged += new System.EventHandler(this.uploadControl_Changed);
             // 
             // btnBrowseSrcDir
             // 
             this.btnBrowseSrcDir.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
             this.btnBrowseSrcDir.Image = ((System.Drawing.Image)(resources.GetObject("btnBrowseSrcDir.Image")));
-            this.btnBrowseSrcDir.Location = new System.Drawing.Point(436, 32);
+            this.btnBrowseSrcDir.Location = new System.Drawing.Point(436, 42);
             this.btnBrowseSrcDir.Name = "btnBrowseSrcDir";
             this.btnBrowseSrcDir.Size = new System.Drawing.Size(20, 20);
-            this.btnBrowseSrcDir.TabIndex = 4;
+            this.btnBrowseSrcDir.TabIndex = 2;
             this.btnBrowseSrcDir.UseVisualStyleBackColor = true;
             this.btnBrowseSrcDir.Click += new System.EventHandler(this.btnBrowseSrcDir_Click);
             // 
-            // lblFiles
+            // btnClose
             // 
-            this.lblFiles.AutoSize = true;
-            this.lblFiles.Location = new System.Drawing.Point(10, 55);
-            this.lblFiles.Name = "lblFiles";
-            this.lblFiles.Size = new System.Drawing.Size(115, 13);
-            this.lblFiles.TabIndex = 5;
-            this.lblFiles.Text = "Файлы для передачи";
+            this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnClose.Location = new System.Drawing.Point(406, 487);
+            this.btnClose.Name = "btnClose";
+            this.btnClose.Size = new System.Drawing.Size(75, 23);
+            this.btnClose.TabIndex = 3;
+            this.btnClose.Text = "Закрыть";
+            this.btnClose.UseVisualStyleBackColor = true;
             // 
-            // tvFiles
+            // btnUpload
             // 
-            this.tvFiles.CheckBoxes = true;
-            this.tvFiles.Location = new System.Drawing.Point(13, 71);
-            this.tvFiles.Name = "tvFiles";
-            treeNode3.Name = "Node1";
-            treeNode3.Text = "BaseDAT\\";
-            treeNode4.Name = "Node0";
-            treeNode4.Text = "C:\\SCADA\\";
-            this.tvFiles.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
-            treeNode4});
-            this.tvFiles.Size = new System.Drawing.Size(443, 250);
-            this.tvFiles.TabIndex = 6;
+            this.btnUpload.Location = new System.Drawing.Point(325, 487);
+            this.btnUpload.Name = "btnUpload";
+            this.btnUpload.Size = new System.Drawing.Size(75, 23);
+            this.btnUpload.TabIndex = 2;
+            this.btnUpload.Text = "Передать";
+            this.btnUpload.UseVisualStyleBackColor = true;
+            this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
             // 
             // folderBrowserDialog
             // 
             this.folderBrowserDialog.Description = "Выберите директорию конфигурации";
             // 
+            // openFileDialog
+            // 
+            this.openFileDialog.CheckFileExists = false;
+            this.openFileDialog.DefaultExt = "*.zip";
+            this.openFileDialog.Filter = "Архивы конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*";
+            this.openFileDialog.Title = "Выберите файл архива конфигурации";
+            // 
+            // ctrlServerConn
+            // 
+            this.ctrlServerConn.Location = new System.Drawing.Point(12, 12);
+            this.ctrlServerConn.Name = "ctrlServerConn";
+            this.ctrlServerConn.ServersSettings = null;
+            this.ctrlServerConn.Size = new System.Drawing.Size(469, 55);
+            this.ctrlServerConn.TabIndex = 0;
+            this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged);
+            // 
             // FrmUploadConfig
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.btnClose;
-            this.ClientSize = new System.Drawing.Size(493, 448);
+            this.ClientSize = new System.Drawing.Size(493, 522);
             this.Controls.Add(this.btnClose);
             this.Controls.Add(this.btnUpload);
             this.Controls.Add(this.gbOptions);
@@ -175,11 +236,16 @@ private void InitializeComponent()
         private System.Windows.Forms.GroupBox gbOptions;
         private System.Windows.Forms.Button btnClose;
         private System.Windows.Forms.Button btnUpload;
-        private System.Windows.Forms.Label lblSrcDir;
         private System.Windows.Forms.TextBox txtSrcDir;
         private System.Windows.Forms.Button btnBrowseSrcDir;
         private System.Windows.Forms.Label lblFiles;
         private System.Windows.Forms.TreeView tvFiles;
         private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog;
+        private System.Windows.Forms.RadioButton rbGetFromDir;
+        private System.Windows.Forms.RadioButton rbGetFromArc;
+        private System.Windows.Forms.Button btnSelectSrcFile;
+        private System.Windows.Forms.TextBox txtSrcFile;
+        private System.Windows.Forms.CheckBox chkClearSpecificFiles;
+        private System.Windows.Forms.OpenFileDialog openFileDialog;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
index ca7ae3e81..ec9f6799c 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -63,8 +63,10 @@ private void ShowUploadSettings(ServersSettings.UploadSettings uploadSettings)
             if (uploadSettings == null)
             {
                 gbOptions.Enabled = false;
-                txtSrcDir.Text = "";
+                rbGetFromDir.Checked = true;
+                txtSrcDir.Text = txtSrcFile.Text = "";
                 tvFiles.Nodes.Clear();
+                chkClearSpecificFiles.Checked = false;
                 btnUpload.Enabled = false;
             }
             else
@@ -72,7 +74,14 @@ private void ShowUploadSettings(ServersSettings.UploadSettings uploadSettings)
                 gbOptions.Enabled = true;
                 txtSrcDir.Text = uploadSettings.SrcDir;
                 FillTreeView(uploadSettings);
+                txtSrcFile.Text = uploadSettings.SrcFile;
+                chkClearSpecificFiles.Checked = uploadSettings.ClearSpecificFiles;
                 btnUpload.Enabled = true;
+
+                if (uploadSettings.GetFromDir)
+                    rbGetFromDir.Checked = true;
+                else
+                    rbGetFromArc.Checked = true;
             }
         }
 
@@ -190,24 +199,29 @@ private void SaveServersSettings()
         }
 
         /// 
-        /// Извлечь параметры передачи конфигурации
+        /// Конвертировать базу конфигурации в формат DAT, если необходимо
         /// 
-        public void RetrieveUploadOptions(out List fileNames, out ConfigParts configParts)
+        private void ConvertBaseToDAT(string srcDir)
         {
-            fileNames = new List();
-            configParts = ConfigParts.All;
+            string workBaseDATDir = ScadaUtils.NormalDir(AppData.Settings.AppSett.BaseDATDir);
+            string srcBaseDATDir = Path.Combine(srcDir, "BaseDAT\\");
+
+            if (string.Equals(workBaseDATDir, srcBaseDATDir, StringComparison.OrdinalIgnoreCase))
+            {
+                if (!ImportExport.PassBase(Tables.TableInfoList, workBaseDATDir, out string msg))
+                    AppUtils.ProcError(msg);
+            }
         }
 
         /// 
         /// Передать конфигурацию
         /// 
-        private void UploadConfig(ServersSettings.ConnectionSettings connectionSettings,
-            string rootDir, List fileNames, ConfigParts configParts)
+        private void UploadConfig(ServersSettings.ServerSettings serverSettings)
         {
             // передача
             string logFileName = AppData.AppDirs.LogDir + "ScadaAdminUpload.txt";
-            bool uploadOK = DownloadUpload.UploadConfig(connectionSettings,
-                rootDir, fileNames, configParts, logFileName, out bool logCreated, out string msg);
+            bool uploadOK = DownloadUpload.UploadConfig(serverSettings,
+                logFileName, out bool logCreated, out string msg);
 
             // отображение сообщения о результате
             if (uploadOK)
@@ -249,9 +263,56 @@ private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e)
             uploadSettingsModified = false;
         }
 
+        private void rbGet_CheckedChanged(object sender, EventArgs e)
+        {
+            if (((RadioButton)sender).Checked) // чтобы исключить двойное срабатывание
+            {
+                bool getFromDir = rbGetFromDir.Checked;
+                txtSrcDir.Enabled = getFromDir;
+                btnBrowseSrcDir.Enabled = getFromDir;
+                tvFiles.Enabled = getFromDir;
+                txtSrcFile.Enabled = !getFromDir;
+                btnSelectSrcFile.Enabled = !getFromDir;
+                uploadSettingsModified = true;
+            }
+        }
+
+        private void uploadControl_Changed(object sender, EventArgs e)
+        {
+            uploadSettingsModified = true;
+        }
+
+        private void tvFiles_AfterCheck(object sender, TreeViewEventArgs e)
+        {
+            uploadSettingsModified = true;
+        }
+
         private void btnBrowseSrcDir_Click(object sender, EventArgs e)
         {
+            // выбор директории конфигурации
+            folderBrowserDialog.SelectedPath = txtSrcDir.Text.Trim();
 
+            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
+                txtSrcDir.Text = ScadaUtils.NormalDir(folderBrowserDialog.SelectedPath);
+
+            txtSrcDir.Focus();
+            txtSrcDir.DeselectAll();
+        }
+
+        private void btnSelectSrcFile_Click(object sender, EventArgs e)
+        {
+            // выбор файла архива конфигурации
+            string fileName = txtSrcFile.Text.Trim();
+            openFileDialog.FileName = fileName;
+
+            if (fileName != "")
+                openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName);
+
+            if (openFileDialog.ShowDialog() == DialogResult.OK)
+                txtSrcFile.Text = openFileDialog.FileName;
+
+            txtSrcFile.Focus();
+            txtSrcFile.DeselectAll();
         }
 
         private void btnUpload_Click(object sender, EventArgs e)
@@ -267,8 +328,10 @@ private void btnUpload_Click(object sender, EventArgs e)
                     SaveServersSettings();
                 }
 
-                RetrieveUploadOptions(out List fileNames, out ConfigParts configParts);
-                UploadConfig(serverSettings.Connection, serverSettings.Upload.SrcDir, fileNames, configParts);
+                if (serverSettings.Upload.GetFromDir)
+                    ConvertBaseToDAT(serverSettings.Upload.SrcDir);
+
+                UploadConfig(serverSettings);
             }
         }
     }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
index 0507ec929..3e7d47c4c 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
@@ -118,6 +118,21 @@
     System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
   
   
+  
+    
+        R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R
+        fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N
+        VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc
+        iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d
+        gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i
+        Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq
+        LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB
+        AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF
+        FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS
+        BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28
+        tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs=
+
+  
   
     
         R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R
@@ -136,6 +151,9 @@
   
     17, 17
   
+  
+    180, 17
+  
   
     52
   
diff --git a/ScadaAgent/ScadaAgentCore/RelPath.cs b/ScadaAgent/ScadaAgentCore/RelPath.cs
index 4c53a7dca..70810af76 100644
--- a/ScadaAgent/ScadaAgentCore/RelPath.cs
+++ b/ScadaAgent/ScadaAgentCore/RelPath.cs
@@ -64,5 +64,16 @@ public RelPath(ConfigParts configPart, AppFolder appFolder, string path = "")
         /// Получить или установить путь относительно папки приложения
         /// 
         public string Path { get; set; }
+
+        /// 
+        /// Получить признак, что путь является маской для поиска файлов
+        /// 
+        public bool IsMask
+        {
+            get
+            {
+                return Path != null && (Path.IndexOf('*') >= 0 || Path.IndexOf('?') >= 0);
+            }
+        }
     }
 }
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 2a935b708..47cbf77cf 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -282,22 +282,37 @@ private string GetAppFolderDir(ConfigParts configPart, AppFolder appFolder, char
         }
 
         /// 
-        /// Разделить исключаемые пути по группам
+        /// Подготовить исключаемые пути: разделить по группам, применить поиск файлов по маске
         /// 
-        private PathDict SeparatePaths(ICollection relPaths)
+        private PathDict PrepareExcludedPaths(ICollection relPaths)
         {
             PathDict pathDict = new PathDict();
 
             foreach (RelPath relPath in relPaths)
             {
                 PathList pathList = pathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder);
-                string absPath = GetAbsPath(relPath);
-                char lastPathSym = absPath[absPath.Length - 1];
+                bool pathIsMask = relPath.IsMask;
+                string[] absPathArr;
 
-                if (lastPathSym == Path.DirectorySeparatorChar || lastPathSym == Path.AltDirectorySeparatorChar)
-                    pathList.Dirs.Add(absPath);
+                if (relPath.IsMask)
+                {
+                    string dir = GetAbsPath(relPath.ConfigPart, relPath.AppFolder, "");
+                    absPathArr = Directory.GetFiles(dir, relPath.Path);
+                }
                 else
-                    pathList.Files.Add(absPath);
+                {
+                    absPathArr = new string[] { GetAbsPath(relPath) };
+                }
+
+                foreach (string absPath in absPathArr)
+                {
+                    char lastPathSym = absPath[absPath.Length - 1];
+
+                    if (lastPathSym == Path.DirectorySeparatorChar || lastPathSym == Path.AltDirectorySeparatorChar)
+                        pathList.Dirs.Add(absPath);
+                    else
+                        pathList.Files.Add(absPath);
+                }
             }
 
             return pathDict;
@@ -553,11 +568,19 @@ public bool GetServiceStatus(ServiceApp serviceApp, out ServiceStatus status)
         /// Получить абсолютный путь из относительного
         /// 
         public string GetAbsPath(RelPath relPath)
+        {
+            return GetAbsPath(relPath.ConfigPart, relPath.AppFolder, relPath.Path);
+        }
+
+        /// 
+        /// Получить абсолютный путь из относительного
+        /// 
+        public string GetAbsPath(ConfigParts configPart, AppFolder appFolder, string path)
         {
             return Path.Combine(Settings.Directory,
-                GetConfigPartDir(relPath.ConfigPart, null),
-                GetAppFolderDir(relPath.AppFolder, null, relPath.ConfigPart == ConfigParts.Webstation),
-                relPath.Path);
+                GetConfigPartDir(configPart, Path.DirectorySeparatorChar),
+                GetAppFolderDir(appFolder, Path.DirectorySeparatorChar, configPart == ConfigParts.Webstation),
+                path);
         }
 
         /// 
@@ -598,7 +621,7 @@ public bool PackConfig(string destFileName, ConfigOptions configOptions)
             try
             {
                 List configPaths = GetConfigPaths(configOptions.ConfigParts);
-                PathDict pathDict = SeparatePaths(configOptions.ExcludedPaths);
+                PathDict excludedPathDict = PrepareExcludedPaths(configOptions.ExcludedPaths);
 
                 using (FileStream fileStream = 
                     new FileStream(destFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
@@ -607,7 +630,7 @@ public bool PackConfig(string destFileName, ConfigOptions configOptions)
                     {
                         foreach (RelPath relPath in configPaths)
                         {
-                            PackDir(zipArchive, relPath, pathDict);
+                            PackDir(zipArchive, relPath, excludedPathDict);
                         }
 
                         return true;
@@ -632,7 +655,7 @@ public bool UnpackConfig(string srcFileName, ConfigOptions configOptions)
             {
                 // удаление существующей конфигурации
                 List configPaths = GetConfigPaths(configOptions.ConfigParts);
-                PathDict pathDict = SeparatePaths(configOptions.ExcludedPaths);
+                PathDict pathDict = PrepareExcludedPaths(configOptions.ExcludedPaths);
 
                 foreach (RelPath relPath in configPaths)
                 {

From f222b1f0a07bf26791d00c3cd8bff78c843616aa Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sat, 12 May 2018 21:42:10 +0300
Subject: [PATCH 069/100] Debug of Admin and Agent

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |   3 +-
 .../ScadaAdmin/AppCode/DownloadUpload.cs      |   4 +-
 .../ScadaAdmin/AppCode/ServersSettings.cs     |   2 +-
 ScadaAdmin/ScadaAdmin/FrmMain.cs              |   8 +-
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |   2 +-
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |   2 +
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      | 107 +++++++++++++++---
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs    |  76 ++++++++-----
 8 files changed, 154 insertions(+), 50 deletions(-)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index 36c8dbc45..f8a505d36 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -262,7 +262,8 @@ private static void SetToDefault()
             UnableRestartServer = "Не удалось перезапустить службу Сервера";
             CommRestarted = "Служба Коммуникатора перезапущена";
             UnableRestartComm = "Не удалось перезапустить службу Коммуникатора";
-            UploadSuccessful = "Передача завершена успешно за {0} с.";
+            UploadSuccessful = "Передача завершена успешно за {0} с.\r\n" +
+                "Проверьте работоспособность удалённого сервера.";
             UploadError = "Ошибка при передаче конфигурации";
 
             ChooseBaseTableFile = "Выберите файл таблицы базы конфигурации";
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index 6517113f2..dcc9cf328 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -144,7 +144,7 @@ private static void PackConfig(string srcDir, List selectedFiles,
                             {
                                 string dirInArc = Path.GetDirectoryName(fileName.Substring(srcDirLen))
                                     .Replace('\\', '/');
-                                zipFile.AddFile(path, dirInArc);
+                                zipFile.AddFile(fileName, dirInArc);
                             }
                         }
                     }
@@ -154,6 +154,8 @@ private static void PackConfig(string srcDir, List selectedFiles,
                         zipFile.AddFile(path, dirInArc);
                     }
                 }
+
+                zipFile.Save();
             }
         }
 
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
index b4be304e7..428b48621 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs
@@ -265,7 +265,7 @@ public void LoadFromXml(XmlNode xmlNode)
                 XmlNode selectedFilesNode = xmlNode.SelectSingleNode("SelectedFiles");
                 if (selectedFilesNode != null)
                 {
-                    XmlNodeList pathNodeList = xmlNode.SelectNodes("Path");
+                    XmlNodeList pathNodeList = selectedFilesNode.SelectNodes("Path");
                     foreach (XmlNode pathNode in pathNodeList)
                     {
                         SelectedFiles.Add(pathNode.InnerText);
diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.cs b/ScadaAdmin/ScadaAdmin/FrmMain.cs
index c25cbf1d7..ca66da019 100644
--- a/ScadaAdmin/ScadaAdmin/FrmMain.cs
+++ b/ScadaAdmin/ScadaAdmin/FrmMain.cs
@@ -797,13 +797,13 @@ private void miDbPassToServer_Click(object sender, EventArgs e)
             if (AppData.Connected)
             {
                 // резервное копирование файла базы конфигурации
-                string msg;
-                if (settings.AppSett.AutoBackupBase && 
-                    !ImportExport.BackupSDF(settings.AppSett.BaseSDFFile, settings.AppSett.BackupDir, out msg))
+                Settings.AppSettings appSettings = settings.AppSett;
+                if (appSettings.AutoBackupBase && 
+                    !ImportExport.BackupSDF(appSettings.BaseSDFFile, appSettings.BackupDir, out string msg))
                     AppUtils.ProcError(msg);
 
                 // конвертирование базы конфигурации в формат DAT
-                if (ImportExport.PassBase(Tables.TableInfoList, settings.AppSett.BaseDATDir, out msg))
+                if (ImportExport.PassBase(Tables.TableInfoList, appSettings.BaseDATDir, out msg))
                     ScadaUiUtils.ShowInfo(msg);
                 else
                     AppUtils.ProcError(msg);
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index a59f151b8..7d89dc83c 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -21,7 +21,7 @@
     Unable to restart the Server service
     The Communicator service restarted
     Unable to restart the Communicator service
-    Upload completed successfully in {0} sec.
+    Upload completed successfully in {0} sec.
Check the remote server.
     Error uploading configuration
   
   
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index 5baaf41c1..b61bb6097 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -132,9 +132,11 @@ private void SaveServersSettings()
         private void DownloadConfig(ServersSettings.ServerSettings serverSettings)
         {
             // скачивание
+            Cursor = Cursors.WaitCursor;
             string logFileName = AppData.AppDirs.LogDir + "ScadaAdminDownload.txt";
             bool downloadOK = DownloadUpload.DownloadConfig(serverSettings,
                 logFileName, out bool logCreated, out string msg);
+            Cursor = Cursors.Default;
 
             // отображение сообщения о результате
             if (downloadOK)
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
index ec9f6799c..edb688555 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -40,6 +40,21 @@ namespace ScadaAdmin.Remote
     /// 
     public partial class FrmUploadConfig : Form
     {
+        /// 
+        /// Информация узла дерева
+        /// 
+        private class NodeInfo
+        {
+            /// 
+            /// Получить или установить путь относительно директории конфигурации
+            /// 
+            public string Path { get; set; }
+            /// 
+            /// Получить или установить признак, что узел соответствует директории
+            /// 
+            public bool IsDirectory { get; set; }
+        }
+
         private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами
         private bool uploadSettingsModified;     // последние выбранные настройки передачи были изменены
 
@@ -96,20 +111,22 @@ private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
                 tvFiles.Nodes.Clear();
 
                 string srcDir = ScadaUtils.NormalDir(uploadSettings.SrcDir);
+                int srcDirLen = srcDir.Length;
                 TreeNode rootNode = tvFiles.Nodes.Add(srcDir);
 
                 // добавление узла базы конфигурации
-                AddDirToTreeView(rootNode, srcDir + "BaseDAT\\");
+                HashSet selectedFiles = new HashSet(uploadSettings.SelectedFiles);
+                AddDirToTreeView(rootNode, srcDir + "BaseDAT\\", srcDirLen, selectedFiles);
 
                 // добавление узла интерфейса
-                AddDirToTreeView(rootNode, srcDir + "Interface\\");
+                AddDirToTreeView(rootNode, srcDir + "Interface\\", srcDirLen, selectedFiles);
 
                 // добавление узла Коммуникатора
                 string commDir = srcDir + "ScadaComm\\";
                 if (Directory.Exists(commDir))
                 {
                     TreeNode commNode = rootNode.Nodes.Add("ScadaComm\\");
-                    AddDirToTreeView(commNode, commDir + "Config\\");
+                    AddDirToTreeView(commNode, commDir + "Config\\", srcDirLen, selectedFiles);
                 }
 
                 // добавление узла Сервера
@@ -117,7 +134,7 @@ private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
                 if (Directory.Exists(serverDir))
                 {
                     TreeNode serverNode = rootNode.Nodes.Add("ScadaServer\\");
-                    AddDirToTreeView(serverNode, serverDir + "Config\\");
+                    AddDirToTreeView(serverNode, serverDir + "Config\\", srcDirLen, selectedFiles);
                 }
 
                 // добавление узла Вебстанции
@@ -125,8 +142,8 @@ private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
                 if (Directory.Exists(webDir))
                 {
                     TreeNode serverNode = rootNode.Nodes.Add("ScadaWeb\\");
-                    AddDirToTreeView(serverNode, webDir + "config\\");
-                    AddDirToTreeView(serverNode, webDir + "storage\\");
+                    AddDirToTreeView(serverNode, webDir + "config\\", srcDirLen, selectedFiles);
+                    AddDirToTreeView(serverNode, webDir + "storage\\", srcDirLen, selectedFiles);
                 }
 
                 rootNode.Expand();
@@ -140,26 +157,29 @@ private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
         /// 
         /// Добавить директорию в дерево
         /// 
-        private void AddDirToTreeView(TreeNode parentNode, string dir)
+        private void AddDirToTreeView(TreeNode parentNode, string dir, int rootDirLen, HashSet selectedFiles)
         {
-            AddDirToTreeView(parentNode, new DirectoryInfo(dir));
+            AddDirToTreeView(parentNode, new DirectoryInfo(dir), rootDirLen, selectedFiles);
         }
 
         /// 
         /// Добавить директорию в дерево
         /// 
-        private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo)
+        private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo, 
+            int rootDirLen, HashSet selectedFiles)
         {
             if (dirInfo.Exists)
             {
                 TreeNode dirNode = parentNode.Nodes.Add(dirInfo.Name + "\\");
+                string dirNodePath = ScadaUtils.NormalDir(dirInfo.FullName.Substring(rootDirLen));
+                dirNode.Tag = new NodeInfo() { Path = dirNodePath, IsDirectory = true };
 
                 // добавление поддиректорий
                 DirectoryInfo[] subdirInfoArr = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
 
                 foreach (DirectoryInfo subdirInfo in subdirInfoArr)
                 {
-                    AddDirToTreeView(dirNode, subdirInfo);
+                    AddDirToTreeView(dirNode, subdirInfo, rootDirLen, selectedFiles);
                 }
 
                 // добавление файлов
@@ -168,11 +188,37 @@ private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo)
                 foreach (FileInfo fileInfo in fileInfoArr)
                 {
                     if (fileInfo.Extension != ".bak")
-                        dirNode.Nodes.Add(fileInfo.Name);
+                    {
+                        TreeNode fileNode = dirNode.Nodes.Add(fileInfo.Name);
+                        string fileNodePath = fileInfo.FullName.Substring(rootDirLen);
+                        fileNode.Tag = new NodeInfo() { Path = fileNodePath, IsDirectory = false };
+
+                        if (selectedFiles.Contains(fileNodePath))
+                            fileNode.Checked = true;
+                    }
+                }
+
+                // выбор узла и его дочерних узлов после того, как они добавлены в дерево
+                if (selectedFiles.Contains(dirNodePath))
+                {
+                    dirNode.Checked = true;
+                    CheckAllChildNodes(dirNode, true);
                 }
             }
         }
 
+        /// 
+        /// Установить или снять выбор дочерних узлов дерева
+        /// 
+        private void CheckAllChildNodes(TreeNode treeNode, bool nodeChecked)
+        {
+            foreach (TreeNode node in treeNode.Nodes)
+            {
+                node.Checked = nodeChecked;
+                CheckAllChildNodes(node, nodeChecked);
+            }
+        }
+
         /// 
         /// Проверить настройки передачи конфигурации
         /// 
@@ -186,7 +232,29 @@ private bool ValidateUploadSettings()
         /// 
         private void ApplyUploadSettings(ServersSettings.UploadSettings uploadSettings)
         {
+            uploadSettings.GetFromDir = rbGetFromDir.Checked;
             uploadSettings.SrcDir = txtSrcDir.Text;
+            uploadSettings.SrcFile = txtSrcFile.Text;
+            uploadSettings.ClearSpecificFiles = chkClearSpecificFiles.Checked;
+
+            uploadSettings.SelectedFiles.Clear();
+            TraverseNodes(tvFiles.Nodes[0]);
+
+            // Получить выбранные файлы на основе выбранных узлов дерева
+            void TraverseNodes(TreeNode node)
+            {
+                if (node.Tag is NodeInfo nodeInfo && node.Checked)
+                {
+                    uploadSettings.SelectedFiles.Add(nodeInfo.Path);
+                }
+                else
+                {
+                    foreach (TreeNode childNode in node.Nodes)
+                    {
+                        TraverseNodes(childNode);
+                    }
+                }
+            }
         }
 
         /// 
@@ -203,12 +271,19 @@ private void SaveServersSettings()
         /// 
         private void ConvertBaseToDAT(string srcDir)
         {
-            string workBaseDATDir = ScadaUtils.NormalDir(AppData.Settings.AppSett.BaseDATDir);
+            Settings.AppSettings appSettings = AppData.Settings.AppSett;
+            string workBaseDATDir = ScadaUtils.NormalDir(appSettings.BaseDATDir);
             string srcBaseDATDir = Path.Combine(srcDir, "BaseDAT\\");
 
             if (string.Equals(workBaseDATDir, srcBaseDATDir, StringComparison.OrdinalIgnoreCase))
             {
-                if (!ImportExport.PassBase(Tables.TableInfoList, workBaseDATDir, out string msg))
+                // резервное копирование
+                if (appSettings.AutoBackupBase &&
+                    !ImportExport.BackupSDF(appSettings.BaseSDFFile, appSettings.BackupDir, out string msg))
+                    AppUtils.ProcError(msg);
+
+                // конвертирование
+                if (!ImportExport.PassBase(Tables.TableInfoList, workBaseDATDir, out msg))
                     AppUtils.ProcError(msg);
             }
         }
@@ -219,9 +294,11 @@ private void ConvertBaseToDAT(string srcDir)
         private void UploadConfig(ServersSettings.ServerSettings serverSettings)
         {
             // передача
+            Cursor = Cursors.WaitCursor;
             string logFileName = AppData.AppDirs.LogDir + "ScadaAdminUpload.txt";
             bool uploadOK = DownloadUpload.UploadConfig(serverSettings,
                 logFileName, out bool logCreated, out string msg);
+            Cursor = Cursors.Default;
 
             // отображение сообщения о результате
             if (uploadOK)
@@ -284,6 +361,10 @@ private void uploadControl_Changed(object sender, EventArgs e)
 
         private void tvFiles_AfterCheck(object sender, TreeViewEventArgs e)
         {
+            // установка выбора для дочерних узлов
+            if (e.Action != TreeViewAction.Unknown)
+                CheckAllChildNodes(e.Node, e.Node.Checked);
+
             uploadSettingsModified = true;
         }
 
diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index 47cbf77cf..e5cba5326 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -288,30 +288,34 @@ private PathDict PrepareExcludedPaths(ICollection relPaths)
         {
             PathDict pathDict = new PathDict();
 
-            foreach (RelPath relPath in relPaths)
+            if (relPaths != null)
             {
-                PathList pathList = pathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder);
-                bool pathIsMask = relPath.IsMask;
-                string[] absPathArr;
-
-                if (relPath.IsMask)
-                {
-                    string dir = GetAbsPath(relPath.ConfigPart, relPath.AppFolder, "");
-                    absPathArr = Directory.GetFiles(dir, relPath.Path);
-                }
-                else
-                {
-                    absPathArr = new string[] { GetAbsPath(relPath) };
-                }
-
-                foreach (string absPath in absPathArr)
+                foreach (RelPath relPath in relPaths)
                 {
-                    char lastPathSym = absPath[absPath.Length - 1];
+                    PathList pathList = pathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder);
+                    bool pathIsMask = relPath.IsMask;
+                    string[] absPathArr;
 
-                    if (lastPathSym == Path.DirectorySeparatorChar || lastPathSym == Path.AltDirectorySeparatorChar)
-                        pathList.Dirs.Add(absPath);
+                    if (relPath.IsMask)
+                    {
+                        string dir = GetAbsPath(relPath.ConfigPart, relPath.AppFolder, "");
+                        absPathArr = Directory.Exists(dir) ? 
+                            Directory.GetFiles(dir, relPath.Path) : new string[0];
+                    }
                     else
-                        pathList.Files.Add(absPath);
+                    {
+                        absPathArr = new string[] { GetAbsPath(relPath) };
+                    }
+
+                    foreach (string absPath in absPathArr)
+                    {
+                        char lastSym = absPath[absPath.Length - 1];
+
+                        if (lastSym == Path.DirectorySeparatorChar || lastSym == Path.AltDirectorySeparatorChar)
+                            pathList.Dirs.Add(absPath);
+                        else
+                            pathList.Files.Add(absPath);
+                    }
                 }
             }
 
@@ -368,22 +372,20 @@ private void PackDir(ZipArchive zipArchive, RelPath relPath, PathDict excludedPa
         /// 
         /// Очистить директорию
         /// 
-        private void ClearDir(string dir, PathList excludedPaths, out bool dirEmpty)
+        private void ClearDir(DirectoryInfo dirInfo, PathList excludedPaths, out bool dirEmpty)
         {
-            if (excludedPaths.Dirs.Contains(dir))
+            if (excludedPaths.Dirs.Contains(dirInfo.FullName))
             {
                 dirEmpty = false;
             }
             else
             {
-                DirectoryInfo dirInfo = new DirectoryInfo(dir);
-
                 // очистка поддиректорий
                 DirectoryInfo[] subdirInfoArr = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
 
                 foreach (DirectoryInfo subdirInfo in subdirInfoArr)
                 {
-                    ClearDir(subdirInfo.FullName, excludedPaths, out bool subdirEmpty);
+                    ClearDir(subdirInfo, excludedPaths, out bool subdirEmpty);
                     if (subdirEmpty)
                         subdirInfo.Delete();
                 }
@@ -407,8 +409,13 @@ private void ClearDir(string dir, PathList excludedPaths, out bool dirEmpty)
         /// 
         private void ClearDir(RelPath relPath, PathDict excludedPathDict)
         {
-            ClearDir(GetAbsPath(relPath), excludedPathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder), 
-                out bool dirEmpty);
+            DirectoryInfo dirInfo = new DirectoryInfo(GetAbsPath(relPath));
+
+            if (dirInfo.Exists)
+            {
+                ClearDir(dirInfo, excludedPathDict.GetOrAdd(relPath.ConfigPart, relPath.AppFolder),
+                    out bool dirEmpty);
+            }
         }
 
         /// 
@@ -493,8 +500,19 @@ public bool ControlService(ServiceApp serviceApp, ServiceCommand command)
             {
                 string batchFileName = Path.Combine(Settings.Directory,
                     GetServiceDir(serviceApp, null), GetServiceBatchFile(command));
-                Process.Start(batchFileName);
-                return true;
+
+                if (File.Exists(batchFileName))
+                {
+                    Process.Start(batchFileName);
+                    return true;
+                }
+                else
+                {
+                    log.WriteError(string.Format(Localization.UseRussian ?
+                        "Не найден файл для управления службой {0}" :
+                        "File {0} for service control not found", batchFileName));
+                    return false;
+                }
             }
             catch (Exception ex)
             {

From b6f49a3c246aa6199ef14cd14cb043bcf120becf Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 00:46:23 +0300
Subject: [PATCH 070/100] ScadaAdmin: upload config works

---
 ScadaAdmin/Res/file.png                       | Bin 0 -> 404 bytes
 ScadaAdmin/Res/folder_closed2.png             | Bin 0 -> 480 bytes
 ScadaAdmin/Res/folder_open2.png               | Bin 0 -> 524 bytes
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  19 ++--
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |  14 ++-
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |   4 +-
 .../Remote/FrmUploadConfig.Designer.cs        |  16 +++
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      | 100 ++++++++++++++----
 .../ScadaAdmin/Remote/FrmUploadConfig.resx    |  51 +++++++++
 ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj |   6 ++
 ScadaAgent/ScadaAgentSvc/svc_install.bat      |   2 +
 ScadaAgent/ScadaAgentSvc/svc_uninstall.bat    |   2 +
 12 files changed, 176 insertions(+), 38 deletions(-)
 create mode 100644 ScadaAdmin/Res/file.png
 create mode 100644 ScadaAdmin/Res/folder_closed2.png
 create mode 100644 ScadaAdmin/Res/folder_open2.png
 create mode 100644 ScadaAgent/ScadaAgentSvc/svc_install.bat
 create mode 100644 ScadaAgent/ScadaAgentSvc/svc_uninstall.bat

diff --git a/ScadaAdmin/Res/file.png b/ScadaAdmin/Res/file.png
new file mode 100644
index 0000000000000000000000000000000000000000..2283e3d8848e25dee10ad1c9a646cbca73a8a99b
GIT binary patch
literal 404
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b
z3=DinK$vl=HlH+5kiEpy*OmPdE03sv*v6^Psu&m;6+K-XLo813owV2Qu!BI$@s4n&
zd5kJ5S{VYoAtfRvfww{yK44sNiD8kqBlDxB_=?KfWK
zpWohj(O@4I#&@}9*)v7Y76E~2-V8ge?%m({M#cB@%w4aZJ@k#qw_S5eZ)X4_`jjnMnA*i)K`b-qOTbP|o9i{lq4o^Xq>mzFu_uc>j@YyR|QD)rg7b
z&idzDdv4|1y_;25pEYBD)>QrGS(BuL_!$<>v%8pB*gP7vyD|e~zH{V+y;W$*O6K%9
zqQ>%?dBTF@-DxYErP}fuW;U+bUg(>{HiIRZpMjyt^2F6N_8!v{VehIKFE*}PzQmDf
w$^SVh0t`O}Pgg&ebxsLQ0AB&2=Kufz

literal 0
HcmV?d00001

diff --git a/ScadaAdmin/Res/folder_closed2.png b/ScadaAdmin/Res/folder_closed2.png
new file mode 100644
index 0000000000000000000000000000000000000000..546f85ed20a37aa41756b8b156ed95d33252bb86
GIT binary patch
literal 480
zcmV<60U!Q}P)bT_1##0sCc
zl|wPu>T~Db24_#lf?;#B|JMd93tRh(s6*Q
zQPLij%#Gv;o@*kFh+GqCLgb%_UPMio12i?9vN5C)k!m83kHRhoxJ)T}0WG!+ph!EW
z8{hHSh)82xY9jr>^8v0?!i1t7Y-xj{NYikxw~xt?C?h&DA+!OXVc~dyIjEh`V0Zf~
z()os&VXA03gK7^oN3?@lg?JaYC0{5-dGq-)BCCi9B88F*xfDv7Yt=&A%y2jUqxl8u
W|M{H>o7Fi00000N(ONe|BTw*LAwerb#W+ma1@+eM8Uy9
z&>^5S*w}VxMAR4qC9yB>-CytC_nt#iZG6;K@W6p{&;6dy{oZ@wUx#;8?7e@L?{wM)
z!G()UEY_F3lK`coVyDxl(U@nxmdyyBJZ=BgLFxFSRy~C?$#f%vsLR3N3=i(D<$n&Y
z-n{G00E{*>0!IZZOWe5HDxA9c;#|=|d9F;FD1vkXdif@rfXxCzTBNk-#7)&X8|%08
z8Gw=+XDxvbpSuH;JR8@=s{IDUk;H`wUq_BkuS#PvggGD5sUS081!##5
zhirccl1o?Cf?oiwG^s7o8&xI`dO8H5A#>m)P7ACO_&Vg-R?O=y7p&ZAdj4@+qj8C$
zD6?FT@$v++1k9K;4zbZ8c0As2{l?K5aSW-#pu1BU{B#2&GN
zEcfY0fp@vl^a_CPexF@q(dHUTX@pdh6cQm6LJEXb+~3&b(eoz%N&Eysvd7m*VPug2
O0000
   
     Choose a configuration directory
+    Configuration directory is required.
+    File name of a configuration archive is required.
   
   
     Connection to server
@@ -544,7 +546,15 @@
     Import the configuration database to SDF format after downloading
     Download
     Close
-    Directory is required.
-    Archive file name is required.
+  
+  
+    Upload Configuration
+    Upload options
+    Configuration directory:
+    Files to upload
+    Configuration archive file:
+    Clear server specific files such as registration keys
+    Upload
+    Close
   
 
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index b61bb6097..7cbf22e07 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -92,13 +92,13 @@ private bool ValidateDownloadSettings()
             {
                 if (string.IsNullOrWhiteSpace(txtDestDir.Text))
                 {
-                    ScadaUiUtils.ShowError(AppPhrases.DestDirRequired);
+                    ScadaUiUtils.ShowError(AppPhrases.ConfigDirRequired);
                     return false;
                 }
             }
             else if (string.IsNullOrWhiteSpace(txtDestFile.Text))
             {
-                ScadaUiUtils.ShowError(AppPhrases.DestFileRequired);
+                ScadaUiUtils.ShowError(AppPhrases.ConfigArcRequired);
                 return false;
             }
 
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
index 73b05c7cf..015d511f2 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs
@@ -28,6 +28,7 @@ protected override void Dispose(bool disposing)
         /// 
         private void InitializeComponent()
         {
+            this.components = new System.ComponentModel.Container();
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmUploadConfig));
             System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("BaseDAT\\");
             System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("C:\\SCADA\\", new System.Windows.Forms.TreeNode[] {
@@ -46,6 +47,7 @@ private void InitializeComponent()
             this.btnUpload = new System.Windows.Forms.Button();
             this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
             this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
+            this.ilTree = new System.Windows.Forms.ImageList(this.components);
             this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
             this.gbOptions.SuspendLayout();
             this.SuspendLayout();
@@ -124,6 +126,8 @@ private void InitializeComponent()
             // tvFiles
             // 
             this.tvFiles.CheckBoxes = true;
+            this.tvFiles.ImageIndex = 0;
+            this.tvFiles.ImageList = this.ilTree;
             this.tvFiles.Location = new System.Drawing.Point(13, 81);
             this.tvFiles.Name = "tvFiles";
             treeNode1.Name = "Node1";
@@ -132,9 +136,12 @@ private void InitializeComponent()
             treeNode2.Text = "C:\\SCADA\\";
             this.tvFiles.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
             treeNode2});
+            this.tvFiles.SelectedImageIndex = 0;
             this.tvFiles.Size = new System.Drawing.Size(443, 237);
             this.tvFiles.TabIndex = 4;
             this.tvFiles.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.tvFiles_AfterCheck);
+            this.tvFiles.BeforeCollapse += new System.Windows.Forms.TreeViewCancelEventHandler(this.tvFiles_BeforeCollapse);
+            this.tvFiles.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.tvFiles_BeforeExpand);
             // 
             // lblFiles
             // 
@@ -197,6 +204,14 @@ private void InitializeComponent()
             this.openFileDialog.Filter = "Архивы конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*";
             this.openFileDialog.Title = "Выберите файл архива конфигурации";
             // 
+            // ilTree
+            // 
+            this.ilTree.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("ilTree.ImageStream")));
+            this.ilTree.TransparentColor = System.Drawing.Color.Transparent;
+            this.ilTree.Images.SetKeyName(0, "folder_closed2.png");
+            this.ilTree.Images.SetKeyName(1, "folder_open2.png");
+            this.ilTree.Images.SetKeyName(2, "file.png");
+            // 
             // ctrlServerConn
             // 
             this.ctrlServerConn.Location = new System.Drawing.Point(12, 12);
@@ -247,5 +262,6 @@ private void InitializeComponent()
         private System.Windows.Forms.TextBox txtSrcFile;
         private System.Windows.Forms.CheckBox chkClearSpecificFiles;
         private System.Windows.Forms.OpenFileDialog openFileDialog;
+        private System.Windows.Forms.ImageList ilTree;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
index edb688555..ed47e959b 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -55,8 +55,14 @@ private class NodeInfo
             public bool IsDirectory { get; set; }
         }
 
+        // Ключи пиктограмм узлов дерева
+        private const string FolderClosedImageKey = "folder_closed2.png";
+        private const string FolderOpenImageKey = "folder_open2.png";
+        private const string FileImageKey = "file.png";
+
         private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами
         private bool uploadSettingsModified;     // последние выбранные настройки передачи были изменены
+        private TreeNode rootNode;               // корневой узел дерева
 
 
         /// 
@@ -65,8 +71,10 @@ private class NodeInfo
         public FrmUploadConfig()
         {
             InitializeComponent();
+
             serversSettings = new ServersSettings();
             uploadSettingsModified = false;
+            rootNode = null;
         }
 
 
@@ -88,7 +96,7 @@ private void ShowUploadSettings(ServersSettings.UploadSettings uploadSettings)
             {
                 gbOptions.Enabled = true;
                 txtSrcDir.Text = uploadSettings.SrcDir;
-                FillTreeView(uploadSettings);
+                FillTreeView(uploadSettings.SrcDir, uploadSettings.SelectedFiles);
                 txtSrcFile.Text = uploadSettings.SrcFile;
                 chkClearSpecificFiles.Checked = uploadSettings.ClearSpecificFiles;
                 btnUpload.Enabled = true;
@@ -103,30 +111,30 @@ private void ShowUploadSettings(ServersSettings.UploadSettings uploadSettings)
         /// 
         /// Заполнить дерево выбранных файлов
         /// 
-        private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
+        private void FillTreeView(string srcDir, List selectedFiles)
         {
             try
             {
                 tvFiles.BeginUpdate();
                 tvFiles.Nodes.Clear();
 
-                string srcDir = ScadaUtils.NormalDir(uploadSettings.SrcDir);
+                srcDir = ScadaUtils.NormalDir(srcDir);
                 int srcDirLen = srcDir.Length;
-                TreeNode rootNode = tvFiles.Nodes.Add(srcDir);
+                rootNode = tvFiles.Nodes.Add(srcDir);
 
                 // добавление узла базы конфигурации
-                HashSet selectedFiles = new HashSet(uploadSettings.SelectedFiles);
-                AddDirToTreeView(rootNode, srcDir + "BaseDAT\\", srcDirLen, selectedFiles);
+                HashSet selFiles = new HashSet(selectedFiles);
+                AddDirToTreeView(rootNode, srcDir + "BaseDAT\\", srcDirLen, selFiles);
 
                 // добавление узла интерфейса
-                AddDirToTreeView(rootNode, srcDir + "Interface\\", srcDirLen, selectedFiles);
+                AddDirToTreeView(rootNode, srcDir + "Interface\\", srcDirLen, selFiles);
 
                 // добавление узла Коммуникатора
                 string commDir = srcDir + "ScadaComm\\";
                 if (Directory.Exists(commDir))
                 {
                     TreeNode commNode = rootNode.Nodes.Add("ScadaComm\\");
-                    AddDirToTreeView(commNode, commDir + "Config\\", srcDirLen, selectedFiles);
+                    AddDirToTreeView(commNode, commDir + "Config\\", srcDirLen, selFiles);
                 }
 
                 // добавление узла Сервера
@@ -134,7 +142,7 @@ private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
                 if (Directory.Exists(serverDir))
                 {
                     TreeNode serverNode = rootNode.Nodes.Add("ScadaServer\\");
-                    AddDirToTreeView(serverNode, serverDir + "Config\\", srcDirLen, selectedFiles);
+                    AddDirToTreeView(serverNode, serverDir + "Config\\", srcDirLen, selFiles);
                 }
 
                 // добавление узла Вебстанции
@@ -142,8 +150,8 @@ private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
                 if (Directory.Exists(webDir))
                 {
                     TreeNode serverNode = rootNode.Nodes.Add("ScadaWeb\\");
-                    AddDirToTreeView(serverNode, webDir + "config\\", srcDirLen, selectedFiles);
-                    AddDirToTreeView(serverNode, webDir + "storage\\", srcDirLen, selectedFiles);
+                    AddDirToTreeView(serverNode, webDir + "config\\", srcDirLen, selFiles);
+                    AddDirToTreeView(serverNode, webDir + "storage\\", srcDirLen, selFiles);
                 }
 
                 rootNode.Expand();
@@ -157,20 +165,21 @@ private void FillTreeView(ServersSettings.UploadSettings uploadSettings)
         /// 
         /// Добавить директорию в дерево
         /// 
-        private void AddDirToTreeView(TreeNode parentNode, string dir, int rootDirLen, HashSet selectedFiles)
+        private void AddDirToTreeView(TreeNode parentNode, string dir, int rootDirLen, HashSet selFiles)
         {
-            AddDirToTreeView(parentNode, new DirectoryInfo(dir), rootDirLen, selectedFiles);
+            AddDirToTreeView(parentNode, new DirectoryInfo(dir), rootDirLen, selFiles);
         }
 
         /// 
         /// Добавить директорию в дерево
         /// 
         private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo, 
-            int rootDirLen, HashSet selectedFiles)
+            int rootDirLen, HashSet selFiles)
         {
             if (dirInfo.Exists)
             {
-                TreeNode dirNode = parentNode.Nodes.Add(dirInfo.Name + "\\");
+                TreeNode dirNode = parentNode.Nodes.Add(dirInfo.Name);
+                dirNode.ImageKey = dirNode.SelectedImageKey = FolderClosedImageKey;
                 string dirNodePath = ScadaUtils.NormalDir(dirInfo.FullName.Substring(rootDirLen));
                 dirNode.Tag = new NodeInfo() { Path = dirNodePath, IsDirectory = true };
 
@@ -179,7 +188,7 @@ private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo,
 
                 foreach (DirectoryInfo subdirInfo in subdirInfoArr)
                 {
-                    AddDirToTreeView(dirNode, subdirInfo, rootDirLen, selectedFiles);
+                    AddDirToTreeView(dirNode, subdirInfo, rootDirLen, selFiles);
                 }
 
                 // добавление файлов
@@ -190,16 +199,17 @@ private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo,
                     if (fileInfo.Extension != ".bak")
                     {
                         TreeNode fileNode = dirNode.Nodes.Add(fileInfo.Name);
+                        fileNode.ImageKey = fileNode.SelectedImageKey = FileImageKey;
                         string fileNodePath = fileInfo.FullName.Substring(rootDirLen);
                         fileNode.Tag = new NodeInfo() { Path = fileNodePath, IsDirectory = false };
 
-                        if (selectedFiles.Contains(fileNodePath))
+                        if (selFiles.Contains(fileNodePath))
                             fileNode.Checked = true;
                     }
                 }
 
                 // выбор узла и его дочерних узлов после того, как они добавлены в дерево
-                if (selectedFiles.Contains(dirNodePath))
+                if (selFiles.Contains(dirNodePath))
                 {
                     dirNode.Checked = true;
                     CheckAllChildNodes(dirNode, true);
@@ -224,6 +234,20 @@ private void CheckAllChildNodes(TreeNode treeNode, bool nodeChecked)
         /// 
         private bool ValidateUploadSettings()
         {
+            if (rbGetFromDir.Checked)
+            {
+                if (string.IsNullOrWhiteSpace(txtSrcDir.Text))
+                {
+                    ScadaUiUtils.ShowError(AppPhrases.ConfigDirRequired);
+                    return false;
+                }
+            }
+            else if (string.IsNullOrWhiteSpace(txtSrcFile.Text))
+            {
+                ScadaUiUtils.ShowError(AppPhrases.ConfigArcRequired);
+                return false;
+            }
+
             return true;
         }
 
@@ -238,7 +262,7 @@ private void ApplyUploadSettings(ServersSettings.UploadSettings uploadSettings)
             uploadSettings.ClearSpecificFiles = chkClearSpecificFiles.Checked;
 
             uploadSettings.SelectedFiles.Clear();
-            TraverseNodes(tvFiles.Nodes[0]);
+            TraverseNodes(rootNode);
 
             // Получить выбранные файлы на основе выбранных узлов дерева
             void TraverseNodes(TreeNode node)
@@ -321,6 +345,8 @@ private void FrmUploadConfig_Load(object sender, EventArgs e)
             // перевод формы
             Translator.TranslateForm(this, "ScadaAdmin.Remote.CtrlServerConn");
             Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmUploadConfig");
+            openFileDialog.Title = AppPhrases.ChooseArchiveFile;
+            openFileDialog.Filter = AppPhrases.ArchiveFileFilter;
             folderBrowserDialog.Description = AppPhrases.ChooseConfigDir;
 
             // загрузка настроек
@@ -361,20 +387,52 @@ private void uploadControl_Changed(object sender, EventArgs e)
 
         private void tvFiles_AfterCheck(object sender, TreeViewEventArgs e)
         {
-            // установка выбора для дочерних узлов
             if (e.Action != TreeViewAction.Unknown)
-                CheckAllChildNodes(e.Node, e.Node.Checked);
+            {
+                // установка или снятие выбора для дочерних узлов
+                TreeNode node = e.Node;
+                CheckAllChildNodes(node, node.Checked);
+
+                // снятие выбора родительских узлов
+                if (!node.Checked)
+                {
+                    while (node.Parent != null)
+                    {
+                        node = node.Parent;
+                        node.Checked = false;
+                    }
+                }
+            }
 
             uploadSettingsModified = true;
         }
 
+        private void tvFiles_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
+        {
+            // установка пиктограммы узла дерева
+            TreeNode node = e.Node;
+            if (node == rootNode || node.Tag is NodeInfo nodeInfo && nodeInfo.IsDirectory)
+                node.ImageKey = node.SelectedImageKey = FolderClosedImageKey;
+        }
+
+        private void tvFiles_BeforeExpand(object sender, TreeViewCancelEventArgs e)
+        {
+            // установка пиктограммы узла дерева
+            TreeNode node = e.Node;
+            if (node == rootNode || node.Tag is NodeInfo nodeInfo && nodeInfo.IsDirectory)
+                node.ImageKey = node.SelectedImageKey = FolderOpenImageKey;
+        }
+
         private void btnBrowseSrcDir_Click(object sender, EventArgs e)
         {
             // выбор директории конфигурации
             folderBrowserDialog.SelectedPath = txtSrcDir.Text.Trim();
 
             if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
+            {
                 txtSrcDir.Text = ScadaUtils.NormalDir(folderBrowserDialog.SelectedPath);
+                FillTreeView(txtSrcDir.Text, ctrlServerConn.SelectedSettings.Upload.SelectedFiles);
+            }
 
             txtSrcDir.Focus();
             txtSrcDir.DeselectAll();
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
index 3e7d47c4c..7fcbd03d8 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx
@@ -131,6 +131,57 @@
         FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS
         BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28
         tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs=
+
+  
+  
+    313, 17
+  
+  
+    
+        AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
+        LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
+        ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACC
+        CQAAAk1TRnQBSQFMAgEBAwEAAUgBAAFIAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
+        AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
+        AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
+        AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
+        AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm
+        AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM
+        AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA
+        ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz
+        AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ
+        AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM
+        AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA
+        AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA
+        AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ
+        AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/
+        AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA
+        AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm
+        ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ
+        Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz
+        AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA
+        AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM
+        AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM
+        ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM
+        Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA
+        AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM
+        AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ
+        AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz
+        AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm
+        AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw
+        AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD/2MAAfcKZjUAAfcC9ALz
+        BBkB3QFmFQAB7APrAm0B6gISARMCFAQAAuwC6wFtAeoBEgETARQBFQERAQcEAAH3A/QBGQLzAxkBZhUA
+        AXMJUgFLARQEAAHsARwBeQVSAVECSwFEBAAB9wT0A/MCGQFmFQAB7AF5AXoDWQE4AzIBSwEUBAAB7AF5
+        ARwBmgN6AlkBUwFSAUoBBwMAAfcB9QX0ARkB8wEZAWYVAAFzAZoCegNZATgCMgFRARMEAAHsAXoCHAR6
+        A1kBUQFEAwABtQP1BPQC8wFmFQAB7QKaAnoDWQE4ATIBUQETBAAB7AGaAXkBHAd6AVkBUQEHAgAB7wL/
+        AvUE9AEZAWYVAAEcAaACmgJ6BFkBUgESBAABHAGaAaABmQEcB3oBdAFzAgABtQP/AvUE9AFmFQABHAPD
+        A6ADWQFSARIEAAEcA6AEHAFzBewCAAG7BP8D9QL0AWYVAAYcAXkDoAFSARIEAAEcBaAFegHsBAABuwb/
+        AvUB9AFmFQABHAOaAnoG7AQAARwEoAF6BuwEAAG7Bv8B9wNmFQABHAEaBMMBHAkAARwBmgSgARwJAAG7
+        Bv8BtQHuAWYBBxUAAbwFHAG8CQABvAUcAbwJAAEJBv8BtQFmAQc2AAUJAbsBBwG7AfFVAAFCAU0BPgcA
+        AT4DAAEoAwABQAMAARADAAEBAQABAQUAAYAXAAP/AQAG/wIABP8BwAEHAgAE/wHAAQcCAAHAAQMBwAED
+        AcABBwIAAcABAwHAAQMBwAEHAgABwAEDAcABAQHAAQcCAAHAAQMBwAEBAcABBwIAAcABAwHAAQABwAEH
+        AgABwAEDAcABAAHAAQcCAAHAAQMBwAEAAcABBwIAAcABAwHAAQMBwAEHAgABwAEDAcABAwHAAQcCAAHA
+        AX8BwAF/AcABBwIAAcABfwHAAX8BwAEPAgAE/wHAAR8CAAb/AgAL
 
   
   
diff --git a/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
index 3a321fe38..57fbf4239 100644
--- a/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
+++ b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj
@@ -63,6 +63,12 @@
   
   
     
+    
+      PreserveNewest
+    
+    
+      PreserveNewest
+    
   
   
     
diff --git a/ScadaAgent/ScadaAgentSvc/svc_install.bat b/ScadaAgent/ScadaAgentSvc/svc_install.bat
new file mode 100644
index 000000000..efae5ba90
--- /dev/null
+++ b/ScadaAgent/ScadaAgentSvc/svc_install.bat
@@ -0,0 +1,2 @@
+cd /d "%~dp0"
+C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe ScadaAgentSvc.exe
diff --git a/ScadaAgent/ScadaAgentSvc/svc_uninstall.bat b/ScadaAgent/ScadaAgentSvc/svc_uninstall.bat
new file mode 100644
index 000000000..224054c40
--- /dev/null
+++ b/ScadaAgent/ScadaAgentSvc/svc_uninstall.bat
@@ -0,0 +1,2 @@
+cd /d "%~dp0"
+C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u ScadaAgentSvc.exe

From f1922aae64d2d0bbbdec2dbf2866ccf2f34413cf Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 16:18:38 +0300
Subject: [PATCH 071/100] ScadaAdmin: server status

---
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  22 ++
 .../ScadaAdmin/AppCode/DownloadUpload.cs      |  25 ++-
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |  18 ++
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |   5 +-
 .../Remote/FrmServerStatus.Designer.cs        | 204 +++++++++++++++++-
 .../ScadaAdmin/Remote/FrmServerStatus.cs      | 190 +++++++++++++++-
 .../ScadaAdmin/Remote/FrmServerStatus.resx    | 123 +++++++++++
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      |  13 +-
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |   3 +
 9 files changed, 580 insertions(+), 23 deletions(-)
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.resx

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
index ef02b5a3e..f608bd8a0 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs
@@ -49,6 +49,7 @@ static AppPhrases()
         public static string UnableCreateSession { get; private set; }
         public static string LoggedOn { get; private set; }
         public static string UnableLogin { get; private set; }
+        public static string ConnectAgentError { get; private set; }
         public static string DownloadDataEmpty { get; private set; }
         public static string DownloadSuccessful { get; private set; }
         public static string DownloadError { get; private set; }
@@ -239,6 +240,12 @@ static AppPhrases()
         public static string ConfigDirRequired { get; private set; }
         public static string ConfigArcRequired { get; private set; }
 
+        // Словарь ScadaAdmin.Remote.FrmServerStatus
+        public static string UndefinedSvcStatus { get; private set; }
+        public static string NormalSvcStatus { get; private set; }
+        public static string StoppedSvcStatus { get; private set; }
+        public static string ErrorSvcStatus { get; private set; }
+
         private static void SetToDefault()
         {
             BaseSDFFileNotFound = "Файл базы конфигурации в формате SDF {0} не найден.";
@@ -250,6 +257,7 @@ private static void SetToDefault()
             UnableCreateSession = "Не удалось создать сессию";
             LoggedOn = "Вход в систему выполнен";
             UnableLogin = "Не удалось войти в систему - {0}";
+            ConnectAgentError = "Ошибка при соединении с Агентом";
             DownloadDataEmpty = "Отсутствуют данные для скачивания";
             DownloadSuccessful = "Скачивание завершено успешно за {0} с.";
             DownloadError = "Ошибка при скачивании конфигурации";
@@ -428,6 +436,11 @@ private static void SetToDefault()
             ChooseConfigDir = "Выберите директорию конфигурации";
             ConfigDirRequired = "Укажите директорию конфигурации.";
             ConfigArcRequired = "Укажите имя файла архива конфигурации.";
+
+            UndefinedSvcStatus = "Не определён";
+            NormalSvcStatus = "Норма";
+            StoppedSvcStatus = "Остановлен";
+            ErrorSvcStatus = "Ошибка";
         }
 
         public static void Init()
@@ -447,6 +460,7 @@ public static void Init()
                 UnableCreateSession = dict.GetPhrase("UnableCreateSession", UnableCreateSession);
                 LoggedOn = dict.GetPhrase("LoggedOn", LoggedOn);
                 UnableLogin = dict.GetPhrase("UnableLogin", UnableLogin);
+                ConnectAgentError = dict.GetPhrase("ConnectAgentError", ConnectAgentError);
                 DownloadDataEmpty = dict.GetPhrase("DownloadDataEmpty", DownloadDataEmpty);
                 DownloadSuccessful = dict.GetPhrase("DownloadSuccessful", DownloadSuccessful);
                 DownloadError = dict.GetPhrase("DownloadError", DownloadError);
@@ -665,6 +679,14 @@ public static void Init()
                 ConfigDirRequired = dict.GetPhrase("ConfigDirRequired", ConfigDirRequired);
                 ConfigArcRequired = dict.GetPhrase("ConfigArcRequired", ConfigArcRequired);
             }
+
+            if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Remote.FrmServerStatus", out dict))
+            {
+                UndefinedSvcStatus = dict.GetPhrase("UndefinedSvcStatus", UndefinedSvcStatus);
+                NormalSvcStatus = dict.GetPhrase("NormalSvcStatus", NormalSvcStatus);
+                StoppedSvcStatus = dict.GetPhrase("StoppedSvcStatus", StoppedSvcStatus);
+                ErrorSvcStatus = dict.GetPhrase("ErrorSvcStatus", ErrorSvcStatus);
+            }
         }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index dcc9cf328..583bbfc03 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -101,7 +101,7 @@ private static void Connect(ServersSettings.ConnectionSettings connectionSetting
 
             // создание сессии
             if (client.CreateSession(out sessionID))
-                writer.WriteLine(AppPhrases.SessionCreated, sessionID);
+                writer?.WriteLine(AppPhrases.SessionCreated, sessionID);
             else
                 throw new ScadaException(AppPhrases.UnableCreateSession);
 
@@ -111,7 +111,7 @@ private static void Connect(ServersSettings.ConnectionSettings connectionSetting
 
             if (client.Login(out string errMsg, sessionID, connectionSettings.Username,
                 encryptedPassword, connectionSettings.ScadaInstance))
-                writer.WriteLine(AppPhrases.LoggedOn);
+                writer?.WriteLine(AppPhrases.LoggedOn);
             else
                 throw new ScadaException(string.Format(AppPhrases.UnableLogin, errMsg));
         }
@@ -411,5 +411,26 @@ public static bool UploadConfig(ServersSettings.ServerSettings serverSettings,
                 catch { }
             }
         }
+
+        /// 
+        /// Соединиться с Агентом
+        /// 
+        public static bool Connect(ServersSettings.ConnectionSettings connectionSettings,
+            out AgentSvcClient client, out long sessionID, out string errMsg)
+        {
+            try
+            {
+                Connect(connectionSettings, null, out client, out sessionID);
+                errMsg = "";
+                return true;
+            }
+            catch (Exception ex)
+            {
+                client = null;
+                sessionID = 0;
+                errMsg = AppPhrases.ConnectAgentError + ":\r\n" + ex.Message;
+                return false;
+            }
+        }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index 7439962b4..073de6f2d 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -11,6 +11,7 @@
     Unable to create session
     Logged on
     Unable to login - {0}
+    Error connecting to Agent
     No data to download
     Download completed successfully in {0} sec.
     Error downloading configuration
@@ -547,6 +548,23 @@
     Download
     Close
   
+  
+    Server Status
+    Actions
+    Connect
+    Disconnect
+    Status
+    Server service
+    Restart
+    Communicator service
+    Restart
+    Update time
+    Close
+    Undefined
+    Normal
+    Stopped
+    Error
+  
   
     Upload Configuration
     Upload options
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index 7cbf22e07..ceddb0e23 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -184,10 +184,7 @@ private void FrmDownloadConfig_Load(object sender, EventArgs e)
 
             // загрузка настроек
             if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
-            {
-                AppData.ErrLog.WriteError(errMsg);
-                ScadaUiUtils.ShowError(errMsg);
-            }
+                AppUtils.ProcError(errMsg);
 
             // отображение настроек
             ctrlServerConn.ServersSettings = serversSettings;
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs
index 91f5b949d..cc75a74f7 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs
@@ -29,11 +29,211 @@ protected override void Dispose(bool disposing)
         private void InitializeComponent()
         {
             this.components = new System.ComponentModel.Container();
+            this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn();
+            this.gbAction = new System.Windows.Forms.GroupBox();
+            this.btnConnect = new System.Windows.Forms.Button();
+            this.btnDisconnect = new System.Windows.Forms.Button();
+            this.gbStatus = new System.Windows.Forms.GroupBox();
+            this.lblServerStatus = new System.Windows.Forms.Label();
+            this.txtServerStatus = new System.Windows.Forms.TextBox();
+            this.btnRestartServer = new System.Windows.Forms.Button();
+            this.btnRestartComm = new System.Windows.Forms.Button();
+            this.txtCommStatus = new System.Windows.Forms.TextBox();
+            this.lblCommStatus = new System.Windows.Forms.Label();
+            this.txtUpdateTime = new System.Windows.Forms.TextBox();
+            this.lblUpdateTime = new System.Windows.Forms.Label();
+            this.btnClose = new System.Windows.Forms.Button();
+            this.timer = new System.Windows.Forms.Timer(this.components);
+            this.gbAction.SuspendLayout();
+            this.gbStatus.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // ctrlServerConn
+            // 
+            this.ctrlServerConn.Location = new System.Drawing.Point(12, 12);
+            this.ctrlServerConn.Name = "ctrlServerConn";
+            this.ctrlServerConn.ServersSettings = null;
+            this.ctrlServerConn.Size = new System.Drawing.Size(469, 55);
+            this.ctrlServerConn.TabIndex = 1;
+            this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged);
+            // 
+            // gbAction
+            // 
+            this.gbAction.Controls.Add(this.btnDisconnect);
+            this.gbAction.Controls.Add(this.btnConnect);
+            this.gbAction.Location = new System.Drawing.Point(12, 73);
+            this.gbAction.Name = "gbAction";
+            this.gbAction.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
+            this.gbAction.Size = new System.Drawing.Size(469, 55);
+            this.gbAction.TabIndex = 2;
+            this.gbAction.TabStop = false;
+            this.gbAction.Text = "Действия";
+            // 
+            // btnConnect
+            // 
+            this.btnConnect.Location = new System.Drawing.Point(13, 19);
+            this.btnConnect.Name = "btnConnect";
+            this.btnConnect.Size = new System.Drawing.Size(100, 23);
+            this.btnConnect.TabIndex = 0;
+            this.btnConnect.Text = "Соединиться";
+            this.btnConnect.UseVisualStyleBackColor = true;
+            this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);
+            // 
+            // btnDisconnect
+            // 
+            this.btnDisconnect.Location = new System.Drawing.Point(119, 19);
+            this.btnDisconnect.Name = "btnDisconnect";
+            this.btnDisconnect.Size = new System.Drawing.Size(100, 23);
+            this.btnDisconnect.TabIndex = 1;
+            this.btnDisconnect.Text = "Разъединиться";
+            this.btnDisconnect.UseVisualStyleBackColor = true;
+            this.btnDisconnect.Click += new System.EventHandler(this.btnDisconnect_Click);
+            // 
+            // gbStatus
+            // 
+            this.gbStatus.Controls.Add(this.txtUpdateTime);
+            this.gbStatus.Controls.Add(this.lblUpdateTime);
+            this.gbStatus.Controls.Add(this.btnRestartComm);
+            this.gbStatus.Controls.Add(this.txtCommStatus);
+            this.gbStatus.Controls.Add(this.lblCommStatus);
+            this.gbStatus.Controls.Add(this.btnRestartServer);
+            this.gbStatus.Controls.Add(this.txtServerStatus);
+            this.gbStatus.Controls.Add(this.lblServerStatus);
+            this.gbStatus.Location = new System.Drawing.Point(12, 134);
+            this.gbStatus.Name = "gbStatus";
+            this.gbStatus.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10);
+            this.gbStatus.Size = new System.Drawing.Size(469, 111);
+            this.gbStatus.TabIndex = 3;
+            this.gbStatus.TabStop = false;
+            this.gbStatus.Text = "Статус";
+            // 
+            // lblServerStatus
+            // 
+            this.lblServerStatus.AutoSize = true;
+            this.lblServerStatus.Location = new System.Drawing.Point(13, 24);
+            this.lblServerStatus.Name = "lblServerStatus";
+            this.lblServerStatus.Size = new System.Drawing.Size(91, 13);
+            this.lblServerStatus.TabIndex = 0;
+            this.lblServerStatus.Text = "Служба Сервера";
+            // 
+            // txtServerStatus
+            // 
+            this.txtServerStatus.Location = new System.Drawing.Point(150, 20);
+            this.txtServerStatus.Name = "txtServerStatus";
+            this.txtServerStatus.ReadOnly = true;
+            this.txtServerStatus.Size = new System.Drawing.Size(200, 20);
+            this.txtServerStatus.TabIndex = 1;
+            // 
+            // btnRestartServer
+            // 
+            this.btnRestartServer.Location = new System.Drawing.Point(356, 19);
+            this.btnRestartServer.Name = "btnRestartServer";
+            this.btnRestartServer.Size = new System.Drawing.Size(100, 23);
+            this.btnRestartServer.TabIndex = 2;
+            this.btnRestartServer.Text = "Перезапустить";
+            this.btnRestartServer.UseVisualStyleBackColor = true;
+            this.btnRestartServer.Click += new System.EventHandler(this.btnRestartServer_Click);
+            // 
+            // btnRestartComm
+            // 
+            this.btnRestartComm.Location = new System.Drawing.Point(356, 48);
+            this.btnRestartComm.Name = "btnRestartComm";
+            this.btnRestartComm.Size = new System.Drawing.Size(100, 23);
+            this.btnRestartComm.TabIndex = 5;
+            this.btnRestartComm.Text = "Перезапустить";
+            this.btnRestartComm.UseVisualStyleBackColor = true;
+            this.btnRestartComm.Click += new System.EventHandler(this.btnRestartComm_Click);
+            // 
+            // txtCommStatus
+            // 
+            this.txtCommStatus.Location = new System.Drawing.Point(150, 49);
+            this.txtCommStatus.Name = "txtCommStatus";
+            this.txtCommStatus.ReadOnly = true;
+            this.txtCommStatus.Size = new System.Drawing.Size(200, 20);
+            this.txtCommStatus.TabIndex = 4;
+            // 
+            // lblCommStatus
+            // 
+            this.lblCommStatus.AutoSize = true;
+            this.lblCommStatus.Location = new System.Drawing.Point(13, 53);
+            this.lblCommStatus.Name = "lblCommStatus";
+            this.lblCommStatus.Size = new System.Drawing.Size(129, 13);
+            this.lblCommStatus.TabIndex = 3;
+            this.lblCommStatus.Text = "Служба Коммуникатора";
+            // 
+            // txtUpdateTime
+            // 
+            this.txtUpdateTime.Location = new System.Drawing.Point(150, 78);
+            this.txtUpdateTime.Name = "txtUpdateTime";
+            this.txtUpdateTime.ReadOnly = true;
+            this.txtUpdateTime.Size = new System.Drawing.Size(200, 20);
+            this.txtUpdateTime.TabIndex = 7;
+            // 
+            // lblUpdateTime
+            // 
+            this.lblUpdateTime.AutoSize = true;
+            this.lblUpdateTime.Location = new System.Drawing.Point(13, 82);
+            this.lblUpdateTime.Name = "lblUpdateTime";
+            this.lblUpdateTime.Size = new System.Drawing.Size(103, 13);
+            this.lblUpdateTime.TabIndex = 6;
+            this.lblUpdateTime.Text = "Время обновления";
+            // 
+            // btnClose
+            // 
+            this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnClose.Location = new System.Drawing.Point(406, 251);
+            this.btnClose.Name = "btnClose";
+            this.btnClose.Size = new System.Drawing.Size(75, 23);
+            this.btnClose.TabIndex = 4;
+            this.btnClose.Text = "Закрыть";
+            this.btnClose.UseVisualStyleBackColor = true;
+            // 
+            // timer
+            // 
+            this.timer.Interval = 1000;
+            this.timer.Tick += new System.EventHandler(this.timer_Tick);
+            // 
+            // FrmServerStatus
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(800, 450);
-            this.Text = "FrmServerStatus";
+            this.CancelButton = this.btnClose;
+            this.ClientSize = new System.Drawing.Size(493, 286);
+            this.Controls.Add(this.btnClose);
+            this.Controls.Add(this.gbStatus);
+            this.Controls.Add(this.gbAction);
+            this.Controls.Add(this.ctrlServerConn);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+            this.MaximizeBox = false;
+            this.MinimizeBox = false;
+            this.Name = "FrmServerStatus";
+            this.ShowInTaskbar = false;
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+            this.Text = "Статус сервера";
+            this.Load += new System.EventHandler(this.FrmServerStatus_Load);
+            this.gbAction.ResumeLayout(false);
+            this.gbStatus.ResumeLayout(false);
+            this.gbStatus.PerformLayout();
+            this.ResumeLayout(false);
+
         }
 
         #endregion
+
+        private CtrlServerConn ctrlServerConn;
+        private System.Windows.Forms.GroupBox gbAction;
+        private System.Windows.Forms.Button btnConnect;
+        private System.Windows.Forms.Button btnDisconnect;
+        private System.Windows.Forms.GroupBox gbStatus;
+        private System.Windows.Forms.Label lblServerStatus;
+        private System.Windows.Forms.TextBox txtServerStatus;
+        private System.Windows.Forms.Button btnRestartServer;
+        private System.Windows.Forms.Button btnRestartComm;
+        private System.Windows.Forms.TextBox txtCommStatus;
+        private System.Windows.Forms.Label lblCommStatus;
+        private System.Windows.Forms.TextBox txtUpdateTime;
+        private System.Windows.Forms.Label lblUpdateTime;
+        private System.Windows.Forms.Button btnClose;
+        private System.Windows.Forms.Timer timer;
     }
 }
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
index abe6dd03a..fe928ffd2 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
@@ -1,19 +1,195 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Form for checking status of a remote server
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada;
+using Scada.UI;
+using ScadaAdmin.AgentSvcRef;
+using System;
 using System.Windows.Forms;
 
 namespace ScadaAdmin.Remote
 {
+    /// 
+    /// Form for checking status of a remote server
+    /// Форма для проверки статуса удалённого сервера
+    /// 
     public partial class FrmServerStatus : Form
     {
+        private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами
+        private AgentSvcClient client;           // клиент для взаимодействия с сервером
+        private long sessionID;                  // ид. сессии взаимодействия с сервером
+
+
+        /// 
+        /// Конструктор
+        /// 
         public FrmServerStatus()
         {
             InitializeComponent();
+            serversSettings = new ServersSettings();
+            client = null;
+            sessionID = 0;
+        }
+
+
+        /// 
+        /// Разъединиться с удалённым сервером
+        /// 
+        private void Disconnect()
+        {
+            timer.Stop();
+            client = null;
+            btnConnect.Enabled = true;
+            btnDisconnect.Enabled = false;
+            gbStatus.Enabled = false;
+            txtServerStatus.Text = txtCommStatus.Text = txtUpdateTime.Text = "";
+        }
+
+        /// 
+        /// Получить строковое представление статуса службы
+        /// 
+        private string StatusToString(ServiceStatus status)
+        {
+            switch (status)
+            {
+                case ServiceStatus.Normal:
+                    return AppPhrases.NormalSvcStatus;
+                case ServiceStatus.Stopped:
+                    return AppPhrases.StoppedSvcStatus;
+                case ServiceStatus.Error:
+                    return AppPhrases.ErrorSvcStatus;
+                default: // ServiceStatus.Undefined
+                    return AppPhrases.UndefinedSvcStatus;
+            }
+        }
+
+
+        private void FrmServerStatus_Load(object sender, EventArgs e)
+        {
+            // перевод формы
+            Translator.TranslateForm(this, "ScadaAdmin.Remote.CtrlServerConn");
+            Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmServerStatus");
+
+            // загрузка настроек
+            if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
+                AppUtils.ProcError(errMsg);
+
+            // отображение настроек
+            ctrlServerConn.ServersSettings = serversSettings;
+        }
+
+        private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e)
+        {
+            Disconnect();
+        }
+
+        private void btnConnect_Click(object sender, EventArgs e)
+        {
+            // соединение с удалённым сервером
+            if (!timer.Enabled)
+            {
+                btnConnect.Enabled = false;
+                btnDisconnect.Enabled = true;
+                gbStatus.Enabled = true;
+                timer.Start();
+            }
+        }
+
+        private void btnDisconnect_Click(object sender, EventArgs e)
+        {
+            // разъединение с удалённым сервером
+            Disconnect();
+        }
+
+        private void btnRestartServer_Click(object sender, EventArgs e)
+        {
+            // перезапуск службы Сервера на удалённом сервере
+            if (client != null)
+            {
+                if (client.ControlService(sessionID, ServiceApp.Server, ServiceCommand.Restart))
+                    ScadaUiUtils.ShowInfo(AppPhrases.ServerRestarted);
+                else
+                    ScadaUiUtils.ShowError(AppPhrases.UnableRestartServer);
+            }
+        }
+
+        private void btnRestartComm_Click(object sender, EventArgs e)
+        {
+            // перезапуск службы Коммуникатора на удалённом сервере
+            if (client != null)
+            {
+                if (client.ControlService(sessionID, ServiceApp.Communicator, ServiceCommand.Restart))
+                    ScadaUiUtils.ShowInfo(AppPhrases.CommRestarted);
+                else
+                    ScadaUiUtils.ShowError(AppPhrases.UnableRestartComm);
+            }
+        }
+
+        private void timer_Tick(object sender, EventArgs e)
+        {
+            timer.Stop();
+
+            // соединение
+            if (client == null)
+            {
+                if (!DownloadUpload.Connect(ctrlServerConn.SelectedSettings.Connection, 
+                    out client, out sessionID, out string errMsg))
+                {
+                    Disconnect();
+                    ScadaUiUtils.ShowError(errMsg);
+                }
+            }
+
+            // запрос данных
+            if (client != null)
+            {
+                ServiceStatus status;
+
+                try
+                {
+                    txtServerStatus.Text = client.GetServiceStatus(out status, sessionID, ServiceApp.Server) ?
+                        StatusToString(status) : "---";
+                }
+                catch (Exception ex)
+                {
+                    txtServerStatus.Text = ex.Message;
+                }
+
+                try
+                {
+                    txtCommStatus.Text = client.GetServiceStatus(out status, sessionID, ServiceApp.Communicator) ?
+                        StatusToString(status) : "---";
+                }
+                catch (Exception ex)
+                {
+                    txtCommStatus.Text = ex.Message;
+                }
+
+                txtUpdateTime.Text = DateTime.Now.ToLocalizedString();
+                timer.Start();
+            }
         }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.resx
new file mode 100644
index 000000000..e22c5ac68
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.resx
@@ -0,0 +1,123 @@
+
+
+  
+  
+    
+    
+      
+        
+          
+            
+              
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+              
+            
+          
+          
+            
+              
+                
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+                
+              
+              
+            
+          
+        
+      
+    
+  
+  
+    text/microsoft-resx
+  
+  
+    2.0
+  
+  
+    System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    17, 17
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
index ed47e959b..9743aebac 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -120,7 +120,7 @@ private void FillTreeView(string srcDir, List selectedFiles)
 
                 srcDir = ScadaUtils.NormalDir(srcDir);
                 int srcDirLen = srcDir.Length;
-                rootNode = tvFiles.Nodes.Add(srcDir);
+                rootNode = tvFiles.Nodes.Add(srcDir.TrimEnd('\\'));
 
                 // добавление узла базы конфигурации
                 HashSet selFiles = new HashSet(selectedFiles);
@@ -133,7 +133,7 @@ private void FillTreeView(string srcDir, List selectedFiles)
                 string commDir = srcDir + "ScadaComm\\";
                 if (Directory.Exists(commDir))
                 {
-                    TreeNode commNode = rootNode.Nodes.Add("ScadaComm\\");
+                    TreeNode commNode = rootNode.Nodes.Add("ScadaComm");
                     AddDirToTreeView(commNode, commDir + "Config\\", srcDirLen, selFiles);
                 }
 
@@ -141,7 +141,7 @@ private void FillTreeView(string srcDir, List selectedFiles)
                 string serverDir = srcDir + "ScadaServer\\";
                 if (Directory.Exists(serverDir))
                 {
-                    TreeNode serverNode = rootNode.Nodes.Add("ScadaServer\\");
+                    TreeNode serverNode = rootNode.Nodes.Add("ScadaServer");
                     AddDirToTreeView(serverNode, serverDir + "Config\\", srcDirLen, selFiles);
                 }
 
@@ -149,7 +149,7 @@ private void FillTreeView(string srcDir, List selectedFiles)
                 string webDir = srcDir + "ScadaWeb\\";
                 if (Directory.Exists(webDir))
                 {
-                    TreeNode serverNode = rootNode.Nodes.Add("ScadaWeb\\");
+                    TreeNode serverNode = rootNode.Nodes.Add("ScadaWeb");
                     AddDirToTreeView(serverNode, webDir + "config\\", srcDirLen, selFiles);
                     AddDirToTreeView(serverNode, webDir + "storage\\", srcDirLen, selFiles);
                 }
@@ -351,10 +351,7 @@ private void FrmUploadConfig_Load(object sender, EventArgs e)
 
             // загрузка настроек
             if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
-            {
-                AppData.ErrLog.WriteError(errMsg);
-                ScadaUiUtils.ShowError(errMsg);
-            }
+                AppUtils.ProcError(errMsg);
 
             // отображение настроек
             ctrlServerConn.ServersSettings = serversSettings;
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index 0d1d8285b..6c9d710b3 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -275,6 +275,9 @@
     
       FrmDownloadConfig.cs
     
+    
+      FrmServerStatus.cs
+    
     
       FrmUploadConfig.cs
     

From f8c55ff59e038f3d21be34d63efc417551f41beb Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 20:17:48 +0300
Subject: [PATCH 072/100] ScadaAdmin: connection settings

---
 ScadaAdmin/Res/key.png                        | Bin 0 -> 430 bytes
 ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs   |  26 ++
 .../ScadaAdmin/AppCode/ServersSettings.cs     |  41 ++-
 ScadaAdmin/ScadaAdmin/AppCode/Settings.cs     |   8 +
 .../ScadaAdmin/Lang/ScadaAdmin.en-GB.xml      |  15 +
 .../Remote/CtrlServerConn.Designer.cs         |   3 +
 .../ScadaAdmin/Remote/CtrlServerConn.cs       | 121 +++++++-
 .../Remote/FrmConnSettings.Designer.cs        | 269 ++++++++++++++++++
 .../ScadaAdmin/Remote/FrmConnSettings.cs      | 151 ++++++++++
 .../ScadaAdmin/Remote/FrmConnSettings.resx    | 135 +++++++++
 .../ScadaAdmin/Remote/FrmDownloadConfig.cs    |   1 +
 .../ScadaAdmin/Remote/FrmServerStatus.cs      |   1 +
 .../ScadaAdmin/Remote/FrmUploadConfig.cs      |   1 +
 ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj       |   9 +
 ScadaData/ScadaData/ScadaUtils.Crypto.cs      |  10 +
 15 files changed, 777 insertions(+), 14 deletions(-)
 create mode 100644 ScadaAdmin/Res/key.png
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.cs
 create mode 100644 ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.resx

diff --git a/ScadaAdmin/Res/key.png b/ScadaAdmin/Res/key.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d388f0bf8d668f25ce2fa471a77cedabe64a5dc
GIT binary patch
literal 430
zcmV;f0a5;mP)t<+GOz&!0SJ`1bw{!@u8O7>-{0rMvdX+bihmS%*ttmy&G2hYvsgzqxz%S9$CGcLD+&MI
     public class ServersSettings
     {
+        /// 
+        /// Директория конфигурации по умолчанию
+        /// 
+        private const string DefConfigDir = @"C:\SCADA\";
+        /// 
+        /// Архив конфигурации по умолчанию
+        /// 
+        private const string DefConfigArc = @"C:\SCADA\config.zip";
+
         /// 
         /// Remote server connection settings
         /// Настройки подключения к удалённому серверу
@@ -168,8 +177,8 @@ public DownloadSettings()
             private void SetToDefault()
             {
                 SaveToDir = true;
-                DestDir = "";
-                DestFile = "";
+                DestDir = DefConfigDir;
+                DestFile = DefConfigArc;
                 IncludeSpecificFiles = true;
                 ImportBase = true;
             }
@@ -182,8 +191,8 @@ public void LoadFromXml(XmlNode xmlNode)
                     throw new ArgumentNullException("xmlNode");
 
                 SaveToDir = xmlNode.GetChildAsBool("SaveToDir", true);
-                DestDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("DestDir", @"C:\SCADA\"));
-                DestFile = xmlNode.GetChildAsString("DestFile", @"C:\SCADA\config.zip");
+                DestDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("DestDir", DefConfigDir));
+                DestFile = xmlNode.GetChildAsString("DestFile", DefConfigArc);
                 IncludeSpecificFiles = xmlNode.GetChildAsBool("IncludeSpecificFiles", true);
                 ImportBase = xmlNode.GetChildAsBool("ImportBase", true);
             }
@@ -245,9 +254,9 @@ public UploadSettings()
             private void SetToDefault()
             {
                 GetFromDir = true;
-                SrcDir = "";
+                SrcDir = DefConfigDir;
                 SelectedFiles.Clear();
-                SrcFile = "";
+                SrcFile = DefConfigArc;
                 ClearSpecificFiles = true;
             }
             /// 
@@ -259,7 +268,7 @@ public void LoadFromXml(XmlNode xmlNode)
                     throw new ArgumentNullException("xmlNode");
 
                 GetFromDir = xmlNode.GetChildAsBool("GetFromDir", true);
-                SrcDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("SrcDir", @"C:\SCADA\"));
+                SrcDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("SrcDir", DefConfigDir));
 
                 SelectedFiles.Clear();
                 XmlNode selectedFilesNode = xmlNode.SelectSingleNode("SelectedFiles");
@@ -272,7 +281,7 @@ public void LoadFromXml(XmlNode xmlNode)
                     }
                 }
 
-                SrcFile = xmlNode.GetChildAsString("SrcFile", @"C:\SCADA\config.zip");
+                SrcFile = xmlNode.GetChildAsString("SrcFile", DefConfigArc);
                 ClearSpecificFiles = xmlNode.GetChildAsBool("ClearSpecificFiles", true);
             }
             /// 
@@ -456,5 +465,21 @@ public bool Save(string fileName, out string errMsg)
                 return false;
             }
         }
+
+        /// 
+        /// Получить наименования существующих подключений
+        /// 
+        public HashSet GetExistingNames(string exceptName = null)
+        {
+            HashSet existingNames = new HashSet();
+
+            foreach (ServerSettings serverSettings in Servers.Values)
+            {
+                if (!string.Equals(serverSettings.Connection.Name, exceptName, StringComparison.Ordinal))
+                    existingNames.Add(serverSettings.Connection.Name);
+            }
+
+            return existingNames;
+        }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs b/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs
index f92d2b7a4..fa809facc 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs
@@ -125,6 +125,10 @@ public FormState()
             /// Получить или установить ширину дерева проводника
             /// 
             public int ExplorerWidth { get; set; }
+            /// 
+            /// Получить или установить наименование соединения с удалённым сервером
+            /// 
+            public string ServerConn { get; set; }
 
             /// 
             /// Установить состояние главной формы по умолчанию
@@ -138,6 +142,7 @@ public void SetToDefault()
                 Height = 0;
                 Maximized = false;
                 ExplorerWidth = 0;
+                ServerConn = "";
             }
         }
 
@@ -310,6 +315,8 @@ public void LoadFormState()
                                 FormSt.Maximized = bool.Parse(val);
                             else if (nameL == "explorerwidth")
                                 FormSt.ExplorerWidth = int.Parse(val);
+                            else if (nameL == "serverconn")
+                                FormSt.ServerConn = val;
                         }
                         catch
                         {
@@ -351,6 +358,7 @@ public bool SaveFormState(out string errMsg)
                 rootElem.AppendParamElem("Height", FormSt.Height);
                 rootElem.AppendParamElem("Maximized", FormSt.Maximized);
                 rootElem.AppendParamElem("ExplorerWidth", FormSt.ExplorerWidth);
+                rootElem.AppendParamElem("ServerConn", FormSt.ServerConn);
 
                 // сохранение в файле
                 xmlDoc.Save(AppData.AppDirs.ConfigDir + FormStateFileName);
diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
index 073de6f2d..566683197 100644
--- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
+++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml
@@ -537,6 +537,21 @@
     Create
     Edit
     Remove
+    Are you sure you want to delete the connection?
+  
+  
+    Connection Settings
+    Name
+    Server
+    Port
+    Username
+    Password
+    System instance
+    Secret key
+    Generate secret key
+    Empty field values are not allowed.
+    A connection with this name already exists.
+    Incorrect secret key.
   
   
     Download Configuration
diff --git a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs
index d99a29045..d48122186 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs
@@ -58,6 +58,7 @@ private void InitializeComponent()
             this.btnRemoveConn.TabIndex = 3;
             this.btnRemoveConn.Text = "Удалить";
             this.btnRemoveConn.UseVisualStyleBackColor = true;
+            this.btnRemoveConn.Click += new System.EventHandler(this.btnRemoveConn_Click);
             // 
             // btnEditConn
             // 
@@ -67,6 +68,7 @@ private void InitializeComponent()
             this.btnEditConn.TabIndex = 2;
             this.btnEditConn.Text = "Настроить";
             this.btnEditConn.UseVisualStyleBackColor = true;
+            this.btnEditConn.Click += new System.EventHandler(this.btnEditConn_Click);
             // 
             // btnCreateConn
             // 
@@ -76,6 +78,7 @@ private void InitializeComponent()
             this.btnCreateConn.TabIndex = 1;
             this.btnCreateConn.Text = "Создать";
             this.btnCreateConn.UseVisualStyleBackColor = true;
+            this.btnCreateConn.Click += new System.EventHandler(this.btnCreateConn_Click);
             // 
             // cbConnection
             // 
diff --git a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs
index 1008aaa68..d1fa8336b 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs
@@ -23,6 +23,7 @@
  * Modified : 2018
  */
 
+using Scada;
 using System;
 using System.ComponentModel;
 using System.Windows.Forms;
@@ -31,7 +32,7 @@ namespace ScadaAdmin.Remote
 {
     /// 
     /// Control for selecting a connection to a remote server
-    /// Элемент управления для выбора соединения с удалённым сервером
+    /// Элемент управления для выбора подключения к удалённому серверу
     /// 
     public partial class CtrlServerConn : UserControl
     {
@@ -60,7 +61,7 @@ public ServersSettings ServersSettings
             set
             {
                 serversSettings = value;
-                FillServerList();
+                FillConnList();
             }
         }
 
@@ -77,25 +78,30 @@ public ServersSettings.ServerSettings SelectedSettings
 
 
         /// 
-        /// Заполнить список серверов
+        /// Заполнить список подключений
         /// 
-        private void FillServerList()
+        private void FillConnList()
         {
             try
             {
                 cbConnection.BeginUpdate();
                 cbConnection.Items.Clear();
+                int selInd = 0;
 
                 if (serversSettings != null)
                 {
+                    string defConnName = AppData.Settings.FormSt.ServerConn;
+
                     foreach (ServersSettings.ServerSettings serverSettings in serversSettings.Servers.Values)
                     {
-                        cbConnection.Items.Add(serverSettings);
+                        int ind = cbConnection.Items.Add(serverSettings);
+                        if (string.Equals(serverSettings.Connection.Name, defConnName))
+                            selInd = ind;
                     }
                 }
 
                 if (cbConnection.Items.Count > 0)
-                    cbConnection.SelectedIndex = 0;
+                    cbConnection.SelectedIndex = selInd;
             }
             finally
             {
@@ -103,6 +109,33 @@ private void FillServerList()
             }
         }
 
+        /// 
+        /// Добавить настройки сервера в общие настройки и выпадающий список
+        /// 
+        private void AddToLists(ServersSettings.ServerSettings serverSettings)
+        {
+            // добавление в общие настройки
+            string connName = serverSettings.Connection.Name;
+            serversSettings.Servers.Add(connName, serverSettings);
+
+            // добавление в выпадающий список
+            int ind = serversSettings.Servers.IndexOfKey(connName);
+            if (ind >= 0)
+            {
+                cbConnection.Items.Insert(ind, serverSettings);
+                cbConnection.SelectedIndex = ind;
+            }
+        }
+
+        /// 
+        /// Сохранить настройки взаимодействия с удалёнными серверами
+        /// 
+        private void SaveServersSettings()
+        {
+            if (!serversSettings.Save(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg))
+                AppUtils.ProcError(errMsg);
+        }
+
         /// 
         /// Вызвать событие SelectedSettingsChanged
         /// 
@@ -121,7 +154,83 @@ private void OnSelectedSettingsChanged()
 
         private void cbConnection_SelectedIndexChanged(object sender, EventArgs e)
         {
+            btnCreateConn.Enabled = serversSettings != null;
+            btnEditConn.Enabled = btnRemoveConn.Enabled = SelectedSettings != null;
             OnSelectedSettingsChanged();
         }
+
+        private void btnCreateConn_Click(object sender, EventArgs e)
+        {
+            // создание новых настроек
+            ServersSettings.ServerSettings serverSettings = new ServersSettings.ServerSettings();
+            FrmConnSettings frmConnSettings = new FrmConnSettings()
+            {
+                ConnectionSettings = serverSettings.Connection,
+                ExistingNames = ServersSettings.GetExistingNames()
+            };
+
+            if (frmConnSettings.ShowDialog() == DialogResult.OK)
+            {
+                AddToLists(serverSettings);
+                SaveServersSettings();
+            }
+        }
+
+        private void btnEditConn_Click(object sender, EventArgs e)
+        {
+            // редактирование настроек
+            ServersSettings.ServerSettings serverSettings = SelectedSettings;
+            string oldName = serverSettings.Connection.Name;
+
+            FrmConnSettings frmConnSettings = new FrmConnSettings()
+            {
+                ConnectionSettings = serverSettings.Connection,
+                ExistingNames = ServersSettings.GetExistingNames(oldName)
+            };
+
+            if (frmConnSettings.ShowDialog() == DialogResult.OK)
+            {
+                // обновление наименования, если оно изменилось
+                if (!string.Equals(oldName, serverSettings.Connection.Name, StringComparison.Ordinal))
+                {
+                    serversSettings.Servers.Remove(oldName);
+                    cbConnection.BeginUpdate();
+                    cbConnection.Items.RemoveAt(cbConnection.SelectedIndex);
+                    AddToLists(serverSettings);
+                    cbConnection.EndUpdate();
+                }
+
+                // сохранение настроек
+                SaveServersSettings();
+            }
+        }
+
+        private void btnRemoveConn_Click(object sender, EventArgs e)
+        {
+            // удаление настроек
+            if (MessageBox.Show(AppPhrases.DeleteConnConfirm, CommonPhrases.QuestionCaption, 
+                MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes)
+            {
+                // удаление из общих настроек
+                ServersSettings.ServerSettings serverSettings = SelectedSettings;
+                serversSettings.Servers.Remove(serverSettings.Connection.Name);
+
+                // удаление из выпадающего списка
+                cbConnection.BeginUpdate();
+                int selInd = cbConnection.SelectedIndex;
+                cbConnection.Items.RemoveAt(selInd);
+
+                if (cbConnection.Items.Count > 0)
+                {
+                    cbConnection.SelectedIndex = selInd >= cbConnection.Items.Count ? 
+                        cbConnection.Items.Count - 1 : selInd;
+                }
+
+                cbConnection.EndUpdate();
+
+                // сохранение настроек
+                SaveServersSettings();
+            }
+        }
     }
 }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs
new file mode 100644
index 000000000..6a8feded9
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs
@@ -0,0 +1,269 @@
+namespace ScadaAdmin.Remote
+{
+    partial class FrmConnSettings
+    {
+        /// 
+        /// Required designer variable.
+        /// 
+        private System.ComponentModel.IContainer components = null;
+
+        /// 
+        /// Clean up any resources being used.
+        /// 
+        /// true if managed resources should be disposed; otherwise, false.
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// 
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// 
+        private void InitializeComponent()
+        {
+            this.components = new System.ComponentModel.Container();
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmConnSettings));
+            this.lblName = new System.Windows.Forms.Label();
+            this.txtName = new System.Windows.Forms.TextBox();
+            this.txtHost = new System.Windows.Forms.TextBox();
+            this.lblHost = new System.Windows.Forms.Label();
+            this.numPort = new System.Windows.Forms.NumericUpDown();
+            this.lblPort = new System.Windows.Forms.Label();
+            this.txtUsername = new System.Windows.Forms.TextBox();
+            this.lblUsername = new System.Windows.Forms.Label();
+            this.txtPassword = new System.Windows.Forms.TextBox();
+            this.lblPassword = new System.Windows.Forms.Label();
+            this.txtScadaInstance = new System.Windows.Forms.TextBox();
+            this.lblScadaInstance = new System.Windows.Forms.Label();
+            this.txtSecretKey = new System.Windows.Forms.TextBox();
+            this.lblSecretKey = new System.Windows.Forms.Label();
+            this.btnGenSecretKey = new System.Windows.Forms.Button();
+            this.btnOK = new System.Windows.Forms.Button();
+            this.btnCancel = new System.Windows.Forms.Button();
+            this.toolTip = new System.Windows.Forms.ToolTip(this.components);
+            ((System.ComponentModel.ISupportInitialize)(this.numPort)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // lblName
+            // 
+            this.lblName.AutoSize = true;
+            this.lblName.Location = new System.Drawing.Point(9, 9);
+            this.lblName.Name = "lblName";
+            this.lblName.Size = new System.Drawing.Size(83, 13);
+            this.lblName.TabIndex = 0;
+            this.lblName.Text = "Наименование";
+            // 
+            // txtName
+            // 
+            this.txtName.Location = new System.Drawing.Point(12, 25);
+            this.txtName.Name = "txtName";
+            this.txtName.Size = new System.Drawing.Size(250, 20);
+            this.txtName.TabIndex = 1;
+            // 
+            // txtHost
+            // 
+            this.txtHost.Location = new System.Drawing.Point(12, 64);
+            this.txtHost.Name = "txtHost";
+            this.txtHost.Size = new System.Drawing.Size(169, 20);
+            this.txtHost.TabIndex = 3;
+            // 
+            // lblHost
+            // 
+            this.lblHost.AutoSize = true;
+            this.lblHost.Location = new System.Drawing.Point(9, 48);
+            this.lblHost.Name = "lblHost";
+            this.lblHost.Size = new System.Drawing.Size(44, 13);
+            this.lblHost.TabIndex = 2;
+            this.lblHost.Text = "Сервер";
+            // 
+            // numPort
+            // 
+            this.numPort.Location = new System.Drawing.Point(187, 64);
+            this.numPort.Maximum = new decimal(new int[] {
+            65535,
+            0,
+            0,
+            0});
+            this.numPort.Name = "numPort";
+            this.numPort.Size = new System.Drawing.Size(75, 20);
+            this.numPort.TabIndex = 5;
+            this.numPort.Value = new decimal(new int[] {
+            10002,
+            0,
+            0,
+            0});
+            // 
+            // lblPort
+            // 
+            this.lblPort.AutoSize = true;
+            this.lblPort.Location = new System.Drawing.Point(184, 48);
+            this.lblPort.Name = "lblPort";
+            this.lblPort.Size = new System.Drawing.Size(32, 13);
+            this.lblPort.TabIndex = 4;
+            this.lblPort.Text = "Порт";
+            // 
+            // txtUsername
+            // 
+            this.txtUsername.Location = new System.Drawing.Point(12, 103);
+            this.txtUsername.Name = "txtUsername";
+            this.txtUsername.Size = new System.Drawing.Size(250, 20);
+            this.txtUsername.TabIndex = 7;
+            // 
+            // lblUsername
+            // 
+            this.lblUsername.AutoSize = true;
+            this.lblUsername.Location = new System.Drawing.Point(9, 87);
+            this.lblUsername.Name = "lblUsername";
+            this.lblUsername.Size = new System.Drawing.Size(80, 13);
+            this.lblUsername.TabIndex = 6;
+            this.lblUsername.Text = "Пользователь";
+            // 
+            // txtPassword
+            // 
+            this.txtPassword.Location = new System.Drawing.Point(12, 142);
+            this.txtPassword.Name = "txtPassword";
+            this.txtPassword.Size = new System.Drawing.Size(250, 20);
+            this.txtPassword.TabIndex = 9;
+            this.txtPassword.UseSystemPasswordChar = true;
+            // 
+            // lblPassword
+            // 
+            this.lblPassword.AutoSize = true;
+            this.lblPassword.Location = new System.Drawing.Point(9, 126);
+            this.lblPassword.Name = "lblPassword";
+            this.lblPassword.Size = new System.Drawing.Size(45, 13);
+            this.lblPassword.TabIndex = 8;
+            this.lblPassword.Text = "Пароль";
+            // 
+            // txtScadaInstance
+            // 
+            this.txtScadaInstance.Location = new System.Drawing.Point(12, 181);
+            this.txtScadaInstance.Name = "txtScadaInstance";
+            this.txtScadaInstance.Size = new System.Drawing.Size(250, 20);
+            this.txtScadaInstance.TabIndex = 11;
+            // 
+            // lblScadaInstance
+            // 
+            this.lblScadaInstance.AutoSize = true;
+            this.lblScadaInstance.Location = new System.Drawing.Point(9, 165);
+            this.lblScadaInstance.Name = "lblScadaInstance";
+            this.lblScadaInstance.Size = new System.Drawing.Size(112, 13);
+            this.lblScadaInstance.TabIndex = 10;
+            this.lblScadaInstance.Text = "Экземпляр системы";
+            // 
+            // txtSecretKey
+            // 
+            this.txtSecretKey.Location = new System.Drawing.Point(12, 230);
+            this.txtSecretKey.Multiline = true;
+            this.txtSecretKey.Name = "txtSecretKey";
+            this.txtSecretKey.Size = new System.Drawing.Size(250, 40);
+            this.txtSecretKey.TabIndex = 14;
+            // 
+            // lblSecretKey
+            // 
+            this.lblSecretKey.AutoSize = true;
+            this.lblSecretKey.Location = new System.Drawing.Point(9, 214);
+            this.lblSecretKey.Name = "lblSecretKey";
+            this.lblSecretKey.Size = new System.Drawing.Size(91, 13);
+            this.lblSecretKey.TabIndex = 12;
+            this.lblSecretKey.Text = "Секретный ключ";
+            // 
+            // btnGenSecretKey
+            // 
+            this.btnGenSecretKey.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
+            this.btnGenSecretKey.Image = ((System.Drawing.Image)(resources.GetObject("btnGenSecretKey.Image")));
+            this.btnGenSecretKey.Location = new System.Drawing.Point(242, 207);
+            this.btnGenSecretKey.Name = "btnGenSecretKey";
+            this.btnGenSecretKey.Size = new System.Drawing.Size(20, 20);
+            this.btnGenSecretKey.TabIndex = 13;
+            this.toolTip.SetToolTip(this.btnGenSecretKey, "Генерировать секретный ключ");
+            this.btnGenSecretKey.UseVisualStyleBackColor = true;
+            this.btnGenSecretKey.Click += new System.EventHandler(this.btnGenSecretKey_Click);
+            // 
+            // btnOK
+            // 
+            this.btnOK.Location = new System.Drawing.Point(106, 276);
+            this.btnOK.Name = "btnOK";
+            this.btnOK.Size = new System.Drawing.Size(75, 23);
+            this.btnOK.TabIndex = 15;
+            this.btnOK.Text = "OK";
+            this.btnOK.UseVisualStyleBackColor = true;
+            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
+            // 
+            // btnCancel
+            // 
+            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnCancel.Location = new System.Drawing.Point(187, 276);
+            this.btnCancel.Name = "btnCancel";
+            this.btnCancel.Size = new System.Drawing.Size(75, 23);
+            this.btnCancel.TabIndex = 16;
+            this.btnCancel.Text = "Отмена";
+            this.btnCancel.UseVisualStyleBackColor = true;
+            // 
+            // FrmConnSettings
+            // 
+            this.AcceptButton = this.btnOK;
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.btnCancel;
+            this.ClientSize = new System.Drawing.Size(274, 311);
+            this.Controls.Add(this.btnCancel);
+            this.Controls.Add(this.btnOK);
+            this.Controls.Add(this.btnGenSecretKey);
+            this.Controls.Add(this.txtSecretKey);
+            this.Controls.Add(this.lblSecretKey);
+            this.Controls.Add(this.txtScadaInstance);
+            this.Controls.Add(this.lblScadaInstance);
+            this.Controls.Add(this.lblPassword);
+            this.Controls.Add(this.txtPassword);
+            this.Controls.Add(this.txtUsername);
+            this.Controls.Add(this.lblUsername);
+            this.Controls.Add(this.lblPort);
+            this.Controls.Add(this.numPort);
+            this.Controls.Add(this.txtHost);
+            this.Controls.Add(this.lblHost);
+            this.Controls.Add(this.txtName);
+            this.Controls.Add(this.lblName);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+            this.MaximizeBox = false;
+            this.MinimizeBox = false;
+            this.Name = "FrmConnSettings";
+            this.ShowIcon = false;
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "Настройки соединения";
+            this.Load += new System.EventHandler(this.FrmConnSettings_Load);
+            ((System.ComponentModel.ISupportInitialize)(this.numPort)).EndInit();
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label lblName;
+        private System.Windows.Forms.TextBox txtName;
+        private System.Windows.Forms.TextBox txtHost;
+        private System.Windows.Forms.Label lblHost;
+        private System.Windows.Forms.NumericUpDown numPort;
+        private System.Windows.Forms.Label lblPort;
+        private System.Windows.Forms.TextBox txtUsername;
+        private System.Windows.Forms.Label lblUsername;
+        private System.Windows.Forms.TextBox txtPassword;
+        private System.Windows.Forms.Label lblPassword;
+        private System.Windows.Forms.TextBox txtScadaInstance;
+        private System.Windows.Forms.Label lblScadaInstance;
+        private System.Windows.Forms.TextBox txtSecretKey;
+        private System.Windows.Forms.Label lblSecretKey;
+        private System.Windows.Forms.Button btnGenSecretKey;
+        private System.Windows.Forms.Button btnOK;
+        private System.Windows.Forms.Button btnCancel;
+        private System.Windows.Forms.ToolTip toolTip;
+    }
+}
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.cs
new file mode 100644
index 000000000..4838a8ea8
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.cs
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : SCADA-Administrator
+ * Summary  : Remote server connection settings form
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada;
+using Scada.UI;
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace ScadaAdmin.Remote
+{
+    /// 
+    /// Remote server connection settings form
+    /// Форма настроек подключения к удалённому серверу
+    /// 
+    public partial class FrmConnSettings : Form
+    {
+        /// 
+        /// Конструктор
+        /// 
+        public FrmConnSettings()
+        {
+            InitializeComponent();
+        }
+
+
+        /// 
+        /// Получить или установить редактируемые настройки подключения
+        /// 
+        public ServersSettings.ConnectionSettings ConnectionSettings { get; set; }
+
+        /// 
+        /// Получить или установить существующие наименования настроек
+        /// 
+        public HashSet ExistingNames { get; set; }
+
+
+        /// 
+        /// Установить элементы управления в соответствии с настройками
+        /// 
+        private void SettingsToControls()
+        {
+            if (ConnectionSettings != null)
+            {
+                txtName.Text = ConnectionSettings.Name;
+                txtHost.Text = ConnectionSettings.Host;
+                numPort.SetValue(ConnectionSettings.Port);
+                txtUsername.Text = ConnectionSettings.Username;
+                txtPassword.Text = ConnectionSettings.Password;
+                txtScadaInstance.Text = ConnectionSettings.ScadaInstance;
+                txtSecretKey.Text = ScadaUtils.BytesToHex(ConnectionSettings.SecretKey);
+            }
+        }
+
+        /// 
+        /// Установить настройки в соответствии с элементами управления
+        /// 
+        private void ControlsToSettings()
+        {
+            if (ConnectionSettings != null)
+            {
+                ConnectionSettings.Name = txtName.Text.Trim();
+                ConnectionSettings.Host = txtHost.Text.Trim();
+                ConnectionSettings.Port = (int)numPort.Value;
+                ConnectionSettings.Username = txtUsername.Text.Trim();
+                ConnectionSettings.Password = txtPassword.Text;
+                ConnectionSettings.ScadaInstance = txtScadaInstance.Text.Trim();
+                ConnectionSettings.SecretKey = ScadaUtils.HexToBytes(txtSecretKey.Text.Trim());
+            }
+        }
+
+        /// 
+        /// Проверить значения элементов управления
+        /// 
+        private bool ValidateControls()
+        {
+            if (string.IsNullOrWhiteSpace(txtName.Text) ||
+                string.IsNullOrWhiteSpace(txtHost.Text) ||
+                string.IsNullOrWhiteSpace(txtUsername.Text) ||
+                string.IsNullOrWhiteSpace(txtPassword.Text) ||
+                string.IsNullOrWhiteSpace(txtScadaInstance.Text) ||
+                string.IsNullOrWhiteSpace(txtSecretKey.Text))
+            {
+                ScadaUiUtils.ShowError(AppPhrases.EmptyFieldsNotAllowed);
+                return false;
+            }
+
+            if (ExistingNames.Contains(txtName.Text.Trim()))
+            {
+                ScadaUiUtils.ShowError(AppPhrases.ConnNameDuplicated);
+                return false;
+            }
+
+            if (!ScadaUtils.HexToBytes(txtSecretKey.Text.Trim(), out byte[] bytes))
+            {
+                ScadaUiUtils.ShowError(AppPhrases.IncorrectSecretKey);
+                return false;
+            }
+
+            return true;
+        }
+
+
+        private void FrmConnSettings_Load(object sender, EventArgs e)
+        {
+            // перевод формы
+            Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmConnSettings", toolTip);
+
+            // отображение настроек
+            SettingsToControls();
+        }
+
+        private void btnGenSecretKey_Click(object sender, EventArgs e)
+        {
+            // генерация секретного ключа
+            txtSecretKey.Text = ScadaUtils.BytesToHex(ScadaUtils.GetRandomBytes(ScadaUtils.SecretKeySize));
+            txtSecretKey.Focus();
+        }
+
+        private void btnOK_Click(object sender, EventArgs e)
+        {
+            if (ValidateControls())
+            {
+                ControlsToSettings();
+                DialogResult = DialogResult.OK;
+            }
+        }
+    }
+}
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.resx
new file mode 100644
index 000000000..1758942e8
--- /dev/null
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.resx
@@ -0,0 +1,135 @@
+
+
+  
+  
+    
+    
+      
+        
+          
+            
+              
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+              
+            
+          
+          
+            
+              
+                
+                
+              
+              
+              
+              
+              
+            
+          
+          
+            
+              
+                
+              
+              
+            
+          
+        
+      
+    
+  
+  
+    text/microsoft-resx
+  
+  
+    2.0
+  
+  
+    System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+    System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+  
+  
+  
+    
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL
+        EwAACxMBAJqcGAAAAAd0SU1FB+IFDRAyEEEzoOEAAAEpSURBVDhPYxh8IMxe1ODUtsz/m+cE/Z/VYPl/
+        Qr7q/74syf/BNsI6UCX4wcoJ7v//f53///+vdf8/PJ8EpDf+//qy63+GF8t/qBL8YFKpwf//39f9f/+4
+        /X91ot7/j097////se5/vBMrcQZ0Zij///mm/f//z7P//3/f/P//t0X/753N/e+gxUacAZEOYqrV0TL/
+        /7+uARrQ9f/ppYT/zsa8/x31eJKgSgiDaEcRj+4suf//Xpb/tzPgfm2tw+MKlSIedGfL/f//PO//zZ3W
+        X0wUWc5AhYkHNXHi//8/CP/vZczxx8mAxxoqTDwoDBT6//9x7N9989Q/KosyP4AKEw8SHbn+vT6g9d1U
+        me2+sSp3EFSYeBDpIOroa8j+1kKDxxMqNDwBAwMAUEuGdf4YP7YAAAAASUVORK5CYII=
+
+  
+  
+    17, 17
+  
+
\ No newline at end of file
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
index ceddb0e23..b375b11d7 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs
@@ -255,6 +255,7 @@ private void btnDownload_Click(object sender, EventArgs e)
                     SaveServersSettings();
                 }
 
+                AppData.Settings.FormSt.ServerConn = serverSettings.Connection.Name;
                 DownloadConfig(serverSettings);
             }
         }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
index fe928ffd2..18b9207cb 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs
@@ -113,6 +113,7 @@ private void btnConnect_Click(object sender, EventArgs e)
                 btnConnect.Enabled = false;
                 btnDisconnect.Enabled = true;
                 gbStatus.Enabled = true;
+                AppData.Settings.FormSt.ServerConn = ctrlServerConn.SelectedSettings.Connection.Name;
                 timer.Start();
             }
         }
diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
index 9743aebac..7a65fae41 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs
@@ -467,6 +467,7 @@ private void btnUpload_Click(object sender, EventArgs e)
                 if (serverSettings.Upload.GetFromDir)
                     ConvertBaseToDAT(serverSettings.Upload.SrcDir);
 
+                AppData.Settings.FormSt.ServerConn = serverSettings.Connection.Name;
                 UploadConfig(serverSettings);
             }
         }
diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
index 6c9d710b3..499f3d47c 100644
--- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
+++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj
@@ -199,6 +199,12 @@
     
       CtrlServerConn.cs
     
+    
+      Form
+    
+    
+      FrmConnSettings.cs
+    
     
       Form
     
@@ -272,6 +278,9 @@
     
       CtrlServerConn.cs
     
+    
+      FrmConnSettings.cs
+    
     
       FrmDownloadConfig.cs
     
diff --git a/ScadaData/ScadaData/ScadaUtils.Crypto.cs b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
index d6f94860a..398852434 100644
--- a/ScadaData/ScadaData/ScadaUtils.Crypto.cs
+++ b/ScadaData/ScadaData/ScadaUtils.Crypto.cs
@@ -71,6 +71,16 @@ public static long GetRandomLong()
             return BitConverter.ToInt64(randomArr, 0);
         }
 
+        /// 
+        /// Получить случайный массив байт
+        /// 
+        public static byte[] GetRandomBytes(int count)
+        {
+            byte[] randomArr = new byte[count];
+            Rng.GetBytes(randomArr);
+            return randomArr;
+        }
+
         /// 
         /// Вычислить хеш-функцию MD5 по массиву байт
         /// 

From a7bbd6ce75da1814f2cee093f8b949c9ea1e8732 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 20:50:08 +0300
Subject: [PATCH 073/100] ScadaComm: write service status

---
 ScadaComm/ScadaCommCommon/CommUtils.cs        |  4 +-
 ScadaComm/ScadaCommSvc/Manager.cs             | 66 +++++++++++++++++--
 .../version-history/communicator-history.html |  5 +-
 3 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/ScadaComm/ScadaCommCommon/CommUtils.cs b/ScadaComm/ScadaCommCommon/CommUtils.cs
index 2705169d1..9a66fd0d2 100644
--- a/ScadaComm/ScadaCommCommon/CommUtils.cs
+++ b/ScadaComm/ScadaCommCommon/CommUtils.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2015
- * Modified : 2017
+ * Modified : 2018
  */
 
 using Scada.Data.Configuration;
diff --git a/ScadaComm/ScadaCommSvc/Manager.cs b/ScadaComm/ScadaCommSvc/Manager.cs
index f60e4964b..5f23d526f 100644
--- a/ScadaComm/ScadaCommSvc/Manager.cs
+++ b/ScadaComm/ScadaCommSvc/Manager.cs
@@ -42,6 +42,44 @@ namespace Scada.Comm.Svc
     /// 
     internal sealed class Manager
     {
+        /// 
+        /// Наименования состояний работы
+        /// 
+        private static class WorkStateNames
+        {
+            /// 
+            /// Статический конструктор
+            /// 
+            static WorkStateNames()
+            {
+                if (Localization.UseRussian)
+                {
+                    Normal = "норма";
+                    Stopped = "остановлен";
+                    Error = "ошибка";
+                }
+                else
+                {
+                    Normal = "normal";
+                    Stopped = "stopped";
+                    Error = "error";
+                }
+            }
+
+            /// 
+            /// Норма
+            /// 
+            public static readonly string Normal;
+            /// 
+            /// Остановлен
+            /// 
+            public static readonly string Stopped;
+            /// 
+            /// Ошибка
+            /// 
+            public static readonly string Error;
+        }
+
         /// 
         /// Имя основного Log-файла программы
         /// 
@@ -66,6 +104,7 @@ internal sealed class Manager
         private string infoFileName;              // полное имя файла информации
         private Thread startThread;               // поток повторения попыток запуска
         private DateTime startDT;                 // дата и время запуска работы
+        private string workState;                 // состояние работы
         private bool linesStarted;                // потоки линий связи запущены
         private string[] lineCaptions;            // обозначения линий связи
         private object lineCmdLock;               // объект для синхронизации выполнения команд над линиями связи
@@ -83,6 +122,7 @@ public Manager()
             infoFileName = "";
             startThread = null;
             startDT = DateTime.MinValue;
+            workState = "";
             linesStarted = false;
             lineCaptions = null;
             lineCmdLock = new object();
@@ -286,7 +326,7 @@ private void WriteInfo()
                 StringBuilder sbInfo = new StringBuilder();
 
                 TimeSpan workSpan = DateTime.Now - startDT;
-                string workStr = workSpan.Days > 0 ? workSpan.ToString(@"d\.hh\:mm\:ss") :
+                string workDur = workSpan.Days > 0 ? workSpan.ToString(@"d\.hh\:mm\:ss") :
                     workSpan.ToString(@"hh\:mm\:ss");
 
                 if (Localization.UseRussian)
@@ -295,7 +335,8 @@ private void WriteInfo()
                         .AppendLine("SCADA-Коммуникатор")
                         .AppendLine("------------------")
                         .Append("Запуск       : ").AppendLine(startDT.ToLocalizedString())
-                        .Append("Время работы : ").AppendLine(workStr)
+                        .Append("Время работы : ").AppendLine(workDur)
+                        .Append("Состояние    : ").AppendLine(workState)
                         .Append("Версия       : ").AppendLine(CommUtils.AppVersion)
                         .Append("SCADA-Сервер : ").AppendLine(Settings.Params.ServerUse ?
                             (ServerComm == null ? "не инициализирован" : ServerComm.CommStateDescr) :
@@ -310,7 +351,8 @@ private void WriteInfo()
                         .AppendLine("SCADA-Communicator")
                         .AppendLine("------------------")
                         .Append("Started        : ").AppendLine(startDT.ToLocalizedString())
-                        .Append("Execution time : ").AppendLine(workStr)
+                        .Append("Execution time : ").AppendLine(workDur)
+                        .Append("State          : ").AppendLine(workState)
                         .Append("Version        : ").AppendLine(CommUtils.AppVersion)
                         .Append("SCADA-Server   : ").AppendLine(Settings.Params.ServerUse ?
                             (ServerComm == null ? "not initialized" : ServerComm.CommStateDescr) :
@@ -398,6 +440,7 @@ private bool StartOperation()
             }
             else
             {
+                workState = WorkStateNames.Error;
                 WriteInfo();
                 return false;
             }
@@ -502,14 +545,20 @@ private bool StartThreads()
                     commandReader.StartThread();
                 }
 
-                // запуск потока записи информации о работе приложения
                 if (linesStarted)
                 {
+                    // запуск потока записи информации о работе приложения
                     infoThread = new Thread(new ThreadStart(WriteInfoExecute));
                     infoThread.Start();
-                }
 
-                return linesStarted;
+                    workState = WorkStateNames.Normal;
+                    return true;
+                }
+                else
+                {
+                    workState = WorkStateNames.Error;
+                    return false;
+                }
             }
             catch (Exception ex)
             {
@@ -595,6 +644,7 @@ private void StopThreads()
                 Thread.Sleep(ScadaUtils.ThreadDelay);
 
                 // запись информации о работе программы
+                workState = WorkStateNames.Stopped;
                 WriteInfo();
             }
             catch (Exception ex)
@@ -839,9 +889,11 @@ public void StartService()
 
                 // запуск работы
                 if (!StartOperation())
-                    AppLog.WriteAction(Localization.UseRussian ? 
+                {
+                    AppLog.WriteAction(Localization.UseRussian ?
                         "Нормальная работа программы невозможна." :
                         "Normal program execution is impossible.", Log.ActTypes.Error);
+                }
             }
             else
             {
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
index 421f6ec2e..ed61dc90a 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
@@ -10,7 +10,10 @@
 
     

История приложения Коммуникатор

-
5.1.0.2 (21.12.2017)
+    
5.1.0.3 (В разработке)
+- В файл состояния выводится состояние работы службы
+
+5.1.0.2 (21.12.2017)
 - Исправлена ошибка при разрыве соединения в канале связи UDP
 
 5.1.0.1 (18.10.2017)

From 97b02efa19ccc21faa30f0310ee9827b09d513d5 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 21:09:50 +0300
Subject: [PATCH 074/100] ScadaComm: update year

---
 .../Properties/AssemblyInfo.cs                |   2 +-
 ScadaComm/ScadaCommCtrl/FrmAbout.resx         | 923 +++++++++---------
 .../ScadaCommCtrl/Properties/AssemblyInfo.cs  |   2 +-
 .../ScadaCommMono/Properties/AssemblyInfo.cs  |   2 +-
 .../ScadaCommSvc/Properties/AssemblyInfo.cs   |   2 +-
 5 files changed, 465 insertions(+), 466 deletions(-)

diff --git a/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs
index 4958905b3..5ff05e896 100644
--- a/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs
+++ b/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyProduct("Rapid SCADA")]
-[assembly: AssemblyCopyright("Copyright © 2015-2016")]
+[assembly: AssemblyCopyright("Copyright © 2015-2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
diff --git a/ScadaComm/ScadaCommCtrl/FrmAbout.resx b/ScadaComm/ScadaCommCtrl/FrmAbout.resx
index 5ddd4b666..b5da92898 100644
--- a/ScadaComm/ScadaCommCtrl/FrmAbout.resx
+++ b/ScadaComm/ScadaCommCtrl/FrmAbout.resx
@@ -760,238 +760,237 @@
         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
-        +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
-        85ranFwGI//Z
+        +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
 
   
   
@@ -1634,236 +1633,236 @@
         adrD5CulR/ufzbbatPl6YzH5Wr6lviMP8Rk0d7CYwPt3ftnKONLYP32ACQEVFRUZg5Eco510EHLGi0CS
         813K5Uv34/LnMnYKf/0Yvi39JT4JeK3c1/o9fAPmj479+PuNRP8A7pvgvyROve/j/wAP92+ERvtOH3V/
         7P5zJW7tWO7fs4HtdGGOYy5VwOaa4jDPm6Vvrm69rYmhqSuhD3KoGItpX/3d/IlxHFY069oWtfvenFPU
-        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
+        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
 
   
 
\ No newline at end of file
diff --git a/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs
index abc535d59..8cb7e0207 100644
--- a/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs
+++ b/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyProduct("Rapid SCADA")]
-[assembly: AssemblyCopyright("Copyright © 2008-2016")]
+[assembly: AssemblyCopyright("Copyright © 2008-2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
diff --git a/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs
index 2b0c04c70..2a30f40de 100644
--- a/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs
+++ b/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyProduct("Rapid SCADA")]
-[assembly: AssemblyCopyright("Copyright © 2015-2016")]
+[assembly: AssemblyCopyright("Copyright © 2015-2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
diff --git a/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs
index 81571d64c..f099fa262 100644
--- a/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs
+++ b/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyProduct("Rapid SCADA")]
-[assembly: AssemblyCopyright("Copyright © 2006-2016")]
+[assembly: AssemblyCopyright("Copyright © 2006-2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 

From 7ee0eaaa29fd5f090f9d2a479f465c7ac644996e Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 21:10:05 +0300
Subject: [PATCH 075/100] ScadaAdmin: update year

---
 ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs b/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs
index 8642062b7..56a0a2c59 100644
--- a/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs
+++ b/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs
@@ -9,7 +9,7 @@
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyProduct("Rapid SCADA")]
-[assembly: AssemblyCopyright("Copyright © 2010-2017")]
+[assembly: AssemblyCopyright("Copyright © 2010-2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 

From e2b3d115320152e7daccd3ccc6b72919fea734f7 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 21:10:19 +0300
Subject: [PATCH 076/100] ScadaAgent: fix service command

---
 ScadaAgent/ScadaAgentCore/ScadaInstance.cs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
index e5cba5326..e5954f0e5 100644
--- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
+++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs
@@ -503,7 +503,11 @@ public bool ControlService(ServiceApp serviceApp, ServiceCommand command)
 
                 if (File.Exists(batchFileName))
                 {
-                    Process.Start(batchFileName);
+                    Process.Start(new ProcessStartInfo()
+                    {
+                        FileName = batchFileName,
+                        UseShellExecute = false
+                    });
                     return true;
                 }
                 else

From 194603bf46481bcdb1d9cc3b2bf59f5abd8bae42 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Sun, 13 May 2018 21:32:58 +0300
Subject: [PATCH 077/100] ScadaAdmin: settings form fix

---
 ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs
index 6a8feded9..7cd12e3f1 100644
--- a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs
+++ b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs
@@ -235,7 +235,7 @@ private void InitializeComponent()
             this.MaximizeBox = false;
             this.MinimizeBox = false;
             this.Name = "FrmConnSettings";
-            this.ShowIcon = false;
+            this.ShowInTaskbar = false;
             this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
             this.Text = "Настройки соединения";
             this.Load += new System.EventHandler(this.FrmConnSettings_Load);

From 8d08e60a683aef76507bd379466271d7a8c22ab2 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 14 May 2018 09:57:05 +0300
Subject: [PATCH 078/100] ScadaAgent: delete ScadaAgentCtrl and add
 ScadaAgentTest

---
 ScadaAgent/ScadaAgent.sln                     |  12 +-
 ScadaAgent/ScadaAgentCtrl/App.config          |  18 ---
 ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs |  87 ------------
 ScadaAgent/ScadaAgentCtrl/FrmMain.cs          | 104 --------------
 ScadaAgent/ScadaAgentTest/App.config          |  18 +++
 .../AgentSvcRef}/AgentSvc.wsdl                |   0
 .../AgentSvcRef}/Reference.cs                 |  86 +++++------
 .../AgentSvcRef}/Reference.svcmap             |  16 +--
 ...est.AgentSvcRef.BrowseResponse.datasource} |   2 +-
 ...ntSvcRef.CreateSessionResponse.datasource} |   2 +-
 ...Ref.GetAvailableConfigResponse.datasource} |   2 +-
 ...vcRef.GetServiceStatusResponse.datasource} |   2 +-
 ...Test.AgentSvcRef.LoginResponse.datasource} |   2 +-
 ...entSvcRef.UploadConfigResponse.datasource} |   2 +-
 .../AgentSvcRef}/configuration.svcinfo        |   2 +-
 .../AgentSvcRef}/configuration91.svcinfo      |   6 +-
 .../AgentSvcRef}/item.disco                   |   0
 .../Connected Services/AgentSvcRef/item.xsd}  |   0
 .../Connected Services/AgentSvcRef/item1.xsd} |   7 +
 .../Connected Services/AgentSvcRef/item2.xsd} |   0
 .../Connected Services/AgentSvcRef/item3.xsd} |   0
 .../Connected Services/AgentSvcRef/item4.xsd} |   0
 ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs |  90 ++++++++++++
 ScadaAgent/ScadaAgentTest/FrmMain.cs          | 134 ++++++++++++++++++
 .../FrmMain.resx                              |   0
 .../Program.cs                                |   2 +-
 .../Properties/AssemblyInfo.cs                |  16 +--
 .../Properties/Resources.Designer.cs          |   4 +-
 .../Properties/Resources.resx                 |   0
 .../Properties/Settings.Designer.cs           |   4 +-
 .../Properties/Settings.settings              |   0
 .../ScadaAgentTest.csproj}                    |  66 +++++----
 32 files changed, 366 insertions(+), 318 deletions(-)
 delete mode 100644 ScadaAgent/ScadaAgentCtrl/App.config
 delete mode 100644 ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs
 delete mode 100644 ScadaAgent/ScadaAgentCtrl/FrmMain.cs
 create mode 100644 ScadaAgent/ScadaAgentTest/App.config
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1 => ScadaAgentTest/Connected Services/AgentSvcRef}/AgentSvc.wsdl (100%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1 => ScadaAgentTest/Connected Services/AgentSvcRef}/Reference.cs (77%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1 => ScadaAgentTest/Connected Services/AgentSvcRef}/Reference.svcmap (70%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource => ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.BrowseResponse.datasource} (76%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource => ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.CreateSessionResponse.datasource} (75%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource => ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse.datasource} (75%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource => ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse.datasource} (75%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource => ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.LoginResponse.datasource} (76%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource => ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.UploadConfigResponse.datasource} (76%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1 => ScadaAgentTest/Connected Services/AgentSvcRef}/configuration.svcinfo (63%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1 => ScadaAgentTest/Connected Services/AgentSvcRef}/configuration91.svcinfo (98%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1 => ScadaAgentTest/Connected Services/AgentSvcRef}/item.disco (100%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/item3.xsd => ScadaAgentTest/Connected Services/AgentSvcRef/item.xsd} (100%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd => ScadaAgentTest/Connected Services/AgentSvcRef/item1.xsd} (92%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/item31.xsd => ScadaAgentTest/Connected Services/AgentSvcRef/item2.xsd} (100%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd => ScadaAgentTest/Connected Services/AgentSvcRef/item3.xsd} (100%)
 rename ScadaAgent/{ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd => ScadaAgentTest/Connected Services/AgentSvcRef/item4.xsd} (100%)
 create mode 100644 ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs
 create mode 100644 ScadaAgent/ScadaAgentTest/FrmMain.cs
 rename ScadaAgent/{ScadaAgentCtrl => ScadaAgentTest}/FrmMain.resx (100%)
 rename ScadaAgent/{ScadaAgentCtrl => ScadaAgentTest}/Program.cs (93%)
 rename ScadaAgent/{ScadaAgentCtrl => ScadaAgentTest}/Properties/AssemblyInfo.cs (75%)
 rename ScadaAgent/{ScadaAgentCtrl => ScadaAgentTest}/Properties/Resources.Designer.cs (94%)
 rename ScadaAgent/{ScadaAgentCtrl => ScadaAgentTest}/Properties/Resources.resx (100%)
 rename ScadaAgent/{ScadaAgentCtrl => ScadaAgentTest}/Properties/Settings.Designer.cs (94%)
 rename ScadaAgent/{ScadaAgentCtrl => ScadaAgentTest}/Properties/Settings.settings (100%)
 rename ScadaAgent/{ScadaAgentCtrl/ScadaAgentCtrl.csproj => ScadaAgentTest/ScadaAgentTest.csproj} (69%)

diff --git a/ScadaAgent/ScadaAgent.sln b/ScadaAgent/ScadaAgent.sln
index d12f42104..52c5a1b70 100644
--- a/ScadaAgent/ScadaAgent.sln
+++ b/ScadaAgent/ScadaAgent.sln
@@ -7,12 +7,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScadaAgentCore", "ScadaAgen
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentMono", "ScadaAgentMono\ScadaAgentMono.csproj", "{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentCtrl", "ScadaAgentCtrl\ScadaAgentCtrl.csproj", "{67AEE6A7-0F2E-4273-8253-231E6BF3C943}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentNet", "ScadaAgentNet\ScadaAgentNet.csproj", "{C377283B-858B-4EFC-A560-E90FF2F26B03}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentSvc", "ScadaAgentSvc\ScadaAgentSvc.csproj", "{593318B1-3CB4-441B-B273-E3F37DF070B5}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaAgentTest", "ScadaAgentTest\ScadaAgentTest.csproj", "{C5B4F9FA-E4AE-418E-9CE8-8CB92C9CBFB8}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -27,10 +27,6 @@ Global
 		{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{45E8CD64-3FB3-4B29-BFD4-2823D8F2AA02}.Release|Any CPU.Build.0 = Release|Any CPU
-		{67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{67AEE6A7-0F2E-4273-8253-231E6BF3C943}.Release|Any CPU.Build.0 = Release|Any CPU
 		{C377283B-858B-4EFC-A560-E90FF2F26B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{C377283B-858B-4EFC-A560-E90FF2F26B03}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{C377283B-858B-4EFC-A560-E90FF2F26B03}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -39,6 +35,10 @@ Global
 		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{593318B1-3CB4-441B-B273-E3F37DF070B5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C5B4F9FA-E4AE-418E-9CE8-8CB92C9CBFB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C5B4F9FA-E4AE-418E-9CE8-8CB92C9CBFB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C5B4F9FA-E4AE-418E-9CE8-8CB92C9CBFB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C5B4F9FA-E4AE-418E-9CE8-8CB92C9CBFB8}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/ScadaAgent/ScadaAgentCtrl/App.config b/ScadaAgent/ScadaAgentCtrl/App.config
deleted file mode 100644
index e84d9ebed..000000000
--- a/ScadaAgent/ScadaAgentCtrl/App.config
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-     
-        
-    
-    
-        
-            
-                
-            
-        
-        
-            
-        
-    
-
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs
deleted file mode 100644
index efbdeb042..000000000
--- a/ScadaAgent/ScadaAgentCtrl/FrmMain.Designer.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-namespace Scada.Agent.Ctrl
-{
-    partial class FrmMain
-    {
-        /// 
-        /// Required designer variable.
-        /// 
-        private System.ComponentModel.IContainer components = null;
-
-        /// 
-        /// Clean up any resources being used.
-        /// 
-        /// true if managed resources should be disposed; otherwise, false.
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// 
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// 
-        private void InitializeComponent()
-        {
-            this.button1 = new System.Windows.Forms.Button();
-            this.button2 = new System.Windows.Forms.Button();
-            this.button3 = new System.Windows.Forms.Button();
-            this.SuspendLayout();
-            // 
-            // button1
-            // 
-            this.button1.Location = new System.Drawing.Point(12, 12);
-            this.button1.Name = "button1";
-            this.button1.Size = new System.Drawing.Size(100, 23);
-            this.button1.TabIndex = 0;
-            this.button1.Text = "Create Session";
-            this.button1.UseVisualStyleBackColor = true;
-            this.button1.Click += new System.EventHandler(this.button1_Click);
-            // 
-            // button2
-            // 
-            this.button2.Location = new System.Drawing.Point(118, 12);
-            this.button2.Name = "button2";
-            this.button2.Size = new System.Drawing.Size(100, 23);
-            this.button2.TabIndex = 1;
-            this.button2.Text = "Download";
-            this.button2.UseVisualStyleBackColor = true;
-            this.button2.Click += new System.EventHandler(this.button2_Click);
-            // 
-            // button3
-            // 
-            this.button3.Location = new System.Drawing.Point(224, 12);
-            this.button3.Name = "button3";
-            this.button3.Size = new System.Drawing.Size(100, 23);
-            this.button3.TabIndex = 2;
-            this.button3.Text = "Upload";
-            this.button3.UseVisualStyleBackColor = true;
-            this.button3.Click += new System.EventHandler(this.button3_Click);
-            // 
-            // FrmMain
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(800, 450);
-            this.Controls.Add(this.button3);
-            this.Controls.Add(this.button2);
-            this.Controls.Add(this.button1);
-            this.Name = "FrmMain";
-            this.Text = "Form1";
-            this.ResumeLayout(false);
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.Button button1;
-        private System.Windows.Forms.Button button2;
-        private System.Windows.Forms.Button button3;
-    }
-}
-
diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs b/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
deleted file mode 100644
index 2b9480659..000000000
--- a/ScadaAgent/ScadaAgentCtrl/FrmMain.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using Scada.Agent.Ctrl.ServiceReference1;
-using System;
-using System.IO;
-using System.Windows.Forms;
-
-namespace Scada.Agent.Ctrl
-{
-    public partial class FrmMain : Form
-    {
-        private long sessionID = 0;
-
-
-        public FrmMain()
-        {
-            InitializeComponent();
-        }
-
-
-        private void button1_Click(object sender, System.EventArgs e)
-        {
-            AgentSvcClient client = new AgentSvcClient();
-
-            try
-            {
-                client.CreateSession(out sessionID);
-                MessageBox.Show("Session ID = " + sessionID);
-
-                if (client.Login(sessionID, "admin", "", "Default", out string errMsg))
-                    MessageBox.Show("Login OK");
-                else
-                    MessageBox.Show(errMsg);
-            }
-            finally
-            {
-                client.Close();
-            }
-        }
-
-        private void button2_Click(object sender, System.EventArgs e)
-        {
-            AgentSvcClient client = new AgentSvcClient();
-
-            try
-            {
-                //Stream stream = client.DownloadFile(sessionID, new RelPath());
-                Stream stream = client.DownloadConfig(sessionID, new ConfigOptions());
-
-                if (stream == null)
-                {
-                    MessageBox.Show("Stream is null.");
-                }
-                else
-                {
-                    DateTime t0 = DateTime.UtcNow;
-                    byte[] buf = new byte[1024];
-                    Stream saver = File.Create(@"C:\SCADA\config.zip");
-                    int cnt;
-
-                    while ((cnt = stream.Read(buf, 0, buf.Length)) > 0)
-                    {
-                        saver.Write(buf, 0, cnt);
-                    }
-
-                    saver.Close();
-                    MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms");
-
-                    /*int cnt = stream.Read(buf, 0, buf.Length);
-                    string s = System.Text.Encoding.ASCII.GetString(buf, 0, cnt);
-                    MessageBox.Show(s);*/
-                }
-            }
-            finally
-            {
-                client.Close();
-            }
-        }
-
-        private void button3_Click(object sender, EventArgs e)
-        {
-            AgentSvcClient client = new AgentSvcClient();
-            Stream stream = null;
-
-            try
-            {
-                DateTime t0 = DateTime.UtcNow;
-                ConfigOptions configOptions = new ConfigOptions();
-
-                /*byte[] buffer = System.Text.Encoding.ASCII.GetBytes("I'm Muzzy");
-                stream = new MemoryStream(buffer.Length);
-                stream.Write(buffer, 0, buffer.Length);
-                stream.Position = 0;*/
-
-                stream = File.Open(@"C:\SCADA\config.zip", FileMode.Open);
-                client.UploadConfig(configOptions, sessionID, stream);
-                MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms");
-            }
-            finally
-            {
-                stream?.Close();
-                client.Close();
-            }
-        }
-    }
-}
diff --git a/ScadaAgent/ScadaAgentTest/App.config b/ScadaAgent/ScadaAgentTest/App.config
new file mode 100644
index 000000000..70e82ccb5
--- /dev/null
+++ b/ScadaAgent/ScadaAgentTest/App.config
@@ -0,0 +1,18 @@
+
+
+  
+    
+  
+  
+    
+      
+        
+      
+    
+    
+      
+    
+  
+
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/AgentSvc.wsdl
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/AgentSvc.wsdl
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/AgentSvc.wsdl
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.cs
similarity index 77%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.cs
index 64168ad01..1c5ad0b7e 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.cs	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.cs	
@@ -8,26 +8,26 @@
 // 
 //------------------------------------------------------------------------------
 
-namespace Scada.Agent.Ctrl.ServiceReference1 {
+namespace Scada.Agent.Test.AgentSvcRef {
     
     
     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
-    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.AgentSvc")]
+    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="AgentSvcRef.AgentSvc")]
     public interface AgentSvc {
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")]
-        Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse CreateSession(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request);
+        Scada.Agent.Test.AgentSvcRef.CreateSessionResponse CreateSession(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request);
         
         // CODEGEN: Generating message contract since the operation has multiple return values.
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")]
-        System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request);
+        System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")]
-        Scada.Agent.Ctrl.ServiceReference1.LoginResponse Login(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request);
+        Scada.Agent.Test.AgentSvcRef.LoginResponse Login(Scada.Agent.Test.AgentSvcRef.LoginRequest request);
         
         // CODEGEN: Generating message contract since the operation has multiple return values.
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")]
-        System.Threading.Tasks.Task LoginAsync(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request);
+        System.Threading.Tasks.Task LoginAsync(Scada.Agent.Test.AgentSvcRef.LoginRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")]
         bool ControlService(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command);
@@ -36,18 +36,18 @@ public interface AgentSvc {
         System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")]
-        Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse GetServiceStatus(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request);
+        Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse GetServiceStatus(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request);
         
         // CODEGEN: Generating message contract since the operation has multiple return values.
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")]
-        System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request);
+        System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")]
-        Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse GetAvailableConfig(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request);
+        Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse GetAvailableConfig(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request);
         
         // CODEGEN: Generating message contract since the operation has multiple return values.
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")]
-        System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request);
+        System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")]
         System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions configOptions);
@@ -57,17 +57,17 @@ public interface AgentSvc {
         
         // CODEGEN: Generating message contract since the operation UploadConfig is neither RPC nor document wrapped.
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")]
-        Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse UploadConfig(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request);
+        Scada.Agent.Test.AgentSvcRef.UploadConfigResponse UploadConfig(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")]
-        System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request);
+        System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")]
-        Scada.Agent.Ctrl.ServiceReference1.BrowseResponse Browse(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request);
+        Scada.Agent.Test.AgentSvcRef.BrowseResponse Browse(Scada.Agent.Test.AgentSvcRef.BrowseRequest request);
         
         // CODEGEN: Generating message contract since the operation has multiple return values.
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")]
-        System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request);
+        System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Test.AgentSvcRef.BrowseRequest request);
         
         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")]
         System.IO.Stream DownloadFile(long sessionID, Scada.Agent.RelPath relPath);
@@ -315,12 +315,12 @@ public BrowseResponse(bool BrowseResult, string[] directories, string[] files) {
     }
     
     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
-    public interface AgentSvcChannel : Scada.Agent.Ctrl.ServiceReference1.AgentSvc, System.ServiceModel.IClientChannel {
+    public interface AgentSvcChannel : Scada.Agent.Test.AgentSvcRef.AgentSvc, System.ServiceModel.IClientChannel {
     }
     
     [System.Diagnostics.DebuggerStepThroughAttribute()]
     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
-    public partial class AgentSvcClient : System.ServiceModel.ClientBase, Scada.Agent.Ctrl.ServiceReference1.AgentSvc {
+    public partial class AgentSvcClient : System.ServiceModel.ClientBase, Scada.Agent.Test.AgentSvcRef.AgentSvc {
         
         public AgentSvcClient() {
         }
@@ -342,38 +342,38 @@ public AgentSvcClient(System.ServiceModel.Channels.Binding binding, System.Servi
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.CreateSession(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request) {
+        Scada.Agent.Test.AgentSvcRef.CreateSessionResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.CreateSession(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request) {
             return base.Channel.CreateSession(request);
         }
         
         public bool CreateSession(out long sessionID) {
-            Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest();
-            Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).CreateSession(inValue);
+            Scada.Agent.Test.AgentSvcRef.CreateSessionRequest inValue = new Scada.Agent.Test.AgentSvcRef.CreateSessionRequest();
+            Scada.Agent.Test.AgentSvcRef.CreateSessionResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).CreateSession(inValue);
             sessionID = retVal.sessionID;
             return retVal.CreateSessionResult;
         }
         
-        public System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Ctrl.ServiceReference1.CreateSessionRequest request) {
+        public System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request) {
             return base.Channel.CreateSessionAsync(request);
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        Scada.Agent.Ctrl.ServiceReference1.LoginResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.Login(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request) {
+        Scada.Agent.Test.AgentSvcRef.LoginResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.Login(Scada.Agent.Test.AgentSvcRef.LoginRequest request) {
             return base.Channel.Login(request);
         }
         
         public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName, out string errMsg) {
-            Scada.Agent.Ctrl.ServiceReference1.LoginRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.LoginRequest();
+            Scada.Agent.Test.AgentSvcRef.LoginRequest inValue = new Scada.Agent.Test.AgentSvcRef.LoginRequest();
             inValue.sessionID = sessionID;
             inValue.username = username;
             inValue.encryptedPassword = encryptedPassword;
             inValue.scadaInstanceName = scadaInstanceName;
-            Scada.Agent.Ctrl.ServiceReference1.LoginResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).Login(inValue);
+            Scada.Agent.Test.AgentSvcRef.LoginResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).Login(inValue);
             errMsg = retVal.errMsg;
             return retVal.LoginResult;
         }
         
-        public System.Threading.Tasks.Task LoginAsync(Scada.Agent.Ctrl.ServiceReference1.LoginRequest request) {
+        public System.Threading.Tasks.Task LoginAsync(Scada.Agent.Test.AgentSvcRef.LoginRequest request) {
             return base.Channel.LoginAsync(request);
         }
         
@@ -386,37 +386,37 @@ public System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Sca
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetServiceStatus(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request) {
+        Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.GetServiceStatus(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request) {
             return base.Channel.GetServiceStatus(request);
         }
         
         public bool GetServiceStatus(long sessionID, Scada.Agent.ServiceApp serviceApp, out Scada.Agent.ServiceStatus status) {
-            Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest();
+            Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest inValue = new Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest();
             inValue.sessionID = sessionID;
             inValue.serviceApp = serviceApp;
-            Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetServiceStatus(inValue);
+            Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).GetServiceStatus(inValue);
             status = retVal.status;
             return retVal.GetServiceStatusResult;
         }
         
-        public System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusRequest request) {
+        public System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request) {
             return base.Channel.GetServiceStatusAsync(request);
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.GetAvailableConfig(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request) {
+        Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.GetAvailableConfig(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request) {
             return base.Channel.GetAvailableConfig(request);
         }
         
         public bool GetAvailableConfig(long sessionID, out Scada.Agent.ConfigParts configParts) {
-            Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest();
+            Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest inValue = new Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest();
             inValue.sessionID = sessionID;
-            Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).GetAvailableConfig(inValue);
+            Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).GetAvailableConfig(inValue);
             configParts = retVal.configParts;
             return retVal.GetAvailableConfigResult;
         }
         
-        public System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigRequest request) {
+        public System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request) {
             return base.Channel.GetAvailableConfigAsync(request);
         }
         
@@ -429,47 +429,47 @@ public System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.UploadConfig(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request) {
+        Scada.Agent.Test.AgentSvcRef.UploadConfigResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.UploadConfig(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request) {
             return base.Channel.UploadConfig(request);
         }
         
         public void UploadConfig(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) {
-            Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage inValue = new Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage();
+            Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage inValue = new Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage();
             inValue.ConfigOptions = ConfigOptions;
             inValue.SessionID = SessionID;
             inValue.Stream = Stream;
-            Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).UploadConfig(inValue);
+            Scada.Agent.Test.AgentSvcRef.UploadConfigResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).UploadConfig(inValue);
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        System.Threading.Tasks.Task Scada.Agent.Ctrl.ServiceReference1.AgentSvc.UploadConfigAsync(Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage request) {
+        System.Threading.Tasks.Task Scada.Agent.Test.AgentSvcRef.AgentSvc.UploadConfigAsync(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request) {
             return base.Channel.UploadConfigAsync(request);
         }
         
-        public System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) {
-            Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage inValue = new Scada.Agent.Ctrl.ServiceReference1.ConfigUploadMessage();
+        public System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) {
+            Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage inValue = new Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage();
             inValue.ConfigOptions = ConfigOptions;
             inValue.SessionID = SessionID;
             inValue.Stream = Stream;
-            return ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).UploadConfigAsync(inValue);
+            return ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).UploadConfigAsync(inValue);
         }
         
         [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
-        Scada.Agent.Ctrl.ServiceReference1.BrowseResponse Scada.Agent.Ctrl.ServiceReference1.AgentSvc.Browse(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request) {
+        Scada.Agent.Test.AgentSvcRef.BrowseResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.Browse(Scada.Agent.Test.AgentSvcRef.BrowseRequest request) {
             return base.Channel.Browse(request);
         }
         
         public bool Browse(long sessionID, Scada.Agent.RelPath relPath, out string[] directories, out string[] files) {
-            Scada.Agent.Ctrl.ServiceReference1.BrowseRequest inValue = new Scada.Agent.Ctrl.ServiceReference1.BrowseRequest();
+            Scada.Agent.Test.AgentSvcRef.BrowseRequest inValue = new Scada.Agent.Test.AgentSvcRef.BrowseRequest();
             inValue.sessionID = sessionID;
             inValue.relPath = relPath;
-            Scada.Agent.Ctrl.ServiceReference1.BrowseResponse retVal = ((Scada.Agent.Ctrl.ServiceReference1.AgentSvc)(this)).Browse(inValue);
+            Scada.Agent.Test.AgentSvcRef.BrowseResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).Browse(inValue);
             directories = retVal.directories;
             files = retVal.files;
             return retVal.BrowseResult;
         }
         
-        public System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Ctrl.ServiceReference1.BrowseRequest request) {
+        public System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Test.AgentSvcRef.BrowseRequest request) {
             return base.Channel.BrowseAsync(request);
         }
         
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.svcmap
similarity index 70%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.svcmap
index 273c3ad27..27dce9b1d 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.svcmap	
@@ -1,5 +1,5 @@
 
-
+
   
     false
     true
@@ -22,13 +22,13 @@
     
   
   
-    
-    
-    
-    
-    
-    
-    
+    
+    
+    
+    
+    
+    
+    
   
   
     
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.BrowseResponse.datasource
similarity index 76%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.BrowseResponse.datasource
index 8b5413e0f..0b62e42ed 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.BrowseResponse.datasource	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.BrowseResponse.datasource	
@@ -6,5 +6,5 @@
     cause the file to be unrecognizable by the program.
 -->
 
-   Scada.Agent.Ctrl.ServiceReference1.BrowseResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+   Scada.Agent.Test.AgentSvcRef.BrowseResponse
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.CreateSessionResponse.datasource
similarity index 75%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.CreateSessionResponse.datasource
index 3c959ba46..afebfb821 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse.datasource	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.CreateSessionResponse.datasource	
@@ -6,5 +6,5 @@
     cause the file to be unrecognizable by the program.
 -->
 
-   Scada.Agent.Ctrl.ServiceReference1.CreateSessionResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+   Scada.Agent.Test.AgentSvcRef.CreateSessionResponse
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse.datasource
similarity index 75%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse.datasource
index 0f904b4ce..477ee8f06 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse.datasource	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse.datasource	
@@ -6,5 +6,5 @@
     cause the file to be unrecognizable by the program.
 -->
 
-   Scada.Agent.Ctrl.ServiceReference1.GetAvailableConfigResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+   Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse.datasource
similarity index 75%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse.datasource
index 3e6fb6f86..1c7b71986 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse.datasource	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse.datasource	
@@ -6,5 +6,5 @@
     cause the file to be unrecognizable by the program.
 -->
 
-   Scada.Agent.Ctrl.ServiceReference1.GetServiceStatusResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+   Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.LoginResponse.datasource
similarity index 76%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.LoginResponse.datasource
index 26cdb25a0..bf22d3b92 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.LoginResponse.datasource	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.LoginResponse.datasource	
@@ -6,5 +6,5 @@
     cause the file to be unrecognizable by the program.
 -->
 
-   Scada.Agent.Ctrl.ServiceReference1.LoginResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+   Scada.Agent.Test.AgentSvcRef.LoginResponse
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.UploadConfigResponse.datasource
similarity index 76%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.UploadConfigResponse.datasource
index 158d4e2eb..759deeea0 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse.datasource	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.UploadConfigResponse.datasource	
@@ -6,5 +6,5 @@
     cause the file to be unrecognizable by the program.
 -->
 
-   Scada.Agent.Ctrl.ServiceReference1.UploadConfigResponse, ScadaAgentCtrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
+   Scada.Agent.Test.AgentSvcRef.UploadConfigResponse
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration.svcinfo
similarity index 63%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration.svcinfo
index 47aeac9b9..38bb543c7 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration.svcinfo	
@@ -5,6 +5,6 @@
     
   
   
-    
+    
   
 
\ No newline at end of file
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration91.svcinfo
similarity index 98%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration91.svcinfo
index aebb32cab..8031434d2 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration91.svcinfo	
@@ -1,5 +1,5 @@
 
-
+
   
     
       
@@ -112,7 +112,7 @@
     
   
   
-    
+    
       
         
           http://localhost:10002/ScadaAgent/ScadaAgentSvc/
@@ -127,7 +127,7 @@
           BasicHttpBinding_AgentSvc
         
         
-          ServiceReference1.AgentSvc
+          AgentSvcRef.AgentSvc
         
         
           System.ServiceModel.Configuration.AddressHeaderCollectionElement
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.disco
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.disco
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item3.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.xsd
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item3.xsd
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.xsd
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item1.xsd
similarity index 92%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item1.xsd
index 76a301227..e13908491 100644
--- a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item2.xsd	
+++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item1.xsd	
@@ -86,9 +86,16 @@
   
     
       
+      
     
   
   
+  
+    
+      
+    
+  
+  
   
     
       
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item31.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item2.xsd
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item31.xsd
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item2.xsd
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item3.xsd
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.xsd
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item3.xsd
diff --git a/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item4.xsd
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd
rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item4.xsd
diff --git a/ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs b/ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs
new file mode 100644
index 000000000..286481f92
--- /dev/null
+++ b/ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs
@@ -0,0 +1,90 @@
+namespace Scada.Agent.Test
+{
+    partial class FrmMain
+    {
+        /// 
+        /// Required designer variable.
+        /// 
+        private System.ComponentModel.IContainer components = null;
+
+        /// 
+        /// Clean up any resources being used.
+        /// 
+        /// true if managed resources should be disposed; otherwise, false.
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// 
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// 
+        private void InitializeComponent()
+        {
+            this.btnCreateSession = new System.Windows.Forms.Button();
+            this.btnDownload = new System.Windows.Forms.Button();
+            this.btnUpload = new System.Windows.Forms.Button();
+            this.SuspendLayout();
+            // 
+            // btnCreateSession
+            // 
+            this.btnCreateSession.Location = new System.Drawing.Point(12, 12);
+            this.btnCreateSession.Name = "btnCreateSession";
+            this.btnCreateSession.Size = new System.Drawing.Size(100, 23);
+            this.btnCreateSession.TabIndex = 0;
+            this.btnCreateSession.Text = "Create Session";
+            this.btnCreateSession.UseVisualStyleBackColor = true;
+            this.btnCreateSession.Click += new System.EventHandler(this.btnCreateSession_Click);
+            // 
+            // btnDownload
+            // 
+            this.btnDownload.Location = new System.Drawing.Point(12, 41);
+            this.btnDownload.Name = "btnDownload";
+            this.btnDownload.Size = new System.Drawing.Size(100, 23);
+            this.btnDownload.TabIndex = 1;
+            this.btnDownload.Text = "Download";
+            this.btnDownload.UseVisualStyleBackColor = true;
+            this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click);
+            // 
+            // btnUpload
+            // 
+            this.btnUpload.Location = new System.Drawing.Point(12, 70);
+            this.btnUpload.Name = "btnUpload";
+            this.btnUpload.Size = new System.Drawing.Size(100, 23);
+            this.btnUpload.TabIndex = 2;
+            this.btnUpload.Text = "Upload";
+            this.btnUpload.UseVisualStyleBackColor = true;
+            this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
+            // 
+            // FrmMain
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(284, 311);
+            this.Controls.Add(this.btnUpload);
+            this.Controls.Add(this.btnDownload);
+            this.Controls.Add(this.btnCreateSession);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+            this.MaximizeBox = false;
+            this.Name = "FrmMain";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "Agent Test";
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btnCreateSession;
+        private System.Windows.Forms.Button btnDownload;
+        private System.Windows.Forms.Button btnUpload;
+    }
+}
+
diff --git a/ScadaAgent/ScadaAgentTest/FrmMain.cs b/ScadaAgent/ScadaAgentTest/FrmMain.cs
new file mode 100644
index 000000000..d06a12a2a
--- /dev/null
+++ b/ScadaAgent/ScadaAgentTest/FrmMain.cs
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 Mikhail Shiryaev
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * 
+ * Product  : Rapid SCADA
+ * Module   : ScadaAgentTest
+ * Summary  : Simple application for testing Agent
+ * 
+ * Author   : Mikhail Shiryaev
+ * Created  : 2018
+ * Modified : 2018
+ */
+
+using Scada.Agent.Test.AgentSvcRef;
+using System;
+using System.IO;
+using System.Windows.Forms;
+
+namespace Scada.Agent.Test
+{
+    /// 
+    /// Simple application for testing Agent
+    /// Простое приложение для тестирования Агента
+    /// 
+    public partial class FrmMain : Form
+    {
+        private const string SecretKey = "5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1";
+        private const string DefConfigArc = @"C:\SCADA\config.zip";
+
+        private long sessionID = 0;
+
+
+        public FrmMain()
+        {
+            InitializeComponent();
+        }
+
+
+        private void btnCreateSession_Click(object sender, EventArgs e)
+        {
+            AgentSvcClient client = new AgentSvcClient();
+
+            try
+            {
+                if (client.CreateSession(out sessionID))
+                {
+                    MessageBox.Show("Session created: " + sessionID);
+
+                    string encPwd = CryptoUtils.EncryptPassword("12345", sessionID, ScadaUtils.HexToBytes(SecretKey));
+
+                    if (client.Login(sessionID, "admin", encPwd, "Default", out string errMsg))
+                        MessageBox.Show("Logged on.");
+                    else
+                        MessageBox.Show(errMsg);
+                }
+                else
+                {
+                    MessageBox.Show("Unable to create session.");
+                }
+            }
+            finally
+            {
+                client.Close();
+            }
+        }
+
+        private void btnDownload_Click(object sender, EventArgs e)
+        {
+            AgentSvcClient client = new AgentSvcClient();
+
+            try
+            {
+                Stream stream = client.DownloadConfig(sessionID, new ConfigOptions());
+
+                if (stream == null)
+                {
+                    MessageBox.Show("Download stream is null.");
+                }
+                else
+                {
+                    DateTime t0 = DateTime.UtcNow;
+                    byte[] buf = new byte[1024];
+
+                    using (FileStream fileStream = 
+                        File.Open(DefConfigArc, FileMode.Create, FileAccess.Write, FileShare.Read))
+                    {
+                        stream.CopyTo(fileStream);
+                    }
+
+                    stream.Close();
+                    MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms");
+                }
+            }
+            finally
+            {
+                client.Close();
+            }
+        }
+
+        private void btnUpload_Click(object sender, EventArgs e)
+        {
+            AgentSvcClient client = new AgentSvcClient();
+
+            try
+            {
+                DateTime t0 = DateTime.UtcNow;
+
+                using (FileStream fileStream = 
+                    File.Open(DefConfigArc, FileMode.Open, FileAccess.Read, FileShare.Read))
+                {
+                    client.UploadConfig(new ConfigOptions(), sessionID, fileStream);
+                }
+
+                MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms");
+            }
+            finally
+            {
+                client.Close();
+            }
+        }
+    }
+}
diff --git a/ScadaAgent/ScadaAgentCtrl/FrmMain.resx b/ScadaAgent/ScadaAgentTest/FrmMain.resx
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/FrmMain.resx
rename to ScadaAgent/ScadaAgentTest/FrmMain.resx
diff --git a/ScadaAgent/ScadaAgentCtrl/Program.cs b/ScadaAgent/ScadaAgentTest/Program.cs
similarity index 93%
rename from ScadaAgent/ScadaAgentCtrl/Program.cs
rename to ScadaAgent/ScadaAgentTest/Program.cs
index 89aa955a4..f104b38fc 100644
--- a/ScadaAgent/ScadaAgentCtrl/Program.cs
+++ b/ScadaAgent/ScadaAgentTest/Program.cs
@@ -1,7 +1,7 @@
 using System;
 using System.Windows.Forms;
 
-namespace Scada.Agent.Ctrl
+namespace Scada.Agent.Test
 {
     static class Program
     {
diff --git a/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentTest/Properties/AssemblyInfo.cs
similarity index 75%
rename from ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs
rename to ScadaAgent/ScadaAgentTest/Properties/AssemblyInfo.cs
index 2c7eab398..e233dfa8e 100644
--- a/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs
+++ b/ScadaAgent/ScadaAgentTest/Properties/AssemblyInfo.cs
@@ -1,16 +1,16 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
+using Scada.Agent;
+using System.Reflection;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
-[assembly: AssemblyTitle("ScadaAgentCtrl")]
+[assembly: AssemblyTitle("ScadaAgentTest")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ScadaAgentCtrl")]
-[assembly: AssemblyCopyright("Copyright ©  2018")]
+[assembly: AssemblyProduct("Rapid SCADA")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -20,7 +20,7 @@
 [assembly: ComVisible(false)]
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("67aee6a7-0f2e-4273-8253-231e6bf3c943")]
+[assembly: Guid("c5b4f9fa-e4ae-418e-9ce8-8cb92c9cbfb8")]
 
 // Version information for an assembly consists of the following four values:
 //
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion(AgentUtils.AppVersion)]
+[assembly: AssemblyFileVersion(AgentUtils.AppVersion)]
diff --git a/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs b/ScadaAgent/ScadaAgentTest/Properties/Resources.Designer.cs
similarity index 94%
rename from ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs
rename to ScadaAgent/ScadaAgentTest/Properties/Resources.Designer.cs
index 95e08f008..629ee0126 100644
--- a/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs
+++ b/ScadaAgent/ScadaAgentTest/Properties/Resources.Designer.cs
@@ -8,7 +8,7 @@
 // 
 //------------------------------------------------------------------------------
 
-namespace Scada.Agent.Ctrl.Properties {
+namespace Scada.Agent.Test.Properties {
     using System;
     
     
@@ -39,7 +39,7 @@ internal Resources() {
         internal static global::System.Resources.ResourceManager ResourceManager {
             get {
                 if (object.ReferenceEquals(resourceMan, null)) {
-                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Scada.Agent.Ctrl.Properties.Resources", typeof(Resources).Assembly);
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Scada.Agent.Test.Properties.Resources", typeof(Resources).Assembly);
                     resourceMan = temp;
                 }
                 return resourceMan;
diff --git a/ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx b/ScadaAgent/ScadaAgentTest/Properties/Resources.resx
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx
rename to ScadaAgent/ScadaAgentTest/Properties/Resources.resx
diff --git a/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs b/ScadaAgent/ScadaAgentTest/Properties/Settings.Designer.cs
similarity index 94%
rename from ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs
rename to ScadaAgent/ScadaAgentTest/Properties/Settings.Designer.cs
index 620cff267..f8ad98ccf 100644
--- a/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs
+++ b/ScadaAgent/ScadaAgentTest/Properties/Settings.Designer.cs
@@ -8,11 +8,11 @@
 // 
 //------------------------------------------------------------------------------
 
-namespace Scada.Agent.Ctrl.Properties {
+namespace Scada.Agent.Test.Properties {
     
     
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
     internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
         
         private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
diff --git a/ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings b/ScadaAgent/ScadaAgentTest/Properties/Settings.settings
similarity index 100%
rename from ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings
rename to ScadaAgent/ScadaAgentTest/Properties/Settings.settings
diff --git a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentTest/ScadaAgentTest.csproj
similarity index 69%
rename from ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj
rename to ScadaAgent/ScadaAgentTest/ScadaAgentTest.csproj
index 1f299194c..1af8f433f 100644
--- a/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj
+++ b/ScadaAgent/ScadaAgentTest/ScadaAgentTest.csproj
@@ -4,10 +4,10 @@
   
     Debug
     AnyCPU
-    {67AEE6A7-0F2E-4273-8253-231E6BF3C943}
+    {C5B4F9FA-E4AE-418E-9CE8-8CB92C9CBFB8}
     WinExe
-    Scada.Agent.Ctrl
-    ScadaAgentCtrl
+    Scada.Agent.Test
+    ScadaAgentTest
     v4.6.1
     512
     true
@@ -32,16 +32,24 @@
     4
   
   
+    
+      ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll
+    
+    
+      ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll
+    
     
-    
-    
+    
+    
     
     
+    
+    
     
     
   
   
-    
+    
       True
       True
       Reference.svcmap
@@ -67,38 +75,38 @@
       Resources.resx
       True
     
-    
-    
+    
+    
       Designer
     
-    
+    
       Designer
     
-    
+    
       Designer
     
-    
+    
       Designer
     
-    
+    
       Designer
     
-    
+    
       Reference.svcmap
     
-    
+    
       Reference.svcmap
     
-    
+    
       Reference.svcmap
     
-    
+    
       Reference.svcmap
     
-    
+    
       Reference.svcmap
     
-    
+    
       Reference.svcmap
     
     
@@ -114,32 +122,32 @@
   
     
   
+  
+    
+      {5163526d-91e4-414d-97fe-090e1e7fda6b}
+      ScadaAgentCore
+    
+  
   
     
   
   
-    
+    
   
   
-    
+    
   
   
-    
+    
   
   
-    
+    
   
   
-    
+    
       WCF Proxy Generator
       Reference.cs
     
   
-  
-    
-      {5163526d-91e4-414d-97fe-090e1e7fda6b}
-      ScadaAgentCore
-    
-  
   
 
\ No newline at end of file

From 6d8c7254ac45ff78847fed019221e005947f20ae Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 14 May 2018 09:57:20 +0300
Subject: [PATCH 079/100] ScadaAdmin: close download stream

---
 ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
index 583bbfc03..718bde63c 100644
--- a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
+++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs
@@ -281,6 +281,7 @@ public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings,
                     }
                 }
 
+                downloadStream.Close();
                 msg = string.Format(AppPhrases.DownloadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds);
                 writer.WriteLine(msg);
                 return true;

From 818e415fdb8bdcf4c436277d4c96e53af1c8a845 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 14 May 2018 10:36:34 +0300
Subject: [PATCH 080/100] ScadaAgent: dispose upload stream

---
 ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs b/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs
index 9150665da..041c5fc4e 100644
--- a/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs
+++ b/ScadaAgent/ScadaAgentNet/ConfigUploadMessage.cs
@@ -23,6 +23,7 @@
  * Modified : 2018
  */
 
+using System;
 using System.IO;
 using System.ServiceModel;
 
@@ -33,7 +34,7 @@ namespace Scada.Agent.Net
     /// Сообщение для загрузки конфигурации
     /// 
[MessageContract] - public class ConfigUploadMessage + public class ConfigUploadMessage : IDisposable { /// /// Идентификатор сессии @@ -52,5 +53,18 @@ public class ConfigUploadMessage /// [MessageBodyMember] public Stream Stream; + + + /// + /// Очистить ресурсы объекта + /// + public void Dispose() + { + if (Stream != null) + { + Stream.Close(); + Stream = null; + } + } } } From 56e5e5ee7f2e6b54391efed61f95b75ecc16f5b5 Mon Sep 17 00:00:00 2001 From: 2mik Date: Mon, 14 May 2018 12:43:40 +0300 Subject: [PATCH 081/100] ScadaAdmin: update default configuration --- ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml b/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml index 9324c9dac..ea12ef034 100644 --- a/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml +++ b/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml @@ -12,14 +12,17 @@ true - C:\SCADA\ - + C:\SCADA3\ + C:\SCADA\config.zip + true + true + true C:\SCADA\ - true - - + + C:\SCADA\config.zip + true \ No newline at end of file From 97367dd412005d115714fca8f105f6467821a739 Mon Sep 17 00:00:00 2001 From: 2mik Date: Mon, 14 May 2018 15:31:12 +0300 Subject: [PATCH 082/100] ScadaAdmin: fix timer --- .../Remote/FrmServerStatus.Designer.cs | 105 +++++++++--------- .../ScadaAdmin/Remote/FrmServerStatus.cs | 5 + 2 files changed, 58 insertions(+), 52 deletions(-) diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs index cc75a74f7..dcb76a5fe 100644 --- a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs @@ -31,17 +31,17 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn(); this.gbAction = new System.Windows.Forms.GroupBox(); - this.btnConnect = new System.Windows.Forms.Button(); this.btnDisconnect = new System.Windows.Forms.Button(); + this.btnConnect = new System.Windows.Forms.Button(); this.gbStatus = new System.Windows.Forms.GroupBox(); - this.lblServerStatus = new System.Windows.Forms.Label(); - this.txtServerStatus = new System.Windows.Forms.TextBox(); - this.btnRestartServer = new System.Windows.Forms.Button(); + this.txtUpdateTime = new System.Windows.Forms.TextBox(); + this.lblUpdateTime = new System.Windows.Forms.Label(); this.btnRestartComm = new System.Windows.Forms.Button(); this.txtCommStatus = new System.Windows.Forms.TextBox(); this.lblCommStatus = new System.Windows.Forms.Label(); - this.txtUpdateTime = new System.Windows.Forms.TextBox(); - this.lblUpdateTime = new System.Windows.Forms.Label(); + this.btnRestartServer = new System.Windows.Forms.Button(); + this.txtServerStatus = new System.Windows.Forms.TextBox(); + this.lblServerStatus = new System.Windows.Forms.Label(); this.btnClose = new System.Windows.Forms.Button(); this.timer = new System.Windows.Forms.Timer(this.components); this.gbAction.SuspendLayout(); @@ -69,16 +69,6 @@ private void InitializeComponent() this.gbAction.TabStop = false; this.gbAction.Text = "Действия"; // - // btnConnect - // - this.btnConnect.Location = new System.Drawing.Point(13, 19); - this.btnConnect.Name = "btnConnect"; - this.btnConnect.Size = new System.Drawing.Size(100, 23); - this.btnConnect.TabIndex = 0; - this.btnConnect.Text = "Соединиться"; - this.btnConnect.UseVisualStyleBackColor = true; - this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click); - // // btnDisconnect // this.btnDisconnect.Location = new System.Drawing.Point(119, 19); @@ -89,6 +79,16 @@ private void InitializeComponent() this.btnDisconnect.UseVisualStyleBackColor = true; this.btnDisconnect.Click += new System.EventHandler(this.btnDisconnect_Click); // + // btnConnect + // + this.btnConnect.Location = new System.Drawing.Point(13, 19); + this.btnConnect.Name = "btnConnect"; + this.btnConnect.Size = new System.Drawing.Size(100, 23); + this.btnConnect.TabIndex = 0; + this.btnConnect.Text = "Соединиться"; + this.btnConnect.UseVisualStyleBackColor = true; + this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click); + // // gbStatus // this.gbStatus.Controls.Add(this.txtUpdateTime); @@ -107,32 +107,22 @@ private void InitializeComponent() this.gbStatus.TabStop = false; this.gbStatus.Text = "Статус"; // - // lblServerStatus - // - this.lblServerStatus.AutoSize = true; - this.lblServerStatus.Location = new System.Drawing.Point(13, 24); - this.lblServerStatus.Name = "lblServerStatus"; - this.lblServerStatus.Size = new System.Drawing.Size(91, 13); - this.lblServerStatus.TabIndex = 0; - this.lblServerStatus.Text = "Служба Сервера"; - // - // txtServerStatus + // txtUpdateTime // - this.txtServerStatus.Location = new System.Drawing.Point(150, 20); - this.txtServerStatus.Name = "txtServerStatus"; - this.txtServerStatus.ReadOnly = true; - this.txtServerStatus.Size = new System.Drawing.Size(200, 20); - this.txtServerStatus.TabIndex = 1; + this.txtUpdateTime.Location = new System.Drawing.Point(150, 78); + this.txtUpdateTime.Name = "txtUpdateTime"; + this.txtUpdateTime.ReadOnly = true; + this.txtUpdateTime.Size = new System.Drawing.Size(200, 20); + this.txtUpdateTime.TabIndex = 7; // - // btnRestartServer + // lblUpdateTime // - this.btnRestartServer.Location = new System.Drawing.Point(356, 19); - this.btnRestartServer.Name = "btnRestartServer"; - this.btnRestartServer.Size = new System.Drawing.Size(100, 23); - this.btnRestartServer.TabIndex = 2; - this.btnRestartServer.Text = "Перезапустить"; - this.btnRestartServer.UseVisualStyleBackColor = true; - this.btnRestartServer.Click += new System.EventHandler(this.btnRestartServer_Click); + this.lblUpdateTime.AutoSize = true; + this.lblUpdateTime.Location = new System.Drawing.Point(13, 82); + this.lblUpdateTime.Name = "lblUpdateTime"; + this.lblUpdateTime.Size = new System.Drawing.Size(103, 13); + this.lblUpdateTime.TabIndex = 6; + this.lblUpdateTime.Text = "Время обновления"; // // btnRestartComm // @@ -161,22 +151,32 @@ private void InitializeComponent() this.lblCommStatus.TabIndex = 3; this.lblCommStatus.Text = "Служба Коммуникатора"; // - // txtUpdateTime + // btnRestartServer // - this.txtUpdateTime.Location = new System.Drawing.Point(150, 78); - this.txtUpdateTime.Name = "txtUpdateTime"; - this.txtUpdateTime.ReadOnly = true; - this.txtUpdateTime.Size = new System.Drawing.Size(200, 20); - this.txtUpdateTime.TabIndex = 7; + this.btnRestartServer.Location = new System.Drawing.Point(356, 19); + this.btnRestartServer.Name = "btnRestartServer"; + this.btnRestartServer.Size = new System.Drawing.Size(100, 23); + this.btnRestartServer.TabIndex = 2; + this.btnRestartServer.Text = "Перезапустить"; + this.btnRestartServer.UseVisualStyleBackColor = true; + this.btnRestartServer.Click += new System.EventHandler(this.btnRestartServer_Click); // - // lblUpdateTime + // txtServerStatus // - this.lblUpdateTime.AutoSize = true; - this.lblUpdateTime.Location = new System.Drawing.Point(13, 82); - this.lblUpdateTime.Name = "lblUpdateTime"; - this.lblUpdateTime.Size = new System.Drawing.Size(103, 13); - this.lblUpdateTime.TabIndex = 6; - this.lblUpdateTime.Text = "Время обновления"; + this.txtServerStatus.Location = new System.Drawing.Point(150, 20); + this.txtServerStatus.Name = "txtServerStatus"; + this.txtServerStatus.ReadOnly = true; + this.txtServerStatus.Size = new System.Drawing.Size(200, 20); + this.txtServerStatus.TabIndex = 1; + // + // lblServerStatus + // + this.lblServerStatus.AutoSize = true; + this.lblServerStatus.Location = new System.Drawing.Point(13, 24); + this.lblServerStatus.Name = "lblServerStatus"; + this.lblServerStatus.Size = new System.Drawing.Size(91, 13); + this.lblServerStatus.TabIndex = 0; + this.lblServerStatus.Text = "Служба Сервера"; // // btnClose // @@ -210,6 +210,7 @@ private void InitializeComponent() this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Статус сервера"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FrmServerStatus_FormClosed); this.Load += new System.EventHandler(this.FrmServerStatus_Load); this.gbAction.ResumeLayout(false); this.gbStatus.ResumeLayout(false); diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs index 18b9207cb..9c61fb72c 100644 --- a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs @@ -100,6 +100,11 @@ private void FrmServerStatus_Load(object sender, EventArgs e) ctrlServerConn.ServersSettings = serversSettings; } + private void FrmServerStatus_FormClosed(object sender, FormClosedEventArgs e) + { + timer.Stop(); + } + private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e) { Disconnect(); From 9a52ea7275d0ce1889dace8ff3ded68f87b44680 Mon Sep 17 00:00:00 2001 From: 2mik Date: Mon, 14 May 2018 20:25:41 +0300 Subject: [PATCH 083/100] ScadaAgent: fixes --- ScadaAgent/ScadaAgentCore/ScadaInstance.cs | 2 +- .../ScadaAgentMono/Config/ScadaAgentConfig.xml | 2 +- .../ScadaAgentSvc/Config/ScadaAgentConfig.xml | 7 +++++++ ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj | 13 +++++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 ScadaAgent/ScadaAgentSvc/Config/ScadaAgentConfig.xml diff --git a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs index e5954f0e5..3639898f4 100644 --- a/ScadaAgent/ScadaAgentCore/ScadaInstance.cs +++ b/ScadaAgent/ScadaAgentCore/ScadaInstance.cs @@ -329,7 +329,7 @@ private void PackDir(ZipArchive zipArchive, string srcDir, string entryPrefix, P { srcDir = ScadaUtils.NormalDir(srcDir); - if (!excludedPaths.Dirs.Contains(srcDir)) + if (!excludedPaths.Dirs.Contains(srcDir) && Directory.Exists(srcDir)) { DirectoryInfo srcDirInfo = new DirectoryInfo(srcDir); diff --git a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml index e2123f580..8f0ba006a 100644 --- a/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml +++ b/ScadaAgent/ScadaAgentMono/Config/ScadaAgentConfig.xml @@ -2,6 +2,6 @@ 5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1 - + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentSvc/Config/ScadaAgentConfig.xml b/ScadaAgent/ScadaAgentSvc/Config/ScadaAgentConfig.xml new file mode 100644 index 000000000..01055f6a6 --- /dev/null +++ b/ScadaAgent/ScadaAgentSvc/Config/ScadaAgentConfig.xml @@ -0,0 +1,7 @@ + + + 5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1 + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj index 57fbf4239..898c5b4f0 100644 --- a/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj +++ b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj @@ -85,5 +85,18 @@ ProjectInstaller.cs + + + Lang\ScadaData.en-GB.xml + PreserveNewest + + + Lang\ScadaData.ru-RU.xml + PreserveNewest + + + PreserveNewest + + \ No newline at end of file From 75d6bc61ee10ef03079c64c5afcdd84de9855ec1 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 16 May 2018 14:59:30 +0300 Subject: [PATCH 084/100] PlgSchBasicComp: update name --- .../ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs b/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs index 96c2f7343..bac7520a0 100644 --- a/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs +++ b/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs @@ -51,7 +51,7 @@ public override string Name { return Localization.UseRussian ? "Основные компоненты схем" : - "Basic scheme components"; + "Basic Scheme Components"; } } From 73762ac2fae565d7a8e9be1a2b29d46053c89764 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 16 May 2018 17:45:14 +0300 Subject: [PATCH 085/100] ScadaDoc: history in English --- ScadaDoc/ScadaDoc/ScadaDoc.csproj | 8 ++++++++ .../use-cases/remote-server-management.html | 15 +++++++++++++++ .../administrator-history.html | 16 ++++++++++++++++ .../version-history/communicator-history.html | 16 ++++++++++++++++ .../content/en/version-history/index.html | 17 +++++++++++++++++ .../en/version-history/server-history.html | 16 ++++++++++++++++ .../version-history/webstation-history.html | 19 +++++++++++++++++++ .../use-cases/remote-server-management.html | 15 +++++++++++++++ ScadaDoc/ScadaDoc/js/contents-en.js | 9 +++++++-- ScadaDoc/ScadaDoc/js/contents-ru.js | 1 + 10 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management.html create mode 100644 ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html create mode 100644 ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html create mode 100644 ScadaDoc/ScadaDoc/content/en/version-history/index.html create mode 100644 ScadaDoc/ScadaDoc/content/en/version-history/server-history.html create mode 100644 ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html create mode 100644 ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html diff --git a/ScadaDoc/ScadaDoc/ScadaDoc.csproj b/ScadaDoc/ScadaDoc/ScadaDoc.csproj index adcc7784e..cad89f6dc 100644 --- a/ScadaDoc/ScadaDoc/ScadaDoc.csproj +++ b/ScadaDoc/ScadaDoc/ScadaDoc.csproj @@ -22,6 +22,7 @@ + true @@ -118,6 +119,12 @@ + + + + + + @@ -258,6 +265,7 @@ + diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management.html b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management.html new file mode 100644 index 000000000..a83ac21f3 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management.html @@ -0,0 +1,15 @@ + + + + Managing Remote Server using Agent - Rapid SCADA Documentation + + + + + + +

Managing Remote Server using Agent

+ + + + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html new file mode 100644 index 000000000..db74f13e5 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html @@ -0,0 +1,16 @@ + + + + Administrator History - Rapid SCADA Documentation + + + + + + +

Administrator History

+ +
5.1.0.0 (In development)
+- Interaction with Agent for downloading and uploading configurations
+ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html new file mode 100644 index 000000000..afe4d378f --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html @@ -0,0 +1,16 @@ + + + + Communicator History - Rapid SCADA Documentation + + + + + + +

Communicator History

+ +
5.1.0.3 (In development)
+- The status of the service is displayed in the status file
+ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/index.html b/ScadaDoc/ScadaDoc/content/en/version-history/index.html new file mode 100644 index 000000000..c1c45b862 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/index.html @@ -0,0 +1,17 @@ + + + + Rapid SCADA Documentation + + + + + + + + + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/server-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/server-history.html new file mode 100644 index 000000000..968054dda --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/server-history.html @@ -0,0 +1,16 @@ + + + + Server History - Rapid SCADA Documentation + + + + + + +

Server History

+ +
5.1.0.3 (March 16, 2018)
+- Localization of the file filter for modules is fixed
+ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html new file mode 100644 index 000000000..65d6381de --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html @@ -0,0 +1,19 @@ + + + + Webstation History - Rapid SCADA Documentation + + + + + + +

Webstation History

+ +
5.0.5.0 (March 16, 2018)
+- Fixed error of jumping value formatting
+- Fixed error of formatting values after changing the culture
+- Queue for sending Ajax requests
+- Protect sensitive files from accessing through a browser
+ + diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html new file mode 100644 index 000000000..c3f7f8b75 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html @@ -0,0 +1,15 @@ + + + + Управление удалённым сервером с помощью Агента - Документация Rapid SCADA + + + + + + +

Управление удалённым сервером с помощью Агента

+ + + + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/js/contents-en.js b/ScadaDoc/ScadaDoc/js/contents-en.js index 804053588..feb7a5772 100644 --- a/ScadaDoc/ScadaDoc/js/contents-en.js +++ b/ScadaDoc/ScadaDoc/js/contents-en.js @@ -41,7 +41,12 @@ function addContents(context) { addArticle(context, "use-cases/", "Use Cases"); addArticle(context, "use-cases/modbus-protocol.html", "Connecting Devices Using Modbus Protocol", 1); addArticle(context, "use-cases/opc-standard.html", "Connecting Devices Using OPC Standard", 1); + addArticle(context, "use-cases/remote-server-management.html", "Managing Remote Server using Agent", 1); - /*addArticle(context, "", "Version History"); - addArticle(context, "version-history/scada-history.html", "History of Rapid SCADA", 1);*/ + addArticle(context, "version-history/", "Version History"); + addArticle(context, "version-history/scada-history.html", "History of Rapid SCADA", 1); + addArticle(context, "version-history/server-history.html", "Server History", 1); + addArticle(context, "version-history/communicator-history.html", "Communicator History", 1); + addArticle(context, "version-history/administrator-history.html", "Administrator History", 1); + addArticle(context, "version-history/webstation-history.html", "Webstation History", 1); } diff --git a/ScadaDoc/ScadaDoc/js/contents-ru.js b/ScadaDoc/ScadaDoc/js/contents-ru.js index c1a5f9da8..24ee4fa75 100644 --- a/ScadaDoc/ScadaDoc/js/contents-ru.js +++ b/ScadaDoc/ScadaDoc/js/contents-ru.js @@ -41,6 +41,7 @@ function addContents(context) { addArticle(context, "use-cases/", "Сценарии использования"); addArticle(context, "use-cases/modbus-protocol.html", "Подключение устройств по протоколу Modbus", 1); addArticle(context, "use-cases/opc-standard.html", "Подключение устройств с использованием стандарта OPC", 1); + addArticle(context, "use-cases/remote-server-management.html", "Управление удалённым сервером с помощью Агента", 1); addArticle(context, "version-history/", "История версий"); addArticle(context, "version-history/scada-history.html", "История Rapid SCADA", 1); From 8acd2fbfe2f3eb7abc0ba7775208976b95afb853 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 16 May 2018 17:45:26 +0300 Subject: [PATCH 086/100] ScadaDoc: history --- .../content/en/version-history/scada-history.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html index 6057781a9..133d615d4 100644 --- a/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html +++ b/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html @@ -9,5 +9,15 @@

Rapid SCADA History

+
Rapid SCADA 5.5.1 (March 16, 2018)
+  Server 5.1.0.3
+  Communicator 5.1.0.2
+    Modbus Driver 5.1.0.2
+    OPC Driver 5.0.2.0
+  Webstation 5.0.5.0
+    Basic Scheme Components 5.0.0.0
+  Administrator 5.0.0.2
+  Table Editor 5.0.1.0
+  Scheme Editor 5.2.1.0
From f0388e93de5fb659f99d1bded90ba299d46917f1 Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 17 May 2018 12:25:32 +0300 Subject: [PATCH 087/100] ScadaDoc: upload config --- ScadaDoc/ScadaDoc/ScadaDoc.csproj | 2 ++ .../server_download1_en.png | Bin 0 -> 13490 bytes .../server_upload1_en.png | Bin 0 -> 12652 bytes .../content/ru/modules/mod-auto-control.html | 2 +- .../server_download1_ru.png | Bin 0 -> 11178 bytes .../server_upload1_ru.png | Bin 0 -> 14054 bytes .../use-cases/remote-server-management.html | 33 ++++++++++++++++++ 7 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download1_en.png create mode 100644 ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload1_en.png create mode 100644 ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download1_ru.png create mode 100644 ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload1_ru.png diff --git a/ScadaDoc/ScadaDoc/ScadaDoc.csproj b/ScadaDoc/ScadaDoc/ScadaDoc.csproj index cad89f6dc..7d7669a7a 100644 --- a/ScadaDoc/ScadaDoc/ScadaDoc.csproj +++ b/ScadaDoc/ScadaDoc/ScadaDoc.csproj @@ -119,6 +119,7 @@ + @@ -265,6 +266,7 @@ + diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download1_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download1_en.png new file mode 100644 index 0000000000000000000000000000000000000000..13c930ef17bff8c90aa9e390ec352a0a836debd0 GIT binary patch literal 13490 zcma*O1zc2bw>CTqh=PD9f^)0@5wrHMD?qhop2j3=G`^3|;eX z{^vaJcb@m0_xrxhZ)W(dxo7Wv*IL)Q*0qB_DSpJkBEbTIKsYke5-K3j0|f9Ae*6%y zl#qM203VOO$bFOmq3-`OoAYA;%M&|kEeHsN+j;+b5XX#53Ib7qWF+3Jxyh52ztq^ z#^cd0O^H4}>TvR?cZH9r-+vl3`}x5G%iICeWa`;4maorN}ExVXq;i&?bKmSk!Cpf^lwc?lB1TbKwKcRlfHX!&7vS*zwiHY9x^X z0SKf58Y2UN%yB^=X`mNk$!MT^16A($jc)jtzAHja-FX2`&TA&x{ap(!)WgL%TxZYF z{>ciFgFw=W9{yr7kc$6@tXE`YPnSga_zFHTn!M!&o06Tm2vJ0CRtlx5C_~u3;Vn*9 z=w~^2EFWF{a5J5ng>WM%ith$i>#G4^p&g*C7m> zUxixi+|L&-3;SN)joNj=ctK*BctebRZ#IzY0{PrIbA}v$9`n#E{rT6? zGRWfvJXM%d4ea#v#T&>p&Z0ejnxJ6St>3;w!?a{6Y`m&j4XekoyZbp!_Ro?@E(d12 z?l(H~6Kgk%Mt5IY1nkc|KC#B+!ft&THt?Au$1s#u)K&44C#!R@~`b$tPErhGuyzGmXgcjt`-MB$mMj zPqf6nqq!2|F$83T7)@O%6j(F89psY@Hezk^#}S@fRn1(1z?|WwS=)CKY*bX^2(rmB zGXOW8;MwJ|i(48W*}l=l?=Dgxa%R((V57^*x=G{6ZE_sW1ev~E5=)Is@(gqqIYYw) zJq|s-xw$#SlQd1M{(J{Py|YIyirZ&d zM&jjz1M3#d=3GA&3qLW!AZsPam)F0pW*UL!M-_ogrun5Cd;MC z4A(=3R8SOI)CRTvneOr49}bXM#UES7hajrK2mij4q4E9_CtIVmz>WuPY=A)DxiCQ> zC_mtzfR<7JzYK?1(E5?m)mH(AuL4#bn!X!ifTUZvi01gKjW0zS8AGyX$|IR9<~G@e z{hcB#i5{ZfhI&2#sSLFf4NoHp1s0Tt%OxZ_?WLkqA|onKg(Al>LC?zS>+N74=Dui{ z(Cq1Xz#W>L^?zZ{5wy^`up?Nsmv2M)1k!EGX1&+@ytt>?(B;SS&HpY@qgvqZ7{kkc zZqLT(veH%^1eWN*4Dh-cq*XIO(S{0nXG2w6DD{#0AYO6nz5{NUbaW*stBCD#KW`0PC7v#sC40T zOPM%VMN8OX?bkz+XA$lfLQ25!!4-^#80}wI>6na;oGh+-AlNDr%Jz$v zZPYBz9cO^syOowsu(32RsYx^n4zlF)fNnH>0<)-p{Ln~e4=0YK2DQoOeP?ePYbUhq zwHL9;VAXI6_44pMyTK#Z84mr@)3RP0Q7}1nEWO6&8Yyg7vYmTQ3DQ?)ze^*m`7C#B zIp>Oc$JfY{FdngcK*~&V8VMP*BmoVX7 z3Y+=nvL9}UwX1R=rxngVFuUdd0Q6j7Ft}uMe@^G)#M2Iru&c+8&J&eZo;`*F*(R@~ ztVidbm0ay(Uq$jvJcKeCCo*of7hD@(un^o<^;{LV9HuZx>Z-~32~h8*a4 z`^rs-w~2^?A?SO3j+v$9e6^(}izV-8BnBwa^sNaZ_yxmZ!Yv3?cpu;XZSnt`p>wJI zLcU_A+t!V{_CYt+~bnYSGL2<=cE{1Gw%PA^Ps)$nk=8*T& z`|TGgn_KRJXaAJS66%9EKr5S?Ag}8q3p{EH{kZTxeYI;`w5e^hWZ2*Pd1ua;d?)`y zPnb4s-CwwG5zVG{e%}VB5a+м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 OBqOOPQToBa_kRKMe6QvJ literal 0 HcmV?d00001 diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload1_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload1_en.png new file mode 100644 index 0000000000000000000000000000000000000000..739fc36b3a39626f46e48a52cd62eddc733482c3 GIT binary patch literal 12652 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

Модуль автоматического управления

Обзор

-

Модуль автоматического управления позволяет в автоматическом режиме отправлять команды при выполнении определённых условий. Без регистрации модуль работает в демонстрационном режиме с ограничением времени полнофункциональной работы 10 минут после перезапуска.Модуль подключается к программе SCADA-Сервер. Настройка модуля выполняется с помощью удобной формы, показанной на следующем рисунке.

+

Модуль автоматического управления позволяет в автоматическом режиме отправлять команды при выполнении определённых условий. Без регистрации модуль работает в демонстрационном режиме с ограничением времени полнофункциональной работы 10 минут после перезапуска. Модуль подключается к программе SCADA-Сервер. Настройка модуля выполняется с помощью удобной формы, показанной на следующем рисунке.

Форма конфигурации модуля

diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download1_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download1_ru.png new file mode 100644 index 0000000000000000000000000000000000000000..68cf312919cd7cd5c8fb14d5ebfcecc5bba0bcde GIT binary patch literal 11178 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

Управление удалённым сервером с помощью Агента

+

Служба Агент устанавливается на удалённый сервер и обеспечивает обмен конфигурациями между сервером и рабочей станцией инженера, на которой происходит работа над проектом SCADA-системы.

+ +

Установка

+ +

Агент работает на операционных системах Windows и Linux. Агент не имеет пользовательского интерфейса и работает как служба Windows или как демон на Linux. Пошаговая инструкия по установке Агента находится в архиве его дистрибутива.

+ +

Для взаимодейтвия с Агентом необходима программа Администратор версии не ниже 5.1.0.0. Администратор устанавливается в составе Rapid SCADA.

+ +

Сценарии использования

+ +

Исходные данные: имеется удалённый сервер с установленной Rapid SCADA и Агентом, а также отдельная рабочая станция инженера, с которой осуществляются описанные в статье действия.

+ +

Изменение существующей конфигурации

+ +

Рекомендуется хранить конфигурации (проекты) Rapid SCADA на отдельном файловом сервере, который резервируется, либо использовать системы контроля версий типа Git. Чтобы передать необходимую для работы конфигурацию на производственный сервер, отредактируйте её на рабочей станции и используйте приложение Администратор для передачи.

+ +

Однако, возможна ситуация, когда конфигурация Rapid SCADA хранится только на удалённом сервере. В этом случае, чтобы отредактировать конфигурацию, необходимо сначала её скачать на рабочую станцию. Предварительно откройте в Администраторе файл базы конфигурации в формате SDF, в который будет импортирована редактируемая конфигурация. Выберите пункт меню Удалённый сервер > Скачать конфигурацию..., откроется форма, показанная на рисунке ниже.

+ +

+ Скачивание конфигурации
+

+ +

Для сценария с последующим редактированием конфигурации необходимо выбрать параметры скачивания именно так, как показано на рисунке. После успешного скачивания откроется форма импорта конфигурации из формата DAT в формат SDF. Дело в том, что рабочая копия конфигурации на сервере хранится в специализированном формате DAT, а для редактирования используется формат SDF. После успешного выполнения импорта редактируйте базу конфигурации Rapid SCADA и конфигурацию всех приложений на рабочей станции.

+ +

После того, как необходимое редактирование конфигурации завершено, передайте её обратно на удалённый сервер. Для этого выберите пункт меню Удалённый сервер > Передать конфигурацию..., откроется следующая форма:

+ +

+ Передача конфигурации
+

+ +

Сначала отметьте корневой узел дерева, чтобы выбрать все файлы конфигурации для передачи, а затем раскройте каждый узел дерева, чтобы проверить и исключить из выбора посторонние файлы, если они присутствуют. После успешной передачи конфигурации Агент перезапустит службы Сервера и Коммуникатора на удалённом сервере, чтобы изменения вступили в силу. Обязательно проверьте работоспособность сервера после передачи конфигурации.

+ +

Перенос конфигурации с одного сервера на другой

\ No newline at end of file From 0e2da062d93b8250b33c9664c500565919736e23 Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 17 May 2018 18:03:04 +0300 Subject: [PATCH 088/100] ScadaDoc: article about Agent --- ScadaDoc/ScadaDoc/ScadaDoc.csproj | 10 +++ .../server_connection_en.png | Bin 0 -> 7454 bytes .../server_download2_en.png | Bin 0 -> 9968 bytes .../server_status_en.png | Bin 0 -> 7185 bytes .../server_upload2_en.png | Bin 0 -> 12720 bytes .../use-cases/remote-server-management.html | 58 ++++++++++++++++++ .../server_connection_ru.png | Bin 0 -> 7722 bytes .../server_download2_ru.png | Bin 0 -> 10935 bytes .../server_status_ru.png | Bin 0 -> 8293 bytes .../server_upload2_ru.png | Bin 0 -> 14147 bytes .../use-cases/remote-server-management.html | 35 +++++++++-- 11 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_connection_en.png create mode 100644 ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download2_en.png create mode 100644 ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_status_en.png create mode 100644 ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload2_en.png create mode 100644 ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_connection_ru.png create mode 100644 ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download2_ru.png create mode 100644 ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_status_ru.png create mode 100644 ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload2_ru.png diff --git a/ScadaDoc/ScadaDoc/ScadaDoc.csproj b/ScadaDoc/ScadaDoc/ScadaDoc.csproj index 7d7669a7a..00bb633de 100644 --- a/ScadaDoc/ScadaDoc/ScadaDoc.csproj +++ b/ScadaDoc/ScadaDoc/ScadaDoc.csproj @@ -119,7 +119,12 @@ + + + + + @@ -266,7 +271,12 @@ + + + + + diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_connection_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_connection_en.png new file mode 100644 index 0000000000000000000000000000000000000000..55d33a86f48cb48e781540c56c57a32474d1c409 GIT binary patch literal 7454 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

d>jHtohOggNa(_p_HlB+Y)Co(jw7x;k!omny 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 literal 0 HcmV?d00001 diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_status_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_status_en.png new file mode 100644 index 0000000000000000000000000000000000000000..0993f25fa6fa2fd6d4655716fcafe9ff048e2914 GIT binary patch literal 7185 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 literal 0 HcmV?d00001 diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload2_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload2_en.png new file mode 100644 index 0000000000000000000000000000000000000000..da67b70b422eb56a0e574c3d57cdd3d58c08a2b9 GIT binary patch literal 12720 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

Managing Remote Server using Agent

+

The Agent service is installed on a remote server and provides the exchange of configurations between the server and a workstation of an engineer who is working on a SCADA system project.

+

Installation

+ +

Agent works on Windows and Linux operating systems. Agent does not have a user interface and it works as a Windows service or as a Linux daemon. The step-by-step installation manual of Agent is in the distributive package.

+ +

To interact with Agent, the Administrator application 5.1.0.0 or higher is needed. Administrator is installed as a part of Rapid SCADA.

+ +

Use Cases

+ +

Initial condition: there is a remote server with installed Rapid SCADA and Agent, as well as an engineer's workstation which is used for the manipulations described in the article.

+ +

Edit Existing Configuration

+ +

It is recommended to store Rapid SCADA configurations (projects) on a file server that is backed up, or use a version control system such as Git. To upload a configuration to a production server, edit the configuration on a workstation and use the Administrator application for transfer.

+ +

It is possible that a configuration of Rapid SCADA is stored only on a remote server. In this case, in order to edit the configuration, you have to download it to the workstation first. Before this, open the configuration database file in SDF format using Administrator. The configuration will be imported into this SDF database for editing. Then click the menu item Remote Server > Download configuration... to open the form shown in the figure below.

+ +

+ Download Configuration
+

+ +

In the case of subsequent editing of the configuration, you have to set the download parameters exactly as shown in the figure. After the successful download, the form for importing the configuration from the DAT format to the SDF format will open. The cause is that a working copy of the configuration on the server is stored in the specialized DAT format, while the SDF format is used for editing. After successful import, edit the Rapid SCADA configuration database and settings of the all applications on the workstation.

+ +

Before the first using of the download and upload feature, create a connection to the server as shown in the following figure. The user name and password are verified by the Agent according to the configuration database deployed on the remote server. The specified user must have the Administrator role. The System instance and Secret key fields must match the corresponding Agent settings.

+ +

+ Connection Settings
+

+ +

After the configuration editing is completed, upload it back to the remote server. To do this, choose the menu item Remote Server > Upload configuration... The following form appears:

+ +

+ Upload Configuration
+

+ +

First, tick the root node of the tree to select all the configuration files for uploading, and then expand each node in the tree to check the selected files and exclude redundant files if they are present. After successful uploading the configuration, the Agent restarts the Server and Communicator services on the remote server to apply the changes. Test the server is up after the configuration is uploaded.

+ +

Copy Configuration from One Server to Another

+ +

This scenario is possible if there are test and production servers or main and standby servers. Consider the transfer of the configuration from the server 1 to the server 2.

+ +

Open the downloading dialog and set the download options as shown in the figure. The difference is that the configuration is saved into the archive, the server-specific files are not downloaded, and the configuration database import is not executed. After the download is complete, it is a good idea to open the saved archive file and check the configuration files it contains.

+ +

+ Download Configuration
+

+ +

Then, open the upload dialog and create a connection to the server 2. Select the previously saved configuration archive file as the source and untick the checkbox of clearing server-specific files. After uploading the configuration, verify that the server 2 works well.

+ +

+ Upload Configuration
+

+ +

Check the server status with help of the form which is called from the menu Remote Server > Server Status... Select the connection to the server and click the Connect button. In case of the error status of the Server or Communicator service, connect to the file system of the remote server and analyze the Rapid SCADA application logs. In addition, this form allows to remotely restart the the Server and Communicator services.

+ +

+ Server Status
+

\ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_connection_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_connection_ru.png new file mode 100644 index 0000000000000000000000000000000000000000..61bdbad497049f9a0bee6c5d6bb2bb35f403a19b GIT binary patch literal 7722 zcmaiZby$>J*Y_Z$5<{0TfT(mg41&_#-Kq4@Lx*%qNSA`NC?%js3=Bi3#2_FH-3}?~ zH=gS|=Q-y*?|Z#}+}C~Ywc}oEullXMp8{$}=(jKpoM%tep8x=LDFj#6xR~}Gh?21v06^UR`@urESJ(jn3?0gH zPxPP`dj;yTu7moBKr6l58u=B)Pi||_|MaQrQi$sbClMHrgGS9ti1ozAV{5A|-67_A z#HJ1i=SVOyCVd{UZdk9sh#1~>%-E1O2|J>o%%C1eD9*FN}n;X=u7qJV({Y| z=?kCtCQVNIdtYXL?FMU{efB|f0E!8yMi~HBk4S)k0vRyC`xY87cBcnhhV@T^PQr$- zmxoV7Q?yoKrgfm#+ao#bu&CCS7AP7OB}~6s%HvE3Q9_YUjm5_ezw-weQIPfLwQpAw zTniNl$2G4ZgSaC5zix+ z??xuMyyFwDdUf=ig&52E$R;$!6|PTMINR`+z`}&MD13Kp$%tFP*Q9lA1SKy)S0_b6 zRXNj*9&WArFiV*ZtX1s0Ut&l@SWVW8d&z92Z?PJ|p35>snqub29!4b96hrgwPOp>D zV5f-u1{QmIwZsTH9lxxQ9UyO*4~WmEAsA1fp%MSBhZ&1*F28SdbC>Jh@EjovOTh4! zS;%dp6l(5DjGCIDr-RyGakvGxJ~>6`MqBLX-e+d@F}4N7#)Ls-fWJ+FiyH*cpo+y0 z(_jJtB*LM9O&k&we{bl)rB< z`!5?L9KLqaz?C>eP=Ahq&97(Ym1_SN(mWd1=MmW8fOp`AOV*(o<0ON zUsCYA|IZW2_I-rFE5^|tgA^(WWKGmkvvqt=9(SpWTdxbn!n4u_ixodtCOrEV^p>ow;*lyLIpCqVK094j8}{9!mnevROcYFzi1S@z+L1 zLqll88oJ^`GW=0>p$-&b>3Dx1W2^;kzIUEZrFpPF{w;6#l|##?xp|uvO9)8~WFx0x z?c#L3YK}55h}ux}QO+Lh(gA_nXmBfR;|ILKjZ#+7N}xJ{^>MhlYok)7ne3%Vc5P5h z6>@EPmHuPDSraRxz4Dep87SFBj00E(e0I(RMJJ&)u9@FA|omIZA?zO3L!|Ertuhnc`ebL`dP(xuq+kCtyJSe+SJ3j6Vqe-gjCQ76AIE zKK^oz^*Gl3RSyr^k9OD_${)uQNY1>)?>WTAXd2FjCi#67?{2`o?~%gt_IV-xB-|^r z9G?&iJw!4(hExu$hre5>RZVG({BU$RqP^6~zRfJM@M=wUp{4$K2=yUCOl6-Pw4tBg ze&m=w*%wHawuN`N_}aVvQDT|~q~+(JicvbR-R!0g&&t>0kk_%8!?h(+9NxIsdUaK#FPS8dC$?GfSwVDzjs&#jR-X0*{6zg0pZVGs6cw`1%^ zH{;ER+8}zO7tqd-P14a!zR7HqF`)@xB`WET4A`n@mumF1_aKY;v#uFBv`ZA(%~dCb z%bl%q;44utXwm*eg;m&CoCQVu$v7P3 z5La%kf!>U=R1nAEp3UILl9CV~VAwSWzrOG*O5UaDm6?h+Ol)QtM&^V=$NItO(gwzw zxWe%2R_f~hcy%{g7NV%TDR`NCwl2QFdej1AZ z`T6LLBCBF6b}atxl2DIef_xA52zfOC|J96RDAFTYKo$%D0RN7kegmq0dUV@yUexWM zGsrGlL0zx~_v{=XU-Wlg-IWEy_m}4$5=YzQ3aEY_in2c8S)Cwzsy3_511)@YnfCdC z$XW&*z*lsc5aTTPEn2__mqmme171P}QyAs>%L>B|)IT06H1L_-2AnM~qR=DHsquoF z4MY57nTB{@d&FKOXa^OgYP8qk_>sPkK4JG?m*75?#yzv*M)%NkG_*ba5;W*>6Ohrn zsm@VRk!V=bCcE}UelCC?ptin{$?;Ay#>rdqzF(;f2mB^mr0UL z>6Oo+U#uDEQxaBApgh_p68@OtAC+=dMJYf8{QJCbX3wJ>-hM6w1U6AzT{4KvmUv zR<}7SKi6-I6+7E1r_A6I|^XOO#!8e^_gHtm5 znE9|a>-sv2q-P8&(tw!mG}Q8?TH6_pa%Am;v{|mJ@hxnC7!4H#@VnV@JO6{|P4>h$ zGxz`q9~TD*DN@L3DH_Cz8;KAJR!c}@Bm7lBE(2a7!KBvZ$?zZOuol?2(8DL-r4|eY zkT3FE)&GFk|5v7nW&L&}8+$Jh00|kQNHJ6$$5|Q*!=Nq23pe)p z>$_pt>o=&%kA9=DQhsePKVF{R3tKB*RNXz?h49@Ga;Y~pi+k%>V$U%;y`X(eFt)dV z3>Ci$5107REh!eT9{cQmR4+hG`*(&j#>kbA|EGW$2RN1X!-n7)ji(4`f=^Qt0Fa4) zNdD)@KO6&wiVH-1tDT0CX#fnKX`@|SspXkn5?Uh3!|<)N(erLKeNn@EHW~mBVBQ}i zy*3(BxgrG=)2E^W0?G;g?Pz~gF8}A&DvBsmxXj1_Msl`LXvt3WzJ#@{1z;pY+z$ji zz{fucYbY}WR~0r=0;R^Ip0&2zF`K;@b|qjnZQptXQ4S1ZB)H_45Nhy?ZcS5FoRXYT zj8`0Pv{H7_rAR5MFTDNE>*7Mzv*a|4+~y;+(KC__R8GGonin4*XpURi|Gjd4ILCyC zkEn|9!ZE5EPDFvt*~4CjRbO zg@Y%A>^MGV0HzWXA6H%Z64?Dk$H>f{n3J7Wt)dc6t;#*u^uz!-`;!#`P7bZ3y5N5|H$EgpL`G>ORbO#FNzy(<|HOJUj z4&?{$5InE9OQNb*8`G1*(bLt_yC<^Xjm~^Y%>a1w8I6I^H0}4$8Ah5&zg1bF;5Is> zp%PCvb4*pbVSD3XYUCtUtf@8!Kjuy4ej2NUK|8xXyn&(^9_=P5rFe>dYkBhCdkdRhHpSmR z`azyL4e@nYjGa2V^ib4&P3f!o;w1g8&QCQV8_ebNBDV}hkKOv%?Yt-tq)32b&kZOv zYc5eM;S>tn_qpR}U)bUuphEzl*rpzqqK`;Pkib`Sj&OJN*D*egC!hdHiWk8SnBFM3 zt)^8ZCe7`12Gsz{BagLjNwviZuC~m%kk=aXO!Jv16(-y8nuzn55L1VE(Q{+GIpmj#SB?<~&? z^NKDrze7hwuNEvrCoXPbruya5{d|$f*mgN_uo!&a#2a$@!q4)igg1Eq`XB^hXk-b% ztgE4m&3F}c&~kY&v-tBk{p_Zv`5N&ozF>!7g-s6+A(33^R%ihnU9S8eK zXQAuvwV_MnGeN6oA(I!kE~!TcS+l6KG}Q!ni_CRbm{w(XP*LE|?T-^r!ep(LutRTH z8LvA77Y{>=F5!OddwDmozb$)2ABv7o0iqVueZ(E3iD%@xft) z8_5(Kf4aHk7e)3fy9!Wa)(4*Ev{kO?2JeT_)P2eK)uJOxY~`?}f5}<~o^AO_{TlNN zK4=bYXr-@?jmbZZU?^^uqfmhGmt_lS(NWl56j6*@_M}NvMbV~c) zj%7#i@SJ!cwPrvS`te9t39#$4Z|6HaTl zt?7f_7c6#f@SIM0LHDlL92%) zw`W$_J}UdR?SH*z3kyGA>_IROH ze}(Y|74&COUb7wb*nZ3UM*`EWdpLyiS^RX;C*_2fqwrhO)$2rv4|!If+syo;nK5Cj z==zyPLSY6sqoRx3j$Y12{CyWb){;Wb8+R{f9-F|1*I);Ob5nwJaP2z^e2W<2WD^Jh zjoH<1H^qC)q@suL*_`JLExj$1YcEi5YjpT^>p7>Cb^8k1rf|AQZF;E;%=c}2mz%h` zK^<%_4BC(`6WdS^bg_GFU{0LDp+AS<@|x;7`O`0-6wA8(wfblx?f!H{B)DpE;aA=}WLU0?a~;!tiG zvh4y+IgP>f7#O%4i!3BY2qz<1oza|sI+=|9He~NCQ>hRV~{is2(2QXcy-z|-elH1^RK$4E^2Q! zV^O6ZLa&<7w_S);)ugMU;6<&*!_V32xVS){SO-*1a?NMf4STH7Oc9?g&^<1xo6cne zVBhUFNubAu2cQUdDCy7k6tS1Ys(B+a;v>AtSF}`dgh=*V@g`o&s|K=Of`bO9 z4z_VZh%}T(Z%1H< z#tbZ|JLZ^wDlzBHQ~=Y9We(Kw_b2oAY!f_gsmoYTl(5LYOyXTyjKt}YaToe-?I|;~ z6&Nv$RV!WEjLfzvi}!)cN>7|06O0fe^RYP})ue}fMfwUw!pQS#p@$M2)m0jma?-Rp z*_8_>PAoM!GrYyIal@FcEzL%@Dfnl{Yo@=g(WKr;qOCV#_D%;RMEY<&8EK?XS|S92 z^qx)T1U+>#Byg_n$mhSV!GPgUR^k*U_eL$bx^wBM&7G)UPc~3K(tbMtKIG3(FS>%$ z_~qu*WYNK4LvI(JrjF$58_{M#2!8PI!SNODC-^4`B}DfbF&2!bnsjm4Os&^UC`X?R z$bkiL-s;7{MCV=X8{%#)lJ8}}YF0_+ED&$}K>p-Ryd(jq1Ns#&+ErhYWPCS5H@djY zFV45<8kTcBQ!5aVKk4eI<|ym4u25CVF5*f8DQv zAp7KN?*-fI|D<6;FEikSK(jp$hM(Pa70@e5(ZH;xFLh_W$B((cAm4r07Fo1)YQN$( z7gW2o5_GdrDA7$fVY(cCUad(CW7K3Hwq@7VcNc9y@1>qt2vT89@ zk>X+EiImFZO^nZcVDAEQn?VR<4(K{K$9NF?cm{zx55c8%<8M-}1I!f#J7BG@Q%QPB z;R2n!H)a@kwdU_`hX07ltn`#mD8H6UUt^Pwuw;(InQ0kpmVa((zC%CFES4VoPJ(w* zX^L3SY`>1L_rw`>1&$PQm`J(*%_?MHsk~Z4SZpk+kdq)G1_W5uk01TjX}?r)#qkvs z-F6Oli9ru~UQ|D!2HoNLB(9`j=yWBaUdEWgdYf`miBqoDS)YcluCq_#Ese*l_ z)nxA7iSK_nsb5YA?d{FDql5{=11M9`Y{-{Z^lRhLex$m87;p@n9{i zKH7sLSS%sZdalGA8pXi7a+acTGZTY%;hVya6Q7wJQr_{x!l1hCZ0gb5L32V z(qH3<2GPI^Ps?4Yp5Yq$$8*x;p2)DksafL0To*HxRFo{|C*1WmgT0|&N@m6&+B#+} z^f~39!p60M6x(z^BA+;Z?Yx>g@bBB>DD&sC=P(ItWN{O3h1Ps8=G#6Ma$8v5q^sth z=Kq+O9nG$L-cA_%>>c7`$!bf;cspVWG!rgO{~t&B*HzSCS^DoI`tPHuy_FL$hr0JZ38(l0EEj|hf zBpK}oplgVFyaZ&x&e&+RwR2t6xtB8o6Upct*Mq_hO-AX7Q2Dd*6+@dYsnE6YlG!)C z@=klNf)f;z*T+i`Dd)u?sSu}qY;2Tqo_x>IF&YkEDX$`UPs$1+BK7*UYX}a)S$_U> zkPaWWr$K}u7NIQ1{Q7xo6o{uY%1r`h0oP^FSQ8^*Dr`b_K#ge6RlSa%Be?@6Nl)1e zqxFvAVL%r2CaH8;S$CQR!_O?)pSsmbvo_p%9LlLSHh>(2a8ck3A`q8zO;)#w9an=mkwG!-X z1P3EDZV!voa+ZZi(Gh_wTg)3bs`OC{I18uxiDlCz^6a40CEc+|v2>b^=-j*P40F?7k4G;5=sGg$_ z7#M!*1_q#z0kdLbxcrCWN_>3NEPW#>Nih5~#z#oL<&}ip<*3(%Cqt n(0^E8Hs160vqO{>rSPyHV}n2-JQ?XXsvr=`9`F&l ze-F4*Lh024Tu>ZUrNlv{Llhgp4>a@F3a>$+iU^!*BXr<5mYuY=BM5}wdG|r-waqsH zftclG-n<68zS~Ll3DfU&UOY?Bx?y32W?86Y_|)}LU-Z6ecW5?6GWubIamY|qr)>rv zpJ=??n=f6AL?I&PLrL7`X1mQ-3x_)`X9zE`2MfspjzdY*F1u&21$_~AuZJK|+jS?z zn*_KDqw->cK9PQcqJm!Gyn>;CGSD*+AkgqVWxx;%lzagYsQOhp)S%9MF}iXu4F{s9 zHA!FuJSjxLw0m*1RZtYYi;E_GvO!cxqohawa z=jKPd+j9MB_~~gfl!B{MD)XJc8cr8RdZ&r@cMA9QDuH+yc7CvN_I6`C!IU>*`|oUWIH54?=Ekjd2BOa})%+(&idc8Jv|w!)d+?P8$= z8HNj_v$(2IX2`*?G~$D0141M%R^B`HqYeBZW_W4-wwsA1rZTCD!^La>vlt8gsKUr& z?a{(~Laa!Vh{oU|Ci8YePbdEM*2pU!7saMeo-@-E#@1+{L6)_~>c%mxv24Us<12BQ zsNGIe54S@K(5H`?Rl46GF;UR!QPgoy;_pQWvQfGt&>eo%Ucsb{o-oUcD^ll5j(-#b zFlWf}4{Y8I1?hkw_#hA)=ns^Yd68Hk&?h&Hzuo(9;r-7k{yCgT^$14ik>GGjH8cJa zh;*T$)$zFj7Zo7t%RB!Hn~z#BzKG&}y2R!ptI^|_^x_f>oY$gEcGk`u0)e#T6Le=Z zWECY4hppV*@GT}cRv{dc6MJPs(`V*FtU*fL3jS-50l@#*3~pbSG? zUgSHnS&j8DjSXv=SVh@UX~>Y|fyz%k_6e;ER+*QRDlds`3f`f8)Xr~nm?0tg5~k6Z zBivPVI%aqHlOE563=g+oNiso9H_&h+R8|xmu_Tg!3L1Xq{)>Ps4Qf@;vqfywVbTK* z&s~)$SHx`nB#^AcU-+ECSy{4pE}&Uz(joMtl<(449ii+GkGIvoDhvyU3r4Ie!Ma`j zOd=kVG`ZeSN<;;b1}3Q=>G;WXXmv)LL8~t8crgSqMVsD|;}$r~*9dFimoX=rZ76Sn z_|%Pwo@uc73MwIpnBNt2`@}L94qt6X(LHbkkw%j%J9-;;KlCq*x2!zZGCZ`K;i5ix z>gYN8-W9XL+!v)P_&7N?d|9=vu$_Kvj`d4kPQk#!6?IQn3f&t^U5b|=!}dgU-Zk;- zz_jXUQTTo~E}lvEGS}6*k=7x2X0_HoWc2~T7JQFDpV`B1l+3iwF1!ltC)vkMWGmCW zcjx;@0?faA?t!#eKWf6H0%K<>9gcLYJ}7-^%zlahv9ebcAVRyk#)YrT@3CPTs`&nQ zY4h*6;^gH;J_HGUvMHmmwjxY53Vc}`JX9{8toz2ij${mcM17A_vW8nBca$~7)LwWs>aJj|DgZ1Bg7a4|z_ z&~;iRwaXdBZ__mqm*1~=HUi7HhPU(#=<_eG4>pU+TDJ7}1ii28CQ-rk0QGp$LWYFC z$<5ATjKNl@dZ)d!nscS2iAE&7RE4U7);Fz8Fm{hJnaCWgAp$xOt{7qa!d_b!le#_r zX9kQ@WF(!HdSkR79Q%2NA1Bd&W%z1X#KP!Hc$jpIW(7E%lMbTDV&C!cb)tKVG&nXF zTMYE;uyLWBtdoXM0$C4^b^1eEyu^CEcE3kUyws_Hk4Jyc-YF3bsnx3g_$0>n z%G07>_%vmAq%!?Wwa@ZuZy7U3rIH!}jdv!O`BYSGvOU^&0XVyftl-d(NzHP`^UY_^ zwYWLqen~1v!8T8{p=dHyy2Sb!b&8!s^zO}Vb4Gp(Oz=00Ez~QbdrfCe6^sMkEVF|_ z1cmmtljJ)_eOBpSlnVsXqAVd~aySPrn72^o^scc???%0~ik(VEr%m^tLNP~+TG zVx#nn!-nky3zJBo)x~VTC-X>(;|~D5THh>M;P7>BCrRWV=hs7<@%zl5HBUx*?uc9`q-EdP!zkcJw>lw_bRAMgJZOE5GxvuU=7Qqe|)1t97YQ@+Hp~FHolkVIf{14SzuO$Yy~3IJI)QD< zKx9x}p5EMBSW9%^{{IcgD?otcDdyh^%udn@c4AxG{NJ==$C8%^NIcN<`~Tq1e-hu{ zWZ>WP*}3HO+%V{`?7CeJEi36^;PlX(>S`&>Yc6`Me5D*E*D=dni?#@(bNgVyb^6fl@KPeT z^ZmTqUhIe6zC4s!E!=m z<`0vQRg-|q?FRjz1D2XKVQfjs;7iYSHesQttZD9$ulcPkoSE;T(kH`8qMvA=y&|O| zkm?yKBs5b};Q98E9$%D=AxGX{Zi!W!%JRqy-38Pp{(=rdMQuz0EJbX3{WJ;;{u!Pt zI_QwuCGbI?|se7v58Y+*EOSQhZ!f0>(DdE<-cfdC984#==yA#f?qIpfbg@%+Y|{7 z_ehucU{OnQsF^|9eyNDN52%f{q7foWE5s}_EChNL`j?P0Qw7QpP#D&~i%#E-qKlrM zo~6#9vew(nxHuB`TrTZuJfOI-kXM6o7_@j^?bK2WyY7z{sQnqiqPZT|Z$fjGE0-`% z01VRrhS}D`;~RGywqSgVO;Cw=!%|`T@MU-rz2YUcxX|n(UaI6AEf09gcsj}>&oS21G5X+xcm9O(TQSYqC^W& zT$w;1-t*2=`YoQ?agCv&WE{JTtp?3sMPJkgaSSXKwT?xJ#7;6oCMbBk*+fgD9;Ivd z4~ch2Mpg>MhdfekL-`!WL`T259n3cIX`W&xI?LkuVHXoM)rk(PT){z)kDZSHcW@j#a?taHc|pMB+hi0nFVK31E->Sj$q2-i==ErD zh6Y67v16i{Oj33S%{*&M4QC`>;_h?B7!P8C5{-bp@1k^>v)`VsXldp9rg2hKzPOVc^k`$si&dCba&zF`TkIMN z%IM%Cqa-n^X#USHCwM*Plxt;aObmNmN5uu9ope8hmZu!rUTdayf2L`k=)^H?WzA$# z8i;b9+GI_$F*{{K10@Oo={Wjz)BzN&~kySDG3c>&{Xw-%NMGxIl6AC}yJwDDOX6Vg6^8k|BU$DiCN^GH%Fz z`SCEZKM+1Aa^Hb!h3#@&PtKT&8d3@rYZmB#ng@TehGFK!b%$}U*x_xPl&Hh?9Qq3k z_7o4+B5pD&?zP^bq!NbC`V|xRL0r-SVlR>*eSK6QEI$+=I9jg{V+4MRoTczMbMZlj z?#WfMcDVVXO@!E5h)~fB{ifiLeuBxBB6J(I(i`zju-?5MQ8x`1(7c;q5}1H?v31RL zIfMZN&C6zdZo`Tpr=oOzpkmbMOYqZ1+(286l9bR=6p$g>cd+BAjru{GOUqFznStlQ zK`*t>@rYFGHJqcYq(tO+Sb{+GJcFOeF&iPGDlhdxggmtWZT{))iqnJIMDYxf#~Z@3 zYvXc3RWkr}nS2Ky#V{zfoX%Q3hnF=SVi&l*mV@jvg|DqGOB@=qp$i)6r0B`673Vsc z*$HEU!g}K&x6{TE&6k@+v~VTNH22K{wQq_d7ppPPj>lygj-{yFR+oaP<0ahXAZa<1 z*-Ag;d|&3%ShPG9&8

HKw4Z0v5lb)-Alqju4eyvyVP>TpKDWD~qW_miiZtUmgx{ zv>uPjnGdDV*rz|?-6L8_8RD+Au#ZSF=c4e!HYoZi$ikn73hFVGt#QMWq6H+Xd-s4rH-+{+c`E0jwPt^T*-MV)E zY+M^R=P< z`^BXf@8a|{zvub>$&^8BWu9d;80FlptKxF;8^s&+QB5C5_aAk-zsbMhWG!W z$RFMtqx2_$YAe61Ky_{E;iZkc?nf}blOjA?6M>K0k7^1Hx)CE2@Z7e;!_C<|9UxA8 zlb}%B41mBen2g%&S{{%~&Pqk@{Fr~$+XJQto_xRh*F1oj00MVeMnaPgII zp{}JxvCs=Km?R=VyZ&F1ViGucXr*wOurl%n$ZA(-dz!Y{N`pH~1BaWB)&FO1>>C+z z7HtYYSfkq*QW`SV1bsp`f*%i{oziay2|!wpp!~@m#>_#egt#%U5fs8civpBm=5<+7CGkemwg9d=-IL_WIrBkM1 zHh!1({@IiMwJS)OJP2r)+<6udKJEUPi>@np4{f6NT$)xWZ9RVdT363W*&Y`>1Y$6) zU>DugxP~rNqcb_!z|*xof??c&2eE&duiZH_b4PLE-w^6k@O^$!Y9G;uZt!41F_0l4 zu+2mOjrCR-_g>yEr07hPb$G**sJIfDEKfbi>in8kz~^r*0D{NrS%5g_d45;ZB;xI}KT(t7#Zr{(A< zUGQ*5Y2kLmL)2-p*X9-$aSQ#6&fLkAYE(?=z`BBOFzrLhmF2%WQRO;r=623}xR-jl zGDhL`#`vd8SEvMm01-Xe4-qp3nv0+4MvPJG)DO+{K_G;$5ifE%#MsB-AVB&eS*!uM z>0;Y*+3yjG)KPU*vKKbslQb#9GDWWmMthzxDqzKwO1=dhJZ7SmeE6;sLoU*pDUeV0 zp(mrF-ZMQMre`{`T@tzy-OdCen1-T{G>(vmNfEb;$P3G;!*5gqZ;`3)=cO?Q=j)oH zKC4SV7Y+iIe9j%u7B1685B9{I&tPX%jUgt@^t|S5MY*gY5El&6wt(~4p^q>39Plls zoH-U~;V5$H{;_ym{jP71F+qdRIw7|gO4JwG)VIBS-cHCfJ{ynY_Qu8Y+n}=B-*g+T z$WuU@BeyhL9nUxSZu>(Cnzwvcr~w|OR>&2kHVP#@Tc=1GV|aDUn5e@_FLA>TKb_r^RJ$0(o1}+j9P7E$#LZPOXUX#i>WBC^B5k z<8((% z&kQqk!j>|95;Lqi4|;#oM!c`fk=8Ag=1;2zaRveKG#9o1h4kL(6mva|mulUw;PXL# zFXBL2O&*Zh)?HqU-BdZY9*>pnBC}6gJvO3RPnOPZuGe}xHiq$@G{QK?o?$`f8iS(;h4J(m(2wFUP~gH z=^krwUww{y&Aks87#2^12wG1F6tCx4sIO*zEnM*}B3pcDZk3O;yO4$zHHs22ltd+9 zPx!)?u?U3`uMqoMSt+(n2K|rUY z%?U6{iQ>YAx^-uGBw54f1{JxwxUesWJk+1MS@GF-xxH4Fv%!>i+u1nsV1jF3KMjkdCeWn)e7O69H9W==WDa{2%sI{x;kf zV2HF4Wm_PB{!!_TbXRw(qAhqZ6KYGPKk4(;+S1bPWIYd13x-iiYP<&eF^97waJbuu z<6}MoXKRx5SD;UQ+-nfU*~I=a|Ia)fL0_(wD}+&3c1){7Kp?Zo=R*h?|4EGm88!)( zYPEgQRoa&Vw8_m5b{%r_`5|f{Y~^k|0zu;2&C=0tAN81u6e>w?dB)<0!tp3CaNo!$ z!-g56Dy!`Lly}plcPvSn_=E66e~VZ8!iRe+AEu6t^BC=^GbRMGozND?$1CFmSnjSJhqg6(UhWzVqS`PSEiJYo?oPb z5mVO2RWX6xSgo_Wo3GP%n~xuA7~gUtL&MXb2Io!ZCxk6UJJRH0W4*u7NmS$IyFU52 z#bQHg)tk(8zRzwfu|z5!XOZdB+%8MqPb#uZ#q6UI`2c5CZz)<=ZO1s46n_#X+4+t2 z_H~S4<0GcaXMus(f{AG%<7o@aMX98(*-A4{vE(+`O{IJnJW9na2>n?@sRM{-B+uSP zlJW6oZ8wTB^DvA0f1`6$bohfTQEIqGURfNu}f!$J=5G{8B0jm`3Lb3T3UYs!( z2G=n6o)WyJh+flR`7l%y*r_iCmpy&stbzdVEB+dglX z)JIoI^YR}qyq6hWMicbvZ$FmL>Et#jwP1}7rB6n0CPf{%KR?nKIEBva{4Q|yLBUnO zr?{j!2_DxBTegWT{Pf4csUU+9ejr2KM28XUV^yB?SIxIG=!Mth+)yQvLO)ied}Tg~ zt(d0i=L&)TMyG?XnJ2J4sLeNaEOg^l&Y1aB7U$d!%Y{jYChBriJ4vS$Q_6hJh7k6= zMI_^X8r}YbP8WyhV9XYb_s4!&LSs@<34~%>Ph^r+-|l|#{R}ngS>*QFIqO# zMw|ue;$Kc7fiQu@>cydOLCsN547S-uoprW!%YCEb$9knQkhyr@ha+9W z#ZeyL@AqrDNaxi{Hs;R=HAVOZ0KCW55gK4>2bFGx{^MfAb9GM^S!lM!YmtS1U zD=)O7mF3XthcJl>iaOI4EJ%0qppq}j(KsY~HX-%=OU-A@!~@H0mbe2q16&Tozp`j- z2+p*L*9W%`R+KjUy7{nbBp-OJ7d5?tL%>3?s~js8SQgY{>axq?eNH=?s+AN+>X{-2 z-#Fz-Sx&4F8;u{6*?5I0NM{sv`SfgYw|q-9~fcddrl-4lQIzY0?4M{gXb}%=&Z}3+k*^8Woh#AH5{KYqa*yqD%5#|EU)+Q+ z$R*wjoK$roABTqbxv5s@1k}BcXS{wAG@0<0G{!-oW}6i}{tjD?kz0??L^Nbq`}}kD zy$gPNYuPn#Wfl(EMRa=pfz6Q`7?0k@z}NInYup8@sHjKFYGLVYFN=A4iM1r-L`aq_ zIc+>_^L=IPJji(2r?#PKB!+tFw245lAf}S*fhw9fKGwDEvx1G z-^sCy$7c7>LTxtI_Y9TDbZZe8+GsyUlX`WlH+N+c-pFbPUku!@d)y;0-u8MVhOW~K zZcJXJ7Li%wc6cTJ zoFHYEreczsH73MBW>Ce;ZQ4BK9-eNnIB2Nb5?hD!AY`bpFXpxgFl@) zYK|yG*5W&2GF?3j(CT6k2#Q` za;38MGKZcj^wB`OzO}4pHeY4s;8G^`XryiExR~#MWFpYT<%UM!>)4?<^Xnd3OT-fW zlq!|!NY>{)dA^)mP}ZVxFV&5a*(nau5zS<11>|=|*A{?^IiqiFmL=m_wsn zZF9JqM?d4gs}a+7^>2)A7ui#pW5ik{oyieb8K{wLcuo`)^h-K`t$LG9qZivmJC`?X zsX(21BBv>$YP{Km^nk%LuHObDV0Ix)UPMNc%$O)wfCq5 z-&Q2rhXi$?*n4%2^)k2jdG>E;#vGEfn$OD_VeN*MRq7I_zdBeR zu8}eH)A44V$%Jam)Ji`rq9h{REWFugQwWrJI#UN$Y)t|GNFofV-Oeo!pp6L}gAyBK z5z}*@5$RhMDAQ zv!|>(_3FIW+aajnBz529FlZywsMFctt`j-X=fHvSLlobO{&GhohC$6EtEu@j;o4{r z{5Em!&(+Rf+_(;B)YF@lRnin$qq;A&GVKgAowjL8Pt=T;A!$Phuc|5%!vPfM=r!&> zhOBrQMT$R<((p!zYdkF>)iU3YN2xtX%7GTG&T{7khp9@P^+r6=i4O{7MJ_3Dr4VWzf-2m6xJKIGB9Eolzmd@VrD2L zccW%ed!727+x{;bM&k=&JMO)KNIH;E330wY*^YfoJJ*R-_>tel)ONM2LKr_r(~)wj z1pa%YMhivEyP!^cJ;?8@qLMFM?5`=bM&Ck=Rr4xMvO2A^%uJ>n=~Lfp*VjE#uGzFt zjLgR(QaR#ec#`(Rj@MP}!xdqd=d&NM`@sHB6ZWV&`cZRt8GpR~YA{}qaRPox?G0L@ zXA*P~a#g`88LUpPjy)>DG$;e=s z04tC3QQzH3$!$^PBeOq4Ucr+8cnFo(7URxZJegNT>$oh{^^#7Xby5B|wEtfrTpeJ3 f&=HJ5>;j3>W|WZZ#nZ_E+yTi*D!wTdH}v~Il%kGN literal 0 HcmV?d00001 diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_status_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_status_ru.png new file mode 100644 index 0000000000000000000000000000000000000000..de3d124df01dcf8010040199f6ef2de0f569ee9a GIT binary patch literal 8293 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 literal 0 HcmV?d00001 diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload2_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload2_ru.png new file mode 100644 index 0000000000000000000000000000000000000000..600bbb626204b2ab89840370b00a14005d8c4c97 GIT binary patch literal 14147 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 literal 0 HcmV?d00001 diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html index bd5dd7acd..4240678cf 100644 --- a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html +++ b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html @@ -10,7 +10,7 @@

Управление удалённым сервером с помощью Агента

-

Служба Агент устанавливается на удалённый сервер и обеспечивает обмен конфигурациями между сервером и рабочей станцией инженера, на которой происходит работа над проектом SCADA-системы.

+

Служба Агент устанавливается на удалённый сервер и обеспечивает обмен конфигурациями между сервером и рабочей станцией инженера, на которой выполняется работа над проектом SCADA-системы.

Установка

@@ -22,11 +22,11 @@

Сценарии использования

Исходные данные: имеется удалённый сервер с установленной Rapid SCADA и Агентом, а также отдельная рабочая станция инженера, с которой осуществляются описанные в статье действия.

-

Изменение существующей конфигурации

+

Редактирование существующей конфигурации

-

Рекомендуется хранить конфигурации (проекты) Rapid SCADA на отдельном файловом сервере, который резервируется, либо использовать системы контроля версий типа Git. Чтобы передать необходимую для работы конфигурацию на производственный сервер, отредактируйте её на рабочей станции и используйте приложение Администратор для передачи.

+

Рекомендуется хранить конфигурации (проекты) Rapid SCADA на отдельном файловом сервере, который резервируется, либо использовать систему контроля версий типа Git. Чтобы передать необходимую для работы конфигурацию на производственный сервер, отредактируйте её на рабочей станции и используйте приложение Администратор для передачи.

-

Однако, возможна ситуация, когда конфигурация Rapid SCADA хранится только на удалённом сервере. В этом случае, чтобы отредактировать конфигурацию, необходимо сначала её скачать на рабочую станцию. Предварительно откройте в Администраторе файл базы конфигурации в формате SDF, в который будет импортирована редактируемая конфигурация. Выберите пункт меню Удалённый сервер > Скачать конфигурацию..., откроется форма, показанная на рисунке ниже.

+

Возможна ситуация, когда конфигурация Rapid SCADA хранится только на удалённом сервере. В этом случае, чтобы отредактировать конфигурацию, необходимо сначала её скачать на рабочую станцию. Предварительно откройте в Администраторе файл базы конфигурации в формате SDF, в который будет импортирована конфигурация для редактирования. После этого выберите пункт меню Удалённый сервер > Скачать конфигурацию..., откроется форма, показанная на рисунке ниже.

Скачивание конфигурации
@@ -34,6 +34,12 @@

Изменение существующей конфигурации

Для сценария с последующим редактированием конфигурации необходимо выбрать параметры скачивания именно так, как показано на рисунке. После успешного скачивания откроется форма импорта конфигурации из формата DAT в формат SDF. Дело в том, что рабочая копия конфигурации на сервере хранится в специализированном формате DAT, а для редактирования используется формат SDF. После успешного выполнения импорта редактируйте базу конфигурации Rapid SCADA и конфигурацию всех приложений на рабочей станции.

+

При первом использовании функционала скачивания и передачи конфигурации необходимо создать подключение к серверу, как показано на следующем рисунке. Проверка имени и пароля пользователя выполняется Агентом по базе конфигурации, работающей на удалённом сервере. Указанный пользователь должен иметь роль Администратор. Поля Экземпляр системы и Серетный ключ должны совпадать с соответствующими параметрами настройки Агента.

+ +

+ Настройки соединения
+

+

После того, как необходимое редактирование конфигурации завершено, передайте её обратно на удалённый сервер. Для этого выберите пункт меню Удалённый сервер > Передать конфигурацию..., откроется следующая форма:

@@ -42,7 +48,26 @@

Изменение существующей конфигурации

Сначала отметьте корневой узел дерева, чтобы выбрать все файлы конфигурации для передачи, а затем раскройте каждый узел дерева, чтобы проверить и исключить из выбора посторонние файлы, если они присутствуют. После успешной передачи конфигурации Агент перезапустит службы Сервера и Коммуникатора на удалённом сервере, чтобы изменения вступили в силу. Обязательно проверьте работоспособность сервера после передачи конфигурации.

-

Перенос конфигурации с одного сервера на другой

+

Копирование конфигурации с одного сервера на другой

+ +

Данный сценарий возможен в ситауации, когда существует тестовый и производственный сервера или основной и резервный сервера. Рассмотрим перенос конфигурации с сервера 1 на сервер 2.

+ +

Откройте диалог скачивания конфигурации и выберите параметры скачивания, как показано на рисунке. Отличия заключаются в том, что конфигурация сохраняется в архив, специфичные для сервера файлы не скачиваются, и импорт базы конфигурации не вызывается. После завершения скачивания можно открыть сохранённый файл архива и проверить, какие файлы конфигурации в него вошли.

+ +

+ Скачивание конфигурации
+

+ +

Затем вызовите диалог передачи конфигурации и создайте подключение к серверу 2. Выберите в качестве источника сохранённый ранее архив конфигурации и снимите галочку очистки специфичных файлов сервера. После передачи конфигурации проверьте работоспособность сервера 2.

+ +

+ Передача конфигурации
+

+ +

Проверить состояние сервера поможет соответствующая форма, которая вызывается из меню Удалённый сервер > Статус сервера... На форме необходимо выбрать подключение к серверу и нажать кнопку Соединиться. В случае, если состояние службы Сервера или Коммуникатора - ошибка, необходимо подключиться к файловой системе удалённого сервера и проанализировать журналы работы приложений Rapid SCADA. Кроме того, данная форма позволяет удалённо перезапустить службы Сервера и Коммуникатора.

+

+ Статус сервера
+

\ No newline at end of file From 748838cf2b1b3fd4f3271975a655a3af20be51fa Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 17 May 2018 21:11:24 +0300 Subject: [PATCH 089/100] ScadaWeb: fix plugin initialization --- .../version-history/webstation-history.html | 5 +++- .../version-history/webstation-history.html | 5 +++- .../PlgScheme/AppCode/PlgSchemeSpec.cs | 6 ++--- .../ScadaSchemeCommon/CompManager.cs | 26 +++++++++---------- .../ScadaSchemeEditor/AppCode/AppData.cs | 6 ++--- ScadaWeb/ScadaWebCommon5/DictUpdater.cs | 8 +++--- .../ScadaWebCommon5/Plugins/PluginSpec.cs | 16 +++++------- ScadaWeb/ScadaWebCommon5/WebUtils.cs | 2 +- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html index 65d6381de..c5a70a1e6 100644 --- a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html +++ b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html @@ -10,7 +10,10 @@

Webstation History

-
5.0.5.0 (March 16, 2018)
+    
5.0.6.0 (In developemnt)
+- Changed the base class for plugin specification
+
+5.0.5.0 (March 16, 2018)
 - Fixed error of jumping value formatting
 - Fixed error of formatting values after changing the culture
 - Queue for sending Ajax requests
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
index 2b9cfb629..87b767a7e 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
@@ -10,7 +10,10 @@
 
     

История приложения Вебстанция

-
5.0.5.0 (16.03.2018)
+    
5.0.6.0 (В разработке)
+- Изменён родительский класс спецификации плагина
+
+5.0.5.0 (16.03.2018)
 - Исправлена ошибка сбоев форматирования значений
 - Исправлена ошибка форматирования значений после смены культуры
 - Очередь для отправки Ajax-запросов
diff --git a/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs b/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs
index 840759d4b..3012de2f1 100644
--- a/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs
+++ b/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2016
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada.Scheme;
@@ -112,7 +112,7 @@ public override void Init()
 
             // инициализация менеджера компонентов
             CompManager compManager = CompManager.GetInstance();
-            compManager.Init(AppData.GetAppData().AppDirs.BinDir, Log);
+            compManager.Init(AppData.GetAppData().AppDirs, Log);
         }
 
         /// 
diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs
index b3fac217e..5fdccb8d4 100644
--- a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs
+++ b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,11 +20,12 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2017
- * Modified : 2017
+ * Modified : 2018
  */
 
 using Scada.Scheme.Model;
 using Scada.Scheme.Model.PropertyGrid;
+using Scada.Web;
 using Scada.Web.Plugins;
 using System;
 using System.Collections.Generic;
@@ -53,8 +54,8 @@ public sealed class CompManager
         /// 
         private static readonly CompManager instance;
 
-        private string binDir; // директория исполняемых файлов
-        private ILog log;      // журнал приложения
+        private AppDirs appDirs; // директории веб-приложения
+        private ILog log;        // журнал приложения
         private List allSpecs;                    // все спецификации библиотек
         private Dictionary factsByPrefix; // фабрики компонентов, ключ - XML-префикс
         private Dictionary specsByType;   // спецификации библиотек, ключ - имя типа компонента
@@ -81,7 +82,7 @@ static CompManager()
         /// 
private CompManager() { - binDir = ""; + appDirs = null; log = new LogStub(); allSpecs = new List(); factsByPrefix = new Dictionary(); @@ -156,15 +157,10 @@ private bool TypeIsStrandard(Type compType) /// /// Инициализировать менеджер компонентов /// - public void Init(string binDir, Log log) + public void Init(AppDirs appDirs, ILog log) { - if (string.IsNullOrEmpty(binDir)) - throw new ArgumentException("Directory must not be empty.", "binDir"); - if (log == null) - throw new ArgumentNullException("log"); - - this.binDir = binDir; - this.log = log; + this.appDirs = appDirs ?? throw new ArgumentNullException("appDirs"); + this.log = log ?? throw new ArgumentNullException("log"); } /// @@ -180,7 +176,7 @@ public void LoadCompFromFiles() ClearDicts(); AttrTranslator attrTranslator = new AttrTranslator(); - DirectoryInfo dirInfo = new DirectoryInfo(binDir); + DirectoryInfo dirInfo = new DirectoryInfo(appDirs.BinDir); FileInfo[] fileInfoArr = dirInfo.GetFiles(CompLibMask, SearchOption.TopDirectoryOnly); foreach (FileInfo fileInfo in fileInfoArr) @@ -195,6 +191,8 @@ public void LoadCompFromFiles() } else if (pluginSpec is ISchemeComp) { + pluginSpec.AppDirs = appDirs; + pluginSpec.Log = log; pluginSpec.Init(); if (AddComponents((ISchemeComp)pluginSpec, attrTranslator)) diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs index 58ad83a1a..dc25cd760 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs +++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2017 - * Modified : 2017 + * Modified : 2018 */ using Scada.Client; @@ -202,7 +202,7 @@ public void LoadComponents() Web.AppDirs webAppDirs = new Web.AppDirs(); webAppDirs.Init(AppDirs.WebDir); - CompManager.Init(webAppDirs.BinDir, Log); + CompManager.Init(webAppDirs, Log); CompManager.LoadCompFromFiles(); } diff --git a/ScadaWeb/ScadaWebCommon5/DictUpdater.cs b/ScadaWeb/ScadaWebCommon5/DictUpdater.cs index 8308ee1d2..5213bd97d 100644 --- a/ScadaWeb/ScadaWebCommon5/DictUpdater.cs +++ b/ScadaWeb/ScadaWebCommon5/DictUpdater.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2016 - * Modified : 2016 + * Modified : 2018 */ using System; @@ -49,7 +49,7 @@ public class DictUpdater /// /// Журнал /// - protected readonly Log log; + protected readonly ILog log; /// /// Первое обновление настроек /// @@ -66,7 +66,7 @@ protected DictUpdater() /// /// Конструктор /// - public DictUpdater(string directory, string fileNamePrefix, Action initPhrasesAction, Log log = null) + public DictUpdater(string directory, string fileNamePrefix, Action initPhrasesAction, ILog log = null) { if (directory == null) throw new ArgumentNullException("directory"); diff --git a/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs b/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs index 5ca428a35..9cbbdf3cd 100644 --- a/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs +++ b/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2016 - * Modified : 2016 + * Modified : 2018 */ using Scada.Web.Shell; @@ -39,7 +39,7 @@ namespace Scada.Web.Plugins public abstract class PluginSpec { private AppDirs appDirs; // директории веб-приложения - private Log log; // журнал + private ILog log; // журнал /// @@ -122,16 +122,14 @@ public AppDirs AppDirs } set { - if (value == null) - throw new ArgumentNullException("value"); - appDirs = value; + appDirs = value ?? throw new ArgumentNullException("value"); } } /// /// Получить или установить журнал /// - public Log Log + public ILog Log { get { @@ -139,9 +137,7 @@ public Log Log } set { - if (value == null) - throw new ArgumentNullException("value"); - log = value; + log = value ?? throw new ArgumentNullException("value"); } } diff --git a/ScadaWeb/ScadaWebCommon5/WebUtils.cs b/ScadaWeb/ScadaWebCommon5/WebUtils.cs index 2a47f1914..4a544b330 100644 --- a/ScadaWeb/ScadaWebCommon5/WebUtils.cs +++ b/ScadaWeb/ScadaWebCommon5/WebUtils.cs @@ -40,7 +40,7 @@ public static partial class WebUtils /// /// Версия веб-приложения /// - public const string AppVersion = "5.0.5.0"; + public const string AppVersion = "5.0.6.0"; /// /// Шиблон для вставки стилей на веб-страницу /// From 81263749998ca8b695ff4b10ccbf39469af9f79b Mon Sep 17 00:00:00 2001 From: 2mik Date: Thu, 17 May 2018 23:43:07 +0300 Subject: [PATCH 090/100] ScadaWeb: create log stub in plugin by default --- ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs b/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs index 9cbbdf3cd..eb24681c9 100644 --- a/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs +++ b/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs @@ -48,7 +48,7 @@ public abstract class PluginSpec public PluginSpec() { appDirs = new AppDirs(); - log = null; + log = new LogStub(); } From 129bdbcbb528842b2f9fe1fb01ef07e26d2b9bd2 Mon Sep 17 00:00:00 2001 From: 2mik Date: Fri, 18 May 2018 15:56:49 +0300 Subject: [PATCH 091/100] ScadaScheme: change Delete button behaviour --- ScadaDoc/ScadaDoc/ScadaDoc.csproj | 1 + .../scheme-editor-history.html | 21 ++++++++ .../scheme-editor-history.html | 6 ++- .../webstation-plugins-history.html | 2 +- ScadaDoc/ScadaDoc/js/contents-en.js | 1 + .../ScadaSchemeCommon/SchemeUtils.cs | 2 +- .../ScadaSchemeEditor/FrmMain.Designer.cs | 21 ++++---- .../ScadaScheme/ScadaSchemeEditor/FrmMain.cs | 12 ++--- .../ScadaSchemeEditor/FrmMain.resx | 50 +++++++++---------- 9 files changed, 68 insertions(+), 48 deletions(-) create mode 100644 ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html diff --git a/ScadaDoc/ScadaDoc/ScadaDoc.csproj b/ScadaDoc/ScadaDoc/ScadaDoc.csproj index 00bb633de..478d3037c 100644 --- a/ScadaDoc/ScadaDoc/ScadaDoc.csproj +++ b/ScadaDoc/ScadaDoc/ScadaDoc.csproj @@ -129,6 +129,7 @@ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html new file mode 100644 index 000000000..706f13804 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html @@ -0,0 +1,21 @@ + + + + Scheme Editor History - Rapid SCADA Documentation + + + + + + +

Scheme Editor History

+ +
5.2.1.1 (In development)
+- Working with properties, the Delete button does not delete the component
+- Fixed bug in the method which determines using the editor
+
+5.2.1.0 (March 16, 2018)
+- The main menu is added
+- Option to choose a browser
+ + diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html index 7749fe8ea..b8c314d62 100644 --- a/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html +++ b/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html @@ -10,7 +10,11 @@

История приложения Редактор схем

-
5.2.1.0 (16.03.2018)
+    
5.2.1.1 (В разработке)
+- При работе со свойствами кнопка Delete не удаляет компонент
+- Исправлена ошибка в методе определения запуска редактора
+
+5.2.1.0 (16.03.2018)
 - Добавлено главное меню
 - Опция выбора браузера
 
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
index a4e5612a5..e42a437fb 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
@@ -113,7 +113,7 @@ 

Таблицы

Схемы

PlgScheme 5.2.1.1 (В разработке)
-- Исправлена ошибка в методе определения запуска Редактора схем
+- Изменения относятся к Редактору схем
 
 PlgScheme 5.2.1.0 (16.03.2018)
 - Добавлено свойство ширины рамки для написей и рисунков
diff --git a/ScadaDoc/ScadaDoc/js/contents-en.js b/ScadaDoc/ScadaDoc/js/contents-en.js
index feb7a5772..0f942afca 100644
--- a/ScadaDoc/ScadaDoc/js/contents-en.js
+++ b/ScadaDoc/ScadaDoc/js/contents-en.js
@@ -49,4 +49,5 @@ function addContents(context) {
     addArticle(context, "version-history/communicator-history.html", "Communicator History", 1);
     addArticle(context, "version-history/administrator-history.html", "Administrator History", 1);
     addArticle(context, "version-history/webstation-history.html", "Webstation History", 1);
+    addArticle(context, "version-history/scheme-editor-history.html", "Scheme Editor History", 1);
 }
diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs
index 6317dcb64..21a8a0aa6 100644
--- a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs
+++ b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs
@@ -36,7 +36,7 @@ public static class SchemeUtils
         /// 
         /// Версия схем
         /// 
-        public const string SchemeVersion = "5.2.1.0";
+        public const string SchemeVersion = "5.2.1.1";
         /// 
         /// Цвет, устанавливаемый в зависимости от статуса входного канала
         /// 
diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs
index e971c614d..2196ac34f 100644
--- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs
+++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs
@@ -497,7 +497,7 @@ private void InitializeComponent()
             this.miEditCut.Image = ((System.Drawing.Image)(resources.GetObject("miEditCut.Image")));
             this.miEditCut.Name = "miEditCut";
             this.miEditCut.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X)));
-            this.miEditCut.Size = new System.Drawing.Size(144, 22);
+            this.miEditCut.Size = new System.Drawing.Size(180, 22);
             this.miEditCut.Text = "Cut";
             this.miEditCut.Click += new System.EventHandler(this.miEditCut_Click);
             // 
@@ -506,7 +506,7 @@ private void InitializeComponent()
             this.miEditCopy.Image = ((System.Drawing.Image)(resources.GetObject("miEditCopy.Image")));
             this.miEditCopy.Name = "miEditCopy";
             this.miEditCopy.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C)));
-            this.miEditCopy.Size = new System.Drawing.Size(144, 22);
+            this.miEditCopy.Size = new System.Drawing.Size(180, 22);
             this.miEditCopy.Text = "Copy";
             this.miEditCopy.Click += new System.EventHandler(this.miEditCopy_Click);
             // 
@@ -515,21 +515,21 @@ private void InitializeComponent()
             this.miEditPaste.Image = ((System.Drawing.Image)(resources.GetObject("miEditPaste.Image")));
             this.miEditPaste.Name = "miEditPaste";
             this.miEditPaste.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V)));
-            this.miEditPaste.Size = new System.Drawing.Size(144, 22);
+            this.miEditPaste.Size = new System.Drawing.Size(180, 22);
             this.miEditPaste.Text = "Paste";
             this.miEditPaste.Click += new System.EventHandler(this.miEditPaste_Click);
             // 
             // miEditSep1
             // 
             this.miEditSep1.Name = "miEditSep1";
-            this.miEditSep1.Size = new System.Drawing.Size(141, 6);
+            this.miEditSep1.Size = new System.Drawing.Size(177, 6);
             // 
             // miEditUndo
             // 
             this.miEditUndo.Image = ((System.Drawing.Image)(resources.GetObject("miEditUndo.Image")));
             this.miEditUndo.Name = "miEditUndo";
             this.miEditUndo.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z)));
-            this.miEditUndo.Size = new System.Drawing.Size(144, 22);
+            this.miEditUndo.Size = new System.Drawing.Size(180, 22);
             this.miEditUndo.Text = "Undo";
             this.miEditUndo.Click += new System.EventHandler(this.miEditUndo_Click);
             // 
@@ -538,20 +538,20 @@ private void InitializeComponent()
             this.miEditRedo.Image = ((System.Drawing.Image)(resources.GetObject("miEditRedo.Image")));
             this.miEditRedo.Name = "miEditRedo";
             this.miEditRedo.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y)));
-            this.miEditRedo.Size = new System.Drawing.Size(144, 22);
+            this.miEditRedo.Size = new System.Drawing.Size(180, 22);
             this.miEditRedo.Text = "Redo";
             this.miEditRedo.Click += new System.EventHandler(this.miEditRedo_Click);
             // 
             // miEditSep2
             // 
             this.miEditSep2.Name = "miEditSep2";
-            this.miEditSep2.Size = new System.Drawing.Size(141, 6);
+            this.miEditSep2.Size = new System.Drawing.Size(177, 6);
             // 
             // miEditPointer
             // 
             this.miEditPointer.Image = ((System.Drawing.Image)(resources.GetObject("miEditPointer.Image")));
             this.miEditPointer.Name = "miEditPointer";
-            this.miEditPointer.Size = new System.Drawing.Size(144, 22);
+            this.miEditPointer.Size = new System.Drawing.Size(180, 22);
             this.miEditPointer.Text = "Pointer";
             this.miEditPointer.Click += new System.EventHandler(this.miEditPointer_Click);
             // 
@@ -559,8 +559,7 @@ private void InitializeComponent()
             // 
             this.miEditDelete.Image = ((System.Drawing.Image)(resources.GetObject("miEditDelete.Image")));
             this.miEditDelete.Name = "miEditDelete";
-            this.miEditDelete.ShortcutKeys = System.Windows.Forms.Keys.Delete;
-            this.miEditDelete.Size = new System.Drawing.Size(144, 22);
+            this.miEditDelete.Size = new System.Drawing.Size(180, 22);
             this.miEditDelete.Text = "Delete";
             this.miEditDelete.Click += new System.EventHandler(this.miEditDelete_Click);
             // 
@@ -576,7 +575,7 @@ private void InitializeComponent()
             // 
             this.miToolsOptions.Image = ((System.Drawing.Image)(resources.GetObject("miToolsOptions.Image")));
             this.miToolsOptions.Name = "miToolsOptions";
-            this.miToolsOptions.Size = new System.Drawing.Size(125, 22);
+            this.miToolsOptions.Size = new System.Drawing.Size(180, 22);
             this.miToolsOptions.Text = "Options...";
             this.miToolsOptions.Click += new System.EventHandler(this.miToolsOptions_Click);
             // 
diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs
index 8483eb139..e45ee89bf 100644
--- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs
+++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs
@@ -728,16 +728,10 @@ private void FrmMain_Resize(object sender, EventArgs e)
 
         private void FrmMain_KeyDown(object sender, KeyEventArgs e)
         {
-            // реализация горячих клавиш, которые не обрабатываются автоматически главным меню
-            if (ActiveControl == propertyGrid)
+            // реализация горячих клавиш, которые не заданы для элементов главного меню
+            if (ActiveControl != propertyGrid && e.KeyCode == Keys.Escape)
             {
-                if (e.KeyCode == Keys.Delete)
-                    e.Handled = true;
-            }
-            else
-            {
-                if (e.KeyCode == Keys.Escape)
-                    miEditPointer_Click(null, null);
+                miEditPointer_Click(null, null);
             }
         }
 
diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx
index b1add4de1..c0d641af2 100644
--- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx
+++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx
@@ -204,14 +204,14 @@
     
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
         YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHMSURBVDhPYyAG/P//nwXKJAxWbNjXPXvpuidQLsO/f//0
-        b958+q66ddIGqBB+MHnOapP6+vp/VS0zJEH8r9+/t7b3zfiXnFMZA1ZADKifvfLX5DmrFgOdzv/oxZuX
-        afk1/8T5+RWh0oTBso27PnVNnvLz+OmLDQePnfttb+/+V0iIUxoqTRjMX7ltM8gbvVMX7i8H0j5+0a+g
-        UsSBzokLHEuAGpPz6v7Z27v+dfMOWgWVIh4k5NW/C0so/G+QVv/HL741AipMGES1v9WNaH+92b75wU/v
+        b958+q66ddIGqBB+MHnOapP6+vp/VS0zJEH8r9+/t7b1Tv+XnFMZA1ZADKifvfLX5DmrFgOdzv/oxZuX
+        afk1/8T5+RWh0oTBso27PnVNnvLz+OmLDQePnfttb+/2V0iIUxoqTRjMX7ltM8gbvVMX7i8H0j5+0a+g
+        UsSBzokLHEuAGpPz6v7Z27v8dfMOWgWVIh4k5NW/C0so/K+fVv/HL741AipMGES1v9WNaH+92b75wU/v
         khNrfeLP/vbLP//du/T0fJesXV5QZdhBRPsrw8iud5/9G85/twyc9sXUr+uuW96+N/7VV/+7Zu/8bxUz
         fwJUKXYQ2vpsQ1jb0/+OaRv+mwbV/zAJ6t3iXbLpl1fJFQmn9I0JJj71v6BKsQOf+ke/gpvuG9qnbDGQ
         BCq2COkV8qm++sur6ryBWcS0bHmH+N9QpdiBT/29X/4lVwzsklYngQwAiXkWHT9rl7Tqv6ZN8n8ZeaUv
         YIW4gHflxXP2Sav/Gwd0/Vc3CnsMFGK2T1kdqWqS8E7dPPy9sV9bBkQlDuCUsTnCKGTSY1WT2HcGXlV5
-        UGFaAgYGAEqKyTZ3WJd2AAAAAElFTkSuQmCC
+        UGFaAgYGADjeyTBarefvAAAAAElFTkSuQmCC
 
   
   
@@ -250,13 +250,13 @@
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
         YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHnSURBVDhPY6ApmLTlW8zEjV93zNz98dGyA1+OrNj/Zcqy
         I1+loNL4Qe+GrzvqN1z5073u6/PGFR8f1y/+cmfuzo+Pl+36+gmrId2rXv1fcvKLAYjdtfbLsv7593+n
-        9Lx64xJ/4rdW6vY/+gnrv9uX3f04c+vXN6v2f7kJ1gQDK4/942xc8vL/vP1fr9Yv/9pQv+nqn7j6Y/9c
-        C47/t8vY9MskdtVx+/ytD7Xi2/6Edbz8ufjA5/tQrQhQPPP5/6xZn/8XzvnyP7Lr3Qsrpy1/zaIX/zCJ
+        9Lx64xJ/4rdW6vY/+gnrv9uX3f04c+vXN6v2f7kJ1gQDK4/942xc8vL/vP1fr9Yv/9pQv+nKn7j6o/9c
+        C47/t8vY9MskdtVx+/ytD7XiW/+Edbz8ufjA5/tQrQhQPPP5/6xZn/8XzvnyP7Lr3Qsrxy1/zaIX/zCJ
         XpkPkvet36FiGLzghWv59ff1S7/sAWtCBkl9z/57N735H937+X/ZnDf/NbwmrTaKWuEIlWZgCA1llo8/
-        9Nu17M7r+pVfDkFFESCo+el/s+L7/z2bXoFdktjz6H/twreWUGkGY+M0VjuP/X/d6p59a1rxeQtUGAGc
-        Kh7/dyi69t8q8/h/k/ht/w2j1v7X8Jn6HyrNYJK4Rsk2c8E/+5ZTf/OnPSqFCuMGoICFMsFA3Xuyu1bZ
-        lT9p9ef+1a/6zwYVJh5YpOy7GFJ//l9Y3dlcqBBxILHvg5J93vkYf6Bmt8or3xgY/jNCpYgDHpVPnH3q
-        n/6yz9r/0zhyhRdUmHgQ0fM50rnkaqNB4kpRqNCgAgwMAPK/85lL2oFiAAAAAElFTkSuQmCC
+        9Nu17M7r+pVfDkFFESCo+el/s+L7/z2bXoFdktjz6H/twreWUGkGY+M0Vjv3/X/d6p59a1rxeQtUGAGc
+        Kh7/dyi69t8q8/h/k/ht/w2j1v7X8Jn6HyrNYJK4Rsk2c/4/+5aTf/OnPSqFCuMGoICFMsFA3Xuyu1bZ
+        lT9p9Wf/1a/6zwYVJh5YpOy7GFJ/7l9Y3dlcqBBxILHvg5J93vkYf6Bmt8or3xgY/jNCpYgDHpVPnH3q
+        n/6yz9r/0zhyhRdUmHgQ0fM50rnkaqNB4kpRqNCgAgwMAN1984+XEVaTAAAAAElFTkSuQmCC
 
   
   
@@ -265,12 +265,12 @@
         YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHPSURBVDhPY6AaWHbkq9SK/V+mLDvw5cjM3R8f9az/klK4
         8h8nVBo/AGletuvrp7k7Pz6uX/zlTuOKj49bV325UzL/y+fKhV9Socpwg1X7v9ycufXrG/fyB+/1E9Z/
         10rZ9sc+d//XlMnvXhTO+fKiYO7nMJC6JSe/GDgUXfsP1oQMFh/4fD+s4+VP+ej5v13y1t80jl5zzDR2
-        zRf5+Pm/nSZf+ps++f2zrLmfI+ft/3rVOvP4/5XH0LxWv/TLHtfy6+9VPXpu+dbvUAGJmUSvzFeLXPpV
+        zRf5+Pm/HSdf/Js++f2zrLmfI+ft/3rVOvP4/5XH0LxWv/TLHtfy6+9VPXpu+dbvUAGJmUSvzFeLXPpV
         0mf2L/+W98+BLvmfNevzf5P4rZguqF/55ZBT8b1XKp59hxlCQ5mhwgxGUSscNbwmrS6b8+Z/dO/n/95N
-        b/7rhS7GNKBpxect9kUvvqp4T7hpbJzGChVmmLz1s+6UrV/BNns2vfpvVnz/v4bPVEwD8qc9KrVvPf1X
-        0mfNL3HXYm6oMAMowKyAfjaJ3/ZfL2QJWLOqWxcWL6z6z5ZWf+6fVtmVP+rek92hwmCAEWC4QFjd2dyQ
-        +vP/LFL2XYQKkQr+M3pXXntp33L+r33e+ZjEvg9KUAnigYrHYj6vypunAlo/ffWofOIMFSYdeDe+Co3o
-        +RwJ5Q5qwMAAAP6q6T5lxW8NAAAAAElFTkSuQmCC
+        b/7rhS7GNKBpxect9kUvvqp4T7hpbJzGChVmmLz1s+6UrV/BNns2vfpvVnz/v4bPVEwD8qc9KrVvPfVX
+        0mfNL3HXYm6oMAMowKyAfjaJ3/ZfL2QJWLOqWxcWL6z6z5ZWf/afVtmVP+rek92hwmCAEWC4QFjd2dyQ
+        +nP/LFL2XYQKkQr+M3pXXntp33Lur33e+ZjEvg9KUAnigYrHYj6vypunAlo/ffWofOIMFSYdeDe+Co3o
+        +RwJ5Q5qwMAAAPJ06Tid5phHAAAAAElFTkSuQmCC
 
   
   
@@ -289,15 +289,15 @@
   
     
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH3SURBVDhPrZNNTBNBFMdHUMIW2I9ZWmgCLlQkWqWx3Zlu
-        1cTykXDg42AaD1449ADxYjx758TJcPBiPHIxkXAxJpJ4NzEo0pjQxMYYTbwZWjiwu+8x0w6HUgkk+kv2
-        MO/99+2b/3tL/gvIjVuha21C1p5EQtpU+HzgA9IOrrUEi7NYWZjygdP7MqbSTWCeXERmJITmsQo1gsBo
-        MeT0DRSncbeYDMT56ckimHc6ZYeVhUk/ZOYLFW4Amd44ZGmuXqTAEB7exZBbG5Dq66rncwNamB/eqBQc
-        X2hWMBntrr94EkySDvH1J5Vpx5eFhHgNPDMliq2qoqvoWoaS/x1h4gXw6PUgQ7fklX7OxQ9rM6mqMPm1
-        7ETJzgZde1y2DPNj6GfoN8jpVKXOBj1jKOB0u8wpHKRNrKZ19F1rV6VPR+4ApE3Hd41SOdkf/LrRswnc
-        ZtLc3zd1BG4+kldU8laQR/sDL7ZVmxjC0kik/K6vfVxOQj4ho88/OZq/ndCYkjcj5xzmYq+qt7tqHwe1
-        vQ+XtYJKqR2g+o/RSLmU6Hy7bpHBFkMha84eeDH8nNDwy3Bk/XgHjmlcLzryfuDS/s5VLdu08nL+YsbL
-        3691484V7Svw3tEmgUJu55+U/hKYzVvyYhszIbOeCaPuwR275zSz6v+DG4+o479CyBF/3tFH9OOHfwAA
+        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH3SURBVDhPrZNPTBNBFMYHEcMW2D+ztNAEXKhItGhjuzPd
+        KglFTDiIHkzjwQuHHjRejGfvnDgRDl6MRy8mEi7GRBLvJAREGmNJbAyBxJuxlYO7+x4z7XAotcFEf8ke
+        5r1v37753lvyX0BuXAtdaw2y9gwSckaF/w68TzrBtR7BwzmszN/ygdN7MqbSTWCenEVmJITmiQo1gsBo
+        MeT0LRRn8UsxGYjzs5NFMO90yw4r8zN+yMwXKtwAMv1xyNJcvUiBITyYxJBbq5Aa6Knnc0NamB9drRQc
+        X2gWMRntrb94EkySc+LrTyuzji8LCfEr8MyUKLasii6jaxlK/meEiR3g0ctBhm7KK+3fif+u3U5Vhclv
+        ZCdKdjro2tOyZbh7Ff0M/Qo5narU6aBnjAScbpc5hcO0idW0jr5rlVW6PXIHIG06vmuUysnB4GCibw24
+        zaS536/oCNx8LK+o5K0gjw4GXmyzdnMES2OR3fcDndNyEvIJGX2+5Wj+dkJjSt6MnHOYi72uXu+pbQxr
+        P9fPawWVUjtA9b3xyG4p0f1uxSLDLYZC1pw79GL4MaHhp9HIyvEOHNO4XnTsw1DXr52LWrZp5eX8xYwX
+        vl3qxZ0L2mfg/eNNAoXczh8p/SUwm7fkxTZmQmYtCaOm4Ibd186s+v/gxiPq+K8QcgR5CdFE2NbC7AAA
         AABJRU5ErkJggg==
 
   
@@ -312,7 +312,7 @@
         AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
         LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
         ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACs
-        EgAAAk1TRnQBSQFMAgEBBgEAAZABAAGQAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA
+        EgAAAk1TRnQBSQFMAgEBBgEAAZgBAAGYAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA
         AwABIAMAAQEBAAEgBgABIP8AGwADBAEGAw0EEgEYAxIBGAMSARgDEgEYAxIBGAMSARgDEgEYAxIBGAMS
         ARgDDQESAwQBBiAAAwQBBgFzAVkBRQH/AWgBTgE6Af8BOwE4ATYBV5wAAw0BEgMjATYDKwFJAysBSQMr
         AUkDKwFJAysBSQMrAUkDKwFJAysBSQMrAUkDIwE2Aw0BEiAAAWMBWwFUAZYBgQFnAVMB/wHKAbIBpAH/

From 9c49004a1f56c846a0d4a074ed13f2e09ebfcf81 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 18 May 2018 16:14:17 +0300
Subject: [PATCH 092/100] ScadaComm: fix reading bug

---
 ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs b/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs
index 0e9ac54e8..d71167f48 100644
--- a/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs
+++ b/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs
@@ -167,7 +167,7 @@ public override int Read(byte[] buffer, int offset, int maxCount, int timeout, C
                 int curInd = offset;
                 SerialPort.ReadTimeout = 0;
 
-                while (readCnt <= maxCount && !stopReceived && startDT <= nowDT && nowDT <= stopDT)
+                while (readCnt < maxCount && !stopReceived && startDT <= nowDT && nowDT <= stopDT)
                 {
                     bool readOk;
                     try { readOk = SerialPort.Read(buffer, curInd, 1) > 0; }

From 37ebf080ab7116f08c2506b68220cab42ab65c4f Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 18 May 2018 16:14:27 +0300
Subject: [PATCH 093/100] ScadaDoc: update history

---
 .../content/en/version-history/communicator-history.html      | 3 ++-
 .../content/en/version-history/scheme-editor-history.html     | 2 +-
 .../content/en/version-history/webstation-history.html        | 4 ++--
 .../content/ru/version-history/communicator-history.html      | 1 +
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html
index afe4d378f..7686500a9 100644
--- a/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html
+++ b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html
@@ -11,6 +11,7 @@
     

Communicator History

5.1.0.3 (In development)
-- The status of the service is displayed in the status file
+- The status of the service is displayed in the status file +- Fixed a bug in reading from the serial port with a stop condition
diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html index 706f13804..e9b50052d 100644 --- a/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html +++ b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html @@ -12,7 +12,7 @@

Scheme Editor History

5.2.1.1 (In development)
 - Working with properties, the Delete button does not delete the component
-- Fixed bug in the method which determines using the editor
+- Fixed a bug in the method which determines using the editor
 
 5.2.1.0 (March 16, 2018)
 - The main menu is added
diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html
index c5a70a1e6..9a82f48d2 100644
--- a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html
+++ b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html
@@ -14,8 +14,8 @@ 

Webstation History

- Changed the base class for plugin specification 5.0.5.0 (March 16, 2018) -- Fixed error of jumping value formatting -- Fixed error of formatting values after changing the culture +- Fixed a bug of jumping value formatting +- Fixed a bug of formatting values after changing the culture - Queue for sending Ajax requests - Protect sensitive files from accessing through a browser
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html index ed61dc90a..901bfdfe5 100644 --- a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html +++ b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html @@ -12,6 +12,7 @@

История приложения Коммуникатор

5.1.0.3 (В разработке)
 - В файл состояния выводится состояние работы службы
+- Исправлена ошибка считывания из последовательного порта с условием остановки
 
 5.1.0.2 (21.12.2017)
 - Исправлена ошибка при разрыве соединения в канале связи UDP

From e71e5a14a10fff472868261b8df75c997cc123d0 Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Fri, 18 May 2018 17:33:42 +0300
Subject: [PATCH 094/100] ScadaWeb: fix UserMonitor.GetActiveUsers()

---
 ScadaWeb/ScadaWebCommon5/UserMonitor.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ScadaWeb/ScadaWebCommon5/UserMonitor.cs b/ScadaWeb/ScadaWebCommon5/UserMonitor.cs
index 5307b9204..1daa3dce4 100644
--- a/ScadaWeb/ScadaWebCommon5/UserMonitor.cs
+++ b/ScadaWeb/ScadaWebCommon5/UserMonitor.cs
@@ -321,7 +321,7 @@ public UserShot[] GetActiveUsers()
             {
                 lock (userDataDict)
                 {
-                    UserShot[] userShotArr = new UserData[userDataDict.Count];
+                    UserShot[] userShotArr = new UserShot[userDataDict.Count];
                     int i = 0;
 
                     foreach (UserData userData in userDataDict.Values)

From cad014abcdb3bb81711b8d042c4748531e212c8b Mon Sep 17 00:00:00 2001
From: 2mik 
Date: Mon, 21 May 2018 11:57:20 +0300
Subject: [PATCH 095/100] ScadaDoc: add roadmap

---
 ScadaDoc/ScadaDoc/ScadaDoc.csproj             |  2 +
 .../content/en/software-overview/roadmap.html | 88 +++++++++++++++++++
 .../content/ru/software-overview/roadmap.html | 88 +++++++++++++++++++
 ScadaDoc/ScadaDoc/js/contents-en.js           |  1 +
 ScadaDoc/ScadaDoc/js/contents-ru.js           |  1 +
 5 files changed, 180 insertions(+)
 create mode 100644 ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html
 create mode 100644 ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html

diff --git a/ScadaDoc/ScadaDoc/ScadaDoc.csproj b/ScadaDoc/ScadaDoc/ScadaDoc.csproj
index 478d3037c..8fa98119c 100644
--- a/ScadaDoc/ScadaDoc/ScadaDoc.csproj
+++ b/ScadaDoc/ScadaDoc/ScadaDoc.csproj
@@ -112,6 +112,7 @@
     
     
     
+    
     
     
     
@@ -240,6 +241,7 @@
     
     
     
+    
     
     
     
diff --git a/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html b/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html
new file mode 100644
index 000000000..82a1c481a
--- /dev/null
+++ b/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html
@@ -0,0 +1,88 @@
+
+
+
+    Roadmap - Rapid SCADA Documentation
+    
+    
+    
+    
+
+
+    

Roadmap

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Main Features
Unified development environment of Rapid SCADA projectsIn development
The Agent application for interacting with remote serversIn development
Schemes
Binding any properties of scheme components to input channelsNot included in plan
Displaying popups by a linkPlanned in 2018
New scheme componentsCommunity help is appreciated
New images for schemesCommunity help is appreciated
Communicator Drivers
IEC-61850 DriverCommunity help is appreciated
BACnet DriverCommunity help is appreciated
Server Modules
Module for automatic generation of reports on a scheduleNot included in plan
Voice ModuleCommunity help is appreciated
Webstation Plugins
Update Chart Pro Plugin according to feedback from usersNot included in plan
Improvement of Dashboard PluginNot included in plan
Development of a plugin for downloading and uploading archivesNot included in plan
+ + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html b/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html new file mode 100644 index 000000000..718ad03e3 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html @@ -0,0 +1,88 @@ + + + + Дорожная карта - Документация Rapid SCADA + + + + + + +

Дорожная карта

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Основная функциональность
Единая среда разработки проектов Rapid SCADAВ разработке
Приложение Агент для взаимодействия с удалёнными серверамиВ разработке
Мнемосхемы
Привязка произвольных свойств компонентов схем к входным каналамНе включено в план
Вызов всплывающих окон по ссылкеПланируется в 2018
Новые компоненты схемПриветствуется помощь сообщества
Новые изображения для схемПриветствуется помощь сообщества
Драйверы Коммуникатора
Драйвер IEC-61850Приветствуется помощь сообщества
Драйвер BACnetПриветствуется помощь сообщества
Модули Сервера
Модуль автоматической генерации отчётов по расписаниюНе включено в план
Голосовой модульПриветствуется помощь сообщества
Плагины Вебстанции
Обновление плагина Графики Про согласно пожеланиям пользователейНе включено в план
Развитие плагина ДэшбордыНе включено в план
Разработка плагина выгрузки и загрузки архивовНе включено в план
+ + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/js/contents-en.js b/ScadaDoc/ScadaDoc/js/contents-en.js index 0f942afca..4c65ac7d1 100644 --- a/ScadaDoc/ScadaDoc/js/contents-en.js +++ b/ScadaDoc/ScadaDoc/js/contents-en.js @@ -11,6 +11,7 @@ function addContents(context) { addArticle(context, "software-overview/applications/administrator-application.html", "Administrator Application", 2); addArticle(context, "software-overview/applications/table-editor-application.html", "Table Editor Application", 2); addArticle(context, "software-overview/applications/scheme-editor-application.html", "Scheme Editor Application", 2); + addArticle(context, "software-overview/roadmap.html", "Roadmap", 1); addArticle(context, "installation-and-run/", "Installation and Run"); addArticle(context, "installation-and-run/system-requirements.html", "System Requirements", 1); diff --git a/ScadaDoc/ScadaDoc/js/contents-ru.js b/ScadaDoc/ScadaDoc/js/contents-ru.js index 24ee4fa75..a4e87bdbe 100644 --- a/ScadaDoc/ScadaDoc/js/contents-ru.js +++ b/ScadaDoc/ScadaDoc/js/contents-ru.js @@ -11,6 +11,7 @@ function addContents(context) { addArticle(context, "software-overview/applications/administrator-application.html", "Приложение Администратор", 2); addArticle(context, "software-overview/applications/table-editor-application.html", "Приложение Редактор таблиц", 2); addArticle(context, "software-overview/applications/scheme-editor-application.html", "Приложение Редактор схем", 2); + addArticle(context, "software-overview/roadmap.html", "Дорожная карта", 1); addArticle(context, "installation-and-run/", "Установка и запуск"); addArticle(context, "installation-and-run/system-requirements.html", "Системные требования", 1); From dfff01d92f29e31483a23af94a4fcfd4122d2e0d Mon Sep 17 00:00:00 2001 From: 2mik Date: Mon, 21 May 2018 12:03:47 +0300 Subject: [PATCH 096/100] ScadaDoc: update roadmap --- .../content/en/software-overview/roadmap.html | 12 ++++++++++++ .../content/ru/software-overview/roadmap.html | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html b/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html index 82a1c481a..11734729b 100644 --- a/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html +++ b/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html @@ -55,6 +55,10 @@

Roadmap

BACnet Driver Community help is appreciated + + Any new drivers + Community help is appreciated + Server Modules @@ -67,6 +71,10 @@

Roadmap

Voice Module Community help is appreciated + + Any new modules + Community help is appreciated + Webstation Plugins @@ -83,6 +91,10 @@

Roadmap

Development of a plugin for downloading and uploading archives Not included in plan + + Any new plugins + Community help is appreciated + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html b/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html index 718ad03e3..da530a83a 100644 --- a/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html +++ b/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html @@ -55,6 +55,10 @@

Дорожная карта

Драйвер BACnet Приветствуется помощь сообщества + + Любые новые драйверы + Приветствуется помощь сообщества + Модули Сервера @@ -67,6 +71,10 @@

Дорожная карта

Голосовой модуль Приветствуется помощь сообщества + + Любые новые модули + Приветствуется помощь сообщества + Плагины Вебстанции @@ -83,6 +91,10 @@

Дорожная карта

Разработка плагина выгрузки и загрузки архивов Не включено в план + + Любые новые плагины + Приветствуется помощь сообщества + \ No newline at end of file From e4d4cb9fcbf0833ee557a51e4863d98a875901d1 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 23 May 2018 10:21:35 +0300 Subject: [PATCH 097/100] ScadaTableEditor: update ruleset path --- ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj index 1c00dc0ef..71a1568b4 100644 --- a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj +++ b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj @@ -58,7 +58,7 @@ prompt true true - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\ManagedMinimumRules.ruleset + ..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2017\Community\Team Tools\Static Analysis Tools\Rule Sets\ManagedMinimumRules.ruleset app.manifest From 3a7cbebb059f6f5745e47e2c49cc37ba2ab35162 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 23 May 2018 10:25:29 +0300 Subject: [PATCH 098/100] ScadaTableEditor: fix ruleset --- ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj index 71a1568b4..69807a24c 100644 --- a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj +++ b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj @@ -58,7 +58,7 @@ prompt true true - ..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2017\Community\Team Tools\Static Analysis Tools\Rule Sets\ManagedMinimumRules.ruleset + MinimumRecommendedRules.ruleset app.manifest From 267f474d4f5ba7d25ade712d24fe8601fa1e89ec Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 23 May 2018 10:30:56 +0300 Subject: [PATCH 099/100] ScadaTableEditor: fix ruleset again --- ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj index 69807a24c..05265d513 100644 --- a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj +++ b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj @@ -44,10 +44,6 @@ full AnyCPU prompt - true - true - false - ..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\MinimumRecommendedRules.ruleset bin\Release\ @@ -56,9 +52,6 @@ pdbonly AnyCPU prompt - true - true - MinimumRecommendedRules.ruleset app.manifest From 4dc92d457393aba919bbd17d7506e6c8a9d594d3 Mon Sep 17 00:00:00 2001 From: 2mik Date: Wed, 23 May 2018 11:02:59 +0300 Subject: [PATCH 100/100] Update version numbers --- .../en/version-history/administrator-history.html | 2 +- .../en/version-history/communicator-history.html | 2 +- .../content/en/version-history/scada-history.html | 10 +++++++++- .../en/version-history/scheme-editor-history.html | 2 +- .../en/version-history/webstation-history.html | 2 +- .../ru/version-history/administrator-history.html | 2 +- .../ru/version-history/communicator-history.html | 2 +- .../content/ru/version-history/scada-history.html | 10 +++++++++- .../ru/version-history/scheme-editor-history.html | 2 +- .../ru/version-history/webstation-history.html | 2 +- .../webstation-plugins-history.html | 15 ++++++++++++--- 11 files changed, 38 insertions(+), 13 deletions(-) diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html index db74f13e5..b717b5d72 100644 --- a/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html +++ b/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html @@ -10,7 +10,7 @@

Administrator History

-
5.1.0.0 (In development)
+    
5.1.0.0 (May 23, 2018)
 - Interaction with Agent for downloading and uploading configurations
diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html index 7686500a9..096e2152e 100644 --- a/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html +++ b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html @@ -10,7 +10,7 @@

Communicator History

-
5.1.0.3 (In development)
+    
5.1.0.3 (May 23, 2018)
 - The status of the service is displayed in the status file
 - Fixed a bug in reading from the serial port with a stop condition
diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html index 133d615d4..551d84889 100644 --- a/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html +++ b/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html @@ -9,7 +9,15 @@

Rapid SCADA History

-
Rapid SCADA 5.5.1 (March 16, 2018)
+    
Rapid SCADA 5.5.2 (May 23, 2018)
+  Server 5.1.0.3
+  Communicator 5.1.0.3
+  Webstation 5.0.6.0
+  Administrator 5.1.0.0
+  Table Editor 5.0.1.0
+  Scheme Editor 5.2.1.1
+
+Rapid SCADA 5.5.1 (March 16, 2018)
   Server 5.1.0.3
   Communicator 5.1.0.2
     Modbus Driver 5.1.0.2
diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html
index e9b50052d..13a4f09f0 100644
--- a/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html
+++ b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html
@@ -10,7 +10,7 @@
 
     

Scheme Editor History

-
5.2.1.1 (In development)
+    
5.2.1.1 (May 23, 2018)
 - Working with properties, the Delete button does not delete the component
 - Fixed a bug in the method which determines using the editor
 
diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html
index 9a82f48d2..25cf4e525 100644
--- a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html
+++ b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html
@@ -10,7 +10,7 @@
 
     

Webstation History

-
5.0.6.0 (In developemnt)
+    
5.0.6.0 (May 23, 2018)
 - Changed the base class for plugin specification
 
 5.0.5.0 (March 16, 2018)
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html
index 831949abc..1d51ec20c 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html
@@ -10,7 +10,7 @@
 
     

История приложения Администратор

-
5.1.0.0 (В разработке)
+    
5.1.0.0 (23.05.2018)
 - Взаимодействие с Агентом для скачивания и передачи конфигурации
 
 5.0.0.2 (25.09.2017)
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
index 901bfdfe5..73f74dc9e 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
@@ -10,7 +10,7 @@
 
     

История приложения Коммуникатор

-
5.1.0.3 (В разработке)
+    
5.1.0.3 (23.05.2018)
 - В файл состояния выводится состояние работы службы
 - Исправлена ошибка считывания из последовательного порта с условием остановки
 
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html
index f76a9aa16..d4a230d27 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html
@@ -10,7 +10,15 @@
 
     

История Rapid SCADA

-
Rapid SCADA 5.5.1 (16.03.2018)
+    
Rapid SCADA 5.5.2 (23.05.2018)
+  Сервер 5.1.0.3
+  Коммуникатор 5.1.0.3
+  Вебстанция 5.0.6.0
+  Администратор 5.1.0.0
+  Редактор таблиц 5.0.1.0
+  Редактор схем 5.2.1.1
+
+Rapid SCADA 5.5.1 (16.03.2018)
   Сервер 5.1.0.3
   Коммуникатор 5.1.0.2
     Драйвер Modbus 5.1.0.2
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html
index b8c314d62..eec313974 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html
@@ -10,7 +10,7 @@
 
     

История приложения Редактор схем

-
5.2.1.1 (В разработке)
+    
5.2.1.1 (23.05.2018)
 - При работе со свойствами кнопка Delete не удаляет компонент
 - Исправлена ошибка в методе определения запуска редактора
 
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
index 87b767a7e..b516b5374 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
@@ -10,7 +10,7 @@
 
     

История приложения Вебстанция

-
5.0.6.0 (В разработке)
+    
5.0.6.0 (23.05.2018)
 - Изменён родительский класс спецификации плагина
 
 5.0.5.0 (16.03.2018)
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
index e42a437fb..9b5eb4172 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
@@ -15,7 +15,10 @@ 

Графики

- Рефакторинг

Графики Про

-
PlgChartPro 5.0.2.0 (21.12.2017)
+    
PlgChartPro 5.0.2.1 (23.05.2018)
+- Сборка в связи с изменениями в базовых библиотеках
+
+PlgChartPro 5.0.2.0 (21.12.2017)
 - Регистрационная форма перенесена в меню Регистрация
 
 PlgChartPro 5.0.1.1 (25.09.2017)
@@ -46,7 +49,10 @@ 

Конфигуратор

- Исправлена ошибка получения списка плагинов на Linux

Дэшборды

-
PlgDashboard 5.0.1.1 (16.03.2018)
+    
PlgDashboard 5.0.1.2 (22.05.2018)
+- Сборка в связи с изменениями в базовых библиотеках
+
+PlgDashboard 5.0.1.1 (16.03.2018)
 - Обновление в связи с изменениями в базовых библиотеках
 
 PlgDashboard 5.0.1.0 (21.12.2017)
@@ -64,7 +70,10 @@ 

Дэшборды

- Первоначальная разработка плагина

Гибкий отчёт

-
PlgElasticReport 5.0.2.0 (21.12.2017)
+    
PlgElasticReport 5.0.2.1 (23.05.2018)
+- Сборка в связи с изменениями в базовых библиотеках
+
+PlgElasticReport 5.0.2.0 (21.12.2017)
 - Регистрационная форма перенесена в меню Регистрация
 
 PlgElasticReport 5.0.1.2 (25.09.2017)