From 9a0e31e5b82110f101e827f689a7f41ae017a324 Mon Sep 17 00:00:00 2001 From: "kenneth.skovhede@gmail.com" Date: Mon, 6 Jun 2011 18:48:52 +0000 Subject: [PATCH] Preliminary work on the standalone server component git-svn-id: https://duplicati.googlecode.com/svn/branches/v2.0@785 59da171f-624f-0410-aa54-27559c288bec --- Duplicati.sln | 350 +- .../Duplicati.GUI.TrayIcon.csproj | 84 + .../MainForm.Designer.cs | 39 + .../GUI/Duplicati.GUI.TrayIcon/MainForm.cs | 19 + .../GUI/Duplicati.GUI.TrayIcon/Program.cs | 21 + .../Properties/AssemblyInfo.cs | 36 + .../Properties/Resources.Designer.cs | 71 + .../Properties/Resources.resx | 117 + .../Properties/Settings.Designer.cs | 30 + .../Properties/Settings.settings | 7 + .../Duplicati.Library.Backend.SSHv2.csproj | 18 + .../Library/Interface/CommandLineArgument.cs | 1 + Duplicati/Library/Snapshots/app.config | 3 + .../Utility/Duplicati.Library.Utility.csproj | 1 + Duplicati/Library/Utility/WorkerThread.cs | 334 + Duplicati/Server/DatabaseUpgrader.cs | 185 + .../ApplicationSettings.cs | 298 + .../Duplicati.Server.Serialization/Backend.cs | 16 + .../Duplicati.Server.Serialization.csproj | 78 + .../Duplicati.snk | Bin 0 -> 596 bytes .../EncryptionModule.cs | 16 + .../GenericModule.cs | 16 + .../Properties/AssemblyInfo.cs | 36 + .../Schedule.cs | 19 + .../Duplicati.Server.Serialization/Task.cs | 22 + Duplicati/Server/Duplicati.Server.csproj | 271 + Duplicati/Server/DuplicatiOutputParser.cs | 99 + Duplicati/Server/DuplicatiRunner.cs | 580 ++ Duplicati/Server/DynamicSetupHelper.cs | 168 + Duplicati/Server/EventQueue.cs | 129 + Duplicati/Server/LiveControls.cs | 244 + Duplicati/Server/Program.cs | 478 + Duplicati/Server/Properties/AssemblyInfo.cs | 36 + Duplicati/Server/SQLiteLoader.cs | 89 + Duplicati/Server/Scheduler.cs | 275 + Duplicati/Server/SingleInstance.cs | 283 + .../Strings/DatabaseUpgrader.Designer.cs | 114 + .../Server/Strings/DatabaseUpgrader.resx | 146 + .../Strings/DuplicatiRunner.Designer.cs | 144 + Duplicati/Server/Strings/DuplicatiRunner.resx | 147 + .../Strings/DynamicSetupHelper.Designer.cs | 72 + .../Server/Strings/DynamicSetupHelper.resx | 123 + Duplicati/Server/Strings/Program.Designer.cs | 193 + Duplicati/Server/Strings/Program.resx | 172 + .../Server/Strings/Scheduler.Designer.cs | 72 + Duplicati/Server/Strings/Scheduler.resx | 123 + Duplicati/Server/Strings/TaskType.Designer.cs | 153 + Duplicati/Server/Strings/TaskType.resx | 150 + Duplicati/Server/TaskPackages.cs | 728 ++ Duplicati/Server/WebServer.cs | 141 + Duplicati/Server/app.config | 3 + thirdparty/HttpServer/Fadd.dll | Bin 0 -> 206336 bytes thirdparty/HttpServer/Fadd.xml | 9136 +++++++++++++++++ thirdparty/HttpServer/Homepage.txt | 1 + thirdparty/HttpServer/HttpServer.MVC.dll | Bin 0 -> 56320 bytes thirdparty/HttpServer/HttpServer.dll | Bin 0 -> 127488 bytes thirdparty/HttpServer/HttpServer.xml | 5778 +++++++++++ thirdparty/HttpServer/license.txt | 69 + thirdparty/HttpServer/xunit.dll | Bin 0 -> 65536 bytes 59 files changed, 21785 insertions(+), 149 deletions(-) create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.Designer.cs create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.cs create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/AssemblyInfo.cs create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.Designer.cs create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.resx create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.Designer.cs create mode 100644 Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.settings create mode 100644 Duplicati/Library/Snapshots/app.config create mode 100644 Duplicati/Library/Utility/WorkerThread.cs create mode 100644 Duplicati/Server/DatabaseUpgrader.cs create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/ApplicationSettings.cs create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/Backend.cs create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/Duplicati.Server.Serialization.csproj create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/Duplicati.snk create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/EncryptionModule.cs create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/GenericModule.cs create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/Properties/AssemblyInfo.cs create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/Schedule.cs create mode 100644 Duplicati/Server/Duplicati.Server.Serialization/Task.cs create mode 100644 Duplicati/Server/Duplicati.Server.csproj create mode 100644 Duplicati/Server/DuplicatiOutputParser.cs create mode 100644 Duplicati/Server/DuplicatiRunner.cs create mode 100644 Duplicati/Server/DynamicSetupHelper.cs create mode 100644 Duplicati/Server/EventQueue.cs create mode 100644 Duplicati/Server/LiveControls.cs create mode 100644 Duplicati/Server/Program.cs create mode 100644 Duplicati/Server/Properties/AssemblyInfo.cs create mode 100644 Duplicati/Server/SQLiteLoader.cs create mode 100644 Duplicati/Server/Scheduler.cs create mode 100644 Duplicati/Server/SingleInstance.cs create mode 100644 Duplicati/Server/Strings/DatabaseUpgrader.Designer.cs create mode 100644 Duplicati/Server/Strings/DatabaseUpgrader.resx create mode 100644 Duplicati/Server/Strings/DuplicatiRunner.Designer.cs create mode 100644 Duplicati/Server/Strings/DuplicatiRunner.resx create mode 100644 Duplicati/Server/Strings/DynamicSetupHelper.Designer.cs create mode 100644 Duplicati/Server/Strings/DynamicSetupHelper.resx create mode 100644 Duplicati/Server/Strings/Program.Designer.cs create mode 100644 Duplicati/Server/Strings/Program.resx create mode 100644 Duplicati/Server/Strings/Scheduler.Designer.cs create mode 100644 Duplicati/Server/Strings/Scheduler.resx create mode 100644 Duplicati/Server/Strings/TaskType.Designer.cs create mode 100644 Duplicati/Server/Strings/TaskType.resx create mode 100644 Duplicati/Server/TaskPackages.cs create mode 100644 Duplicati/Server/WebServer.cs create mode 100644 Duplicati/Server/app.config create mode 100644 thirdparty/HttpServer/Fadd.dll create mode 100644 thirdparty/HttpServer/Fadd.xml create mode 100644 thirdparty/HttpServer/Homepage.txt create mode 100644 thirdparty/HttpServer/HttpServer.MVC.dll create mode 100644 thirdparty/HttpServer/HttpServer.dll create mode 100644 thirdparty/HttpServer/HttpServer.xml create mode 100644 thirdparty/HttpServer/license.txt create mode 100644 thirdparty/HttpServer/xunit.dll diff --git a/Duplicati.sln b/Duplicati.sln index bd30ed5b2..ba6d168fe 100644 --- a/Duplicati.sln +++ b/Duplicati.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati", "Duplicati\GUI\Duplicati.csproj", "{1470F75F-D364-4010-91D0-FD4DDA1C5159}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.GUI", "Duplicati\GUI\Duplicati.GUI.csproj", "{1470F75F-D364-4010-91D0-FD4DDA1C5159}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Utility", "Duplicati\Library\Utility\Duplicati.Library.Utility.csproj", "{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}" EndProject @@ -51,6 +51,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.T EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.SSHv2", "Duplicati\Library\Backend\SSHv2\Duplicati.Library.Backend.SSHv2.csproj", "{FF2BF37C-E502-4C98-BEA0-701671DDFA08}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Server", "Duplicati\Server\Duplicati.Server.csproj", "{19E661D2-C5DA-4F35-B3EE-7586E5734B5F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Server.Serialization", "Duplicati\Server\Duplicati.Server.Serialization\Duplicati.Server.Serialization.csproj", "{33FD1D24-C28F-4C71-933F-98F1586EA76C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.GUI.TrayIcon", "Duplicati\GUI\Duplicati.GUI.TrayIcon\Duplicati.GUI.TrayIcon.csproj", "{17566860-3D98-4604-AA5B-47661F75609F}" +EndProject Global GlobalSection(SubversionScc) = preSolution Svn-Managed = True @@ -70,314 +76,311 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Debug|x86.ActiveCfg = Debug|x86 {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Debug|x86.Build.0 = Debug|x86 {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Release|Any CPU.ActiveCfg = Release|Any CPU {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Release|Any CPU.Build.0 = Release|Any CPU - {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Release|Mixed Platforms.ActiveCfg = Release|x86 {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Release|x86.ActiveCfg = Release|x86 {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Release|x86.Build.0 = Release|x86 {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Test|Any CPU.ActiveCfg = Release|Any CPU {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Test|Any CPU.Build.0 = Release|Any CPU - {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Test|Mixed Platforms.ActiveCfg = Release|x86 {1470F75F-D364-4010-91D0-FD4DDA1C5159}.Test|x86.ActiveCfg = Release|Any CPU {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|Mixed Platforms.Build.0 = Debug|x86 {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|x86.ActiveCfg = Debug|x86 {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Debug|x86.Build.0 = Debug|x86 {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|Any CPU.ActiveCfg = Release|Any CPU {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|Any CPU.Build.0 = Release|Any CPU - {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|Mixed Platforms.Build.0 = Release|x86 {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|x86.ActiveCfg = Release|x86 {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Release|x86.Build.0 = Release|x86 {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Test|Any CPU.ActiveCfg = Release|Any CPU {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Test|Any CPU.Build.0 = Release|Any CPU - {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Test|Mixed Platforms.Build.0 = Release|x86 {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}.Test|x86.ActiveCfg = Release|Any CPU {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|Mixed Platforms.Build.0 = Debug|x86 {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|x86.ActiveCfg = Debug|x86 {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Debug|x86.Build.0 = Debug|x86 {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|Any CPU.ActiveCfg = Release|Any CPU {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|Any CPU.Build.0 = Release|Any CPU - {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|Mixed Platforms.Build.0 = Release|x86 {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|x86.ActiveCfg = Release|x86 {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Release|x86.Build.0 = Release|x86 {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Test|Any CPU.ActiveCfg = Release|Any CPU {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Test|Any CPU.Build.0 = Release|Any CPU - {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Test|Mixed Platforms.Build.0 = Release|x86 {10D2D1B7-C664-41D8-9B3A-00040C3D421B}.Test|x86.ActiveCfg = Release|Any CPU {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Mixed Platforms.Build.0 = Debug|x86 {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|x86.ActiveCfg = Debug|x86 {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|x86.Build.0 = Debug|x86 {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Any CPU.ActiveCfg = Release|Any CPU {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Any CPU.Build.0 = Release|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Mixed Platforms.Build.0 = Release|x86 {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|x86.ActiveCfg = Release|x86 {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|x86.Build.0 = Release|x86 {FC9B7611-836F-4127-8B44-A7C31F506807}.Test|Any CPU.ActiveCfg = Release|Any CPU {FC9B7611-836F-4127-8B44-A7C31F506807}.Test|Any CPU.Build.0 = Release|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {FC9B7611-836F-4127-8B44-A7C31F506807}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {FC9B7611-836F-4127-8B44-A7C31F506807}.Test|Mixed Platforms.Build.0 = Release|x86 {FC9B7611-836F-4127-8B44-A7C31F506807}.Test|x86.ActiveCfg = Release|Any CPU {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Mixed Platforms.Build.0 = Debug|x86 {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|x86.ActiveCfg = Debug|x86 {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|x86.Build.0 = Debug|x86 {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Any CPU.ActiveCfg = Release|Any CPU {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Any CPU.Build.0 = Release|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Mixed Platforms.Build.0 = Release|x86 {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|x86.ActiveCfg = Release|x86 {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|x86.Build.0 = Release|x86 {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Test|Any CPU.ActiveCfg = Release|Any CPU {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Test|Any CPU.Build.0 = Release|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Test|Mixed Platforms.Build.0 = Release|x86 {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Test|x86.ActiveCfg = Release|Any CPU {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|Any CPU.Build.0 = Debug|Any CPU - {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|Mixed Platforms.Build.0 = Debug|x86 {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|x86.ActiveCfg = Debug|x86 {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Debug|x86.Build.0 = Debug|x86 {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|Any CPU.ActiveCfg = Release|Any CPU {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|Any CPU.Build.0 = Release|Any CPU - {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|Mixed Platforms.Build.0 = Release|x86 {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|x86.ActiveCfg = Release|x86 {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Release|x86.Build.0 = Release|x86 {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Test|Any CPU.ActiveCfg = Release|Any CPU {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Test|Any CPU.Build.0 = Release|Any CPU - {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Test|Mixed Platforms.Build.0 = Release|x86 {19ECCE09-B5EB-406C-8C57-BAC66997D469}.Test|x86.ActiveCfg = Release|Any CPU {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Any CPU.Build.0 = Debug|Any CPU - {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Mixed Platforms.Build.0 = Debug|x86 {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|x86.ActiveCfg = Debug|x86 {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|x86.Build.0 = Debug|x86 {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Any CPU.ActiveCfg = Release|Any CPU {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Any CPU.Build.0 = Release|Any CPU - {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Mixed Platforms.Build.0 = Release|x86 {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|x86.ActiveCfg = Release|x86 {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|x86.Build.0 = Release|x86 {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Test|Any CPU.ActiveCfg = Release|Any CPU {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Test|Any CPU.Build.0 = Release|Any CPU - {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Test|Mixed Platforms.Build.0 = Release|x86 {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Test|x86.ActiveCfg = Release|Any CPU {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|Mixed Platforms.Build.0 = Debug|x86 {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|x86.ActiveCfg = Debug|x86 {47FE73E1-0832-44F7-96B9-2580273206C3}.Debug|x86.Build.0 = Debug|x86 {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|Any CPU.Build.0 = Release|Any CPU - {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|Mixed Platforms.Build.0 = Release|x86 {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|x86.ActiveCfg = Release|x86 {47FE73E1-0832-44F7-96B9-2580273206C3}.Release|x86.Build.0 = Release|x86 {47FE73E1-0832-44F7-96B9-2580273206C3}.Test|Any CPU.ActiveCfg = Release|Any CPU {47FE73E1-0832-44F7-96B9-2580273206C3}.Test|Any CPU.Build.0 = Release|Any CPU - {47FE73E1-0832-44F7-96B9-2580273206C3}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {47FE73E1-0832-44F7-96B9-2580273206C3}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {47FE73E1-0832-44F7-96B9-2580273206C3}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {47FE73E1-0832-44F7-96B9-2580273206C3}.Test|Mixed Platforms.Build.0 = Release|x86 {47FE73E1-0832-44F7-96B9-2580273206C3}.Test|x86.ActiveCfg = Release|Any CPU {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Mixed Platforms.Build.0 = Debug|x86 {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|x86.ActiveCfg = Debug|x86 {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|x86.Build.0 = Debug|x86 {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Any CPU.ActiveCfg = Release|Any CPU {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Any CPU.Build.0 = Release|Any CPU - {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Mixed Platforms.Build.0 = Release|x86 {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|x86.ActiveCfg = Release|x86 {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|x86.Build.0 = Release|x86 {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Test|Any CPU.ActiveCfg = Release|Any CPU {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Test|Any CPU.Build.0 = Release|Any CPU - {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Test|Mixed Platforms.Build.0 = Release|x86 {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Test|x86.ActiveCfg = Release|Any CPU {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|Mixed Platforms.Build.0 = Debug|x86 {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|x86.ActiveCfg = Debug|x86 {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Debug|x86.Build.0 = Debug|x86 {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|Any CPU.ActiveCfg = Release|Any CPU {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|Any CPU.Build.0 = Release|Any CPU - {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|Mixed Platforms.Build.0 = Release|x86 {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|x86.ActiveCfg = Release|x86 {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Release|x86.Build.0 = Release|x86 {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Test|Any CPU.ActiveCfg = Release|Any CPU {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Test|Any CPU.Build.0 = Release|Any CPU - {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Test|Mixed Platforms.Build.0 = Release|x86 {C03F6DFD-805A-4BE0-9338-64870ADDB4A2}.Test|x86.ActiveCfg = Release|Any CPU {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|Any CPU.Build.0 = Debug|Any CPU - {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|Mixed Platforms.Build.0 = Debug|x86 {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|x86.ActiveCfg = Debug|x86 {81765A64-3661-4E3E-B850-2F6F87A51F74}.Debug|x86.Build.0 = Debug|x86 {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|Any CPU.ActiveCfg = Release|Any CPU {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|Any CPU.Build.0 = Release|Any CPU - {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|Mixed Platforms.Build.0 = Release|x86 {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|x86.ActiveCfg = Release|x86 {81765A64-3661-4E3E-B850-2F6F87A51F74}.Release|x86.Build.0 = Release|x86 {81765A64-3661-4E3E-B850-2F6F87A51F74}.Test|Any CPU.ActiveCfg = Release|Any CPU {81765A64-3661-4E3E-B850-2F6F87A51F74}.Test|Any CPU.Build.0 = Release|Any CPU - {81765A64-3661-4E3E-B850-2F6F87A51F74}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {81765A64-3661-4E3E-B850-2F6F87A51F74}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {81765A64-3661-4E3E-B850-2F6F87A51F74}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {81765A64-3661-4E3E-B850-2F6F87A51F74}.Test|Mixed Platforms.Build.0 = Release|x86 {81765A64-3661-4E3E-B850-2F6F87A51F74}.Test|x86.ActiveCfg = Release|Any CPU {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|Mixed Platforms.Build.0 = Debug|x86 {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|x86.ActiveCfg = Debug|x86 {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Debug|x86.Build.0 = Debug|x86 {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|Any CPU.Build.0 = Release|Any CPU - {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|Mixed Platforms.Build.0 = Release|x86 {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|x86.ActiveCfg = Release|x86 {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Release|x86.Build.0 = Release|x86 {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Test|Any CPU.ActiveCfg = Release|Any CPU {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Test|Any CPU.Build.0 = Release|Any CPU - {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Test|Mixed Platforms.Build.0 = Release|x86 {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F}.Test|x86.ActiveCfg = Release|Any CPU {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|Mixed Platforms.Build.0 = Debug|x86 {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|x86.ActiveCfg = Debug|x86 {BAE27510-8B5D-44B2-B33E-372A98908041}.Debug|x86.Build.0 = Debug|x86 {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|Any CPU.ActiveCfg = Release|Any CPU {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|Any CPU.Build.0 = Release|Any CPU - {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|Mixed Platforms.Build.0 = Release|x86 {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|x86.ActiveCfg = Release|x86 {BAE27510-8B5D-44B2-B33E-372A98908041}.Release|x86.Build.0 = Release|x86 {BAE27510-8B5D-44B2-B33E-372A98908041}.Test|Any CPU.ActiveCfg = Release|Any CPU {BAE27510-8B5D-44B2-B33E-372A98908041}.Test|Any CPU.Build.0 = Release|Any CPU - {BAE27510-8B5D-44B2-B33E-372A98908041}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {BAE27510-8B5D-44B2-B33E-372A98908041}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {BAE27510-8B5D-44B2-B33E-372A98908041}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {BAE27510-8B5D-44B2-B33E-372A98908041}.Test|Mixed Platforms.Build.0 = Release|x86 {BAE27510-8B5D-44B2-B33E-372A98908041}.Test|x86.ActiveCfg = Release|Any CPU {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|Mixed Platforms.Build.0 = Debug|x86 {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|x86.ActiveCfg = Debug|x86 {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Debug|x86.Build.0 = Debug|x86 {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|Any CPU.Build.0 = Release|Any CPU - {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|Mixed Platforms.Build.0 = Release|x86 {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|x86.ActiveCfg = Release|x86 {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Release|x86.Build.0 = Release|x86 {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Test|Any CPU.ActiveCfg = Release|Any CPU {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Test|Any CPU.Build.0 = Release|Any CPU - {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Test|Mixed Platforms.Build.0 = Release|x86 {1BFAE226-8364-4086-825C-BB83F6F3EE4C}.Test|x86.ActiveCfg = Release|Any CPU {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|Mixed Platforms.Build.0 = Debug|x86 {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|x86.ActiveCfg = Debug|x86 {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Debug|x86.Build.0 = Debug|x86 {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|Any CPU.ActiveCfg = Release|Any CPU {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|Any CPU.Build.0 = Release|Any CPU - {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|Mixed Platforms.Build.0 = Release|x86 {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|x86.ActiveCfg = Release|x86 {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Release|x86.Build.0 = Release|x86 {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Test|Any CPU.ActiveCfg = Release|Any CPU {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Test|Any CPU.Build.0 = Release|Any CPU - {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Test|Mixed Platforms.Build.0 = Release|x86 {B60D0993-B0C5-457A-90D9-DB6EEB33CE47}.Test|x86.ActiveCfg = Release|Any CPU {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|Mixed Platforms.Build.0 = Debug|x86 {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|x86.ActiveCfg = Debug|x86 {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Debug|x86.Build.0 = Debug|x86 {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|Any CPU.ActiveCfg = Release|Any CPU {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|Any CPU.Build.0 = Release|Any CPU - {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|Mixed Platforms.Build.0 = Release|x86 {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|x86.ActiveCfg = Release|x86 {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Release|x86.Build.0 = Release|x86 {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Test|Any CPU.ActiveCfg = Release|Any CPU {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Test|Any CPU.Build.0 = Release|Any CPU - {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Test|Mixed Platforms.Build.0 = Release|x86 {F2854848-BF78-4A6D-9A2A-2AE2AFB70DF1}.Test|x86.ActiveCfg = Release|Any CPU {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|Mixed Platforms.Build.0 = Debug|x86 {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|x86.ActiveCfg = Debug|x86 {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Debug|x86.Build.0 = Debug|x86 {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|Any CPU.Build.0 = Release|Any CPU - {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|Mixed Platforms.Build.0 = Release|x86 {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|x86.ActiveCfg = Release|x86 {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Release|x86.Build.0 = Release|x86 {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Test|Any CPU.ActiveCfg = Release|Any CPU {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Test|Any CPU.Build.0 = Release|Any CPU - {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Test|Mixed Platforms.Build.0 = Release|x86 {E7280DCA-7776-4A73-B9B5-41FD77FC8799}.Test|x86.ActiveCfg = Release|Any CPU {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|Mixed Platforms.Build.0 = Debug|x86 {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|x86.ActiveCfg = Debug|x86 {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Debug|x86.Build.0 = Debug|x86 {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|Any CPU.ActiveCfg = Release|Any CPU {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|Any CPU.Build.0 = Release|Any CPU - {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|Mixed Platforms.Build.0 = Release|x86 {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|x86.ActiveCfg = Release|x86 {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Release|x86.Build.0 = Release|x86 {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Test|Any CPU.ActiveCfg = Release|Any CPU {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Test|Any CPU.Build.0 = Release|Any CPU - {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Test|Mixed Platforms.Build.0 = Release|x86 {C5899F45-B0FF-483C-9D38-24A9FCAAB237}.Test|x86.ActiveCfg = Release|Any CPU {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Mixed Platforms.Build.0 = Debug|x86 {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|x86.ActiveCfg = Debug|x86 {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|x86.Build.0 = Debug|x86 {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -393,104 +396,153 @@ Global {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Test|x86.Build.0 = Release|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|Mixed Platforms.Build.0 = Debug|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|x86.ActiveCfg = Debug|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Debug|x86.Build.0 = Debug|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|Any CPU.ActiveCfg = Release|Any CPU {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|Any CPU.Build.0 = Release|Any CPU - {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|Mixed Platforms.Build.0 = Release|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|x86.ActiveCfg = Release|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Release|x86.Build.0 = Release|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Test|Any CPU.ActiveCfg = Release|Any CPU {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Test|Any CPU.Build.0 = Release|Any CPU - {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Test|Mixed Platforms.Build.0 = Release|x86 {D63E53E4-A458-4C2F-914D-92F715F58ACE}.Test|x86.ActiveCfg = Release|Any CPU {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|Mixed Platforms.Build.0 = Debug|x86 {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|x86.ActiveCfg = Debug|x86 {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Debug|x86.Build.0 = Debug|x86 {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|Any CPU.Build.0 = Release|Any CPU - {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|Mixed Platforms.Build.0 = Release|x86 {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|x86.ActiveCfg = Release|x86 {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Release|x86.Build.0 = Release|x86 {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Test|Any CPU.ActiveCfg = Release|Any CPU {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Test|Any CPU.Build.0 = Release|Any CPU - {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Test|Mixed Platforms.Build.0 = Release|x86 {4D012CB1-4B92-47F4-89B7-BF80A73A2E99}.Test|x86.ActiveCfg = Release|Any CPU {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|Mixed Platforms.Build.0 = Debug|x86 {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|x86.ActiveCfg = Debug|x86 {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Debug|x86.Build.0 = Debug|x86 {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|Any CPU.ActiveCfg = Release|Any CPU {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|Any CPU.Build.0 = Release|Any CPU - {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|Mixed Platforms.Build.0 = Release|x86 {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|x86.ActiveCfg = Release|x86 {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Release|x86.Build.0 = Release|x86 {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Test|Any CPU.ActiveCfg = Release|Any CPU {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Test|Any CPU.Build.0 = Release|Any CPU - {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Test|Mixed Platforms.Build.0 = Release|x86 {7886BA79-A38A-4288-8B8A-9F29D0E15AC0}.Test|x86.ActiveCfg = Release|Any CPU {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|Mixed Platforms.Build.0 = Debug|x86 {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|x86.ActiveCfg = Debug|x86 {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Debug|x86.Build.0 = Debug|x86 {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|Any CPU.ActiveCfg = Release|Any CPU {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|Any CPU.Build.0 = Release|Any CPU - {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|Mixed Platforms.Build.0 = Release|x86 {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|x86.ActiveCfg = Release|x86 {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Release|x86.Build.0 = Release|x86 {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Test|Any CPU.ActiveCfg = Release|Any CPU {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Test|Any CPU.Build.0 = Release|Any CPU - {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Test|Mixed Platforms.Build.0 = Release|x86 {52826615-7964-47FE-B4B3-1B2DBDF605B9}.Test|x86.ActiveCfg = Release|Any CPU {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|Mixed Platforms.Build.0 = Debug|x86 {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|x86.ActiveCfg = Debug|x86 {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Debug|x86.Build.0 = Debug|x86 {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|Any CPU.Build.0 = Release|Any CPU - {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|Mixed Platforms.Build.0 = Release|x86 {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|x86.ActiveCfg = Release|x86 {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Release|x86.Build.0 = Release|x86 {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Test|Any CPU.ActiveCfg = Release|Any CPU {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Test|Any CPU.Build.0 = Release|Any CPU - {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Test|Mixed Platforms.Build.0 = Release|x86 {C0270709-2A40-43B5-8CF1-69581B9FA2A1}.Test|x86.ActiveCfg = Release|Any CPU {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|x86.ActiveCfg = Debug|Any CPU + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|x86.ActiveCfg = Debug|x86 + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Debug|x86.Build.0 = Debug|x86 {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|Any CPU.Build.0 = Release|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|x86.ActiveCfg = Release|Any CPU + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|Mixed Platforms.Build.0 = Release|x86 + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|x86.ActiveCfg = Release|x86 + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Release|x86.Build.0 = Release|x86 {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Test|Any CPU.ActiveCfg = Release|Any CPU {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Test|Any CPU.Build.0 = Release|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU - {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Test|Mixed Platforms.Build.0 = Release|x86 {FF2BF37C-E502-4C98-BEA0-701671DDFA08}.Test|x86.ActiveCfg = Release|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Debug|x86.ActiveCfg = Debug|x86 + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Debug|x86.Build.0 = Debug|x86 + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Release|Any CPU.Build.0 = Release|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Release|x86.ActiveCfg = Release|x86 + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Release|x86.Build.0 = Release|x86 + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Test|Any CPU.ActiveCfg = Release|x86 + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Test|x86.ActiveCfg = Release|x86 + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F}.Test|x86.Build.0 = Release|x86 + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Debug|x86.ActiveCfg = Debug|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Release|Any CPU.Build.0 = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Release|x86.ActiveCfg = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Test|Any CPU.ActiveCfg = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Test|Any CPU.Build.0 = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Test|Mixed Platforms.Build.0 = Release|Any CPU + {33FD1D24-C28F-4C71-933F-98F1586EA76C}.Test|x86.ActiveCfg = Release|Any CPU + {17566860-3D98-4604-AA5B-47661F75609F}.Debug|Any CPU.ActiveCfg = Debug|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Debug|x86.ActiveCfg = Debug|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Debug|x86.Build.0 = Debug|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Release|Any CPU.ActiveCfg = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Release|Mixed Platforms.Build.0 = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Release|x86.ActiveCfg = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Release|x86.Build.0 = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Test|Any CPU.ActiveCfg = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Test|Mixed Platforms.ActiveCfg = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Test|Mixed Platforms.Build.0 = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Test|x86.ActiveCfg = Release|x86 + {17566860-3D98-4604-AA5B-47661F75609F}.Test|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj new file mode 100644 index 000000000..25af7de26 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj @@ -0,0 +1,84 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {17566860-3D98-4604-AA5B-47661F75609F} + WinExe + Properties + Duplicati.GUI.TrayIcon + Duplicati.GUI.TrayIcon + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + \ No newline at end of file diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.Designer.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.Designer.cs new file mode 100644 index 000000000..eff239a24 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.Designer.cs @@ -0,0 +1,39 @@ +namespace Duplicati.GUI.TrayIcon +{ + partial class MainForm + { + /// + /// 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.Text = "Form1"; + } + + #endregion + } +} + diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.cs new file mode 100644 index 000000000..7ea55bd29 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/MainForm.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 Duplicati.GUI.TrayIcon +{ + public partial class MainForm : Form + { + public MainForm() + { + InitializeComponent(); + } + } +} diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs new file mode 100644 index 000000000..ef343c79a --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace Duplicati.GUI.TrayIcon +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } +} diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/AssemblyInfo.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c5edf1394 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +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("Duplicati.GUI.TrayIcon")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Duplicati.GUI.TrayIcon")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("33531def-3214-4568-bfb0-0bdeabe4a798")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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")] diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.Designer.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.Designer.cs new file mode 100644 index 000000000..92f7e5ae5 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.GUI.TrayIcon.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.GUI.TrayIcon.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.resx b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.resx new file mode 100644 index 000000000..ffecec851 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.Designer.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.Designer.cs new file mode 100644 index 000000000..828ce2482 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.GUI.TrayIcon.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.settings b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.settings new file mode 100644 index 000000000..abf36c5d3 --- /dev/null +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj b/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj index 29ad2c0da..07e54a2e3 100644 --- a/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj +++ b/Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj @@ -36,6 +36,24 @@ Duplicati.snk + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + false + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + False diff --git a/Duplicati/Library/Interface/CommandLineArgument.cs b/Duplicati/Library/Interface/CommandLineArgument.cs index ba6d76741..ff17f8047 100644 --- a/Duplicati/Library/Interface/CommandLineArgument.cs +++ b/Duplicati/Library/Interface/CommandLineArgument.cs @@ -26,6 +26,7 @@ namespace Duplicati.Library.Interface /// /// Primary implementation of the ICommandLineArgument interface. /// + [Serializable] public class CommandLineArgument : Duplicati.Library.Interface.ICommandLineArgument { public enum ArgumentType diff --git a/Duplicati/Library/Snapshots/app.config b/Duplicati/Library/Snapshots/app.config new file mode 100644 index 000000000..89dc7d426 --- /dev/null +++ b/Duplicati/Library/Snapshots/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj index 649457a84..ec431749d 100644 --- a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj +++ b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj @@ -108,6 +108,7 @@ + diff --git a/Duplicati/Library/Utility/WorkerThread.cs b/Duplicati/Library/Utility/WorkerThread.cs new file mode 100644 index 000000000..2134d04a4 --- /dev/null +++ b/Duplicati/Library/Utility/WorkerThread.cs @@ -0,0 +1,334 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Duplicati.Library.Utility +{ + /// + /// Class to encapsulate a thread that runs a list of queued operations + /// + /// The type to operate on + public class WorkerThread where Tx : class + { + /// + /// Locking object for shared data + /// + private object m_lock = new object(); + /// + /// The wait event + /// + private AutoResetEvent m_event; + /// + /// The internal list of tasks to perform + /// + private Queue m_tasks; + /// + /// A flag used to terminate the thread + /// + private volatile bool m_terminate; + /// + /// The coordinating thread + /// + private Thread m_thread; + + /// + /// A value indicating if the coordinating thread is running + /// + private volatile bool m_active; + + /// + /// The current task being processed + /// + private Tx m_currentTask; + /// + /// A callback that performs the actual work on the item + /// + private ProcessItemDelegate m_delegate; + + /// + /// A delegate used to signal a changed state + /// + /// The sender of the event + /// The new state + public delegate void WorkerStateChangedDelegate(WorkerThread sender, RunState state); + + /// + /// An event that is raised when the runner state changes + /// + public event WorkerStateChangedDelegate WorkerStateChanged; + + /// + /// Event that occurs when a new operation is being processed + /// + public event EventHandler StartingWork; + /// + /// Event that occurs when an operation has completed + /// + public event EventHandler CompletedWork; + /// + /// An evnet that occurs when a new task is added to the queue or an existing one is removed + /// + public event EventHandler WorkQueueChanged; + + public delegate void ProcessItemDelegate(Tx item); + + /// + /// The internal state + /// + private volatile RunState m_state; + + /// + /// The states the scheduler can take + /// + public enum RunState + { + /// + /// The program is running as normal + /// + Run, + /// + /// The program is suspended by the user + /// + Paused + } + + /// + /// Constructs a new WorkerThread + /// + /// The callback that performs the work + public WorkerThread(ProcessItemDelegate item, bool paused) + { + m_delegate = item; + m_event = new AutoResetEvent(paused); + m_terminate = false; + m_tasks = new Queue(); + m_state = paused ? WorkerThread.RunState.Paused : WorkerThread.RunState.Run; + + m_thread = new Thread(new ThreadStart(Runner)); + m_thread.IsBackground = true; + m_thread.Start(); + } + + /// + /// Gets a copy of the current queue + /// + public List CurrentTasks + { + get + { + lock(m_lock) + return new List(m_tasks); + } + + } + + /// + /// Gets a value indicating if the worker is running + /// + public bool Active + { + get { return m_active; } + } + + /// + /// Adds a task to the queue + /// + /// The task to add + public void AddTask(Tx task) + { + lock (m_lock) + { + m_tasks.Enqueue(task); + m_event.Set(); + } + + if (WorkQueueChanged != null) + WorkQueueChanged(this, null); + } + + /// + /// Removes a task from the queue, does not remove the task if it is currently running + /// + /// The task to remove + public void RemoveTask(Tx task) + { + lock (m_lock) + { + Queue tmp = new Queue(); + while (m_tasks.Count > 0) + { + Tx n = m_tasks.Dequeue(); + if (n != task) + tmp.Enqueue(n); + } + + m_tasks = tmp; + } + + if (WorkQueueChanged != null) + WorkQueueChanged(this, null); + } + + /// + /// This will clear the pending queue + /// True if the current running thread should be aborted + /// + public void ClearQueue(bool abortThread) + { + lock (m_lock) + m_tasks.Clear(); + + if (abortThread) + { + try + { + m_thread.Abort(); + m_thread.Join(500); + } + catch + { + } + + m_thread = new Thread(new ThreadStart(Runner)); + m_thread.Start(); + } + } + + /// + /// Gets a reference to the currently executing task. + /// BEWARE: This is not protected by a mutex, DO NOT MODIFY IT!!!! + /// + public Tx CurrentTask + { + get + { + return m_currentTask; + } + } + + /// + /// Terminates the thread. Any items still in queue will be removed + /// + /// True if the call should block until the thread has exited, false otherwise + public void Terminate(bool wait) + { + m_terminate = true; + m_event.Set(); + + if (wait) + m_thread.Join(); + } + + /// + /// This is the thread entry point + /// + private void Runner() + { + while (!m_terminate) + { + m_currentTask = null; + + lock (m_lock) + if (m_state == WorkerThread.RunState.Run && m_tasks.Count > 0) + m_currentTask = m_tasks.Dequeue(); + + if (m_currentTask == null && !m_terminate) + if (m_state == WorkerThread.RunState.Run) + m_event.WaitOne(); //Sleep until signaled + else + { + if (WorkerStateChanged != null) + WorkerStateChanged(this, m_state); + + //Sleep for brief periods, until signaled + while (!m_terminate && m_state != WorkerThread.RunState.Run) + m_event.WaitOne(1000 * 60 * 5, false); + + //If we were not terminated, we are now ready to run + if (!m_terminate) + { + m_state = WorkerThread.RunState.Run; + if (WorkerStateChanged != null) + WorkerStateChanged(this, m_state); + } + } + + if (m_terminate) + return; + + if (m_currentTask == null && m_state == WorkerThread.RunState.Run) + lock (m_lock) + if (m_tasks.Count > 0) + m_currentTask = m_tasks.Dequeue(); + + if (m_currentTask == null) + continue; + + if (StartingWork != null) + StartingWork(this, null); + + m_active = true; + m_delegate(m_currentTask); + m_active = false; + + if (CompletedWork != null) + CompletedWork(this, null); + } + } + + /// + /// Gets the current run state + /// + public RunState State { get { return m_state; } } + + /// + /// Instructs Duplicati to run scheduled backups + /// + public void Resume() + { + m_state = RunState.Run; + m_event.Set(); + } + + /// + /// Instructs Duplicati to pause scheduled backups + /// + public void Pause() + { + m_state = RunState.Paused; + m_event.Set(); + } + + /// + /// Waits the specified number of milliseconds for the thread to terminate + /// + /// The number of milliseconds to wait + /// True if the thread is terminated, false if a timeout occured + public bool Join(int millisecondTimeout) + { + if (m_thread != null) + return m_thread.Join(millisecondTimeout); + return true; + } + } +} diff --git a/Duplicati/Server/DatabaseUpgrader.cs b/Duplicati/Server/DatabaseUpgrader.cs new file mode 100644 index 000000000..af3e1ba61 --- /dev/null +++ b/Duplicati/Server/DatabaseUpgrader.cs @@ -0,0 +1,185 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; +using System.Data; + +namespace Duplicati.Server +{ + /// + /// This class will read embedded files from the given folder. + /// Updates should have the form "1.Sample upgrade.sql". + /// When the database schema changes, simply put a new file into the folder. + /// Each upgrade file should ONLY upgrade from the previous version. + /// If done correctly, a user may be upgrade from the very first version + /// to the very latest. + /// + /// The Schema.sql file should ALWAYS have the latests schema, as that will + /// ensure that new installs do not run upgrades after installation. + /// Also remember to update the last line in Schema.sql to insert the + /// current version number in the version table. + /// + /// Currently no upgrades may contain semicolons, except as the SQL statement + /// delimiter. + /// + static class DatabaseUpgrader + { + //This is the "folder" where the embedded resources can be found + private const string FOLDER_NAME = "Database_schema"; + + //This is the name of the schema sql + private const string SCHEMA_NAME = "Schema.sql"; + + /// + /// Ensures that the database is up to date + /// + /// The database connection to use + /// The file the database is placed in + public static void UpgradeDatabase(IDbConnection connection, string sourcefile) + { + //Shorthand for current assembly + System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); + + if (connection.State != ConnectionState.Open) + { + if (string.IsNullOrEmpty(connection.ConnectionString)) + connection.ConnectionString = "Data Source=" + sourcefile; + + connection.Open(); + } + + + int dbversion = 0; + IDbCommand cmd = connection.CreateCommand(); + try + { + //See if the version table is present, + cmd.CommandText = "SELECT COUNT(*) FROM SQLITE_MASTER WHERE Name LIKE 'Version'"; + + int count = Convert.ToInt32(cmd.ExecuteScalar()); + + if (count == 0) + dbversion = -1; //Empty + else if (count == 1) + { + cmd.CommandText = "SELECT max(Version) FROM Version"; + dbversion = Convert.ToInt32(cmd.ExecuteScalar()); + } + else + throw new Exception(Strings.DatabaseUpgrader.TableLayoutError); + + } + catch(Exception ex) + { + //Hopefully a more explanatory error message + throw new Exception(string.Format(Strings.DatabaseUpgrader.DatabaseFormatError, ex.Message), ex); + } + + + //On a new database, we just load the most current schema, and upgrade from there + //This avoids potentitally lenghty upgrades + if (dbversion == -1) + { + cmd.CommandText = new System.IO.StreamReader(asm.GetManifestResourceStream(typeof(DatabaseUpgrader), FOLDER_NAME + "." + SCHEMA_NAME)).ReadToEnd(); + cmd.ExecuteNonQuery(); + UpgradeDatabase(connection, sourcefile); + return; + } + + //Get updates, and sort them according to version + //This enables upgrading through several versions + //ea, from 1 to 8, by stepping 2->3->4->5->6->7->8 + SortedDictionary upgrades = new SortedDictionary(); + string prefix = typeof(DatabaseUpgrader).Namespace + "." + FOLDER_NAME + "."; + int maxversion = -1; + foreach (string s in asm.GetManifestResourceNames()) + { + //The resource name will be "Duplicati.GUI.Database_schema.1.Sample upgrade.sql" + //The number indicates the version that will be upgraded to + if (s.StartsWith(prefix) && !s.Equals(prefix + SCHEMA_NAME)) + { + try + { + string version = s.Substring(prefix.Length, s.IndexOf(".", prefix.Length + 1) - prefix.Length); + int fileversion = int.Parse(version); + maxversion = Math.Max(maxversion, fileversion); + if (fileversion > dbversion) + { + if (!upgrades.ContainsKey(fileversion)) + upgrades.Add(fileversion, ""); + upgrades[fileversion] += new System.IO.StreamReader(asm.GetManifestResourceStream(s)).ReadToEnd(); + } + } + catch + { + } + } + } + + if (dbversion > maxversion) + throw new Exception(string.Format(Strings.DatabaseUpgrader.InvalidVersionError, dbversion, maxversion, System.IO.Path.GetDirectoryName(sourcefile))); + + if (upgrades.Count > 0) + { + string backupfile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(sourcefile), Strings.DatabaseUpgrader.BackupFilenamePrefix + " " + DateTime.Now.ToString("yyyyMMddhhmmss") + ".sqlite"); + + try + { + if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(backupfile))) + System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(backupfile)); + + //Keep a backup + System.IO.File.Copy(sourcefile, backupfile, false); + + int newversion = dbversion; + foreach (int key in upgrades.Keys) + { + //TODO: Find a better way to split SQL statements, as there may be embedded semicolons + //in the SQL, like "UPDATE x WHERE y = ';';" + + //We split them to get a better error message + foreach(string c in upgrades[key].Split(';')) + if (c.Trim().Length > 0) + { + cmd.CommandText = c; + cmd.ExecuteNonQuery(); + } + + newversion = Math.Max(newversion, key); + } + + //Update databaseversion, so we don't run the scripts again + cmd.CommandText = "Update version SET Version = " + newversion.ToString(); + cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + connection.Close(); + //Restore the database + System.IO.File.Copy(backupfile, sourcefile, true); + throw new Exception(string.Format(Strings.DatabaseUpgrader.UpgradeFailure, cmd.CommandText, ex.Message), ex); + } + } + + + } + } +} diff --git a/Duplicati/Server/Duplicati.Server.Serialization/ApplicationSettings.cs b/Duplicati/Server/Duplicati.Server.Serialization/ApplicationSettings.cs new file mode 100644 index 000000000..b174c4734 --- /dev/null +++ b/Duplicati/Server/Duplicati.Server.Serialization/ApplicationSettings.cs @@ -0,0 +1,298 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; + +namespace Duplicati.GUI.Serialization +{ + public class ApplicationSettings + { + public enum NotificationLevel + { + Off, + Start, + StartAndStop, + Continous, + Warnings, + Errors + } + + private IDictionary m_appset; + + private const string RECENT_DURATION = "Recent duration"; + private const string TEMP_PATH = "Temp Path"; + + private const string USE_COMMON_PASSWORD = "Use common password"; + private const string COMMON_PASSWORD_ENCRYPTION_MODULE = "Encryption module used with common password"; + private const string COMMON_PASSWORD = "Common password"; + + private const string SIGNATURE_CACHE_PATH = "Signature Cache Path"; + private const string SIGNATURE_CACHE_ENABLED = "Signature Cache Enabled"; + + private const string DISPLAY_LANGUAGE = "Display Language"; + + private const string STARTUP_DELAY_DURATION = "Startup delay duration"; + private const string THREAD_PRIORITY_OVERRIDE = "Thread priority override"; + private const string UPLOAD_SPEED_LIMIT = "Upload speed limit"; + private const string DOWNLOAD_SPEED_LIMIT = "Download speed limit"; + + private const string HIDE_DONATE_BUTTON = "Hide donate button"; + + private const string BALLON_NOTIFICATION_LEVEL = "Balloon notification level"; + + public ApplicationSettings(IDictionary data) + { + m_appset = data; + } + + /// + /// Creates a detached copy of all the application settings + /// + /// A dictionary with application settings + public Dictionary CreateDetachedCopy() + { + //We need to read/write all values to make sure they have the propper defaults + foreach (System.Reflection.PropertyInfo pi in this.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.DeclaredOnly)) + if (pi.CanRead && pi.CanWrite) + pi.SetValue(this, pi.GetValue(this, null), null); + + //After that, simply copy the values over + Dictionary res = new Dictionary(); + foreach (KeyValuePair k in m_appset) + res[k.Key] = k.Value; + return res; + } + + /// + /// Gets a reference to the internal options + /// + public IDictionary RawOptions { get { return m_appset; } } + + /// + /// Gets or sets the amount of time a log entry will be visible in the list of recent backups + /// + public string RecentBackupDuration + { + get { return string.IsNullOrEmpty(m_appset[RECENT_DURATION]) ? "2W" : m_appset[RECENT_DURATION]; } + set { m_appset[RECENT_DURATION] = value; } + } + + /// + /// Gets or sets the path to store temporary files. May contain environment variables + /// + public string TempPath + { + get + { + if (string.IsNullOrEmpty(m_appset[TEMP_PATH])) + { +#if DEBUG + return System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "TEMP"); +#else + return System.IO.Path.GetTempPath(); +#endif + } + else + return m_appset[TEMP_PATH]; + } + set { m_appset[TEMP_PATH] = value; } + } + + /// + /// Gets or sets a value indicating if Duplicati should apply a common password to backups + /// + public bool UseCommonPassword + { + get + { + bool res; + string tmp; + m_appset.TryGetValue(USE_COMMON_PASSWORD, out tmp); + + if (bool.TryParse(tmp, out res)) + return res; + else + return false; + } + set { m_appset[USE_COMMON_PASSWORD] = value.ToString(); } + } + + /// + /// Gets or sets the encryption module used as default + /// + public string CommonPasswordEncryptionModule + { + get + { + string res; + m_appset.TryGetValue(COMMON_PASSWORD_ENCRYPTION_MODULE, out res); + return string.IsNullOrEmpty(res) ? "aes" : res; + } + set { m_appset[COMMON_PASSWORD_ENCRYPTION_MODULE] = value; } + } + + /// + /// Gets or sets the common password applied to encrypt files. + /// + public string CommonPassword + { + get + { + string res; + m_appset.TryGetValue(COMMON_PASSWORD, out res); + return string.IsNullOrEmpty(res) ? "" : res; + } + set { m_appset[COMMON_PASSWORD] = value; } + } + + /// + /// Gets or sets the path to store signature cache files. May contain environment variables + /// + public string SignatureCachePath + { + get + { + if (string.IsNullOrEmpty(m_appset[SIGNATURE_CACHE_PATH])) + { + if (Duplicati.Library.Utility.Utility.IsClientLinux) + return System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%DUPLICATI_HOME%").TrimStart('"').TrimEnd('"'), "Signature Cache"); + else + return System.IO.Path.Combine(System.IO.Path.Combine(Environment.ExpandEnvironmentVariables(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)), "Duplicati"), "Signature Cache"); + } + else + return m_appset[SIGNATURE_CACHE_PATH]; + } + set { m_appset[SIGNATURE_CACHE_PATH] = value; } + } + + /// + /// Gets or sets a value indicating if the signature cache should be used. + /// + public bool SignatureCacheEnabled + { + get + { + bool res; + if (bool.TryParse(m_appset[SIGNATURE_CACHE_ENABLED], out res)) + return res; + else + return true; + } + set { m_appset[SIGNATURE_CACHE_ENABLED] = value.ToString(); } + } + + /// + /// Gets or sets the language used in the user interface + /// + public string DisplayLanguage + { + get + { + if (string.IsNullOrEmpty(m_appset[DISPLAY_LANGUAGE])) + return ""; + else + return m_appset[DISPLAY_LANGUAGE]; + } + set { m_appset[DISPLAY_LANGUAGE] = value; } + } + + /// + /// Gets or sets the amount of time Duplicati will be paused after startup + /// + public string StartupDelayDuration + { + get { return string.IsNullOrEmpty(m_appset[STARTUP_DELAY_DURATION]) ? "5m" : m_appset[STARTUP_DELAY_DURATION]; } + set { m_appset[STARTUP_DELAY_DURATION] = value; } + } + + /// + /// Gets or sets the thread priority used for the backup thread + /// + public System.Threading.ThreadPriority? ThreadPriorityOverride + { + get + { + if (string.IsNullOrEmpty(m_appset[THREAD_PRIORITY_OVERRIDE])) + return null; + else + return Library.Utility.Utility.ParsePriority(m_appset[THREAD_PRIORITY_OVERRIDE]); + } + set + { + if (value == null) + m_appset[THREAD_PRIORITY_OVERRIDE] = ""; + else + m_appset[THREAD_PRIORITY_OVERRIDE] = value.Value.ToString(); + } + } + + /// + /// Gets or sets the upper limit for download speeds + /// + public string DownloadSpeedLimit + { + get { return m_appset[DOWNLOAD_SPEED_LIMIT]; } + set { m_appset[DOWNLOAD_SPEED_LIMIT] = value == null ? "" : value; } + } + + /// + /// Gets or sets the upper limit for upload speeds + /// + public string UploadSpeedLimit + { + get { return m_appset[UPLOAD_SPEED_LIMIT]; } + set { m_appset[UPLOAD_SPEED_LIMIT] = value == null ? "" : value; } + } + + /// + /// Gets or sets a value indicating if the donate button in Duplicati should be hidden + /// + public bool HideDonateButton + { + get + { + string tmp; + m_appset.TryGetValue(HIDE_DONATE_BUTTON, out tmp); + + return Duplicati.Library.Utility.Utility.ParseBool(tmp, false); + } + set { m_appset[HIDE_DONATE_BUTTON] = value.ToString(); } + } + + /// + /// Gets or sets the balloon notification level + /// + public NotificationLevel BallonNotificationLevel + { + get + { + string v; + m_appset.TryGetValue(BALLON_NOTIFICATION_LEVEL, out v); + if (!string.IsNullOrEmpty(v)) + try { return (NotificationLevel)Enum.Parse(typeof(NotificationLevel), v); } + catch { } + + return NotificationLevel.Warnings; + } + set { m_appset[BALLON_NOTIFICATION_LEVEL] = value.ToString(); } + } + } +} diff --git a/Duplicati/Server/Duplicati.Server.Serialization/Backend.cs b/Duplicati/Server/Duplicati.Server.Serialization/Backend.cs new file mode 100644 index 000000000..e83464dd5 --- /dev/null +++ b/Duplicati/Server/Duplicati.Server.Serialization/Backend.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Duplicati.GUI.Serialization +{ + public class Backend + { + public string ProtocolKey { get; private set; } + public string DisplayName { get; private set; } + public string Description { get; private set; } + + public Duplicati.Library.Interface.ICommandLineArgument[] SupportedCommands { get; private set; } + } +} diff --git a/Duplicati/Server/Duplicati.Server.Serialization/Duplicati.Server.Serialization.csproj b/Duplicati/Server/Duplicati.Server.Serialization/Duplicati.Server.Serialization.csproj new file mode 100644 index 000000000..403ef3807 --- /dev/null +++ b/Duplicati/Server/Duplicati.Server.Serialization/Duplicati.Server.Serialization.csproj @@ -0,0 +1,78 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {33FD1D24-C28F-4C71-933F-98F1586EA76C} + Library + Properties + Duplicati.Server.Serialization + Duplicati.Server.Serialization + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + Duplicati.snk + + + + + + + + + + + + + + + + + + + + + + {C5899F45-B0FF-483C-9D38-24A9FCAAB237} + Duplicati.Library.Interface + + + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65} + Duplicati.Library.Utility + + + + + + + + \ No newline at end of file diff --git a/Duplicati/Server/Duplicati.Server.Serialization/Duplicati.snk b/Duplicati/Server/Duplicati.Server.Serialization/Duplicati.snk new file mode 100644 index 0000000000000000000000000000000000000000..e0c1e2dd86119728adaeefc5f14f2e597dabceeb GIT binary patch literal 596 zcmZQ)VqjoUVPFUfb~IvOVPIfnU}U&>ZqBFG;TL!xbC@f=sW??FHp%RuD04u?d|@dM zp47GKm!Hl%dFaei`<5*qzAgXqbzUyVi_n}?OMO*3eH|OE?krr| zFEl@9)L*-L?Q8KJPtTajTTV9l{O!|eX~_>-AD#yZ=6m07=(;Lz?67b_fmBH7>6XPy zU(fsaYt6=H^BbXYGcsePe{{ZI&XLwz9=grGu+&OTZN+`>n#aL@H_qHKNL{x|{OX?< z|2?cWgj<|a*&Wn5qtR68+v$gad`lNSIGSM4$`K*nE_8`M(8%hLo?+%X^GU{qHtmys zKah1))%qg*H$8)~{Blp<;-4#gv3~y3w(VO5op^Nq_Qo%mz;QX`zXzj&$<=3DJ8QK~doHe9_tNXtnN&4~oeV$j z^o2{LFP>08&A&p7*^IG!Mnm`8x8Lq$er`8lWi+;b>yXC%XWDAv$p-_y)7-T(lU$#a z#IstS7OnePcICwJ+w3(l+=qQ0gsr@P>rWc{j)4B;9b4MXBe*rpp6LBh{}W&Ed`G$N IQKi@%02MtM!T + + + Debug + x86 + 8.0.30703 + 2.0 + {19E661D2-C5DA-4F35-B3EE-7586E5734B5F} + Exe + Properties + Duplicati.Server + Duplicati.Server + v4.0 + + + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\Debug\ + DEBUG;TRACE + full + AnyCPU + prompt + false + false + + + bin\Release\ + TRACE + true + pdbonly + AnyCPU + prompt + true + true + + + + ..\thirdparty\HttpServer\HttpServer.dll + + + ..\thirdparty\HttpServer\HttpServer.MVC.dll + + + ..\..\thirdparty\LightDataModel\LightDatamodel.dll + + + ..\..\thirdparty\LitJSON\LitJson.dll + + + + + + + + + + + + + + + + + + + + + + + DatabaseUpgrader.resx + True + True + + + DuplicatiRunner.resx + True + True + + + DynamicSetupHelper.resx + True + True + + + Program.resx + True + True + + + Scheduler.resx + True + True + + + TaskType.resx + True + True + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + {E7280DCA-7776-4A73-B9B5-41FD77FC8799} + Duplicati.CommandLine.BackendTester + + + {E2AF781D-D1E1-4512-BF2C-D6DA8D0F797F} + Duplicati.CommandLine.Decrypter + + + {81765A64-3661-4E3E-B850-2F6F87A51F74} + Duplicati.CommandLine + + + {B60D0993-B0C5-457A-90D9-DB6EEB33CE47} + Datamodel + + + {33FD1D24-C28F-4C71-933F-98F1586EA76C} + Duplicati.Server.Serialization + + + {1BFAE226-8364-4086-825C-BB83F6F3EE4C} + Duplicati.Library.Backend.CloudFiles + + + {FC9B7611-836F-4127-8B44-A7C31F506807} + Duplicati.Library.Backend.File + + + {F61679A9-E5DE-468A-B5A4-05F92D0143D2} + Duplicati.Library.Backend.FTP + + + {C03F6DFD-805A-4BE0-9338-64870ADDB4A2} + Duplicati.Library.Backend.S3 + + + {FF2BF37C-E502-4C98-BEA0-701671DDFA08} + Duplicati.Library.Backend.SSHv2 + + + {C0270709-2A40-43B5-8CF1-69581B9FA2A1} + Duplicati.Library.Backend.TahoeLAFS + + + {BAE27510-8B5D-44B2-B33E-372A98908041} + Duplicati.Library.Backend.WEBDAV + + + {19ECCE09-B5EB-406C-8C57-BAC66997D469} + Duplicati.Library.Compression + + + {0CA86ECF-5BEC-4909-B4F6-110A03B30B92} + Duplicati.Library.DynamicLoader + + + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87} + Duplicati.Library.Encryption + + + {C5899F45-B0FF-483C-9D38-24A9FCAAB237} + Duplicati.Library.Interface + + + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798} + Duplicati.Library.Logging + + + {10D2D1B7-C664-41D8-9B3A-00040C3D421B} + Duplicati.Library.Main + + + {52826615-7964-47FE-B4B3-1B2DBDF605B9} + Duplicati.Library.Modules.Builtin + + + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65} + Duplicati.Library.Utility + + + {4D012CB1-4B92-47F4-89B7-BF80A73A2E99} + Duplicati.License + + + + + ResXFileCodeGenerator + DatabaseUpgrader.Designer.cs + Designer + + + ResXFileCodeGenerator + DuplicatiRunner.Designer.cs + + + ResXFileCodeGenerator + DynamicSetupHelper.Designer.cs + + + ResXFileCodeGenerator + Program.Designer.cs + Designer + + + ResXFileCodeGenerator + Scheduler.Designer.cs + + + ResXFileCodeGenerator + TaskType.Designer.cs + Designer + + + + + \ No newline at end of file diff --git a/Duplicati/Server/DuplicatiOutputParser.cs b/Duplicati/Server/DuplicatiOutputParser.cs new file mode 100644 index 000000000..4c7cbfea1 --- /dev/null +++ b/Duplicati/Server/DuplicatiOutputParser.cs @@ -0,0 +1,99 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; +using Duplicati.Datamodel; + +namespace Duplicati.Server +{ + public class DuplicatiOutputParser + { + public const string ErrorStatus = "Error"; + public const string OKStatus = "OK"; + public const string WarningStatus = "Warning"; + public const string PartialStatus = "Partial"; + + private const string OK_INDICATOR = "Duration"; + private const string WARNING_INDICATOR = "NumberOfErrors"; + + private const string UPLOAD_SIZE_INDICATOR = "BytesUploaded"; + private const string DOWNLOAD_SIZE_INDICATOR = "BytesDownloaded"; + private const string PARTIAL_INDICATOR = "Unprocessed"; + + private const string METHOD_INDICATOR = "OperationName"; + + public static void ParseData(Log log) + { + string text = log.Blob.StringData; + + log.ParsedStatus = ErrorStatus; + + if (text.IndexOf(OK_INDICATOR) >= 0) + log.ParsedStatus = OKStatus; + + long c = ExtractNumber(text, WARNING_INDICATOR, -1); + if (c > 0) + log.ParsedStatus = WarningStatus; + + if (ExtractValue(text, METHOD_INDICATOR, "").StartsWith("backup", StringComparison.InvariantCultureIgnoreCase)) + c = ExtractNumber(text, UPLOAD_SIZE_INDICATOR, -1); + else + c = ExtractNumber(text, DOWNLOAD_SIZE_INDICATOR, -1); + + if (c == 0) + log.ParsedStatus = WarningStatus; + + log.Transfersize = c; + + + if (log.ParsedStatus == WarningStatus) + { + long missing = ExtractNumber(text, PARTIAL_INDICATOR, 0); + if (missing > 0) + log.ParsedStatus = PartialStatus; + } + + } + + private static long ExtractNumber(string output, string key, long @default) + { + long count; + if (!long.TryParse(ExtractValue(output, key, @default.ToString()), out count)) + count = @default; + + return count; + } + + private static string ExtractValue(string output, string key, string @default) + { + string result = @default; + if (output.IndexOf(key) >= 0) + { + int pos = output.IndexOf(key) + key.Length; + pos = output.IndexOf(':', pos) + 1; + int p2 = output.IndexOfAny(new char[] { '\r', '\n' }, pos); + result = output.Substring(pos, p2 - pos).Trim(); + } + + return result; + } + } +} diff --git a/Duplicati/Server/DuplicatiRunner.cs b/Duplicati/Server/DuplicatiRunner.cs new file mode 100644 index 000000000..03b67aee4 --- /dev/null +++ b/Duplicati/Server/DuplicatiRunner.cs @@ -0,0 +1,580 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; +using Duplicati.Datamodel; +using Duplicati.Library.Main; + +namespace Duplicati.Server +{ + /// + /// This class translates tasks into Duplicati calls, and executes them + /// + public class DuplicatiRunner : Duplicati.Library.Main.LiveControl.ILiveControl + { + public enum RunnerState + { + Started, + Suspended, + Running, + Stopped, + } + + public enum RunnerResult + { + OK, + Partial, + Warning, + Error + } + + public enum StopReason + { + ApplicationExit, + TaskManagerClosing, + UserClosing, + OSShutDown, + None + } + + public delegate void ResultEventDelegate(RunnerResult result, string parsedMessage, string message); + public event ResultEventDelegate ResultEvent; + + public delegate void ProgressEventDelegate(DuplicatiOperation operation, RunnerState state, string message, string submessage, int progress, int subprogress); + public event ProgressEventDelegate ProgressEvent; + + private const int PERCENT_PR_EXTRA_OPERATION = 2; + private int m_extraOperations = 0; + + private DuplicatiOperation m_lastPGOperation; + private DuplicatiOperationMode m_lastPGMode; + private int m_lastPGProgress; + private int m_lastPGSubprogress; + private string m_lastPGmessage; + private string m_lastPGSubmessage; + + private object m_lock = new object(); + private StopReason m_stopReason = StopReason.None; + private Library.Main.LiveControl.ILiveControl m_currentBackupControlInterface; + private bool m_isAborted = false; + + public void ExecuteTask(IDuplicityTask task) + { + Dictionary options = new Dictionary(); + + //Set the log level to be that of the GUI + options["log-level"] = Duplicati.Library.Logging.Log.LogLevel.ToString(); + + string destination = task.GetConfiguration(options); + + string results = ""; + string parsedMessage = ""; + m_isAborted = false; + + try + { + //TODO: Its a bit dirty to set the options after creating the instance + using (Interface i = new Interface(destination, options)) + { + lock (m_lock) + { + m_stopReason = StopReason.None; + m_currentBackupControlInterface = i; + } + + SetupControlInterface(); + + i.OperationProgress += new OperationProgressEvent(Duplicati_OperationProgress); + + switch (task.TaskType) + { + case DuplicityTaskType.FullBackup: + case DuplicityTaskType.IncrementalBackup: + { + //Activate auto-cleanup + options["auto-cleanup"] = ""; + options["force"] = ""; + if (task.Schedule.Task.KeepFull > 0) + m_extraOperations++; + if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime)) + m_extraOperations++; + + Library.Utility.TempFolder tf = null; + try + { + if (ProgressEvent != null) + ProgressEvent(DuplicatiOperation.Backup, RunnerState.Started, task.Schedule.Name, "", 0, -1); + + if (task.Task.IncludeSetup) + { + //Make a copy of the current database + tf = new Duplicati.Library.Utility.TempFolder(); + string filename = System.IO.Path.Combine(tf, System.IO.Path.GetFileName(Program.DatabasePath)); + + System.IO.File.Copy(Program.DatabasePath, filename, true); + using (System.Data.IDbConnection con = (System.Data.IDbConnection)Activator.CreateInstance(SQLiteLoader.SQLiteConnectionType)) + { + con.ConnectionString = "Data Source=" + filename; + + //Open the database, handle any encryption issues automatically + Program.OpenDatabase(con); + + using (System.Data.IDbCommand cmd = con.CreateCommand()) + { + //Remove all log data to minimize the size of the database + cmd.CommandText = "DELETE FROM CommandQueue;"; + cmd.ExecuteNonQuery(); + cmd.CommandText = "DELETE FROM Log;"; + cmd.ExecuteNonQuery(); + cmd.CommandText = "DELETE FROM LogBlob;"; + cmd.ExecuteNonQuery(); + + //Free up unused space + cmd.CommandText = "VACUUM;"; + cmd.ExecuteNonQuery(); + } + } + + options["signature-control-files"] = filename; + } + + options["full-if-sourcefolder-changed"] = ""; + + List> filters = new List>(); + string[] sourceFolders = DynamicSetupHelper.GetSourceFolders(task.Task, new ApplicationSettings(task.Task.DataParent), filters); + + if (options.ContainsKey("filter")) + filters.AddRange(Library.Utility.FilenameFilter.DecodeFilter(options["filter"])); + + options["filter"] = Library.Utility.FilenameFilter.EncodeAsFilter(filters); + + results = i.Backup(sourceFolders); + } + finally + { + if (tf != null) + tf.Dispose(); + + if (ProgressEvent != null) + ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1); + } + break; + } + case DuplicityTaskType.ListBackups: + + List res = new List(); + foreach (ManifestEntry be in i.GetBackupSets()) + { + res.Add(be.Time.ToString()); + foreach (ManifestEntry bei in be.Incrementals) + res.Add(bei.Time.ToString()); + } + + (task as ListBackupsTask).Backups = res.ToArray(); + break; + case DuplicityTaskType.ListBackupEntries: + (task as ListBackupEntriesTask).Backups = i.GetBackupSets(); + break; + case DuplicityTaskType.ListFiles: + (task as ListFilesTask).Files = i.ListCurrentFiles(); + break; + case DuplicityTaskType.ListSourceFolders: + (task as ListSourceFoldersTask).Files = new List(i.ListSourceFolders() ?? new string[0]); + break; + case DuplicityTaskType.ListActualFiles: + (task as ListActualFilesTask).Files = i.ListActualSignatureFiles(); + break; + case DuplicityTaskType.RemoveAllButNFull: + results = i.DeleteAllButNFull(); + break; + case DuplicityTaskType.RemoveOlderThan: + results = i.DeleteOlderThan(); + break; + case DuplicityTaskType.Restore: + options["file-to-restore"] = ((RestoreTask)task).SourceFiles; + if (options.ContainsKey("filter")) + options.Remove("filter"); + + try + { + if (ProgressEvent != null) + ProgressEvent(DuplicatiOperation.Restore, RunnerState.Started, task.Schedule.Name, "", 0, -1); + results = i.Restore(task.LocalPath.Split(System.IO.Path.PathSeparator)); + } + finally + { + if (ProgressEvent != null) + ProgressEvent(DuplicatiOperation.Restore, RunnerState.Stopped, task.Schedule.Name, "", 100, -1); + } + break; + + case DuplicityTaskType.RestoreSetup: + i.RestoreControlFiles(task.LocalPath); + break; + default: + return; + } + } + } + catch (Exception ex) + { + while (ex is System.Reflection.TargetInvocationException && ex.InnerException != null) + ex = ex.InnerException; + + if (ex is System.Threading.ThreadAbortException) + { + m_isAborted = true; + System.Threading.Thread.ResetAbort(); + } + else if (ex is Library.Main.LiveControl.ExecutionStoppedException) + m_isAborted = true; + + if (m_isAborted && m_stopReason != StopReason.None) + { + //If the user has stopped the backup for some reason, write a nicer message + switch (m_stopReason) + { + case StopReason.ApplicationExit: + parsedMessage = Strings.DuplicatiRunner.ApplicationExitLogMesssage; + break; + case StopReason.TaskManagerClosing: + parsedMessage = Strings.DuplicatiRunner.TaskManagerCloseMessage; + break; + case StopReason.UserClosing: + parsedMessage = Strings.DuplicatiRunner.UserClosingMessage; + break; + case StopReason.OSShutDown: + parsedMessage = Strings.DuplicatiRunner.WindowsShutdownMessage; + break; + default: + parsedMessage = string.Format(Strings.DuplicatiRunner.OtherAbortMessage, m_stopReason); + break; + } + } + else + parsedMessage = string.Format(Strings.DuplicatiRunner.ErrorMessage, ex.Message); + + results = "Error: " + ex.ToString(); //Don't localize + + while (ex.InnerException != null) + { + ex = ex.InnerException; + results += Environment.NewLine + "InnerError: " + ex.ToString(); //Don't localize + } + + } + finally + { + lock (m_lock) + m_currentBackupControlInterface = null; + } + + try + { + if (!m_isAborted && (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup)) + { + if (task.Schedule.Task.KeepFull > 0) + { + m_lastPGProgress = 100; + m_lastPGmessage = Strings.DuplicatiRunner.CleaningUpMessage; + m_lastPGSubmessage = ""; + m_lastPGSubprogress = -1; + + ReinvokeLastProgressEvent(); + m_extraOperations--; + + RemoveAllButNFullTask tmpTask = new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.Task.KeepFull); + ExecuteTask(tmpTask); + results += Environment.NewLine + Strings.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result; + } + + if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime)) + { + m_lastPGProgress = 100; + m_lastPGmessage = Strings.DuplicatiRunner.CleaningUpMessage; + m_lastPGSubmessage = ""; + m_lastPGSubprogress = -1; + + ReinvokeLastProgressEvent(); + m_extraOperations--; + + RemoveOlderThanTask tmpTask = new RemoveOlderThanTask(task.Schedule, task.Schedule.Task.KeepTime); + ExecuteTask(tmpTask); + results += Environment.NewLine + Strings.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result; + } + + if (task.Schedule.Task.KeepFull > 0 || !string.IsNullOrEmpty(task.Schedule.Task.KeepTime)) + ReinvokeLastProgressEvent(); + + if (ProgressEvent != null) + ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1); + } + } + catch (Exception ex) + { + results += Environment.NewLine + string.Format(Strings.DuplicatiRunner.CleanupError, ex.Message); + } + + task.IsAborted = m_isAborted; + task.Result = results; + task.RaiseTaskCompleted(results, parsedMessage); + + if (ResultEvent != null && task is FullBackupTask || task is IncrementalBackupTask) + { + Log[] logs = Program.DataConnection.GetObjects("TaskID = ? AND SubAction LIKE ? ORDER BY EndTime DESC", task.Task.ID, "Primary"); + if (logs != null && logs.Length > 0) + { + Datamodel.Log l = logs[0]; + RunnerResult r = RunnerResult.Error; + if (l.ParsedStatus == DuplicatiOutputParser.ErrorStatus) + r = RunnerResult.Error; + else if (l.ParsedStatus == DuplicatiOutputParser.OKStatus) + r = RunnerResult.OK; + else if (l.ParsedStatus == DuplicatiOutputParser.PartialStatus) + r = RunnerResult.Partial; + else if (l.ParsedStatus == DuplicatiOutputParser.WarningStatus) + r = RunnerResult.Warning; + + ResultEvent(r, parsedMessage, results); + } + } + + if (task.Schedule != null && !m_isAborted) + task.Schedule.ScheduledRunCompleted(); //Register as completed if not aborted + } + + void Duplicati_OperationProgress(Interface caller, DuplicatiOperation operation, DuplicatiOperationMode specificmode, int progress, int subprogress, string message, string submessage) + { + m_lastPGOperation = operation; + m_lastPGMode = specificmode; + m_lastPGProgress = progress; + m_lastPGSubprogress = subprogress; + m_lastPGmessage = message; + m_lastPGSubmessage = submessage; + + //If there are extra operations, reserve some space for it by reducing the displayed progress + if (m_extraOperations > 0 && progress > 0) + progress = (int)((m_lastPGProgress / 100.0) * (100 - (m_extraOperations * PERCENT_PR_EXTRA_OPERATION))); + + if (ProgressEvent != null) + try { ProgressEvent(operation, RunnerState.Running, message, submessage, progress, subprogress); } + catch { } + } + + public void ReinvokeLastProgressEvent() + { + Duplicati_OperationProgress(null, m_lastPGOperation, m_lastPGMode, m_lastPGProgress, m_lastPGSubprogress, m_lastPGmessage, m_lastPGSubmessage ); + } + + + private void PerformBackup(Schedule schedule, bool forceFull, string fullAfter) + { + if (forceFull) + ExecuteTask(new FullBackupTask(schedule)); + else + ExecuteTask(new IncrementalBackupTask(schedule, fullAfter)); + } + + public void Restore(Schedule schedule, DateTime when, string where) + { + ExecuteTask(new RestoreTask(schedule, where, when)); + } + + public string[] ListBackups(Schedule schedule) + { + ListBackupsTask task = new ListBackupsTask(schedule); + ExecuteTask(task); + + if (task.IsAborted) + return null; + + return task.Backups; + } + + public List ListBackupEntries(Schedule schedule) + { + ListBackupEntriesTask task = new ListBackupEntriesTask(schedule); + ExecuteTask(task); + + if (task.IsAborted) + return null; + + if (task.Result.StartsWith("Error:")) + throw new Exception(task.Result); + + return task.Backups; + } + + public List> ListActualFiles(Schedule schedule, DateTime when) + { + ListActualFilesTask task = new ListActualFilesTask(schedule, when); + ExecuteTask(task); + + if (task.IsAborted) + return null; + + if (task.Result.StartsWith("Error:")) + throw new Exception(task.Result); + + return task.Files; + } + + public IList ListFiles(Schedule schedule, DateTime when) + { + ListFilesTask task = new ListFilesTask(schedule, when); + ExecuteTask(task); + + if (task.IsAborted) + return null; + + if (task.Result.StartsWith("Error:")) + throw new Exception(task.Result); + return task.Files; + } + + public IList ListSourceFolders(Schedule schedule, DateTime when) + { + ListSourceFoldersTask task = new ListSourceFoldersTask(schedule, when); + ExecuteTask(task); + + if (task.IsAborted) + return null; + + if (task.Result.StartsWith("Error:")) + throw new Exception(task.Result); + + return task.Files; + } + + public void IncrementalBackup(Schedule schedule) + { + PerformBackup(schedule, false, null); + } + + public void FullBackup(Schedule schedule) + { + PerformBackup(schedule, true, null); + } + + /// + /// Gets a value indicating if the last run was aborted + /// + public bool IsAborted { get { return m_isAborted; } } + + /// + /// Function used to apply settings to a new interface + /// + private void SetupControlInterface() + { + //Copy the values to avoid thread race problems + System.Threading.ThreadPriority? priority = Program.LiveControl.ThreadPriority; + long? uploadLimit = Program.LiveControl.UploadLimit; + long? downloadLimit = Program.LiveControl.DownloadLimit; + + if (priority != null) + m_currentBackupControlInterface.SetThreadPriority(priority.Value); + if (uploadLimit != null) + m_currentBackupControlInterface.SetUploadLimit(uploadLimit.Value.ToString() + "b"); + if (downloadLimit != null) + m_currentBackupControlInterface.SetDownloadLimit(downloadLimit.Value.ToString() + "b"); + } + + public void Pause() + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + m_currentBackupControlInterface.Pause(); + } + + public void Resume() + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + m_currentBackupControlInterface.Resume(); + } + + public void Stop() { Stop(StopReason.None); } + public void Terminate() { Terminate(StopReason.None); } + + public void Stop(StopReason reason) + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + { + m_stopReason = reason; + if (m_currentBackupControlInterface.IsStopRequested) + m_currentBackupControlInterface.Terminate(); + else + m_currentBackupControlInterface.Stop(); + } + } + + public void Terminate(StopReason reason) + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + { + m_stopReason = reason; + m_currentBackupControlInterface.Terminate(); + } + } + + public bool IsStopRequested + { + get + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + return m_currentBackupControlInterface.IsStopRequested; + else + return false; + } + } + + public void SetUploadLimit(string limit) + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + m_currentBackupControlInterface.SetUploadLimit(limit); + } + + public void SetDownloadLimit(string limit) + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + m_currentBackupControlInterface.SetDownloadLimit(limit); + } + + public void SetThreadPriority(System.Threading.ThreadPriority priority) + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + m_currentBackupControlInterface.SetThreadPriority(priority); + } + + public void UnsetThreadPriority() + { + lock (m_lock) + if (m_currentBackupControlInterface != null) + m_currentBackupControlInterface.UnsetThreadPriority(); + } + } +} diff --git a/Duplicati/Server/DynamicSetupHelper.cs b/Duplicati/Server/DynamicSetupHelper.cs new file mode 100644 index 000000000..c8a8ef753 --- /dev/null +++ b/Duplicati/Server/DynamicSetupHelper.cs @@ -0,0 +1,168 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; +using Duplicati.Datamodel; + +namespace Duplicati.Server +{ + /// + /// This class generates a list of source folders and matching filters, based on the users choices + /// + public static class DynamicSetupHelper + { + /* + /// + /// Gets a source folder setup, based on the users filter selection + /// + /// The wrapper instance with the user selection + /// The filter settings + /// The source folder string + public static string[] GetSourceFolders(Wizard_pages.WizardSettingsWrapper wrapper, ApplicationSettings settings, List> filters) + { + if (wrapper.SelectFilesUI.Version >= 2 && wrapper.SelectFilesUI.UseSimpleMode) + { + return GetSourceFolders( + wrapper.SelectFilesUI.IncludeDocuments, + wrapper.SelectFilesUI.IncludeMusic, + wrapper.SelectFilesUI.IncludeImages, + wrapper.SelectFilesUI.IncludeDesktop, + wrapper.SelectFilesUI.IncludeSettings, + settings, + filters); + } + else + { + return PrependFilterList(wrapper.SourcePath.Split(System.IO.Path.PathSeparator), settings, filters); + } + }*/ + + /// + /// Gets a source folder setup, based on the users filter selection + /// + /// The Task instance with the user setup + /// The filter settings + /// The source folder string + public static string[] GetSourceFolders(Task task, ApplicationSettings settings, List> filters) + { + if (task.Extensions.SelectFiles_Version >= 2 && task.Extensions.SelectFiles_UseSimpleMode) + { + return GetSourceFolders( + task.Extensions.SelectFiles_IncludeDocuments, + task.Extensions.SelectFiles_IncludeMusic, + task.Extensions.SelectFiles_IncludeImages, + task.Extensions.SelectFiles_IncludeDesktop, + task.Extensions.SelectFiles_IncludeAppData, + settings, + filters); + } + else + { + return PrependFilterList(task.SourcePath.Split(System.IO.Path.PathSeparator), settings, filters); + } + } + + /// + /// Prepends extra filters to exclude the temp folder and the Duplicati signature cache + /// + /// The list of folders being backed up + /// The current set of filters to prepend to + /// The sourceFolders + private static string[] PrependFilterList(string[] sourceFolders, ApplicationSettings settings, List> filters) + { + string[] exFolders = new string[] { + Library.Utility.Utility.AppendDirSeparator(System.Environment.ExpandEnvironmentVariables(settings.SignatureCachePath)), + Library.Utility.Utility.AppendDirSeparator(System.Environment.ExpandEnvironmentVariables(settings.TempPath)) + }; + + foreach (string i in sourceFolders) + foreach (string x in exFolders) + if (x.StartsWith(i, Library.Utility.Utility.ClientFilenameStringComparision)) + filters.Insert(0, new KeyValuePair(false, Library.Utility.FilenameFilter.ConvertGlobbingToRegExp(x))); + + return sourceFolders; + } + + /// + /// Gets a source folder setup, based on the users folder selection + /// + /// The filter settings + /// True if documents should be included + /// True if music should be included + /// True if images should be included + /// True if desktop files should be included + /// True if settings should be included + /// The source folder string + private static string[] GetSourceFolders(bool includeDocuments, bool includeMusic, bool includeImages, bool includeDesktop, bool includeSettings, ApplicationSettings settings, List> filters) + { + string myPictures = Library.Utility.Utility.AppendDirSeparator(System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)); + string myMusic = Library.Utility.Utility.AppendDirSeparator(System.Environment.GetFolderPath(Environment.SpecialFolder.MyMusic)); + string desktop = Library.Utility.Utility.AppendDirSeparator(System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); + string appData = Library.Utility.Utility.AppendDirSeparator(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); + string myDocuments = Library.Utility.Utility.AppendDirSeparator(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); + + List folders = new List(); + List exfolders = new List(); + + (includeDocuments ? folders : exfolders).Add(myDocuments); + (includeImages ? folders : exfolders).Add(myPictures); + (includeMusic ? folders : exfolders).Add(myMusic); + (includeDesktop ? folders : exfolders).Add(desktop); + (includeSettings ? folders : exfolders).Add(appData); + + if (folders.Count == 0) + throw new Exception(Strings.DynamicSetupHelper.NoFoldersInSetupError); + + //Figure out if any folders are subfolders, and only include the parents + for (int i = 0; i < folders.Count; i++) + for (int j = i + 1; j < folders.Count; j++) + if (folders[i].StartsWith(folders[j], Library.Utility.Utility.ClientFilenameStringComparision)) + { + folders.RemoveAt(i); + i--; + break; //Break inner, continue outer + } + else if (folders[j].StartsWith(folders[i], Library.Utility.Utility.ClientFilenameStringComparision)) + { + folders.RemoveAt(j); + i = -1; //Restart loop + break; //Break inner, continue outer + } + + //Add filters to exclude de-selected folders + foreach (string s in exfolders) + { + foreach (string s2 in folders) + if (s.StartsWith(s2)) + { + filters.Insert(0, new KeyValuePair(false, Library.Utility.FilenameFilter.ConvertGlobbingToRegExp(s))); + break; + } + } + + string fi = ""; + foreach (KeyValuePair x in filters) + fi += x.Value + ";"; + + return PrependFilterList(folders.ToArray(), settings, filters); + } + } +} diff --git a/Duplicati/Server/EventQueue.cs b/Duplicati/Server/EventQueue.cs new file mode 100644 index 000000000..c3d5d308a --- /dev/null +++ b/Duplicati/Server/EventQueue.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Duplicati.Server +{ + /// + /// The class that keeps a list of all events that occured + /// + public class EventQueue + { + /// + /// Class that encapsulates all information relating to an event + /// + public class EventData + { + /// + /// Internal counter for sequence numbers + /// + private static long __EventSeqNo = 0; + + /// + /// Gets the sequence number, which can be used for determining the order of events + /// + public long EventSequenceNumber { get; private set; } + /// + /// Gets the time the event occured + /// + public DateTime EventTime { get; private set; } + /// + /// Gets the data related to the event + /// + public object Data { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The event data + public EventData(object data) + { + this.EventSequenceNumber = __EventSeqNo++; + this.EventTime = DateTime.Now; + + this.Data = data; + } + } + + + /// + /// The number of events kept in the queue + /// + private const int MAX_EVENTS = 2000; + + /// + /// The internal list of known events + /// + private List m_events = new List(); + + /// + /// The lock that protects access to the event list + /// + private object m_lock = new object(); + + + /// + /// Gets the list of known events, possibly limited by a start sequence number. + /// + /// The first sequence number to retrieve + /// A list with the events + public IList GetEvents(long firstSeqNo = 0) + { + lock (m_lock) + { + if (m_events.Count == 0) + return new List(); + + int firstIndex = 0; + long firstRecordedNo = m_events[0].EventSequenceNumber; + + firstIndex = Math.Min(Math.Max(0, (int)(firstSeqNo - firstRecordedNo)), m_events.Count); + + if (firstIndex == m_events.Count) + return new List(); + else + return m_events.GetRange(firstIndex, m_events.Count - firstIndex); + } + } + + public long CurrentEventId { get; private set; } + + public void LiveControl_StateChanged(object sender, EventArgs args) + { + } + + public void LiveControl_ThreadPriorityChanged(object sender, EventArgs args) + { + } + + public void LiveControl_ThrottleSpeedChanged(object sender, EventArgs args) + { + } + + public void WorkThread_StartingWork(object sender, EventArgs args) + { + } + + public void WorkThread_CompletedWork(object sender, EventArgs args) + { + } + + public void WorkThread_WorkQueueChanged(object sender, EventArgs args) + { + } + + public void Scheduler_NewSchedule(object sender, EventArgs args) + { + } + + public void Runner_DuplicatiProgress(Duplicati.Library.Main.DuplicatiOperation operation, Duplicati.Server.DuplicatiRunner.RunnerState state, string message, string submessage, int progress, int subprogress) + { + } + + public void DataConnection_AfterDataConnection(object sender, System.Data.LightDatamodel.DataActions args) + { + } + + } +} diff --git a/Duplicati/Server/LiveControls.cs b/Duplicati/Server/LiveControls.cs new file mode 100644 index 000000000..3bc433040 --- /dev/null +++ b/Duplicati/Server/LiveControls.cs @@ -0,0 +1,244 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; + +namespace Duplicati.Server +{ + /// + /// This class keeps track of the users modifications regarding + /// throttling and pause/resume + /// + public class LiveControls + { + /// + /// An event that is activated when the pause state changes + /// + public event EventHandler StateChanged; + + /// + /// An event that is activated when the thread priority changes + /// + public event EventHandler ThreadPriorityChanged; + + /// + /// An event that is activated when the throttle speed changes + /// + public event EventHandler ThrottleSpeedChanged; + + /// + /// The possible states for the live control + /// + public enum LiveControlState + { + /// + /// Indicates that the backups are running + /// + Running, + /// + /// Indicates that the backups are currently suspended + /// + Paused + } + + /// + /// The current control state + /// + private LiveControlState m_state; + + /// + /// Gets the current state for the control + /// + public LiveControlState State { get { return m_state; } } + + /// + /// The internal variable that tracks the the priority + /// + private System.Threading.ThreadPriority? m_priority; + + /// + /// The internal variable that tracks the upload limit + /// + private long? m_uploadLimit; + + /// + /// The internal variable that tracks the download limit + /// + private long? m_downloadLimit; + + /// + /// The object that ensures concurrent operations + /// + private object m_lock = new object(); + + /// + /// Gets the current overridden thread priority + /// + public System.Threading.ThreadPriority? ThreadPriority + { + get { return m_priority; } + set + { + if (m_priority != value) + { + m_priority = value; + if (ThreadPriorityChanged != null) + ThreadPriorityChanged(this, null); + } + } + } + + /// + /// Gets the current upload limit in bps + /// + public long? UploadLimit + { + get { return m_uploadLimit; } + set + { + if (m_uploadLimit != value) + { + m_uploadLimit = value; + if (ThrottleSpeedChanged != null) + ThrottleSpeedChanged(this, null); + } + } + } + + /// + /// Gets the download limit in bps + /// + public long? DownloadLimit + { + get { return m_downloadLimit; } + set + { + if (m_downloadLimit != value) + { + m_downloadLimit = value; + if (ThrottleSpeedChanged != null) + ThrottleSpeedChanged(this, null); + } + } + } + + /// + /// The timer that is activated after a pause period. + /// + private System.Threading.Timer m_waitTimer; + + /// + /// Constructs a new instance of the LiveControl + /// + /// The duration that the backups should be initially suspended + public LiveControls(Datamodel.ApplicationSettings settings) + { + m_state = LiveControlState.Running; + m_waitTimer = new System.Threading.Timer(m_waitTimer_Tick, this, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); + if (!string.IsNullOrEmpty(settings.StartupDelayDuration) && settings.StartupDelayDuration != "0") + { + m_waitTimer.Change((long)Duplicati.Library.Utility.Timeparser.ParseTimeSpan(settings.StartupDelayDuration).TotalMilliseconds, System.Threading.Timeout.Infinite); + m_state = LiveControlState.Paused; + } + + m_priority = settings.ThreadPriorityOverride; + if (!string.IsNullOrEmpty(settings.DownloadSpeedLimit)) + m_downloadLimit = Library.Utility.Sizeparser.ParseSize(settings.DownloadSpeedLimit, "kb"); + if (!string.IsNullOrEmpty(settings.UploadSpeedLimit)) + m_uploadLimit = Library.Utility.Sizeparser.ParseSize(settings.UploadSpeedLimit, "kb"); + } + + /// + /// Event that occurs when the timeout duration is exceeded + /// + /// The sender of the event + /// An unused event argument + private void m_waitTimer_Tick(object sender) + { + lock (m_lock) + Resume(); + } + + /// + /// Internal helper to reset the timeout timer + /// + /// The time to wait + private void ResetTimer(string timeout) + { + lock (m_lock) + if (!string.IsNullOrEmpty(timeout)) + m_waitTimer.Change((long)Duplicati.Library.Utility.Timeparser.ParseTimeSpan(timeout).TotalMilliseconds, System.Threading.Timeout.Infinite); + else + m_waitTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); + } + + /// + /// Pauses the backups until resumed + /// + public void Pause() + { + lock (m_lock) + { + if (m_state == LiveControlState.Running) + { + m_state = LiveControlState.Paused; + if (StateChanged != null) + StateChanged(this, null); + } + } + } + + /// + /// Resumes a backups to the running state + /// + public void Resume() + { + lock (m_lock) + { + if (m_state == LiveControlState.Paused) + { + //Make sure that the timer is cleared + m_waitTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); + + m_state = LiveControlState.Running; + if (StateChanged != null) + StateChanged(this, null); + } + } + } + + /// + /// Suspends the backups for a given period + /// + /// The duration to wait + public void Pause(string timeout) + { + lock (m_lock) + { + if (m_state == LiveControlState.Running) + { + Pause(); + m_waitTimer.Change((long)Duplicati.Library.Utility.Timeparser.ParseTimeSpan(timeout).TotalMilliseconds, System.Threading.Timeout.Infinite); + } + } + } + } +} diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs new file mode 100644 index 000000000..59d29a83f --- /dev/null +++ b/Duplicati/Server/Program.cs @@ -0,0 +1,478 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.LightDatamodel; + +namespace Duplicati.Server +{ + public class Program + { + /// + /// The name of the application, change this to re-brand it + /// + public const string ApplicationName = "Duplicati"; + + /// + /// The path to the directory that contains the main executable + /// + public static readonly string StartupPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + + /// + /// The name of the environment variable that holds the path to the data folder used by Duplicati + /// + public static readonly string DATAFOLDER_ENV_NAME = ApplicationName.ToUpper() + "_HOME"; + + /// + /// The environment variable that holdes the database key used to encrypt the SQLite database + /// + public static readonly string DB_KEY_ENV_NAME = ApplicationName.ToUpper() + "_DB_KEY"; + + /// + /// Gets the folder where Duplicati data is stored + /// + public static string DATAFOLDER { get { return Library.Utility.Utility.AppendDirSeparator(Environment.ExpandEnvironmentVariables("%" + DATAFOLDER_ENV_NAME + "%").TrimStart('"').TrimEnd('"')); } } + + /// + /// A flag indicating if database encryption is in use + /// + public static bool UseDatabaseEncryption; + + /// + /// This is the only access to the database + /// + public static IDataFetcherWithRelations DataConnection; + + /// + /// This is the lock to be used before manipulating the shared resources + /// + public static object MainLock = new object(); + + /// + /// This is the scheduling thread + /// + public static Scheduler Scheduler; + + /// + /// This is the working thread + /// + public static Duplicati.Library.Utility.WorkerThread WorkThread; + + /// + /// The path to the file that contains the current database + /// + public static string DatabasePath; + + /// + /// The actual runner, do not call directly. Only used for events. + /// + public static DuplicatiRunner Runner; + + /// + /// The controller interface for pause/resume and throttle options + /// + public static LiveControls LiveControl; + + /// + /// The application exit event + /// + public static System.Threading.ManualResetEvent ApplicationExitEvent; + + /// + /// The webserver instance + /// + public static WebServer WebServer; + + /// + /// The queue for handling events + /// + public static EventQueue Events; + + /// + /// The main entry point for the application. + /// Commandline arguments + /// + [STAThread] + static void Main(string[] args) + { + //If we are on Windows, append the bundled "win-tools" programs to the search path + //We add it last, to allow the user to override with other versions + if (!Library.Utility.Utility.IsClientLinux) + { + Environment.SetEnvironmentVariable("PATH", + Environment.GetEnvironmentVariable("PATH") + + System.IO.Path.PathSeparator.ToString() + + System.IO.Path.Combine( + System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), + "win-tools") + ); + } + + //If we are on windows we encrypt the database by default + //We do not encrypt on Linux as most distros use a SQLite library without encryption support, + //Linux users can use an encrypted home folder, or install a SQLite library with encryption support + if (!Library.Utility.Utility.IsClientLinux && string.IsNullOrEmpty(Environment.GetEnvironmentVariable(DB_KEY_ENV_NAME))) + { + //Note that the password here is a default password and public knowledge + // + //The purpose of this is to prevent casual read of the database, as well + // as protect from harddisk string scans, not to protect from determined + // attacks. + // + //If you desire better security, start Duplicati once with the commandline option + // --unencrypted-database to decrypt the database. + //Then set the environment variable DUPLICATI_DB_KEY to the desired key, + // and run Duplicati again without the --unencrypted-database option + // to re-encrypt it with the new key + // + //If you change the key, please note that you need to supply the same + // key when restoring the setup, as the setup being backed up will + // be encrypted as well. + Environment.SetEnvironmentVariable(DB_KEY_ENV_NAME, ApplicationName + "_Key_42"); + } + + + //Find commandline options here for handling special startup cases + Dictionary commandlineOptions = CommandLine.CommandLineParser.ExtractOptions(new List(args)); + + foreach (string s in args) + if ( + s.Equals("help", StringComparison.InvariantCultureIgnoreCase) || + s.Equals("/help", StringComparison.InvariantCultureIgnoreCase) || + s.Equals("usage", StringComparison.InvariantCultureIgnoreCase) || + s.Equals("/usage", StringComparison.InvariantCultureIgnoreCase)) + commandlineOptions["help"] = ""; + + //If the commandline issues --help, just stop here + if (commandlineOptions.ContainsKey("help")) + { + Console.WriteLine(Strings.Program.HelpDisplayDialog); + + foreach (Library.Interface.ICommandLineArgument arg in SupportedCommands) + Console.WriteLine(Strings.Program.HelpDisplayFormat, arg.Name, arg.LongDescription); + + return; + } + +#if DEBUG + //Log various information in the logfile + if (!commandlineOptions.ContainsKey("log-file")) + { + commandlineOptions["log-file"] = System.IO.Path.Combine(StartupPath, "Duplicati.debug.log"); + commandlineOptions["log-level"] = Duplicati.Library.Logging.LogMessageType.Profiling.ToString(); + } +#endif + + if (commandlineOptions.ContainsKey("log-level")) + foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) + if (s.Equals(commandlineOptions["log-level"].Trim(), StringComparison.InvariantCultureIgnoreCase)) + Duplicati.Library.Logging.Log.LogLevel = (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s); + + if (commandlineOptions.ContainsKey("log-file")) + { + if (System.IO.File.Exists(commandlineOptions["log-file"])) + System.IO.File.Delete(commandlineOptions["log-file"]); + Duplicati.Library.Logging.Log.CurrentLog = new Duplicati.Library.Logging.StreamLog(commandlineOptions["log-file"]); + } + + //Set the %DUPLICATI_HOME% env variable, if it is not already set + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(DATAFOLDER_ENV_NAME))) + { +#if DEBUG + //debug mode uses a lock file located in the app folder + Environment.SetEnvironmentVariable(DATAFOLDER_ENV_NAME, System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)); +#else + bool portableMode = commandlineOptions.ContainsKey("portable-mode") ? Library.Utility.Utility.ParseBool(commandlineOptions["portable-mode"], true) : false; + + if (portableMode) + { + //Portable mode uses a data folder in the application home dir + Environment.SetEnvironmentVariable(DATAFOLDER_ENV_NAME, System.IO.Path.Combine(StartupPath, "data")); + } + else + { + //Normal release mode uses the systems "Application Data" folder + Environment.SetEnvironmentVariable(DATAFOLDER_ENV_NAME, System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ApplicationName)); + } +#endif + } + + SingleInstance instance = null; + + try + { + try + { + //This will also create Program.DATAFOLDER if it does not exist + instance = new SingleInstance(ApplicationName, Program.DATAFOLDER); + } + catch (Exception ex) + { + Console.WriteLine(Strings.Program.StartupFailure, ex.ToString()); + return; + } + + if (!instance.IsFirstInstance) + { + Console.WriteLine(Strings.Program.AnotherInstanceDetected); + return; + } + + Version sqliteVersion = new Version((string)SQLiteLoader.SQLiteConnectionType.GetProperty("SQLiteVersion").GetValue(null, null)); + if (sqliteVersion < new Version(3, 6, 3)) + { + //The official Mono SQLite provider is also broken with less than 3.6.3 + Console.WriteLine(Strings.Program.WrongSQLiteVersion, sqliteVersion, "3.6.3"); + return; + } + + //Create the connection instance + System.Data.IDbConnection con = (System.Data.IDbConnection)Activator.CreateInstance(SQLiteLoader.SQLiteConnectionType); + + try + { + DatabasePath = System.IO.Path.Combine(Program.DATAFOLDER, "Duplicati.sqlite"); + if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(DatabasePath))) + System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(DatabasePath)); + +#if DEBUG + //Default is to not use encryption for debugging + Program.UseDatabaseEncryption = commandlineOptions.ContainsKey("unencrypted-database") ? !Library.Utility.Utility.ParseBool(commandlineOptions["unencrypted-database"], true) : false; +#else + Program.UseDatabaseEncryption = commandlineOptions.ContainsKey("unencrypted-database") ? !Library.Utility.Utility.ParseBool(commandlineOptions["unencrypted-database"], true) : true; +#endif + con.ConnectionString = "Data Source=" + DatabasePath; + + //Attempt to open the database, handling any encryption present + OpenDatabase(con); + + DatabaseUpgrader.UpgradeDatabase(con, DatabasePath); + } + catch (Exception ex) + { + //Unwrap the reflection exceptions + if (ex is System.Reflection.TargetInvocationException && ex.InnerException != null) + ex = ex.InnerException; + + Console.WriteLine(Strings.Program.DatabaseOpenError, ex.Message); + return; + } + + DataConnection = new DataFetcherWithRelations(new SQLiteDataProvider(con)); + + ApplicationExitEvent = new System.Threading.ManualResetEvent(false); + + Events = new EventQueue(); + + LiveControl = new LiveControls(new Duplicati.Datamodel.ApplicationSettings(DataConnection)); + LiveControl.StateChanged += new EventHandler(LiveControl_StateChanged); + LiveControl.ThreadPriorityChanged += new EventHandler(LiveControl_ThreadPriorityChanged); + LiveControl.ThrottleSpeedChanged += new EventHandler(LiveControl_ThrottleSpeedChanged); + + + Runner = new DuplicatiRunner(); + WorkThread = new Duplicati.Library.Utility.WorkerThread(new Duplicati.Library.Utility.WorkerThread.ProcessItemDelegate(Runner.ExecuteTask), LiveControl.State == LiveControls.LiveControlState.Paused); + Scheduler = new Scheduler(DataConnection, WorkThread, MainLock); + + WorkThread.StartingWork += new EventHandler(Events.WorkThread_StartingWork); + WorkThread.CompletedWork += new EventHandler(Events.WorkThread_CompletedWork); + WorkThread.WorkQueueChanged += new EventHandler(Events.WorkThread_WorkQueueChanged); + Scheduler.NewSchedule += new EventHandler(Events.Scheduler_NewSchedule); + Runner.ProgressEvent += new DuplicatiRunner.ProgressEventDelegate(Events.Runner_DuplicatiProgress); + DataConnection.AfterDataConnection += new System.Data.LightDatamodel.DataConnectionEventHandler(Events.DataConnection_AfterDataConnection); + + LiveControl.StateChanged += new EventHandler(Events.LiveControl_StateChanged); + LiveControl.ThreadPriorityChanged += new EventHandler(Events.LiveControl_ThreadPriorityChanged); + LiveControl.ThrottleSpeedChanged += new EventHandler(Events.LiveControl_ThrottleSpeedChanged); + + + Program.WebServer = new Server.WebServer(8080); + + DataConnection.AfterDataConnection += new DataConnectionEventHandler(DataConnection_AfterDataConnection); + + ApplicationExitEvent.WaitOne(); + } + catch (Exception ex) + { + Console.WriteLine(Strings.Program.SeriousError, ex.ToString()); + } + + + if (Scheduler != null) + Scheduler.Terminate(true); + if (WorkThread != null) + WorkThread.Terminate(true); + if (instance != null) + instance.Dispose(); + +#if DEBUG + //Flush the file + using (Duplicati.Library.Logging.Log.CurrentLog as Duplicati.Library.Logging.StreamLog) + Duplicati.Library.Logging.Log.CurrentLog = null; +#endif + } + + /// + /// Handles a change in the LiveControl and updates the Runner + /// + /// + /// + private static void LiveControl_ThreadPriorityChanged(object sender, EventArgs e) + { + if (LiveControl.ThreadPriority == null) + Runner.UnsetThreadPriority(); + else + Runner.SetThreadPriority(LiveControl.ThreadPriority.Value); + } + + /// + /// Handles a change in the LiveControl and updates the Runner + /// + /// + /// + private static void LiveControl_ThrottleSpeedChanged(object sender, EventArgs e) + { + if (LiveControl.DownloadLimit == null) + Runner.SetDownloadLimit(null); + else + Runner.SetDownloadLimit(LiveControl.DownloadLimit.Value.ToString() + "b"); + + if (LiveControl.UploadLimit == null) + Runner.SetUploadLimit(null); + else + Runner.SetUploadLimit(LiveControl.UploadLimit.Value.ToString() + "b"); + } + + /// + /// This event handler updates the trayicon menu with the current state of the runner. + /// + static void LiveControl_StateChanged(object sender, EventArgs e) + { + switch (LiveControl.State) + { + case LiveControls.LiveControlState.Paused: + WorkThread.Pause(); + Runner.Pause(); + break; + case LiveControls.LiveControlState.Running: + WorkThread.Resume(); + Runner.Resume(); + break; + } + } + + + private static void DataConnection_AfterDataConnection(object sender, DataActions action) + { + if (action == DataActions.Insert || action == DataActions.Update) + Scheduler.Reschedule(); + } + + /// + /// Returns a localized name for a task type + /// + /// + /// + public static string LocalizeTaskType(DuplicityTaskType type) + { + switch (type) + { + case DuplicityTaskType.FullBackup: + return Strings.TaskType.FullBackup; + case DuplicityTaskType.IncrementalBackup: + return Strings.TaskType.IncrementalBackup; + case DuplicityTaskType.ListActualFiles: + return Strings.TaskType.ListActualFiles; + case DuplicityTaskType.ListBackupEntries: + return Strings.TaskType.ListBackupEntries; + case DuplicityTaskType.ListBackups: + return Strings.TaskType.ListBackups; + case DuplicityTaskType.ListFiles: + return Strings.TaskType.ListFiles; + case DuplicityTaskType.RemoveAllButNFull: + return Strings.TaskType.RemoveAllButNFull; + case DuplicityTaskType.RemoveOlderThan: + return Strings.TaskType.RemoveOlderThan; + case DuplicityTaskType.Restore: + return Strings.TaskType.Restore; + case DuplicityTaskType.RestoreSetup: + return Strings.TaskType.RestoreSetup; + default: + return type.ToString(); + } + } + + /// + /// Helper method with logic to handle opening a database in possibly encrypted format + /// + /// The SQLite connection object + internal static void OpenDatabase(System.Data.IDbConnection con) + { + bool noEncryption = !Program.UseDatabaseEncryption; + string password = Environment.GetEnvironmentVariable(DB_KEY_ENV_NAME); + + System.Reflection.MethodInfo setPwdMethod = con.GetType().GetMethod("SetPassword", new Type[] { typeof(string) }); + string attemptedPassword; + + if (noEncryption || string.IsNullOrEmpty(password)) + attemptedPassword = null; //No encryption specified, attempt to open without + else + attemptedPassword = password; //Encryption specified, attempt to open with + + if (setPwdMethod != null) + setPwdMethod.Invoke(con, new object[] { attemptedPassword }); + + try + { + //Attempt to open in preferred state + con.Open(); + } + catch + { + try + { + //We can't try anything else without a password + if (string.IsNullOrEmpty(password)) + throw; + + //Open failed, now try the reverse + if (attemptedPassword == null) + attemptedPassword = password; + else + attemptedPassword = null; + + setPwdMethod.Invoke(con, new object[] { attemptedPassword }); + con.Open(); + } + catch + { + } + + //If the db is not open now, it won't open + if (con.State != System.Data.ConnectionState.Open) + throw; //Report original error + + //The open method succeeded with the non-default method, now change the password + System.Reflection.MethodInfo changePwdMethod = con.GetType().GetMethod("ChangePassword", new Type[] { typeof(string) }); + changePwdMethod.Invoke(con, new object[] { noEncryption ? null : password }); + } + } + + /// + /// Gets a list of all supported commandline options + /// + private static Library.Interface.ICommandLineArgument[] SupportedCommands + { + get + { + return new Duplicati.Library.Interface.ICommandLineArgument[] { + new Duplicati.Library.Interface.CommandLineArgument("help", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Boolean, Strings.Program.HelpCommandDescription, Strings.Program.HelpCommandDescription), + new Duplicati.Library.Interface.CommandLineArgument("unencrypted-database", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Boolean, Strings.Program.UnencrypteddatabaseCommandDescription, Strings.Program.UnencrypteddatabaseCommandDescription), + new Duplicati.Library.Interface.CommandLineArgument("portable-mode", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Boolean, Strings.Program.PortablemodeCommandDescription, Strings.Program.PortablemodeCommandDescription), + new Duplicati.Library.Interface.CommandLineArgument("log-file", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Path, Strings.Program.LogfileCommandDescription, Strings.Program.LogfileCommandDescription), + new Duplicati.Library.Interface.CommandLineArgument("log-level", Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Enumeration, Strings.Program.LoglevelCommandDescription, Strings.Program.LoglevelCommandDescription, "Warning", null, Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))) + }; + } + } + } +} diff --git a/Duplicati/Server/Properties/AssemblyInfo.cs b/Duplicati/Server/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f9d6b89c5 --- /dev/null +++ b/Duplicati/Server/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +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("Duplicati.Server")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Duplicati.Server")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("94819ef2-1899-420c-8a91-77cde270c53e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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")] diff --git a/Duplicati/Server/SQLiteLoader.cs b/Duplicati/Server/SQLiteLoader.cs new file mode 100644 index 000000000..ab826e878 --- /dev/null +++ b/Duplicati/Server/SQLiteLoader.cs @@ -0,0 +1,89 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; + +namespace Duplicati.Server +{ + public static class SQLiteLoader + { + /// + /// A cached copy of the type + /// + private static Type m_type = null; + + /// + /// Returns the SQLiteCommand type for the current architecture + /// + public static Type SQLiteConnectionType + { + get + { + if (m_type == null) + { + string filename = "System.Data.SQLite.dll"; + string basePath = System.IO.Path.Combine(Program.StartupPath, "SQLite"); + + //Default is to use the pinvoke version which requires a native .dll/.so + string assemblyPath = System.IO.Path.Combine(basePath, "pinvoke"); + + //If we run on windows with MS.Net we can use the mixed mode assemblies + if (!Duplicati.Library.Utility.Utility.IsClientLinux && !Duplicati.Library.Utility.Utility.IsMono) + { + //On my x64 system, 32bit appears to work correctly as 32 bit, where loading the 64bit dll fails + if (IntPtr.Size == 8 /*|| (IntPtr.Size == 4 && Is32BitProcessOn64BitProcessor())*/) + { + if (System.IO.File.Exists(System.IO.Path.Combine(System.IO.Path.Combine(basePath, "win64"), filename))) + assemblyPath = System.IO.Path.Combine(basePath, "win64"); + } + else + { + if (System.IO.File.Exists(System.IO.Path.Combine(System.IO.Path.Combine(basePath, "win32"), filename))) + assemblyPath = System.IO.Path.Combine(basePath, "win32"); + } + } + + m_type = System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(assemblyPath, filename)).GetType("System.Data.SQLite.SQLiteConnection"); + } + + return m_type; + } + } + + [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true, CallingConvention = System.Runtime.InteropServices.CallingConvention.Winapi)] + [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)] + private static extern bool IsWow64Process([System.Runtime.InteropServices.In] IntPtr hProcess, [System.Runtime.InteropServices.Out] out bool lpSystemInfo); + + private static bool Is32BitProcessOn64BitProcessor() + { + try + { + bool retVal; + IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle, out retVal); + return retVal; + } + catch + { + return false; //In case the OS is old enough not to have the Wow64 function + } + } + } +} diff --git a/Duplicati/Server/Scheduler.cs b/Duplicati/Server/Scheduler.cs new file mode 100644 index 000000000..223a48369 --- /dev/null +++ b/Duplicati/Server/Scheduler.cs @@ -0,0 +1,275 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Duplicati.Datamodel; +using System.Data.LightDatamodel; +using Duplicati.Library.Utility; + +namespace Duplicati.Server +{ + /// + /// This class handles scheduled runs of backups + /// + public class Scheduler + { + /// + /// The thread that runs the scheduler + /// + private Thread m_thread; + /// + /// The connection to the database + /// + private IDataFetcherCached m_connection; + /// + /// A termination flag + /// + private volatile bool m_terminate; + /// + /// The worker thread that is invoked to do work + /// + private WorkerThread m_worker; + /// + /// The wait event + /// + private AutoResetEvent m_event; + /// + /// The data syncronization lock + /// + private object m_lock = new object(); + /// + /// The program lock for the database connection + /// + private object m_datalock; + + /// + /// An event that is raised when the schedule changes + /// + public event EventHandler NewSchedule; + + /// + /// The currently scheduled items + /// + private Schedule[] m_schedule; + + /// + /// Constructs a new scheduler + /// + /// The database connection + /// The worker thread + /// The database lock object + public Scheduler(IDataFetcherCached connection, WorkerThread worker, object datalock) + { + m_datalock = datalock; + m_connection = connection; + m_thread = new Thread(new ThreadStart(Runner)); + m_worker = worker; + m_schedule = new Schedule[0]; + m_terminate = false; + m_event = new AutoResetEvent(false); + m_thread.IsBackground = true; + m_thread.Start(); + } + + /// + /// Forces the scheduler to re-evaluate the order. + /// Call this method if something changes + /// + public void Reschedule() + { + m_event.Set(); + } + + /// + /// A copy of the current schedule list + /// + public List Schedule + { + get + { + lock (m_lock) + return new List(m_schedule); + } + } + + /// + /// Terminates the thread. Any items still in queue will be removed + /// + /// True if the call should block until the thread has exited, false otherwise + public void Terminate(bool wait) + { + m_terminate = true; + m_event.Set(); + + if (wait) + m_thread.Join(); + } + + /// + /// Returns the next valid date, given the start and the interval + /// + /// The starting time + /// The repetition interval + /// The days the backup is allowed to run + /// The next valid date, or throws an exception if no such date can be found + public static DateTime GetNextValidTime(DateTime start, string repetition, DayOfWeek[] allowedDays) + { + DateTime res = start; + + int i = 50000; + + while (!IsDateAllowed(res, allowedDays) && i-- > 0) + res = Timeparser.ParseTimeInterval(repetition, res); + + if (!IsDateAllowed(res, allowedDays)) + { + StringBuilder sb = new StringBuilder(); + if (allowedDays != null) + foreach (DayOfWeek w in allowedDays) + { + if (sb.Length != 0) + sb.Append(", "); + sb.Append(w.ToString()); + } + + throw new Exception(string.Format(Strings.Scheduler.InvalidTimeSetupError, start, repetition, sb.ToString())); + } + + return res; + } + + /// + /// The actual scheduling procedure + /// + private void Runner() + { + while (!m_terminate) + { + List reps = new List(); + List tmp; + lock (m_datalock) + tmp = new List(m_connection.GetObjects()); + + //Determine schedule list + foreach (Schedule sc in tmp) + { + if (!string.IsNullOrEmpty(sc.Repeat)) + { + DateTime start = sc.NextScheduledTime; + + try { start = GetNextValidTime(sc.NextScheduledTime, sc.Repeat, sc.AllowedWeekdays); } + catch { } //TODO: Report this somehow + + //If time is exceeded, run it now + if (start <= DateTime.Now) + { + //See if it is already queued + List tmplst = m_worker.CurrentTasks; + IDuplicityTask tastTemp = m_worker.CurrentTask; + if (tastTemp != null) + tmplst.Add(tastTemp); + + bool found = false; + foreach (IDuplicityTask t in tmplst) + if (t != null && t is IncrementalBackupTask && ((IncrementalBackupTask)t).Schedule.ID == sc.ID) + { + found = true; + break; + } + + //If it is not already in queue, put it there + if (!found) + m_worker.AddTask(new IncrementalBackupTask(sc)); + + //Caluclate next time, by adding the interval to the start until we have + // passed the current date and time + //TODO: Make this more efficient + int i = 50000; + while (start <= DateTime.Now && i-- > 0) + try { start = GetNextValidTime(Timeparser.ParseTimeInterval(sc.Repeat, start), sc.Repeat, sc.AllowedWeekdays); } + catch + { + //TODO: Report this somehow + continue; + } + + if (start < DateTime.Now) + continue; + } + + //Add to schedule list at the new time + reps.Add(sc); + sc.NextScheduledTime = start; + } + } + + System.Data.LightDatamodel.QueryModel.OperationOrParameter op = System.Data.LightDatamodel.QueryModel.Parser.ParseQuery("ORDER BY When ASC"); + + //Sort them, lock as we assign the m_schedule variable + lock(m_lock) + m_schedule = op.EvaluateList(reps).ToArray(); + + //Raise event if needed + if (NewSchedule != null) + NewSchedule(this, null); + + int waittime = 0; + + //Figure out a sensible amount of time to sleep the thread + if (m_schedule.Length > 0) + { + //When is the next run scheduled? + TimeSpan nextrun = m_schedule[0].NextScheduledTime - DateTime.Now; + if (nextrun.TotalMilliseconds < 0) + continue; + + //Don't sleep for more than 5 minutes + waittime = (int)Math.Min(nextrun.TotalMilliseconds, 60 * 1000 * 5); + } + else + { + //No tasks, check back later + waittime = 60 * 1000; + } + + //Waiting on the event, enables a wakeup call from termination + // never use waittime = 0 + m_event.WaitOne(Math.Max(100, waittime), false); + } + } + + /// + /// Returns true if the time is at an allowed weekday, false otherwise + /// + /// The time to evaluate + /// The allowed days + /// True if the backup is allowed to run, false otherwise + private static bool IsDateAllowed(DateTime time, DayOfWeek[] allowedDays) + { + if (allowedDays == null || allowedDays.Length == 0) + return true; + else + return Array.IndexOf(allowedDays, time.DayOfWeek) >= 0; + } + + } +} diff --git a/Duplicati/Server/SingleInstance.cs b/Duplicati/Server/SingleInstance.cs new file mode 100644 index 000000000..248eb6426 --- /dev/null +++ b/Duplicati/Server/SingleInstance.cs @@ -0,0 +1,283 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; + +namespace Duplicati.Server +{ + /// + /// The purpose of this class is to ensure that there is ever only one instance of the application running. + /// This class is based on file-locking, making it much more cross-platform portable than other versions, + /// that depend on memory communication, such as pipes or shared memory. + /// + public class SingleInstance : IDisposable + { + /// + /// The folder where control files are placed + /// + private const string CONTROL_DIR = "control_dir"; + /// + /// The file that is locked by the first process + /// + private const string CONTROL_FILE = "lock"; + /// + /// The prefix on files that communicate with the first instance + /// + private const string COMM_FILE_PREFIX = "other_invocation_"; + + /// + /// The delegate that is used to inform the first instance of the second invocation + /// + /// The commandlinearguments for the second invocation + public delegate void SecondInstanceDelegate(string[] commandlineargs); + + /// + /// When the user tries to launch the application the second time, this event is raised + /// + public event SecondInstanceDelegate SecondInstanceDetected; + + /// + /// The file that is locked to prevent other access + /// + private System.IO.FileStream m_file; + + /// + /// The folder where control files are placed + /// + private string m_controldir; + + /// + /// The watcher that allows interprocess communication + /// + private System.IO.FileSystemWatcher m_filewatcher; + + /// + /// Gets a value indicating if this is the first instance of the application + /// + public bool IsFirstInstance { get { return m_file != null; } } + + /// + /// Constructs a new SingleInstance object + /// + /// The application name + public SingleInstance(string appname) + : this(appname, System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), appname)) + { } + + /// + /// Constructs a new SingleInstance object + /// + /// The application name + /// The folder in which the control file structure is placed + public SingleInstance(string appname, string basefolder) + { + if (!System.IO.Directory.Exists(basefolder)) + System.IO.Directory.CreateDirectory(basefolder); + + m_controldir = System.IO.Path.Combine(basefolder, CONTROL_DIR); + if (!System.IO.Directory.Exists(m_controldir)) + System.IO.Directory.CreateDirectory(m_controldir); + + string lockfile = System.IO.Path.Combine(m_controldir, CONTROL_FILE); + m_file = null; + + try + { + m_file = new System.IO.FileStream(lockfile, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None); + } + catch + { + } + + //If we have write access + if (m_file != null) + { + m_filewatcher = new System.IO.FileSystemWatcher(m_controldir); + m_filewatcher.Created += new System.IO.FileSystemEventHandler(m_filewatcher_Created); + m_filewatcher.EnableRaisingEvents = true; + + System.IO.StreamWriter sw = new System.IO.StreamWriter(m_file); + sw.WriteLine(System.Diagnostics.Process.GetCurrentProcess().Id); + sw.Flush(); + //Do not dispose the SW, as that will close the file and release the lock + + DateTime startup = System.IO.File.GetLastWriteTime(lockfile); + + //Clean up any files that were created before the app launched + foreach(string s in System.IO.Directory.GetFiles(m_controldir)) + if (s != lockfile && System.IO.File.GetCreationTime(s) < startup) + try { System.IO.File.Delete(s); } + catch { } + } + else + { + //Wait for the initial process to signal that the filewatcher is activated + int retrycount = 5; + while (retrycount > 0 && new System.IO.FileInfo(lockfile).Length == 0) + { + System.Threading.Thread.Sleep(500); + retrycount--; + } + + //HACK: the unix file lock does not allow us to read the file length when the file is locked + if (new System.IO.FileInfo(lockfile).Length == 0) + if (!Library.Utility.Utility.IsClientLinux) + throw new Exception("The file was locked, but had no data"); + + //Notify the other process that we have started + string filename = System.IO.Path.Combine(m_controldir, COMM_FILE_PREFIX + Guid.NewGuid().ToString()); + + + //Write out the commandline arguments + string[] cmdargs = System.Environment.GetCommandLineArgs(); + using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write, System.IO.FileShare.None)) + using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fs)) + for (int i = 1; i < cmdargs.Length; i++) //Skip the first, as that is the filename + sw.WriteLine(cmdargs[i]); + + //Wait for the other process to delete the file, indicating that it is processed + retrycount = 5; + while (retrycount > 0 && System.IO.File.Exists(filename)) + { + System.Threading.Thread.Sleep(500); + retrycount--; + } + + //This may happen if the other process is closing as we write the command + if (System.IO.File.Exists(filename)) + { + //Try to clean up, so the other process does not spuriously show this + try { System.IO.File.Delete(filename); } + catch { } + + throw new Exception("The lock file was locked, but the locking process did not respond to the start command"); + } + } + } + + /// + /// The event that is raised when a new file is created in the control dir + /// + /// The event sender + /// The file event arguments + private void m_filewatcher_Created(object sender, System.IO.FileSystemEventArgs e) + { + //Retry 5 times if the other process is slow on releasing the file lock + int retrycount = 5; + //Indicator and holder of arguments passed + string[] commandline = null; + + do + { + try + { + //If the other process deleted the file, just quit + if (!System.IO.File.Exists(e.FullPath)) + return; + + List args = new List(); + using (System.IO.FileStream fs = new System.IO.FileStream(e.FullPath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.None)) + using (System.IO.StreamReader sr = new System.IO.StreamReader(fs)) + while(!sr.EndOfStream) + args.Add(sr.ReadLine()); + + commandline = args.ToArray(); + + //Remove the file to notify the other process that we have correctly processed the call + System.IO.File.Delete(e.FullPath); + } + catch + { + } + + //If file-reading failed, wait a little before retry + if (commandline == null) + { + System.Threading.Thread.Sleep(500); + retrycount--; + } + + } while (retrycount > 0 && commandline == null); + + //If this happens, we detected the file, but was unable to read it's contents + if (commandline == null) + { + //There is nothing we can do :( + } + else + { + //If we read the data but did not delete the file, the other end still hangs + //and waits for us to clean up, so try again. + retrycount = 5; + while (retrycount > 0 && System.IO.File.Exists(e.FullPath)) + { + try + { + System.IO.File.Delete(e.FullPath); + } + catch + { + //Wait before the retry + System.Threading.Thread.Sleep(500); + } + + retrycount--; + } + + //If this happens, the other process will give an error message + if (System.IO.File.Exists(e.FullPath)) + { + //There is nothing we can do :( + } + + //Finally inform this instance about the call + if (SecondInstanceDetected != null) + SecondInstanceDetected(commandline); + } + + } + + #region IDisposable Members + + public void Dispose() + { + if (m_filewatcher != null) + { + m_filewatcher.EnableRaisingEvents = false; + m_filewatcher.Created -= new System.IO.FileSystemEventHandler(m_filewatcher_Created); + m_filewatcher.Dispose(); + m_filewatcher = null; + } + + if (m_file != null) + { + m_file.Dispose(); + + try { System.IO.File.Delete(m_file.Name); } + catch { } + + m_file = null; + } + } + + #endregion + } +} diff --git a/Duplicati/Server/Strings/DatabaseUpgrader.Designer.cs b/Duplicati/Server/Strings/DatabaseUpgrader.Designer.cs new file mode 100644 index 000000000..82b5dc24d --- /dev/null +++ b/Duplicati/Server/Strings/DatabaseUpgrader.Designer.cs @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.Server.Strings { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class DatabaseUpgrader { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal DatabaseUpgrader() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.Server.Strings.DatabaseUpgrader", typeof(DatabaseUpgrader).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to backup. + /// + internal static string BackupFilenamePrefix { + get { + return ResourceManager.GetString("BackupFilenamePrefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to determine database format: {0}. + /// + internal static string DatabaseFormatError { + get { + return ResourceManager.GetString("DatabaseFormatError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to + ///The database has version {0} but the largest supported version is {1}. + /// + ///This is likely caused by upgrading to a newer version and then downgrading. + ///If this is the case, there is likely a backup file of the previous database version in the folder {2}.. + /// + internal static string InvalidVersionError { + get { + return ResourceManager.GetString("InvalidVersionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown table layout detected. + /// + internal static string TableLayoutError { + get { + return ResourceManager.GetString("TableLayoutError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to execute SQL: {0} + ///Error: {1} + ///Database is NOT upgraded.. + /// + internal static string UpgradeFailure { + get { + return ResourceManager.GetString("UpgradeFailure", resourceCulture); + } + } + } +} diff --git a/Duplicati/Server/Strings/DatabaseUpgrader.resx b/Duplicati/Server/Strings/DatabaseUpgrader.resx new file mode 100644 index 000000000..9a48a0514 --- /dev/null +++ b/Duplicati/Server/Strings/DatabaseUpgrader.resx @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + backup + A string prefixed to the name of the database when making a backup + + + Unable to determine database format: {0} + An error message that is displayed if an error occurs while determining database layout + + + +The database has version {0} but the largest supported version is {1}. + +This is likely caused by upgrading to a newer version and then downgrading. +If this is the case, there is likely a backup file of the previous database version in the folder {2}. + An error message that is displayed if the database version number does not match + + + Unknown table layout detected + An error message that is displayed when the layout of the database is unexpected + + + Failed to execute SQL: {0} +Error: {1} +Database is NOT upgraded. + An error message displayed if one of the upgrade SQL statements fail + + \ No newline at end of file diff --git a/Duplicati/Server/Strings/DuplicatiRunner.Designer.cs b/Duplicati/Server/Strings/DuplicatiRunner.Designer.cs new file mode 100644 index 000000000..1e0c49299 --- /dev/null +++ b/Duplicati/Server/Strings/DuplicatiRunner.Designer.cs @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.Server.Strings { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class DuplicatiRunner { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal DuplicatiRunner() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.Server.Strings.DuplicatiRunner", typeof(DuplicatiRunner).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to The backup was stopped because the application was closed. + /// + internal static string ApplicationExitLogMesssage { + get { + return ResourceManager.GetString("ApplicationExitLogMesssage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removing old backups .... + /// + internal static string CleaningUpMessage { + get { + return ResourceManager.GetString("CleaningUpMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed during cleanup: {0}. + /// + internal static string CleanupError { + get { + return ResourceManager.GetString("CleanupError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cleanup output:. + /// + internal static string CleanupLogdataHeader { + get { + return ResourceManager.GetString("CleanupLogdataHeader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error: {0}. + /// + internal static string ErrorMessage { + get { + return ResourceManager.GetString("ErrorMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The backup was stopped, the reason was: {0}. + /// + internal static string OtherAbortMessage { + get { + return ResourceManager.GetString("OtherAbortMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The backup was stopped because the application was closed by the task manager. + /// + internal static string TaskManagerCloseMessage { + get { + return ResourceManager.GetString("TaskManagerCloseMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The backup was stopped by the user. + /// + internal static string UserClosingMessage { + get { + return ResourceManager.GetString("UserClosingMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The backup was stopped because the machine was being shut down. + /// + internal static string WindowsShutdownMessage { + get { + return ResourceManager.GetString("WindowsShutdownMessage", resourceCulture); + } + } + } +} diff --git a/Duplicati/Server/Strings/DuplicatiRunner.resx b/Duplicati/Server/Strings/DuplicatiRunner.resx new file mode 100644 index 000000000..7bcc29a53 --- /dev/null +++ b/Duplicati/Server/Strings/DuplicatiRunner.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The backup was stopped because the application was closed + + + Removing old backups ... + + + Failed during cleanup: {0} + + + Cleanup output: + + + Error: {0} + + + The backup was stopped, the reason was: {0} + + + The backup was stopped because the application was closed by the task manager + + + The backup was stopped by the user + + + The backup was stopped because the machine was being shut down + + \ No newline at end of file diff --git a/Duplicati/Server/Strings/DynamicSetupHelper.Designer.cs b/Duplicati/Server/Strings/DynamicSetupHelper.Designer.cs new file mode 100644 index 000000000..86687bc5c --- /dev/null +++ b/Duplicati/Server/Strings/DynamicSetupHelper.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.Server.Strings { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class DynamicSetupHelper { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal DynamicSetupHelper() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.Server.Strings.DynamicSetupHelper", typeof(DynamicSetupHelper).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to No folders are included in the backup. + /// + internal static string NoFoldersInSetupError { + get { + return ResourceManager.GetString("NoFoldersInSetupError", resourceCulture); + } + } + } +} diff --git a/Duplicati/Server/Strings/DynamicSetupHelper.resx b/Duplicati/Server/Strings/DynamicSetupHelper.resx new file mode 100644 index 000000000..2bbfb81f8 --- /dev/null +++ b/Duplicati/Server/Strings/DynamicSetupHelper.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + No folders are included in the backup + + \ No newline at end of file diff --git a/Duplicati/Server/Strings/Program.Designer.cs b/Duplicati/Server/Strings/Program.Designer.cs new file mode 100644 index 000000000..3c3742961 --- /dev/null +++ b/Duplicati/Server/Strings/Program.Designer.cs @@ -0,0 +1,193 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.Server.Strings { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Program { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Program() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.Server.Strings.Program", typeof(Program).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Another instance is running, and was notified. + /// + internal static string AnotherInstanceDetected { + get { + return ResourceManager.GetString("AnotherInstanceDetected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to create, open or upgrade the database. + ///Error message: {0}. + /// + internal static string DatabaseOpenError { + get { + return ResourceManager.GetString("DatabaseOpenError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Displays this help. + /// + internal static string HelpCommandDescription { + get { + return ResourceManager.GetString("HelpCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Supported commandline arguments: + /// + ///{0}. + /// + internal static string HelpDisplayDialog { + get { + return ResourceManager.GetString("HelpDisplayDialog", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to --{0}: {1}. + /// + internal static string HelpDisplayFormat { + get { + return ResourceManager.GetString("HelpDisplayFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to set the user interface language: {0}. + /// + internal static string LanguageSelectionError { + get { + return ResourceManager.GetString("LanguageSelectionError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Outputs log information to the file given. + /// + internal static string LogfileCommandDescription { + get { + return ResourceManager.GetString("LogfileCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines the amount of information written in the log file. + /// + internal static string LoglevelCommandDescription { + get { + return ResourceManager.GetString("LoglevelCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Activates portable mode where the database is placed below the program executable. + /// + internal static string PortablemodeCommandDescription { + get { + return ResourceManager.GetString("PortablemodeCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A serious error occured in Duplicati: {0}. + /// + internal static string SeriousError { + get { + return ResourceManager.GetString("SeriousError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Displays the status window. + /// + internal static string ShowstausCommandDescription { + get { + return ResourceManager.GetString("ShowstausCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to start up, perhaps another process is already running? + ///Error message: {0}. + /// + internal static string StartupFailure { + get { + return ResourceManager.GetString("StartupFailure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disables database encryption. + /// + internal static string UnencrypteddatabaseCommandDescription { + get { + return ResourceManager.GetString("UnencrypteddatabaseCommandDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unsupported version of SQLite detected ({0}), must be {1} or higher. + /// + internal static string WrongSQLiteVersion { + get { + return ResourceManager.GetString("WrongSQLiteVersion", resourceCulture); + } + } + } +} diff --git a/Duplicati/Server/Strings/Program.resx b/Duplicati/Server/Strings/Program.resx new file mode 100644 index 000000000..8a7522ece --- /dev/null +++ b/Duplicati/Server/Strings/Program.resx @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + Another instance is running, and was notified + A message displayed in the console when activating Duplicati and it is already running + + + Failed to create, open or upgrade the database. +Error message: {0} + An error message displayed when opening the database fails + + + Displays this help + + + Supported commandline arguments: + +{0} + + + --{0}: {1} + + + Failed to set the user interface language: {0} + An error message displayed if the language cannot be selected + + + Outputs log information to the file given + + + Determines the amount of information written in the log file + + + Activates portable mode where the database is placed below the program executable + + + A serious error occured in Duplicati: {0} + Duplicati crashes + + + Displays the status window + + + Unable to start up, perhaps another process is already running? +Error message: {0} + An error message displayed when Duplicati startup fails + + + Disables database encryption + + + Unsupported version of SQLite detected ({0}), must be {1} or higher + An error message displayed when the wrong version of SQLite is detected + + \ No newline at end of file diff --git a/Duplicati/Server/Strings/Scheduler.Designer.cs b/Duplicati/Server/Strings/Scheduler.Designer.cs new file mode 100644 index 000000000..e6a02c095 --- /dev/null +++ b/Duplicati/Server/Strings/Scheduler.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.Server.Strings { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Scheduler { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Scheduler() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.Server.Strings.Scheduler", typeof(Scheduler).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Unable to find a valid date, given the start date {0}, the repetition interval {1} and the allowed days {2}. + /// + internal static string InvalidTimeSetupError { + get { + return ResourceManager.GetString("InvalidTimeSetupError", resourceCulture); + } + } + } +} diff --git a/Duplicati/Server/Strings/Scheduler.resx b/Duplicati/Server/Strings/Scheduler.resx new file mode 100644 index 000000000..87798b26e --- /dev/null +++ b/Duplicati/Server/Strings/Scheduler.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Unable to find a valid date, given the start date {0}, the repetition interval {1} and the allowed days {2} + + \ No newline at end of file diff --git a/Duplicati/Server/Strings/TaskType.Designer.cs b/Duplicati/Server/Strings/TaskType.Designer.cs new file mode 100644 index 000000000..28c370d3c --- /dev/null +++ b/Duplicati/Server/Strings/TaskType.Designer.cs @@ -0,0 +1,153 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Duplicati.Server.Strings { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class TaskType { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TaskType() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Duplicati.Server.Strings.TaskType", typeof(TaskType).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Full backup. + /// + internal static string FullBackup { + get { + return ResourceManager.GetString("FullBackup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incremental backup. + /// + internal static string IncrementalBackup { + get { + return ResourceManager.GetString("IncrementalBackup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List actual files. + /// + internal static string ListActualFiles { + get { + return ResourceManager.GetString("ListActualFiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List backup entries. + /// + internal static string ListBackupEntries { + get { + return ResourceManager.GetString("ListBackupEntries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List backups. + /// + internal static string ListBackups { + get { + return ResourceManager.GetString("ListBackups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List files. + /// + internal static string ListFiles { + get { + return ResourceManager.GetString("ListFiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove all but n full. + /// + internal static string RemoveAllButNFull { + get { + return ResourceManager.GetString("RemoveAllButNFull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove older than. + /// + internal static string RemoveOlderThan { + get { + return ResourceManager.GetString("RemoveOlderThan", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Restore. + /// + internal static string Restore { + get { + return ResourceManager.GetString("Restore", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Restore setup. + /// + internal static string RestoreSetup { + get { + return ResourceManager.GetString("RestoreSetup", resourceCulture); + } + } + } +} diff --git a/Duplicati/Server/Strings/TaskType.resx b/Duplicati/Server/Strings/TaskType.resx new file mode 100644 index 000000000..28d0ba872 --- /dev/null +++ b/Duplicati/Server/Strings/TaskType.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Full backup + + + Incremental backup + + + List actual files + + + List backup entries + + + List backups + + + List files + + + Remove all but n full + + + Remove older than + + + Restore + + + Restore setup + + \ No newline at end of file diff --git a/Duplicati/Server/TaskPackages.cs b/Duplicati/Server/TaskPackages.cs new file mode 100644 index 000000000..f495ea413 --- /dev/null +++ b/Duplicati/Server/TaskPackages.cs @@ -0,0 +1,728 @@ +#region Disclaimer / License +// Copyright (C) 2010, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; +using Duplicati.Datamodel; + +namespace Duplicati.Server +{ + public enum DuplicityTaskType + { + IncrementalBackup, + FullBackup, + RemoveAllButNFull, + RemoveOlderThan, + Restore, + ListBackups, + ListFiles, + ListSourceFolders, + RestoreSetup, + ListActualFiles, + ListBackupEntries + } + + + public delegate void TaskCompletedHandler(IDuplicityTask owner, string output, string shortMessage); + + public interface IDuplicityTask + { + DuplicityTaskType TaskType { get; } + event TaskCompletedHandler TaskCompleted; + void RaiseTaskCompleted(string output, string parsedMessage); + + + DateTime BeginTime { get; set; } + Task Task { get; } + Schedule Schedule { get; } + + string GetConfiguration(Dictionary options); + string LocalPath { get; } + + string Result { get; set; } + + bool IsAborted { get; set; } + } + + public abstract class BackupTask : IDuplicityTask + { + protected Schedule m_schedule; + protected DateTime m_beginTime; + + protected string m_result; + protected bool m_isAborted = false; + + public bool IsAborted { get { return m_isAborted; } set { m_isAborted = value; } } + public abstract DuplicityTaskType TaskType { get; } + + public Schedule Schedule { get { return m_schedule; } } + public Task Task { get { return m_schedule.Task; } } + public event TaskCompletedHandler TaskCompleted; + public virtual DateTime BeginTime + { + get { return m_beginTime; } + set { m_beginTime = value; } + } + + public BackupTask(Schedule schedule) + { + m_schedule = schedule; + } + + public void RaiseTaskCompleted(string output, string parsedMessage) + { + if (TaskCompleted != null) + TaskCompleted(this, output, parsedMessage); + } + + public abstract string LocalPath { get; } + + public virtual string GetConfiguration(Dictionary options) + { + //Schedule settings have lowest priority, because there is currently no setup + SetupSchedule(options); + + //Now setup the environment + ApplicationSettings appSet = new ApplicationSettings(this.Task.DataParent); + + if (this.Task.ExistsInDb && appSet.SignatureCacheEnabled && !string.IsNullOrEmpty(appSet.SignatureCachePath)) + options["signature-cache-path"] = System.IO.Path.Combine(System.Environment.ExpandEnvironmentVariables(appSet.SignatureCachePath), this.Task.Schedule.ID.ToString()); + + if (!string.IsNullOrEmpty(appSet.TempPath)) + { + string tempdir = System.Environment.ExpandEnvironmentVariables(appSet.TempPath); + if (!System.IO.Directory.Exists(tempdir)) + System.IO.Directory.CreateDirectory(tempdir); + + options["tempdir"] = tempdir; + } + + Dictionary env = appSet.CreateDetachedCopy(); + + //Inject the encryption, backend and compression module names into the environment + env["encryption-module"] = this.Task.EncryptionModule; + env["compression-module"] = this.Task.CompressionModule; + env["backend-module"] = this.Task.Service; + + //If there are any control extensions, let them modify the environment + foreach (Library.Interface.ISettingsControl ic in Library.DynamicLoader.SettingsControlLoader.Modules) + ic.GetConfiguration(env, SettingExtension.GetExtensions(this.Task.Schedule.DataParent, ic.Key), options); + + //Setup encryption module + SetupEncryptionModule(env, this.Task.EncryptionSettingsLookup, options); + + //Setup compression module + SetupCompressionModule(env, this.Task.CompressionSettingsLookup, options); + + //Next is the actual backend setup + string destination = SetupBackend(env, options); + + //Setup any task options + SetupTask(options); + + //Setup any task extension options + SetupTaskExtensions(options); + + //Override everything set in the overrides, this is placed last so it cannot be overriden elsewhere + foreach (TaskOverride ov in this.Task.TaskOverrides) + options[ov.Name] = ov.Value; + + return destination; + } + + protected virtual void SetupEncryptionModule(Dictionary env, IDictionary guiOptions, Dictionary options) + { + foreach (Library.Interface.IEncryption e in Library.DynamicLoader.EncryptionLoader.Modules) + if (e.FilenameExtension == this.Task.EncryptionModule) + { + if (e is Library.Interface.IEncryptionGUI) + { + (e as Library.Interface.IEncryptionGUI).GetConfiguration(env, guiOptions, options); + } + else + { + foreach (string k in guiOptions.Keys) + if (k.StartsWith("--")) + options[k.Substring(2)] = guiOptions[k]; + } + + return; + } + } + + protected virtual void SetupCompressionModule(Dictionary env, IDictionary guiOptions, Dictionary options) + { + foreach (Library.Interface.ICompression e in Library.DynamicLoader.CompressionLoader.Modules) + if (e.FilenameExtension == this.Task.CompressionModule) + { + if (e is Library.Interface.ICompressionGUI) + { + (e as Library.Interface.ICompressionGUI).GetConfiguration(env, guiOptions, options); + } + else + { + foreach (string k in guiOptions.Keys) + if (k.StartsWith("--")) + options[k.Substring(2)] = guiOptions[k]; + } + + return; + } + } + + protected virtual void SetupSchedule(Dictionary options) + { + } + + protected virtual void SetupTask(Dictionary options) + { + if (this.Task.Filters.Count > 0) + options["filter"] = this.Task.EncodedFilter; + + if (!string.IsNullOrEmpty(this.Task.EncryptionModule)) + options["encryption-module"] = this.Task.EncryptionModule; + + if (string.IsNullOrEmpty(this.Task.Encryptionkey)) + options.Add("no-encryption", ""); + else + options.Add("passphrase", this.Task.Encryptionkey); + } + + protected virtual void SetupTaskExtensions(Dictionary options) + { + Datamodel.Task.TaskExtensionWrapper ext = this.Task.Extensions; + + if (!string.IsNullOrEmpty(ext.MaxUploadSize)) + options["totalsize"] = ext.MaxUploadSize; + if (!string.IsNullOrEmpty(ext.VolumeSize)) + options["volsize"] = ext.VolumeSize; + if (!string.IsNullOrEmpty(ext.DownloadBandwidth)) + options["max-download-pr-second"] = ext.DownloadBandwidth; + if (!string.IsNullOrEmpty(ext.UploadBandwidth)) + options["max-upload-pr-second"] = ext.UploadBandwidth; + if (!string.IsNullOrEmpty(ext.ThreadPriority)) + options["thread-priority"] = ext.ThreadPriority; + if (ext.AsyncTransfer) + options["asynchronous-upload"] = ""; + if (ext.IgnoreTimestamps) + options["disable-filetime-check"] = ""; + + if (!string.IsNullOrEmpty(ext.FileSizeLimit)) + options["skip-files-larger-than"] = ext.FileSizeLimit; + } + + protected virtual string SetupBackend(Dictionary environment, Dictionary options) + { + //TODO: Replicated from GUI/GridContainer + const string DESTINATION_EXTENSION_KEY = "Destination"; + + Library.Interface.IBackend selectedBackend = null; + foreach (Library.Interface.IBackend b in Library.DynamicLoader.BackendLoader.Backends) + if (b.ProtocolKey == this.Task.Service) + { + selectedBackend = b; + break; + } + + if (selectedBackend == null) + throw new Exception("Missing backend"); + + string destination; + if (selectedBackend is Library.Interface.IBackendGUI) + { + //Simply invoke the backends setup function + destination = ((Library.Interface.IBackendGUI)selectedBackend).GetConfiguration(environment, this.Task.BackendSettingsLookup, options); + } + else + { + //We store destination with the key "Destination" and other options with the -- prefix + if (!options.ContainsKey(DESTINATION_EXTENSION_KEY)) + throw new Exception("Invalid configuration"); + + destination = options[DESTINATION_EXTENSION_KEY]; + foreach (KeyValuePair k in this.Task.BackendSettingsLookup) + if (k.Key.StartsWith("--")) //All options are prefixed with this + options[k.Key.Substring(2)] = k.Value; + } + + return destination; + } + + public string Result + { + get { return m_result; } + set { m_result = value; } + } + + protected virtual void WriteLogMessage(string action, string subaction, string data, string parsedMessage, bool commit) + { + lock (Program.MainLock) + { + System.Data.LightDatamodel.IDataFetcher con = this.Task.DataParent; + Log l = con.Add(); + LogBlob lb = con.Add(); + lb.StringData = data; + + l.Blob = lb; + this.Task.Logs.Add(l); + + //Keep some of the data in an easy to read manner + DuplicatiOutputParser.ParseData(l); + l.Action = action; + l.SubAction = subaction; + l.BeginTime = m_beginTime; + l.EndTime = DateTime.Now; + l.ParsedMessage = parsedMessage; + + //Find logs that are no longer displayed, and delete them + foreach (Log x in con.GetObjects("EndTime < ?", Library.Utility.Timeparser.ParseTimeInterval(new ApplicationSettings(con).RecentBackupDuration, DateTime.Now, true))) + { + if (x.Blob != null) //Load the blob part if required + con.DeleteObject(x.Blob); + con.DeleteObject(x); + } + + if (commit) + (con as System.Data.LightDatamodel.IDataFetcherWithRelations).CommitAllRecursive(); + } + } + } + + public abstract class FullOrIncrementalTask : BackupTask + { + protected FullOrIncrementalTask(Schedule schedule) + : base(schedule) + { + base.TaskCompleted += new TaskCompletedHandler(DoneEvent); + } + + protected void DoneEvent(IDuplicityTask task, string output, string parsedMessage) + { + WriteLogMessage("Backup", "Primary", output, parsedMessage, true); + } + + public override string GetConfiguration(Dictionary options) + { + return base.GetConfiguration(options); + } + + public override string LocalPath + { + get { return System.Environment.ExpandEnvironmentVariables(this.Task.SourcePath); } + } + } + + public class FullBackupTask : FullOrIncrementalTask + { + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.FullBackup; } } + + public FullBackupTask(Schedule schedule) + : base(schedule) + { + } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + options["full"] = ""; + return destination; + } + + } + + public class IncrementalBackupTask : FullOrIncrementalTask + { + private string m_fullAfter = null; + + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.IncrementalBackup; } } + + public string FullAfter + { + get { return m_fullAfter == null ? m_schedule.Task.FullAfter : m_fullAfter; } + } + + public IncrementalBackupTask(Schedule schedule, string fullAfter) + : this(schedule) + { + m_fullAfter = fullAfter; + } + + public IncrementalBackupTask(Schedule schedule) + : base(schedule) + { + } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + + if (!string.IsNullOrEmpty(this.FullAfter)) + options.Add("full-if-older-than", this.FullAfter); + + return destination; + } + } + + public class ListBackupEntriesTask : BackupTask + { + private List m_backups = null; + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.ListBackupEntries; } } + public List Backups { get { return m_backups; } set { m_backups = value; } } + + public ListBackupEntriesTask(Schedule schedule) + : base(schedule) + { + } + + public override string LocalPath + { + get { throw new NotImplementedException(); } + } + } + + public class ListBackupsTask : BackupTask + { + private string[] m_backups = null; + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.ListBackups; } } + public string[] Backups { get { return m_backups; } set { m_backups = value; } } + + public ListBackupsTask(Schedule schedule) + : base(schedule) + { + this.TaskCompleted += new TaskCompletedHandler(ListBackupsTask_TaskCompleted); + } + + void ListBackupsTask_TaskCompleted(IDuplicityTask owner, string output, string parsedMessage) + { + if (string.IsNullOrEmpty(output)) + return; + + const string DIVIDER = "-------------------------\r\n"; + const string HEADERS = " Type of backup set: Time: Num volumes:"; + + List res = new List(); + + foreach (string part in output.Split(new string[] { DIVIDER }, StringSplitOptions.RemoveEmptyEntries)) + if (part.IndexOf(HEADERS) >= 0) + { + bool passedHeader = false; + foreach (string line in part.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)) + { + if (line.StartsWith(HEADERS)) + passedHeader = true; + else if (passedHeader) + { + string tmp = line.Trim(); + if (tmp.StartsWith("Full")) + tmp = tmp.Substring("Full".Length).Trim(); + else if (tmp.StartsWith("Incremental")) + tmp = tmp.Substring("Incremental".Length).Trim(); + + string datetime = tmp.Substring(0, tmp.LastIndexOf(' ')).Trim(); + /*DateTime dt; + if (DateTime.TryParse(datetime, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt))*/ + res.Add(datetime); + } + } + } + + + //System.Text.RegularExpressions.Regex regexp = new System.Text.RegularExpressions.Regex("---------------- + + m_backups = res.ToArray(); + } + + public override string LocalPath + { + get { throw new NotImplementedException(); } + } + } + + public class ListFilesTask : BackupTask + { + protected IList m_files = null; + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.ListFiles; } } + public IList Files { get { return m_files; } set { m_files = value; } } + protected DateTime m_when; + + public ListFilesTask(Schedule schedule, DateTime when) + : base(schedule) + { + m_when = when; + } + + public string When + { + get + { + if (m_when.Year < 10) + return null; + else + return m_when.ToString("s"); + } + } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + + if (!string.IsNullOrEmpty(When)) + options["restore-time"] = this.When; + + return destination; + } + + public override string LocalPath + { + get { throw new NotImplementedException(); } + } + } + + public class ListSourceFoldersTask : ListFilesTask + { + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.ListSourceFolders; } } + public ListSourceFoldersTask(Schedule schedule, DateTime when) + : base(schedule, when) + { + } + } + + public class ListActualFilesTask : BackupTask + { + protected List> m_files = null; + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.ListActualFiles; } } + public List> Files { get { return m_files; } set { m_files = value; } } + protected DateTime m_when; + + public ListActualFilesTask(Schedule schedule, DateTime when) + : base(schedule) + { + m_when = when; + } + + public string When + { + get + { + if (m_when.Year < 10) + return null; + else + return m_when.ToString("s"); + } + } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + + if (!string.IsNullOrEmpty(When)) + options["restore-time"] = this.When; + + return destination; + } + + public override string LocalPath + { + get { throw new NotImplementedException(); } + } + } + + + public class RestoreSetupTask : BackupTask + { + protected string m_targetdir = null; + + public RestoreSetupTask(Schedule schedule, string targetdir) + : base(schedule) + { + m_targetdir = targetdir; + } + + public override string LocalPath + { + get { return System.Environment.ExpandEnvironmentVariables(this.TargetDir); } + } + + public string TargetDir { get { return m_targetdir; } } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + if (options.ContainsKey("filter")) + options.Remove("filter"); + + return destination; + } + + public override DuplicityTaskType TaskType + { + get { return DuplicityTaskType.RestoreSetup; } + } + } + + public class RestoreTask : BackupTask + { + protected DateTime m_when; + protected string m_targetdir = null; + protected string m_sourceFiles = null; + + public string When + { + get + { + if (m_when.Year < 10) + return null; + else + return m_when.ToString("s"); + } + } + + public string TargetDir { get { return m_targetdir; } } + public string SourceFiles { get { return m_sourceFiles; } } + + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.Restore; } } + + public RestoreTask(Schedule schedule, string targetdir, string sourcefiles) + : this(schedule, targetdir, sourcefiles, new DateTime()) + { + } + + public RestoreTask(Schedule schedule, string targetdir, DateTime when) + : this(schedule, targetdir, null, when) + { + } + + public RestoreTask(Schedule schedule, string targetdir) + : this(schedule, targetdir, null, new DateTime()) + { + } + + public RestoreTask(Schedule schedule, string targetdir, string sourcefiles, DateTime when) + : base(schedule) + { + m_targetdir = targetdir; + m_sourceFiles = sourcefiles; + m_when = when; + base.TaskCompleted += new TaskCompletedHandler(DoneEvent); + } + + void DoneEvent(IDuplicityTask owner, string output, string parsedMessage) + { + WriteLogMessage("Restore", "Primary", output, parsedMessage, true); + } + + public override string LocalPath + { + get { return System.Environment.ExpandEnvironmentVariables(this.TargetDir); } + } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + + options.Add("force", ""); + if (!string.IsNullOrEmpty(When)) + options.Add("restore-time", this.When); + + if (!string.IsNullOrEmpty(this.SourceFiles)) + options.Add("file-to-restore", this.SourceFiles); + + return destination; + } + } + + public class RemoveAllButNFullTask : BackupTask + { + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.RemoveAllButNFull; } } + private int m_fullCount; + public int FullCount { get { return m_fullCount; } } + + public RemoveAllButNFullTask(Schedule schedule, int fullcount) + : base(schedule) + { + m_fullCount = fullcount; + base.TaskCompleted += new TaskCompletedHandler(DoneEvent); + } + + void DoneEvent(IDuplicityTask owner, string output, string parsedMessage) + { + WriteLogMessage("Backup", "Cleanup", output, parsedMessage, false); + } + + public override string LocalPath + { + get + { + throw new MissingMethodException(); + } + } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + + options.Add("delete-all-but-n-full", this.FullCount.ToString()); + options.Add("force", ""); + if (!options.ContainsKey("number-of-retries")) + options["number-of-retries"] = "2"; + + return destination; + } + } + + public class RemoveOlderThanTask : BackupTask + { + public override DuplicityTaskType TaskType { get { return DuplicityTaskType.RemoveOlderThan; } } + + private string m_older; + public string Older { get { return m_older; } } + + public RemoveOlderThanTask(Schedule schedule, string older) + : base(schedule) + { + m_older = older; + base.TaskCompleted += new TaskCompletedHandler(DoneEvent); + } + + void DoneEvent(IDuplicityTask owner, string output, string parsedMessage) + { + WriteLogMessage("Backup", "Cleanup", output, parsedMessage, false); + } + + public override string GetConfiguration(Dictionary options) + { + string destination = base.GetConfiguration(options); + + options.Add("delete-older-than", this.Older); + options.Add("force", ""); + if (!options.ContainsKey("number-of-retries")) + options["number-of-retries"] = "2"; + + return destination; + } + + public override string LocalPath + { + get { throw new NotImplementedException(); } + } + } + + +} diff --git a/Duplicati/Server/WebServer.cs b/Duplicati/Server/WebServer.cs new file mode 100644 index 000000000..825242fa8 --- /dev/null +++ b/Duplicati/Server/WebServer.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using HttpServer.MVC; +using HttpServer.HttpModules; + +namespace Duplicati.Server +{ + public class WebServer + { + private HttpServer.HttpServer m_server; + + public WebServer(int port) + { + m_server = new HttpServer.HttpServer(); + + m_server.Add(new DynamicHandler()); + + FileModule fh = new FileModule("/", System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "webroot")); + fh.AddDefaultMimeTypes(); + m_server.Add(fh); + + m_server.Start(System.Net.IPAddress.Any, port); + } + + private class BodyWriter : System.IO.StreamWriter, IDisposable + { + private HttpServer.IHttpResponse m_resp; + public BodyWriter(HttpServer.IHttpResponse resp) + : base(resp.Body, resp.Encoding) + { + m_resp = resp; + } + + protected override void Dispose(bool disposing) + { + base.Flush(); + m_resp.ContentLength = base.BaseStream.Length; + m_resp.Send(); + + base.Dispose(disposing); + } + } + + private class DynamicHandler : HttpModule + { + private delegate void ProcessSub(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session); + + private readonly Dictionary SUPPORTED_METHODS; + + public DynamicHandler() + { + SUPPORTED_METHODS = new Dictionary(System.StringComparer.InvariantCultureIgnoreCase); + + SUPPORTED_METHODS.Add("list-schedules", ListSchedules); + SUPPORTED_METHODS.Add("get-current-state", GetCurrentState); + } + + + public override bool Process(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session) + { + if (!request.Uri.AbsolutePath.Equals("/control.cgi", StringComparison.InvariantCultureIgnoreCase)) + return false; + + HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString; + + string action = input["action"].Value ?? ""; + + ProcessSub method; + SUPPORTED_METHODS.TryGetValue(action, out method); + + if (method == null) + { + response.Status = System.Net.HttpStatusCode.NotImplemented; + response.Reason = "Unsupported action: " + (action == null ? "" : ""); + response.Send(); + } + else + { + //Default setup + response.Status = System.Net.HttpStatusCode.OK; + response.Reason = "OK"; + //response.ContentType = "text/json"; + response.ContentType = "text/plain"; + + method(request, response, session); + } + + return true; + } + + private void ListSchedules(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session) + { + using (var b = new BodyWriter(response)) + { + LitJson.JsonWriter w = new LitJson.JsonWriter(b); + w.WriteArrayStart(); + + foreach (Datamodel.Schedule s in Program.DataConnection.GetObjects()) + { + w.WriteObjectStart(); + + w.WritePropertyName("name"); + w.Write(s.Name); + w.WritePropertyName("id"); + w.Write(s.ID); + + w.WriteObjectEnd(); + } + + w.WriteArrayEnd(); + } + } + + private void GetCurrentState(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session) + { + using (var b = new BodyWriter(response)) + { + LitJson.JsonWriter w = new LitJson.JsonWriter(b); + + w.WriteObjectStart(); + + w.WritePropertyName("eventid"); + w.Write(Program.Events.CurrentEventId); + + w.WritePropertyName("paused"); + w.Write(Program.LiveControl.State.ToString()); + + w.WritePropertyName("pause-timeout"); + w.Write(0); + + + + w.WriteObjectEnd(); + } + } + + } + } +} diff --git a/Duplicati/Server/app.config b/Duplicati/Server/app.config new file mode 100644 index 000000000..a7d04fa82 --- /dev/null +++ b/Duplicati/Server/app.config @@ -0,0 +1,3 @@ + + + diff --git a/thirdparty/HttpServer/Fadd.dll b/thirdparty/HttpServer/Fadd.dll new file mode 100644 index 0000000000000000000000000000000000000000..2cfbbc56337d4e5895b3e3b5999f5f05a677472e GIT binary patch literal 206336 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
    EC^RP9!tu-SBE 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 O8Q2i5V^rZV3IPDrohsS@ literal 0 HcmV?d00001 diff --git a/thirdparty/HttpServer/Fadd.xml b/thirdparty/HttpServer/Fadd.xml new file mode 100644 index 000000000..6524878e5 --- /dev/null +++ b/thirdparty/HttpServer/Fadd.xml @@ -0,0 +1,9136 @@ + + + + Fadd + + + +

    + Checks if a primitive type is between min and max. + + + Language file items: + + + ItemName + Language text + + + Between + '{0}' must be between {1} and {2}. + + + BetweenString + '{0}' may only have {1} up to {2} letters. + + + BetweenStringLength + '{0}' must be {1} letters long. + + + + + + + Base class for all Fadd validation attributes. + + + + Each validation class should document what their language entries should say, and their names. + This should be done in the remarks section using a table list, example: + + + ItemName + Language text + + + ValidateLetters + '{0}' may only contain letters. + + + ValidateLettersExtra + '{0}' may only contain letters and one of the following characters: {1} + + + It's recommended that the item names (or terms in the table above) equals the validation class name. + i.e. ValidateEmailAttributes adds a language item called "Email". + + + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is supported. + + + + Check's whether a value is empty or not. + + value to check. + true if the value is empty. + + + + Check's whether a value is empty or not. + + value to check. + value is considered to be not specified if the value matches this parameter + true if the value is empty. + + + + Initializes a new instance of the class. + + Value must be equal to this or larger. + Value must be equal or less than this. + Thrown if the max value is more than the min value + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + Thrown if an unsupported object value is supplied + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is supported. + + + + Min value + + + + + Max value + + + + + + + + + + + + + + + Tests it. + + My arg. + The value. + + + + + Tests it. + + My arg. + The value. + + + + + Does the this. + + + + + Modify the id of the testobject + + + + + Tests it. + + My arg. + The value. + + + + + Tests it. + + My arg. + The value. + + + + + Does the this. + + + + + Modify the id of the testobject + + + + + This class creates a command channel which can be used to send a command to a remote end point. + + + + + Try to use this port if it's not occupied. + + + + + Initializes a new instance of the class. + + Dispatcher used to invoke commands comming through the channel. + + + + Initializes a new instance of the class. + + Dispatcher used to invoke commands comming through the channel. + Socket used to transport commands. + + + + Initializes a new instance of the class. + + Dispatcher used to invoke commands comming through the channel. + Channel used to tranport commands. + + + + Releases unmanaged resources and performs other cleanup operations before the + is reclaimed by garbage collection. + + + + + Send unhandled commands through the tunnel. + + + Off by defualt. + + + + + + Handle commands tagged with the interface. + + + Off by default. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Connect to other side. + + + + + + + Close command tunnel + + + + + Stops this instance. + + + + + Invoked when client disconnects + + + + + True if socket should auto reconnect connection is closed due to any network error. + + + + + Parse 'AND' + + + + + Tokens are used to parse a specific part of the text. + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Should be called in to let the Token parse all children. + + The containing the data to parse. + that is being built.. + true if a child have been matched and parsed. + Are called from . + + + + Should be called in to let the Token parse all children. + + The containing the data to parse. + that is being built.. + true if a child have been matched and parsed. + Are called from . + + + + Used to check if another child got a match + + used to read data. + being built. + that should not be included in the check. + true if a child matches the current position in the + + + + Add a possible child token. + + The token. + + + + Get parent token + + + + + This token is the final child in the current leaf, parse no more children + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Used to parse SQL conditions + + + + + Chars interpreted as white spaces: NewLine,LineFeed,Tab,Space + + + + + Initializes a new instance of the class. + + + + + Setup all tokens + + + + + Parse the tree + + Text to parse. + a parsed tree + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Not equal condition + + + + + Base class for all objects that are used to build a tree. + + + + + Adds the specified child. + + The child. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + String representation of the token + + Also include all children in the output + Returns a human friendly string + + + + Used to determine the kind of this token + + + + + Gets or sets the parent. + + The parent. + + + + Last added child in the current node. + + + + + Gets the items. + + The items. + + + + Get one of the children + + zero-based index. + + + + + Depth in parse tree. + + + + + Number of children. + + + + + Used to identify conditions (used by Property to see it the text is a property or something else) + + + + + Condition string + + " != " + + + + Used to determine the kind of this token + + + + + + + + + + + Conditional representation. + + + + + + Used to determine the kind of this token + + + + + + = or == + + + + + Equal condition as string + + " == " + + + + Used to determine the kind of this token + + + + + + We are getting into a sub context (nested conditions) + + + + + Used to determine the kind of this token + + + + + + Parse a OR token + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Used to parse SQL conditions + + + + + New Line, Line Feed, Tab and Space. + + + + + Initializes a new instance of the class. + + + + + Setup all tokens + + + + + Parse the tree + + Text to parse. + a parsed tree + + + + Arguments for + + + + + Initializes a new instance of the class. + + Plugin assembly information. + + + + Evidence that the plugin should be loaded with. + + + + + Plugin assembly information + + + + + Called when an assembly is about to be loaded and we need the evidence for it. + Specify the evidence by using + + PluginManager + Assembly information + + + + This node is returned instead of null. + + + + + Contains language translations used to create multilingual applications + + + The LanguageNode provides a base class for different implementations of a hierachial language structure + + + + + Contains language translations used to create multilingual applications + + + The ILanguageNode provides a base class for different implementations of a hierachial language structure + + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + string if found; otherwise null. + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + check for paths in . + string if found; otherwise null. + + + + Gets a sub category + + The category name + if found; otherwise null. + If name is null + + + + Number of translated texts in the specified language. + + Language to get text from. + Number of text items + + + + Determine if the node contains a text item with the specified name (for the current lcid) + + True if the node contains a language element with the specified name for the current language + + + + Determine if the node contains a text item with the specified name for the specified language + + True if the node contains a language element with the specified name for the specified language + + + + Determine if a category contains a specific language. + + Language to get text from. + true if the specified language contains the text string; false if not. + + + + Checks if current language contains a child node with the specified name. + + Name of child node + true if found; otherwise false. + + + Empties all saved values in the node and its sub nodes + + + + Gets the parent language node. + + + null if no parent node exists. + + + + + Gets the mother of all nodes. + + + Root node will return itself. + + + + + Gets the number of languages (and not the number of text items). + + + + + Gets the name of this node. + + + + + Gets language to use if the requested language is not found. + + + + + Gets a localized text string in the current language. + + Phrase to find, can also contain a path. + text if found; [textName] if not. + + + lang["Name"] // => "Name" + lang["/Users/View/Name"] // => "Name" + lang["Naem"] // => "[Naem]" since it's missing + + + + + + Gets a localized text string in the specified language. + + Phrase to find, can also contain a path. + Get translation from this language. + text if found; [textName] if not. + + + lang["Name"] // => "Name" + lang["Name"] // => "Name" + lang["Naem"] // => "[Naem]" since it's missing + + + + + + An empty language node (used instead of null). + + + + + Initializes a new instance of the class. + + The default LCID. + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + string if found; otherwise null. + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + check for paths in . + string if found; otherwise null. + + + + Number of translated texts in the specified language + + + + + + + Determine if the node contains a text item with the specified name (for the current lcid) + + + + True if the node contains a language element with the specified name for the current language + + + + + Determine if the node contains a text item with the specified name for the specified language + + + + + True if the node contains a language element with the specified name for the specified language + + + + + Determine if a category contains a specific language. + + + + + + + Checks if current language contains a child node with the specified name. + + Name of child node + true if found; otherwise false. + + + Empties all saved values in the node and its sub nodes + + + + Gets a sub category + + The category name + + if found; otherwise null. + + If name is null + + + + Checks paths that are specified in text names + + For instance /user/show/firstname + language to check in + string if language contains a path, otherwise null. + + + + Add a localized text string. + + locale + Name identifying the string. Used to fetch the string later on. + Localized string + + + + Sets a localized text string. If the a string with the specified name exists it will be overwritten. + + locale + Name identifying the string. Used to fetch the string later on. + Localized string + + + + Adds a sub category + + Name of the sub category + If a category with the specified name already exists + If name is null + + + + Value that should be returned if the text is not found. + + + + + + + Set default locale + + Locale to set. + + + + All child nodes. + + + + + Parent language category + + + + + Mother of all nodes. + + + + + Get a localized text string in the current language. + + Phrase to find. + text if found; [textName] if not. + + + lang["Name"] // => "Name" + lang["Naem"] // => "[Naem]" since it's missing + + + + + + Get a localized text string + + + Phrase to find. + text if found; [textName] if not. + + + lang["Name"] // => "Name" + lang["Naem"] // => "[Naem]" since it's missing + + + + + + Number languages + + + + + Returns the name of the node + + + + + LCID to use if the specified or current LCID is not found. + + + + + Initializes a new instance of the class. + + The default LCID. + + + + Add a localized text string. + + locale + Name identifying the string. Used to fetch the string later on. + Localized string + + + + Sets a localized text string. If the a string with the specified name exists it will be overwritten. + + Name identifying the string. Used to fetch the string later on. + locale + Localized string + + + + Adds a sub category + + Name of the sub category + If a category with the specified name already exists + If name is null + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + string if found; otherwise null. + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + check for paths in . + string if found; otherwise null. + + + + Number of translated texts in the specified language + + + + + + + Determine if the node contains a text item with the specified name for the specified language + + + + + True if the node contains a language element with the specified name for the specified language + + + + + Determine if a category contains a specific language. + + + + + + Empties all saved values in the node and its sub nodes + + + + Get a localized text string in the current language. + + Phrase to find. + text if found; [textName] if not. + + + lang["Name"] // => "Name" + lang["Naem"] // => "[Naem]" since it's missing + + + + + + Get a localized text string + + + Phrase to find. + text if found; [textName] if not. + + + lang["Name"] // => "Name" + lang["Naem"] // => "[Naem]" since it's missing + + + + + + Number languages + + + + + This is a bit more advanced command pattern. The regular command pattern + ties the command to the the class that handles the command. This + pattern removes that binding and makes the commands independent of + the logic that executes it. + + The pattern also allows multiple handlers for each command, and you + can also add handlers for unhandled commands. + + + + // Map a handler to a command: + distlight.Add(typeof(MyCommand), OnMyCommand); + + // invoke my command: + if (!distlight.Invoke(new MyCommand(myUserId))) + Console.WriteLine("No one handled the command!"); + + + + + + Add a command handler. + + Must be a class, an attribute. + handler handling the command + If handler have been added to that type already. + + Program.Commands.Add(typeof(MyCommand), OnMyCommand); + + + + + Remove a command handler. + + type to remove + delegated that was mapped to the type. + + + + Invoke a command. + + command to invoke. + Handled that should not be invoked. + true if command was handled. + + + + Invoke a command. + + command to invoke. + true if command was handled. + + + + Invoke a command. + + object that is invoking the command. + command to invoke. + Handled that should not be invoked. + true if command was handled. + + + + Invoke a command. + + object that is invoking the command. + command to invoke. + true if command was handled. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + Handler that should not receive the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + object that is invoking the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + object that is invoking the command. + Handler that should not receive the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke this method when the command is complete, or if you want to wait + on the command. + + + + + + + Tells us if we have a handler for the specified type. + + Type to check + True if a handler have been registered otherwise false. + + + + Handler for unhandled commands. + + returning true will make the command look like it was handled + + + + Design by contract validator + + + + + "{0} must be specified." + + + + + "'{0}' do not equal '{1}'." + + + + + "'{0}' must be between {1} and {2}." + + + + + "'{0}' must be between {1} and {2} characters." + + + + + "'{0}' must be larger or equal to {1}." + + + + + "'{0}' must be larger or equal to {1}." + + + + + "'{0}' must evaluate as true. + + + + + "'{0}' must evaluate as false. + + + + + "'{0}' must be less or equal to {1}." + + + + + "'{0}' must be less or equal to {1}." + + + + + "'{0}' must be specified and not empty." + + + + + "'{1}' must be assignable from {0}." + + + + + Contains language information + + + + + The specified statement/parameter must be true. + + statement/parameter to evaluate. + Name of the message or param. + If statement is not true. + + + + The specified statement/parameter must be false. + + statement/parameter to evaluate. + Name of the message or param. + If statement is true. + + + + Two values can't be equal. + + value/constant to compare to. + parameter value. + parameter name, or a error message. + If contract fails. + and are both required. + + + + Value must be between (or equal) min and max + + minimum value. + maximum value. + parameter value. + parameter name, or a error message. + If contract fails. + + + + Betweens the specified min. + + minimum value. + maximum value. + parameter value to check. May not be null. + parameter name, or a error message. + If contract fails. + + + + Betweens the specified min. + + minimum value. + maximum value. + parameter value. + parameter name, or a error message. + may be null if this parameter is false. + If contract fails. + + + + Checks if the value is equal or larger. + + minimum value. + parameter value. + parameter name, or a error message. + If contract fails. + + + + Checks if the value is equal or larger. + + minimum value. + parameter value. + parameter name, or a error message. + If contract fails. + + + + Checks if the value is equal or larger. + + minimum value. + parameter value. + parameter name, or a error message. + If contract fails. + + + + Checks if the value is equal or larger. + + minimum value. + parameter value (may not be null). + parameter name, or a error message. + If contract fails. + + + + Checks if the value is equal or larger. + + minimum value. + parameter value. + parameter name, or a error message. + may be null if this parameter is false. + If contract fails. + + + + Checks if the value is less or equal. + + maximum value. + parameter value. + parameter name, or a error message. + If contract fails. + + + + Checks if the value is less or equal. + + maximum value. + parameter value. + parameter name, or a error message. + If contract fails. + + + + Checks if the value is less or equal. + + maximum value. + parameter value. + parameter name, or a error message. + may be null if this parameter is false. + If contract fails. + + + + Checks if the value is less or equal. + + max value. + parameter value. + parameter name, or a error message. + If contract fails. + + + + Parameter is required (may not be null). + + parameter value. + parameter name, or a error message. + If contract fails. + + + + The specified string may not be null or empty. + + parameter value. + parameter name, or a error message. + If contract fails. + + + + Check if the specified type can be assigned from the parameter type. + + Type that the parameter must be (or derive/implement). + instance + error message or parameter name + + + + Contains language information + + + Language may only be specified once. + + If language have been previously specified. + + + + Exception thrown when a validation fails. + + + + + Initializes a new instance of the class. + + The original error message (have not been formatted). + Formatted message. + Message arguments. + + + + Initializes a new instance of the class. + + The original error message (have not been formatted). + Formatted message. + + + + Unformatted error message, {0} have not been replaced with parameter name. + + + Can be used if you want to translate messages. + + + + + Arguments to string to format. First argument is parameter name. + + + + + Contains a value in a condition. + + + + + Used to identify conditions (used by Property to see it the text is a property or something else) + + + + + Initializes a new instance of the class. + + Property that this value belongs to. + + + + Returns SQL + + @[propertyName] + + + + Identifier for this token. + + + + + Property that this token belongs to. + + + + + Name of the parameter. + + + + + > + + + + + Returns SQL + + " > " + + + + Used to determine the kind of this token + + + + + + 'AND' SQL token + + + + + SQL 'AND' text + + " AND " + + + + Used to determine the kind of this token + + + + + + Parse >= + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + An IN token. + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parses a condition string and compares it to an item + + + This class is NOT threadsafe. + + + + + Initializes a new instance of the class. + + Conditions, should look like: "Age >= ? AND FirstName == ?". + Parameters used in the condition, for instance 17 and Jonas in the example above. + + Evaluator = new Evaluator("FirstName = ? AND Age = ?", "Adam", 10}); + + + + + Initializes a new instance of the class. + + First index is conditions, the rest is parameters. + + Evaluator = new Evaluator(new object[]{"FirstName = ?", "Adam"}); + + + + + Evaluates an instance. + + The instance. + + + + + Go through a list and find all items. + + + + + + + + Evaluate all tokens in the same level. + + + + + + + Token should be a property name. + + + + + + Will take three of the tokens (property CONDITION target) and evaluate them. + + If values can't be casted to property type + + + + + + + + + + + + + + + + + + + User used during testing. + + + + + Gets or sets the first name. + + The first name. + + + + Gets or sets the last name. + + The last name. + + + + Gets or sets the age. + + The age. + + + + Gets or sets the status. + + The status. + + + + + + + + + Class to subscribe to change events on a file and update a language hierarchy every time the file changes. + + + If the file being watched is deleted or renamed no more changes will be made to the language node. + Also be observant on the fact that the class cannot Remove entries from a , only add or modify entries. + This restriction is needed because a single YamlWatcher only watches One file and a can be connected to several + watchers and files, deleting anything could clear things for another file. + + + + + Loads and watches language files on disk. + + + Future version can watch different file types, and load them using different loaders. + + + + + Load and watch another file on disk. + + Relative or absolute path to language file. + Node that have been loaded. + + + + Parse YAML contents and add any language nodes to the watchers language + + YAML contents + The name of the node to add the contents into + Node that have been loaded. + + + + Root language node. + + + + + files that need to be reloaded + + + + A timer to use as delay if the file is currently in use + + + + Instantiates the class to listen to changes in a file, also reads the file and fills the language node with language entries + + Language node to fill + The filename to watch + Thrown if the specified file does not exist + + + + Load and watch another file on disk. + + Relative or absolute path to language file. + Node that have been loaded. + + + + Parse YAML contents and add any language nodes to the watchers language + + YAML contents + The name of the node to add the contents into + Node that have been loaded. + + + + Callback for when the file should be read again + + + + + Sets the class to watch the specified file + + + + + Callback for when the file changes + + + + + Private loading of file to wrap read failure control + + + + + Fill the root node with languages and categories from the specified file + + Full file path + The root node to fill + + + + Function to stop the watcher + + + + + Root language node. + + + + + + Provides a general view of the model needed for saving migration data in the database + + + The model and mapping must be specified explicitly by the migration user since tables most oftenly + should match a certain coding convention. Explicitly declaring the model also allows for saving + extra version data. + + + + Gets or sets the version number of the migration + + + Gets or sets the date and time for when the database was updated to the migration version + + + + Main exception in the data layer. + + + + + Initializes a new instance of the class. + + Error message. + Inner exception. + + + + Initializes a new instance of the class. + + Error message. + + + + Initializes a new instance of the class. + + SQL query that failed + Error message. + + + + Initializes a new instance of the class. + + SQL query that failed + Error message. + Inner exception. + + + + SQL query that failed. + + + + + Checks whether a field have been specified or not. + + + Language file items: + + + ItemName + Language text + + + AlphaNumeric + '{0}' may only contain alpha numeric letters. + + + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + value is considered to be not specified if the value matches this parameter. + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + + + + Determines if the validation support the specified type. + + Property/Value type. + true if type is supported. + + Used when validation objects are generated. + + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Validates that a string property represents valid Hex value (Value should not either too large or too small for an Int64). + + + + + Name of the language item for this validation. + + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + Thrown if the value supplied is not a + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + + A localized error message if the validation failed; otherwise null. + + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is supported. + + Used when validation objects are generated. + + + + + Contains all validations for a certain type of object. + + + + + true if we should save a list with all generated validators, or generate new ones each time. + + + + + Create a new validation object. + + Type of object to validate + + + + + Validate a specific property. + + Instance to validate + Name of property + A list with all validations that failed. Or an empty list of no validations failed. + + + + Validate a specific property. + + An application specific context that's passed to all validation attributes. Useful if you've implemented your own validations. + Instance to validate + Name of property + + A list with all validations that failed. Or an empty list of no validations failed. + + + + + Validate a specific property. + + Instance to validate + Name of property + List to fill with validation errors, must not be null. + + + + Validate a specific property. + + An application specific context that's passed to all validation attributes. Useful if you've implemented your own validations. + Instance to validate + Name of property + List to fill with validation errors, must not be null. + + + + Validate all properties in the object. + + Instance to validate + A list with validation errors, or an empty list of all validations succeeded. + + + + Validate all properties in the object. + + An application specific context that's passed to all validation attributes. Useful if you've implemented your own validations. + Instance to validate + A list with validation errors, or an empty list of all validations succeeded. + + + + Type that this validator is for. + + + + + Used to be able to provide context to validation classes during validation. + + + + + Initializes a new instance of the class. + + Attribute that is going to be validated. + + + + Attribute about to be used for validation. + + + + + Context that should be passed to the validation class. + + + + + Contains user information about a plugin. + + + Should be returned in the current language. + + + + + + Name of the plugin, it should be in the local language if possible. + + + + + Description of what the plugin does. Shown to the end user. + + + The description may contain links to other pages and images. + Just make sure that your controller can handle them. + Links should be opened in new windows and not leave the market place. + + + + + Author homepage + + + + + Copyright owner of this plugin. + + + + + Contains translation texts that have been loaded into memory + + + + + int is LCID, NameValueCollection contains all phrases. + + + + Instantiates a LanguageNode that holds the language data in memory + The defualt language code + The name of the node + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + string if found; otherwise null. + + + + Get a text string in the specified language. + + Language to fetch from. + name of text to find. + check for paths in . + string if found; otherwise null. + + + + Adds a text entry to the language node + + Name of the entry + Language of the entry + The text of the entry + + + + Sets a localized text string. If the a string with the specified name exists it will be overwritten. + + Name identifying the string. Used to fetch the string later on. + locale + Localized string + + + + Adds a sub category + + Name of the sub category + If a category with the specified name already exists + If name is null + + + + Returns number of text entries in the requested language + + The language to examine + + + + Determine if the node contains a text item with the specified name for the specified language + + + + + True if the node contains a language element with the specified name for the specified language + + + + + Determine if a category contains a specific language. + + + + + + Empties all saved values in the node and its subnodes + + + Returns the requested entry using the systems current language + Name of the entry to retrieve + The entry or if not found in the current language, default language or in parent nodes returns [textName] + + + + A requested text entry in the requested language + + Name of the entry to retrieve + Language code for the language to retrieve the text in + The entry or if not found in the current language, default language or in parent nodes returns [textName] + + + + Returns the number of languages in the node + + Returns the number of languages and Not text entries + + + + + + + + + A command that will be invoked + + + + + Set handled state. + + + + + + true if the command have been handled. + + Can be used to determine if another + handler already have processed the command. + + + + Initializes a new instance of the class. + + The name. + + + + Gets or sets the name. + + The name. + + + + + + + + + + + + + + + + + + + Initializes a new instance of the class. + + The name. + + + + + + + + + Initializes a new instance of the class. + + The name. + + + + + + + + + + + + + + Initializes a new instance of the class. + + The name. + + + + Gets or sets the name. + + The name. + + + + + + + + + Initializes a new instance of the class. + + The name. + + + + Gets or sets the name. + + The name. + + + + ORDER BY SQL Clause. + + + + + Returns SQL + + " ORDER BY " + + + + Used to determine the kind of this token + + + + + Class/Table name + + + + + Initializes a new instance of the class. + + Name of class. + + + + Returns SQL name + + Table name + + + + Used to determine the kind of this token + + + + + Name of class + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parse >= + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Contains a mapping between a database table and a .Net class. + + + + + Gets column name from a property name. + + + + + + + Gets current primary key. + + The primary key if exactly ONE is defined; otherwise null. + + + + Gets table name. + + + + + Gets class type + + + + + Gets all mapped properties + + + + + Gets all primary keys + + + + + SQL92 column types. + + + + + One bit + + + + + Short string + + + + + floating point + + + + + Int column + + + + + DateTime / Timestamp + + + + + Date only + + + + + Time only + + + + + Bool, int(1) + + + + + Long string + + + + + Common operations for columns + + + + + Convert a column type to a .Net type + + column type to convert + + + + + Class for building information strings about a proxy method + + + + + Instantiates a new object to parse and create readable data for a method + + + + + + + ]]> + + The method to generate the name for + The methods name + + + + Joins method name together with all parameter types creating an identifying string for the method + + The method to generate the name for + The method name + + + + Retrieves the call to Type.GetMethod needed to retrieve the method + + The method to retrieve + The correct name of the method to retrieve + + ie. GetMethod("GetUser", new Type[]{typeof(Int32)}) + + + + + Retrieves a string representation of a list putting together all the parameters passed to the method in an object array + + The method for which to generate the argument array string + ie new object[]{value, argument} + + + + Retrieves the argument list + + The method to generate the argument from + A list to which the methods needed types can be added + Ie GetData(int arg1, string arg4) => Int32 arg1, String arg4 + + + + Retrieves a string representing the call to Type.GetMethods needed to retrieve the method + + + ie. GetMethod("GetUserName", new Type[]{typeof(Int32), typeof(String)}); + + + + + Retrieves a string representation of the method return type + + + + + Retrieves the name of a method + + + + + Retrieves a signature for the method, ie _getValuesInt32String + + + + + Retrieves a string for declaring the ObjectProxy method in the form + + + + + Retrieves a list of types the method depends on + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Generic logger interface. + + + Used since we do not want to force everyone to use the Fadd.Logging framework. + Implement your own proxy to use your favorite logging mechanism + + + + + + A dictionary mapping not only values but also sub nodes of the same + type + + + + + Instances the + + + + + Instances the with a given name that can be used to identify the map later + + A unique name in a hierarchy to set for the map + + + + Adds a value + + The key to map the value to + The value to add + Thrown if a value has already been added with the given key + + + + Updates or adds a value defined by the specified key + + The key of the value to update or add + The value to set for the specified key + + + + Removes a value specified by the given key from the + + The key to remove the value for + True if a value was removed + + + + Retrieves a child using a key + + The key the child is mapped to + Null if not found + + + + Returns true if a value mapped to the given key is contained by the map + + Key the value is supposed to be mapped to + True if a key is found + + + + Returns true if a value is mapped + + The value to examine whether or not it is contained by the map + True if the value is found + + + + Returns true if a child exists that is mapped with the given key + + The key to examine child mappings for + True if a child is found + + + + Returns true if the map contains the specified child + + The map to examine whether or not it is contained + True if the map is a child of the instance + + + + Removes a child if contained. Since the name set for the map will be used to remove the map a name must have been specified. + + The map to remove + True if the child was removed + If removed the will be set to null for the map + + + + Removes a child if contained + + The key or name of the child to remove + True if the child was removed + If removed the will be set to null for the map removed + + + + Adds a child to the using the name specified in + + The map to add as a child, must have a defined se + + Thrown if the map is already a child of another instance, + it must be removed from there manually before being added to avoid hiding logical errors in code + + + + + Adds a child to the using the name supplied + + The map to add as a child + The name to set for the map, will override any previous name + + Thrown if the map is already a child of another instance, + it must be removed from there manually before being added to avoid hiding logical errors in code + + + + + Returns an enumerator that can iterate through all the values contained by the map + + + + + Returns an enumerator that can iterate through all the values contained by the map + + + + + Sets or gets a value held by the map + + Key mapping the value + Null if the value wasn't found + + + + Retrieves all values held by the map + + + + + Retrieves all child held by the map + + + + + Retrieves the name identifying the map, is null if no name is set + + + + + Retrieves any parent to the map, is null if no parent is set + + + + + Validates that a string property is an correct email. + + + Language file items: + + + ItemName + Language text + + + Email + '{0}' must be a valid email address. + + + + + + + Localize the error. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation support the specified type. + + Property/Value type. + true if type is supported. + + Used when validation objects are generated. + + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + Thrown if the object isn't a string + + + + Tag commands with this interface to be able to transport them through the + CommandChannel. + + + + + Copy all stuff that have been modified by the command handler. + + Command to copy reply from. + + + + This is a bit more advanced command pattern. The regular command pattern + ties the command to the the class that handles the command. This + pattern removes that binding and makes the commands independent of + the logic that executes it. + + The pattern also allows multiple handlers for each command, and you + can also add handlers for unhandled commands. + + + + + // Map a handler to a command: + dispatcher.Add(typeof(MyCommand), OnMyCommand); + + // invoke my command: + if (!dispatcher.Invoke(new MyCommand(myUserId))) + Console.WriteLine("No one handled the command!"); + + + + + + When asynchronous invokes should be removed (if have not been called.) + + + + + Attributes list used for commands that have not been mapped. + + + + + Classes/interfaces list used for command that have not been mapped. + + + + + Each command is mapped to different handlers + when the command is invoked. This is done once, + then this list is used to invoke the commands (= speed increase) + + + + + Classes/interfaces list used for command that have not been mapped. + + + + + Initializes a new instance of the class. + + + + + Create a new command manager + + Parent manager, it will receive all commands that are + invoked in this instance, or just all unhandled ones. + true if all commands should be sent to the parent; otherwise just all unhandled will be sent. + + + + Add a command handler. + + Must be a class, an attribute. + handler handling the command + If handler have been added to that type already. + + Program.Commands.Add(typeof(MyCommand), OnMyCommand); + + + + + Remove a command handler. + + type to remove + delegated that was mapped to the type. + + + + Invoke a command. + + object that is invoking the command. + command to invoke. + Handled that should not be invoked. + true if command was handled. + + + + Invoke a command. + + command to invoke. + true if command was handled. + + + + Invoke a command. + + command to invoke. + Handled that should not be invoked. + true if command was handled. + + + + Invoke a command. + + object that is invoking the command. + command to invoke. + true if command was handled. + + + + Invoke a command asynchronously + + object that is invoking the command. + Command to invoke + Handler that should not receive the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + IAsyncResult if command was invoked successfully; otherwise null. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + object that is invoking the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + Handler that should not receive the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke this method when the command is complete, or if you want to wait + on the command. + + + + + + + Tells us if we have a handler for the specified type. + + Type to check + True if a handler have been registered otherwise false. + + + + + + + + + + A command handler have canceled a command, this event gives you a chance to + ignore that cancellation. + + command that was canceled. + handler that canceled the command. + true means that we can cancel; false that we should continue + + + + Map a command that have never been mapped. + + + + + + + Map a command to all handlers. + this is done to speed up the invoke process. + + + + + + + Event that can override the property. + + + + + + Handler for unhandled commands. + + returning true will make the command look like it was handled + + + + Used to keep track of all asynchronous commands. + + + + + Gets an indication whether the asynchronous operation has completed. + + + + true if the operation is complete; otherwise, false. + + 2 + + + + Gets a that is used to wait for an asynchronous operation to complete. + + + + A that is used to wait for an asynchronous operation to complete. + + 2 + + + + Gets a user-defined object that qualifies or contains information about an asynchronous operation. + + + + A user-defined object that qualifies or contains information about an asynchronous operation. + + 2 + + + + Gets an indication of whether the asynchronous operation completed synchronously. + + + + true if the asynchronous operation completed synchronously; otherwise, false. + + 2 + + + + Corresponds to "IS NOT NULL". + + + + + " IS NOT NULL" + + + + + + Used to determine the kind of this token + + + + + = + + + + + Returns SQL + + " = " + + + + Used to determine the kind of this token + + + + + + Represents a comma + + + + + Conditional string + + ", " + + + + Used to determine the kind of this token + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + A property name + + + + + Initializes a new instance of the class. + + Name of property. + + + + Returns name of property + + name of property + + + + Used to determine the kind of this token + + + + + + Name of property + + + + Specific exception for errors occured during xml handling + + + Describes an exception occured during migration of database + + + Initializes the exception with a message + The exception message describing the error occured + + + Initializes the exception with a message + The exception message describing the error occured + The exception triggering the throwing of this exception + + + Initializes the + Error message to display + + + Initializes the + Error message to display + Exception that brought the throwing of the xml exception + + + Initializes the + Error messages to display + + + Retrieves the error messages not prepended with readable error string + + + + Connection helper for SQL Server. + + + + + Used + + + + + Create a new connection to the database. + + An open database connection. + If connection fails. + + + + Try to get next sequence value. + + A command to perform actions with, we pass commands since they might be in a transaction. + Name of the sequence/generator. + A generated value. + If something failed + + + + Gets the latest auto incremented value from the database. + + A command to perform actions with, we pass commands since they might be in a transaction.. + Name of the column that the auto incremented value is for. + auto incremented value + If something failed + + + + Modifies the SQL statement to include paging. + + Database mapping + SQL statement generated by the DAL. + 0 based index + number of entries per page + SQL statement with paging + + + helper.Paging("SELECT * FROM users", 5, 10); // --> "SELECT * FROM users LIMIT 10 OFFSET 50" + + + + + + Connection string + + + + + Gets the paramter prefix + + + For SQL @ + For MySQL ? + For Oracle : + + + + + Initializes a new instance of the class. + + The connection string. + + + + Create a new connection to the database. + + An open database connection. + If connection fails. + + + + Try to get + + A command to perform actions with, we pass commands since they might be in a transaction. + Name of the sequence/generator. + A generated value. + If something failed + SQL Server do not support sequences. + + + + Gets the latest auto incremented value from the database. + + A command to perform actions with, we pass commands since they might be in a transaction.. + Name of the column that the auto incremented value is for. + auto incremented value + If something failed + + + + Modifies the SQL statement to include paging. + + Used to generate SQL Servers wierd paging method. + SQL statement generated by the DAL. + 0 based index + number of entries per page + SQL statement with paging + + + helper.Paging("SELECT * FROM users", 5, 10); // --> "SELECT * FROM users LIMIT 10 OFFSET 50" + + + + Only SQL Server 2005 and above is supported. + + + + + Connection string + + + + + + Gets the paramter prefix + + Will return a @ + + + + Validates that a string only contains letter, digits and any of: |-_.:,;'^~¨'*!#¤%&/()=?`´+}][{€$££@§½ ]]> + + + + Language file items: + + + ItemName + Language text + + + AlphaNumeric + '{0}' may only contain alpha numeric letters. + + + + + + + + Input may only be letters and digits, foreign chars (for instance åäö) etc are included. + + + Language file items: + + + ItemName + Language text + + + LettersAndDigits + '{0}' may only contain letters and digits. + + + LettersAndDigitsExtra + '{0}' may only contain letters. digits and '{1}'. + + + + + + + Foreign characters (letters used for instance in the Swedish language) + + + + + Foreign characters (letters used for instance in the Swedish language) and space, dot and comma. + + + + + Space, dot and comma. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The extra characters. + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + Only strings are valid for this type. + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation support the specified type. + + Property/Value type. + true if type is supported. + + Used when validation objects are generated. + + + + + Gets the extra characters. + + The extra characters. + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The extra characters. + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Does validation using the current language. + + + This class is thread safe, meaning that you can have multiple threads using it at the same time. + + + + + Initializes a new instance of the class. + + Node with the validation language. + + + + Localize all error messages. + + A list with validation errors. + containing language strings for the validated model. + A list with localized errors; or an empty list if no validations failed. + + + + Validates a model and returns errors in the current language. + + + Current language are decided by . + + An application specific context that's passed to all validation attributes. Useful if you've implemented your own validations. + Model being validated. + Language node for the model. + A collection with all validations that failed; an empty collection if not validations failed. + + + + + This dispatcher is used to be able to specify which commands that can be invoked. + + + + + A typical usage would be if you have a plugin system and you do not want to allow + all plugins to be able to execute all commands. Then you create a proxy dispatcher + and expose it to the plugins, instead of the core dispatcher which contains all command + mappings. In this way, your core system it still protected while plugins can access + a subset of it. + + + + + + Initializes a new instance of the class. + + Parent dispatcher (that is used by the rest of the system). + Commands that may be invoked. + Commands that may be handled. + + + + Initializes a new instance of the class. + + Parent dispatcher (that is used by the rest of the system). + No commands are allowed unless you use the event. + + + + Add a command handler. + + Must be a class, an attribute. + handler handling the command + If handler have been added to that type already. + The specified command may not be handled. + + Program.Commands.Add(typeof(MyCommand), OnMyCommand); + + + + + Remove a command handler. + + type to remove + delegated that was mapped to the type. + + + + Invoke a command. + + object that is invoking the command. + command to invoke. + Handled that should not be invoked. + true if command was handled. + + + + Invoke a command. + + command to invoke. + true if command was handled. + If you may not invoke the specified command. + + + + Invoke a command. + + command to invoke. + Handled that should not be invoked. + true if command was handled. + + + + Invoke a command. + + object that is invoking the command. + command to invoke. + true if command was handled. + + + + Invoke a command asynchronously + + object that is invoking the command. + Command to invoke + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + IAsyncResult if command was invoked successfully; otherwise null. + If you may not invoke the specified command. + + + + Invoke a command asynchronously + + Command to invoke + object that is invoking the command. + Handler that should not receive the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + IAsyncResult if command was invoked successfully; otherwise null. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke a command asynchronously + + Command to invoke + IAsyncResult if command was invoked successfully; otherwise null. + Handler that should not receive the command. + Callback that is invoked then the command completes. + object that you can use to identify the command in the -method. + + + + Invoke this method when the command is complete, or if you want to wait + on the command. + + + + + + + Tells us if we have a handler for the specified type. + + Type to check + True if a handler have been registered otherwise false. + + + + Occurs when an unhandled exception have been caught. + + + + + This event is invoked when someone tries to add a handler for a command. + + + + + This event is invoked when someone tries to invoke a command. + + + + + Handler for unhandled commands. + + returning true will make the command look like it was handled + + + + A mapped command have been assigned all subscribers that + have been mapped to an interface, subclass, or attribute + that the command contains. + + + + + All delegates that will be invoked for this command. + + + + + Dirty means that a new handler have been added since + the command was last invoked. + This means that we need to recheck whether we got all + handlers. + + + + + Generates Object proxies. + + + Name the proxies with generic types to allow multiple generic types ie ListInt32Proxy and ListStringProxy. + Pretty up the use of properties a bit. + Add tests for interface hierarchies and properties. + Add support for events in interfaces. + + + + + Initializes a new instance of the class. + + Dispatcher used to send events. + + + + Generate an object proxy + + Type to generate a proxy for + + + + + Compiles the proxy type declaration string that has been build + + The type from which to create a proxy + The code to compile + The compiled object or null if it couldn't be created + + + + Add all properties + + + + + + Build code for a proxy class. + + Type to build code for. + a complete class (in text). + + + + + + + + + Returns SQL + + " < " + + + + Used to determine the kind of this token + + + + + + Contains a property value + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parse a OR token + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Contains a property value + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Database transaction. + + + Makes it possible to save a lot of changes only + if all changes can succeed. + + + + + Base interface. + + + + + Creates a new transaction. + + On of the s. + An object representing the new transaction. + + Once the transaction has completed, you must explicitly commit or roll back the transaction by using the Commit or Rollback methods. + + + + + Creates a new transaction. + + An object representing the new transaction. + + Once the transaction has completed, you must explicitly commit or roll back the transaction by using the Commit or Rollback methods. + + + + + Get a single object. + + Type of object to fetch + complete SQL statement with class/properties instead of table/columns. + parameters used in the statement. + object if found; otherwise null + If the class/table mapping is incorrect. + If data layer fails. + + + + Executes an statement in the database. + + Type of object to fetch + complete SQL statement with class/properties instead of table/columns. + parameters used in the statement. + object if found; otherwise null + If the class/table mapping is incorrect. + If data layer fails. + + + + Get a single object. + + Type of object to fetch. + Conditions (corresponds to statements in the WHERE clause). + Parameters used in the where clause. + object if found; otherwise null. + If the class/table mapping is incorrect. + If data layer fails. + + + + Get a single object using its primary key + + Type of object to fetch, must have a defined mapping. + Primary key value + object if found; otherwise null. + If the class/table mapping is incorrect. + If data layer fails. + + + + Retrieves a collection of items. + + Type of item to get. + Conditions to limit. + Parameters used in the condition. + A list of objects; or an empty list + + + + Retrieves all items of a certain type. + + Type of item to get. + A list of objects; or an empty list + + + + Gets all items defined by the . + + type of items to get. + Statement specifying which elements to get. + A list of elements. + + + + Execute a custom SQL query (Object SQL can not be used yet). + + type of items to get. + SQL query. + Parameters used in the query. + A list of elements. + + + + Save or update an object in the database (1. Checks if the PK is empty. 2. Checks if the object exists in the db). + + Value to create/update. + If the class/table mapping is incorrect. + If data layer fails. + + + + Create a new object in the database. + + Object to create. + If the class/table mapping is incorrect. + If data layer fails. + + + + Update an existing object. + + Object to update + If the class/table mapping is incorrect. + If data layer fails. + + + + Checks if an object exists by using it's primary key. + + Type of object to check + Primary key + true if object was found; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Checks if an object exists by providing it. + + object to check + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Checks if an object exists in the database + + Type of object to check. + Conditions. + Arguments used in the conditions. + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Count number of items. + + Type of object to check. + Conditions. + Arguments used in the conditions. + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Count number of items. + + Type of object to check. + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Counts by SQL. Write the whole statement yourself. + + The statement. + Number of returned rows + If data layer fails. + + + + Removes an object by using it's id property. + + Type of object to remove. + Primary key value + RemoveById requires exactly one primary key. + + + + Removes an object by using it's id property. + + Type of object to remove. + + + + Gets class that takes care of all providers. + + + + + Gets logger instance. + + + + + Cancel all changes made with the transaction. + + + Cancel will be called by Dispose if commit have + not been called before the transaction is disposed. + + + + + Write all changes to the database. + + + + + Contains a compiled SQL statements. + + + "Compiled" means that we've converted the statement from ObjectSQL + to real SQL with table and column names. + + + + + Initializes a new instance of the class. + + Mapping between columns and properties + SQL statement. + Properties that have been selected. null if no properties have been specified. + Arguments used in the SQL statement.. + + + + Create a new statement with specialized SQL. + + SQL string + New statement. + + + + Gets properties that are used as arguments to the statement. + + + + + Gets SQL statement. + + + + + Gets mappings between columns and properties. + + + + + Gets properties that have been selected. + + + null if no properties have been specified. + + + + + A found plugin and which of the requested types that it implements. + + + + + Initializes a new instance of the class. + + assembly that the plugin resides in. + plugin type. + assemblies public key. should be used to decide the amount of access for the module. + + + + Add another type + + + + + + Assemblies public key if signed. + + + + + Assembly full path + + + + + Location of DLL. + + + + + Requested types that exists in the assembly + + + + + Assembly public key in byte format. + + + + + Arguments for + + + + + Initializes a new instance of the class. + + Why we were disconnected. + SocketError.Success means that we disconnected due to invalid data/packet from the remote end. + + + + Why we were disconnected. + + + + + Called when a connection have been closed. + + Socket/Tunnel/Channel + Why it was disconnected. + + + + DELETE FROM clause + + + + + FROM SQL clause + + + + + Returns SQL + + " FROM " + + + + Used to determine the kind of this token + + + + + Returns SQL + + "DELETE FROM " + + + + Used to determine the kind of this token + + + + + + Parse >= + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + An IN token. + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Enumeration specifying a detail level in which to display a duration + + + + + Display duration in months and years + + + + + Display duration in days, months and years + + + + + Display duration in hours, days, months and years + + + + + Display duration in hours, days, months and years + + + + + Display duration down to the second + + + + + Interface for all localized date/time helpers. + + + + + Will try to parse the date/time using the local parser. + Will also try the default DateTime.Parse method if date is in an unknown format. + + date/time string + A + If the date/time format is invalid. + If month/day/hour/minute/second are not within their ranges. + + + + Will try to parse the date/time using the local parser. + Will also try the default DateTime.Parse method if date is in an unknown format. + + date string (may be null/empty). + time string (may be null/empty). + A + If the date/time format is invalid. + If month/day/hour/minute/second are not within their ranges. + + + + Tries to parse a date string. + + Can contain a complete date or parts of it (which parts depends on the country). + A + If the date format is invalid. + If month/day are not within their ranges. + + + + Tries to parse a date string. + + Can contain a complete date or parts of it (which parts depends on the country). + array that parsed values are written to. + where in array to start write values + If the date format is invalid. + If month/day are not within their ranges. + + + + Tries to parse a time string. + + Can contain a complete time or parts of it (which parts depends on the country). + A + If the time format is invalid. + If hour/minute/second are not within their ranges. + + + + Tries to parse a time string. + + Can contain a complete time or parts of it (which parts depends on the country). + array that will be filled. Must contain three slots. + Where in the array to start write values + If the time format is invalid. + If hour/minute/second are not within their ranges. + + + + Validate a date. + + year value + month value + day value + true if exceptions should be thrown on incorrect values. + true if specified values are a correct date; otherwise false. + + + + Validate + + hour + minute + second + true if exceptions should be thrown on incorrect values. + true if specified values are a correct date; otherwise false. + + + + Format a date as a string. + + A date/time + Examples: "Yesterday", "On monday" + + + + Format a date/time as a string. + + A date/time + Examples: "Yesterday at 12:20pm", "On monday at 11:38am" + + + + Get duration as a human friendly string. + + Start time of duration + End time of duration + The detail in which to display the duration + Number of time units to display + + A string like: 1 month, 2 weeks, and 3 days. + + + + + Get duration as a human friendly string. Displays all time unit durations. + + Start time of duration + End time of duration + + + + Get duration as a human friendly string. + + The timespan for which to output the duration + The detail in which to display the duration + /// Number of time measures to display + + A string like: 1 month, 2 weeks, and 3 days. + + cannot be used when using this method since counting of months + requires both to and from datetime information, in such a case user + + + + Get duration as a human friendly string. Displays all time unit durations. + + The timespan for which to output the duration + + + + Create a a transaction + + + + + Base class for database handling + + + + + Initializes a new instance of the class. + + The connection helper. + + + + Initializes a new instance of the class. + + Another implementation. + + + + Initializes a new instance of the class. + + The connection helper. + Logger interface. + + + + Get a single object. + + Type of object to fetch + complete SQL statement with class/properties instead of table/columns. + parameters used in the statement. + object if found; otherwise null + If the class/table mapping is incorrect. + If data layer fails. + + + + Gets a list of items. + + Statements to get + parameters used in the statement. + A list of items. + + + + Executes an statement in the database. + + Type of object to fetch + complete SQL statement with class/properties instead of table/columns. + parameters used in the statement. + object if found; otherwise null + If the class/table mapping is incorrect. + If data layer fails. + + + + Get a single object. + + Type of object to fetch. + Conditions (corresponds to statements in the WHERE clause). + Parameters used in the where clause. + object if found; otherwise null. + If the class/table mapping is incorrect. + If data layer fails. + + + + Get a single object using its primary key + + Type of object to fetch, must have a defined mapping. + Primary key value + object if found; otherwise null. + If the class/table mapping is incorrect. + If data layer fails. + + + + Used to assign a property with a value + + Object containing the property. + Name of the property. + Value to set. + + + + Save or update an object in the database (1. Checks if the PK is empty. 2. Checks if the object exists in the db). + + Value to create/update. + If the class/table mapping is incorrect. + If data layer fails. + + + + Create a new object in the database. + + Object to create. + If the class/table mapping is incorrect. + If data layer fails. + + + + Update an existing object. + + Object to update + If the class/table mapping is incorrect. + If data layer fails. + + + + Update an existing object + + + + If SQL query fails. + + + + Checks if an object exists by using it's primary key. + + Type of object to check + Primary key + true if object was found; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Checks if an object exists by providing it. + + object to check + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Checks if an object exists in the database + + Type of object to check. + Conditions. + parameters used in the conditions. + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + DataLayerException. + + + DataLayerException. + + + DataLayerException. + + + + Creates a complete database command with the help of the compiled statement. + + Used to create the command + Statement to execute + parameters used in the statement + A filled command + Parameter count doesn't match argument count in the statement. + + + + Creates a complete database command with the help of the compiled statement. + + Used to create the command + Custom sql to execute + parameters used in the statement + A filled command + Parameter count doesn't match argument count in the statement. + + + + Retrieves a collection of items. + + Type of item to get. + Conditions to limit. + Parameters used in the condition. + A list of objects; or an empty list + + + + Retrieves all items of a certain type. + + Type of item to get. + A list of objects; or an empty list + + + + Execute a custom SQL query (Object SQL can not be used yet). + + type of items to get. + SQL query. + Parameters used in the query. + A list of elements. + + + + Gets all items defined by the . + + type of items to get. + Statement specifying which elements to get. + A list of elements. + + + + Removes an object by using it's id property. + + Type of object to remove. + Primary key value + RemoveById requires exactly one primary key. + + + + Removes an object by using it's id property. + + Type of object to remove. + Data layer failed. + + + + Count number of items. + + Type of object to check. + Conditions. + Arguments used in the conditions. + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Count number of items. + + Type of object to check. + true if object is stored in the database; otherwise false. + If the class/table mapping is incorrect. + If data layer fails. + + + + Counts by SQL. Write the whole statement yourself. + + The statement. + Number of returned rows + If data layer fails. + + + + Creates a connection, we use this method instead of the one in + the connection helper to be able to use transactions (with a single connection). + + A database connection. + + + + Create a command. + + Connection used to create the command + A + + + + Gets or sets logger instance. + + + + + Determines if we are a transaction. + + + + + Gets class that takes care of all providers. + + + + + + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + + + + Cancels all changes. + + + + + Makes all changes permanent in the database. + + + + + We are not creating a connection, but returning the one used + in the transaction. + + A database connection. + + + + Creates the command. + + + + + + Creates a new transaction. + + On of the s. + An object representing the new transaction. + + Once the transaction has completed, you must explicitly commit or roll back the transaction by using the Commit or Rollback methods. + + + + + Creates a new transaction. + + An object representing the new transaction. + + Once the transaction has completed, you must explicitly commit or roll back the transaction by using the Commit or Rollback methods. + + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Determines if we are a transaction. + + + + + Transaction is about to be committed. + + + + + Transaction have been committed. + + + + + Transaction is about to be canceled. + + + + + Transaction have been canceled. + + + + + Don't do anything since someone have already created a transaction. + Let the initial creator commit. + + + + + Don't do anything since someone have already created a transaction. + Let the initial creator commit or rollback. + + To abort the transaction. + + + + Compiles and caches SQL statements to speed up processing. + + + + + Initializes a new instance of the class. + + The providers. + if set to true [cache statements]. + + + + Compiles an object SQL statement + + + + FormatException. + If mapping could not be found. + + + + Recursive scanning after properties. + + + + + + + Compile an Object SQL statement and return the corresponding SQL statement. + + Key used to identify this statement (if caching is turned on) + SQL statement with classes/properties instead of tables/columns. + + + If SQL is malformed. + Failed to find mapping file. + key or objectSql is null. + + + + Goes through a token and all it's children to convert properties/classes to columns/tables. + + Token to process + Mapping file used during conversion. + + + + Get a previously compiled statement. + + Key used when storing the statement. + Compiled statement if found; otherwise null. + If statements are not cached. + + + + Create a new compiled statement. + + Key used to store statement for future use. + ObjectSQL that should be compiled into plain sql. + Compiled statement. + + + + Checks whether a column is empty or not. + + + + + Add a class that determines if a certain type is empty or not. + + Type to check + Object checking values. + Type have already been mapped. + + + + Determines if an object is empty. + + object to check + true if empty; otherwise false. + + + + Implementation checking if a value is empty. + + + + + Determines if an object is empty. + + object to check + true if empty; otherwise false. + + + + Specifies a max length. + + + On a string it specified maximum number of letters, while on int it specifies the max number. + + + Language file items: + + + ItemName + Language text + + + AlphaNumeric + '{0}' may only contain alpha numeric letters. + + + + + + + Initializes a new instance of the class. + + minimum length. should match the type being validated, with the exception of string + where the type should be int. + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is supported. + + + + Minimum length + + + + + thrown when the specified property is not found in the specified class. + + + + + Initializes a new instance of the class. + + Name of the class. + Name of the property. + + + + Specifies a max length. + + + On a string it specified maximum number of letters, while on int it specifies the max number. + + + Language file items: + + + ItemName + Language text + + + Max + '{0}' must be less or equal to {1}. + + + MaxString + '{0}' must be contain {1} or less characters. + + + + + + + Initializes a new instance of the class. + + max length. should match the type being validated, with the exception of string + where the type should be int. + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + If the specified object is not supported. + + Supports basetypes and all types that implements IComparable (passing an int) + + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is supported. + + + + Max length + + + + + This class is used to receive and handle + + + + + Initializes a new instance of the class. + + Dispatcher that the proxy commands will arrive on. + + + + Called when a proxy command arrives. + + + + + + + + Event used to retrieve an instace for a specific type. + + + The instance is used to invoke the requested method. + + + + + Type to instance mappings + + + Maps all types to object instances that are used to invoke the method calls. + + + + + Arguments for + + + + + Initializes a new instance of the class. + + Type of instance wanted. + + + + Type of instance wanted. + + + + + Instance that will be used to invoke method. + + + + + Delegate used by to find instance to invoke on. + + + Arguments + + + + SELECT clause + + + + + Returns SQL + + "SELECT " + + + + Used to determine the kind of this token + + + + + Name of the property to sort by, and if the sort is ascending/descending. + + + + + Initializes a new instance of the class. + + Name of the property. + if set to true sort is ascending. + + + + Returns SQL + + Order by property + + + + Used to determine the kind of this token + + + + + Property that the order by is for + + + + + Ascending or Descending sort + + + + + Name of the property. + + + + + Parse ), which is end of sub context / nesting. + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parse ), which is end of subcontext / nesting. + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parse (, which is start of one level nesting. + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Provides a mapping between properties and columns in a table. + + + + + Get a mapping between a table and a class. + + Name of class, may not be full name + if found; otherwise null. + + + + Arguments for + + Implementation of IPlugin + + + + Called when a plugin have been loaded. + + Plugin being loaded. + Assembly that the plugin exist in. + information about the plugin + Plugin have not been started yet. + + + + Plugin being loaded + + + + + Assembly that the plugin exist in + + + + + information about the plugin + + + + + Invoked when a plugin have been loaded into the system. + + PluginManager that loaded the plugin. + Plugin information. + + + + This delegate is invoked when a command is about to behing invoked or added to the dispatcher. + + Throw if Type may not be handled/invoked. + + + dispatcher that is being used. + arguments with info + + + + Arguments for . + + + + + Initializes a new instance of the class. + + Type of command (if Invoke is called) or Type to handle (if Add is called). + + + + Type of command (if Invoke is called) or Type to handle (if Add is called). + + + + + Receives commands from the client and invoked them in the server dispatcher. + + + + + Initializes a new instance of the class. + + Manager that the incoming commands are invoked in. + + + + Starts the server. + + IP address that we accept incoming connections on. + Port that the server accepts new connections on. + + + + Stops the server. + + + + + Converts a string to a token tree. + + + + + Parses the specified stream. + + Stream with text content. + Tree that will be filled with tokens. + + + + Parses the specified text. + + Text to parse. + Tree that will be filled with tokens. + When we find unsupported tokens. + + + + Prototypes are used to + + The type. + + + + + Get a string for the next chars. + + Number of chars to peek. + A string with characters. + + + + Get a string for the next chars. + + Number of chars to peek + Ignore these characters before starting to count + A string with characters. + + + + Get previous character + + A + Will not change the current position + + + + Scroll back and get that char. + + Number of chars back + A + Will not change the current position + + + + Peek forward on a char + + Which char index (from current position) to get. + A . + + + + Peek forward on a char + + Ignore these characters before string to peek + Which char index (from current position) to get. + A . + + + + Get next position that do not contain the specified chars. + + + + + + + Peek on the next character + + The next character + If trying to peek beyond last character in the string. + + + + Peek forward + + true if extensions should be thrown + if no extensions should be thrown and we are peeking beyond end of text. + + + + Peek at the next character. + + Characters that are ignored (not counted). + the next character, or if no more characters exist. + + + + Read X number of characters + + number of characters to read + A string + Moves current position forward. + + + + Read a character + + A char + Moves current position forward. + + + + Ignore all specified chars + + chars to ignore + true if end of text is not hit. + Moves current position forward. + + + + Returns index of current position as a string. + + + + + All prototype tokens. + + + + + We are at end of text + + + + + Next character is the last one. + + + + + End of context. + + + + + Returns SQL + + ( + + + + Used to determine the kind of this token + + + + + + A IN clause. + + + + + Used to determine the kind of this token + + + + + Provides mappings between tables and classes. + + + + Mappings are loaded using one or more different loaders. In this way + you can provide your own special way of loading mappings, or use one of + our built in loaders such as mirror loader and XmlLoader. + + + You can also add mappings manually by using the method. + + + + + + Add a mapping. + + Mapping file. + + + + Get a mapping file. + + + Will go through all different loaders until of of them return a mapping. + All found mappings are cached. + + class to fetch a mapping for. + if found; otherwise null. + + + + Add a . + + + + + + General usage validator class. + + + Check all FieldXXXXX constants to see what you need to translate. + + + + + '{0}' is not a double. + + + + + '{0}' is not a valid amount. + + Uses Double validation internally + + + + '{0}' is not a number. + + + + + '{0}' must be {1} or {2}. + + + + + + + + '{0}' is not a valid email address. + + + + + + + '{0}' can only contain letters or digits. + + + + + + '{0}' can only contain letters, digits and the following characters: '{1}'. + + + + + + '{0}' can only contain letters, digits and any of the following characters: {1} + + + + + + + '{0}' is required. + + + + + + Used to check if a field is false. + + + + + + Text: True + + + + + + '{0}' may only contain writable characters. + + ascii 32-126, 128-167, 224-238. + + + + Name of the string to display when testing hex fail + + + + + Name of string to display when testing letters fail + + + + + Name of string to display when testing letters fail + + + + + '{0}' may only contain digits + + + + + '{0}' may only contain digits and the following characters: '{1}' + + + + + '{0}' must be between '{1}' and '{2}' + + + + + '{0}' must be '{1}' or more + + + + + '{0}' must be '{1}' or less + + + + + Characters that are valid in alphanumeric fields. + + + + + SQL Safe characters (not including '") + + + + + Space character. + + + + + Regex used to validate emails. + + + + + + Language manager used if no one else have been specified. + + + + + Extra characters that are allowed in passwords. + + + + + + A list with all errors found. + + + + + Language translation for all "name" parameters. + + + + + Language for the validator (i.e. "Field {0} is required.") + + + + + Create a new validator. + + collection to be filled with errors + + + + Create a new validator. + + collection to be filled with errors + language translation for all "name" parameters + + + + Create a new validator. + + language translation for all "name" parameters + + + + Create a new validator + + + + + Check whether the specified field is within the limit. + + field name. + max value. + value to check. + if set to true the field is required. + true if the field is within the limit + + number are check to be less or equal to max. Strings are checked on the number of characters. + + + + + Check whether the specified field is within the limit. + + field name. + min value. + value to check. + if set to true the field is required. + true if the field is within the limit + + number are check to be less or equal to min. Strings are checked on the number of characters. + + + + + Check whether the specified field is within the limit. + + field name. + min value. + max value + value to check. + if set to true the field is required. + true if the field is within the limit + + number are check to be less or equal to min. Strings are checked on the number of characters. + + + + + Validate that a string only contains letters or digits. + + Form parameter name. + value to validate + may not be null or empty if true. + value if valid; otherwise string.Empty + + + + + Validate that a string only contains letters, digits or the specified characters + + Form parameter name. + value to validate + may not be null or empty if true. + any other allowed characters. + value if valid; otherwise string.Empty + + + + + Validate that a string only contains letters or digits or any of the . + + Form parameter name. + value to validate + field may not be empty or null if true + vaue if valid; otherwise string.Empty + + + + + Check's weather a parameter is null or not. + + Parameter in form + true if value is not null/empty; otherwise false. + value that cannot be null or empty. + + + + Validate a string parameter in the form + + Form parameter name. + value to validate as string. + field may not be empty or null if true. + vaue if valid; otherwise string.Empty + + + + + + add default language phrases (only english) + + + + + Checks wether a string contains a specific character. + + source + character to find. + true if found; otherwise false. + + + + format an error message + + string containing the formatting + name of the field that the error ocurred for. + formatted string + + + + format an error message + + string containing the formatting + name of the field that the error ocurred for. + extra value in the formatting + formatted string + + + + format an error message + + string containing the formatting + name of the field that the error ocurred for. + extra value in the formatting + third parameter in the formatting + formatted string + + + + Check whether the specified value is an character. + + Name of the parameter + Parameter value to validate + Paramater is required (adds an error if it's not specified) + value if parameter is an int; char.MinValue if not. + + + + Check whether the specified value is an character. + + Name of the parameter + Parameter value to validate + value if parameter is an int; char.MinValue if not. + + + + Check whether the specified value is an integer. + + Name of the parameter + Parameter value to validate + Paramater is required (adds an error if it's not specified) + value if parameter is an int; 0 if not. + + + + Check whether the specified value is a double. + + Name of the parameter + Parameter value to validate + Paramater is required (adds an error if it's not specified) + value if parameter is a double; 0 if not. + + + + Check whether the specified value is a currency amount. + + Name of the parameter + Parameter value to validate + Paramater is required (adds an error if it's not specified) + value if parameter is a currency amount; 0 if not. + + + + Check whether the specified value is a double. + + Name of the parameter + Parameter value to validate + Paramater is required (adds an error if it's not specified) + value if parameter is a double; 0 if not. + error string + + + + Check whether the specified value is an integer. + + Name of the parameter + Parameter value to validate + Paramater is required (adds an error if it's not specified) + value if parameter contains valid characters; string.Empty if not. + ascii 32-126, 128-167, 224-238. + + + + Check if a value is digits only + + Field name. + value to validate + true if field is required (may not be empty) + string if validated, otherwise string.Empty + + + + Check if a value is digits only + + Field name. + value to validate + extra characters that is allowed. + true if field is required (may not be empty) + string if validated, otherwise string.Empty + + + + Validates a string to consist of letters. + + field name + value to validate + field is required + string if valid, string.Empty if not. + + + + Validates a string to consist of letters plus specified characters. + + The name of the parameter + The value to validate + If the value is required + A string consisting of extra allowed characters + The validated string or string.Empty if validation failed + + + + Validates a string to be in trimmed hex letters + + The name of the parameter + The value to test + If the parameter is required + The value or string.Empty if validation failed + + + + validates email address using a regexp. + + field name + value to validate + field is required (may not be null or empty). + value if validation is ok; otherwise string.Empty. + + + + validates that a certain number is within the specified interval + + field name + value to validate + The maximum value that value is allowed to be + The minimum value that value is allowed to be + field is required (may not be null or empty). + value if validation is ok; otherwise 0. + + + + validates that a certain number is within the specified interval + + field name + value to validate + The maximum value that value is allowed to be + The minimum value that value is allowed to be + field is required (may not be null or empty). + value if validation is ok; otherwise 0. + + + + Checks whether a field contains true (can also be in native language). + + field name + value to validate + field is required (may not be null or empty). + true if value is true; false if value is false or if validation failed. + + Check validation errors to see if error ocurred. + + + + Set default language. + + + + + true of validation generated errors. + + + + + Collection of validation errors. + + + + + General purpose plugin finder class. + + + This class scans a directory after all classes that contains the specified types. + All assembly checking is done in a separate app domain, which means that no dlls are loaded + during the process. + + + + + Initializes a new instance of the class. + + + + + Finds the specified full path. + + Path and wildcards. + Types wanted. + + + List>Type< types = new List>Type<(); + types.Add(typeof(IPlayer)); + types.Add(typeof(IViewer)); + finder.Find("C:\\myapp\\plugins\\plugin*.dll", types); + + + + + + + + Finds the specified full path. + + Path and wildcards. + Types wanted. + + + List>Type< types = new List>Type<(); + types.Add(typeof(IPlayer)); + types.Add(typeof(IViewer)); + finder.Find("C:\\myapp\\plugins\\plugin*.dll", types); + + + + + + + Adds the specified plugin. + + The plugin. + Assembly that the plugin resides in. + Plugin interface type. + Public key, should be used to decide the amount of access for the module. + + + + All found plugins + + + + + Packet sent through the channel. Keeps track of a command and its reply. + + + + + Initializes a new instance of the class. + + The sequence number. + Command . + + + + LIKE keyword + + + + + Conditional string + + " LIKE " + + + + Used to determine the kind of this token + + + + + Operator used for bitwise operations + + + + + Initializes a new instance of the class. + + Bitwise char. + + + + Returns SQL + + The token wrapped with spaces + + + + Used to determine the kind of this token + + + + + + Parse + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + > + + + + + Used to determine the kind of this token + + + + + + Parse == or = + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + An implementation of YAML that only support those things that is needed by the Language loader. + + + + + Parses a line + + row in text file + where to start the parsing (initial white spaces are excluded) + line number in file + used if more lines should be read + + + + + Loads mappings from embedded XML files. + + + + En mapping file can look like this: + + + + + + + + + + + + ]]> + + + + class 'name' is a assembly qualified name. + + + generator can be 'autoincrement' (works with databases such as SQL Server or MySQL), 'sequence' (works with PostgreSQL, looks for a sequence + with the name '[tablename]_id_seq'), 'guid' (Fadd.Data generates the guid), any other values are interpreted as + a sequence name (and will be used as such depending on the database type). + + + Property/Id 'type' attribute is not yet used. + Will be used along with the 'length' attribute when creating/upgrading tables/columns. + + + + + + Initializes a new instance of the class. + + An assembly to look in. + + You can add more assemblies by using + + + + + Add another assembly that mappings can be found in. + + Assembly to add. + + + + Scan after types that match the name. + + name of class to scan for + A list with matches. + + + + Get an mapping. + + Name of class. + if found; otherwise null. + Failed to find any attributes in the class element. + + + + Throw during mapping exceptions. + + + + + Initializes a new instance of the class. + + Error message. + Type that the mapping failed for. + + + + Initializes a new instance of the class. + + Error message. + Inner exception. + Type that the mapping failed for. + + + + Type that the mapping failed for. + + + + + Let's you validate a string field using regular expressions. + + + + + Initializes a new instance of the class. + + The value. + Name in language text to use, or a error message. + + + // will use the supplied text as error message if validation fails. + [ValidateRegularExpression("^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9_\.\-]+\.[a-zA-Z]{2,4}$", "Incorrect email")] + public string Email{get;set;} + + //will use the InvalidEmail text from the language file + [ValidateRegularExpression("^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9_\.\-]+\.[a-zA-Z]{2,4}$", "InvalidEmail")] + public string Email{get;set;} + + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation or if value is empty; otherwise false. + + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is supported. + + + + Regular Expression + + + + + Arguments for + + A plugin implementation + + + + Initializes a new instance of the class. + + Plugin that have been started. + + + + Plugin that have been started. + + + + + Triggered when a plugin have been started. + + Plugin manager + Plugin instance + A plugin implementation + + + + This class is responsible of loading all modules in a system. + + + + + Application interface exposed to the clients. + + + + + Initializes a new instance of the class. + + Interface exposed to plugins. + + + + Initializes a new instance of the class. + + + + + Called when a plugin assembly is about to be loaded. + + Information about the assembly. + Evidence that the should be loaded with. + + The assembly is used to determine which security settings a plugin should be loaded with. + + + + + Loads modules with the correct and correct protection level. + + + + + Loads all modules that can be loaded (their dependencies have been loaded.) + + + + + Call this method as long as it returns true. + + + + Called when a plugin have been loaded. + + Module being loaded. + Assembly that the plugin exist in. + information about the plugin + Plugin have not been started yet. + + + + Manually add a plugin + + Plugin to add + + Used if you want to inject a known plugin to let it be loaded when all dependencies have been met. + + + + + Loads all modules + + + + + Calls start in a . + + plugin to start + + + + + Triggered when all plugins have been loaded, but not started yet. + + + + + Access a loaded plugin. + + plugin if found; otherwise null. + + + + Folder in which plugins resides. + + Can also contain wildcards + + + pluginMgr.Path = "plugins\\plugin*.dll"; + + + + + + All plugins that should not be loaded. + + + + + A list with all loaded plugins. + + + + + A plugin have been loaded into the system + + + + + A plugin have been started. + + + + + An plugin assembly is about to be loaded and the system needs to know which the plugin assembly should be loaded with. + + + Plugins are loaded into the Internet zone per default. + + + + + Called when a plugin is about to be started and we need to get the application interface + that should be used when starting the plugin. + + + + + All plugins must derive this interface. + + + + + Start the module + + Application interface exposed towards the plugins. + + + + This name is used to determine dependencies, should always be in english. + Should not be confused with the human friendly name in . + + + + + Information about the plugin. + + + + + Other plugins that this one depends on. The list should contain s. + + should never be null. + + + + Calculates the number of months and days between two dates (and add the overlapping days). + + + + + Creates a monthspan between two dates + + from which date to calculate. + end date. + Number of months and days between the two dates. + + + + Number of months + + + + + Number of days + + + + + A general code compiler used to compile objects at runtime. + + + This class is NOT thread safe. + + + + + Initializes a new instance of the class. + + + + + Add a type that is used in the generated object + + the type + + + + Fills name spaces and assemblies with info from the added types. + + + + + Compile the code. + + C# code. + An assembly containing the compiled objects + If compilation fails. + + + + Create a new object of the specified type + + Constructor parameters + Type of object to create + object if we could create it; otherwise null + + + + Used to get correct names for generics. + + Type to generate a strig name for. + Type as a code string + + + ).Name; // will become: List`1 + typeName = Compiler.GetTypeName(typeof(List)); // will become: System.Collections.Generic.List + ]]> + + + + + + Used to get correct names for generics. + + Type to generate a strig name for. + true if FullName should be used (including namespace in typename) + Type as a code string + + + ).Name; // will become: List`1 + typeName = Compiler.GetTypeName(typeof(List)); // will become: System.Collections.Generic.List + ]]> + + + + + + Thrown if code compilation fails. + + + contains an item called code which contains the compiled code. + + + + + Initializes a new instance of the class. + + The error message. + A list with all compiler generated errors. + + + + Creates and returns a string representation of the current exception. + + + A string representation of the current exception. + + + + + + + + A list with all compiler generated errors. + + + + + The purpose of this class is to maintain all delegates for + one of following types: attributes, interfaces and classes. + + + These lists are used to map all commands to their subscribers. + + + + + Add a handler + + + + If handler have been added already. + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + + An object that can be used to iterate through the collection. + + 2 + + + + Test object using generic types + + The first value to use the type of + The second value to use the type of + + + + Tests it. + + String format + A value to use in the string + string.Format(myArg, value, typeof(T), typeof(K)) + + + + Tests it. + + String format + A value to use in the string + string.Format(myArg, value, typeof(T), typeof(K)) + + + + Retrieves a dictionary using the two specified types with some random arguments in + + + + + Does the this. + + + + + Modify the id of the testobject + + + + + Delegate used to handle commands. + + that the command was invoked in. + true if command was handled. + command arguments. + + + + Event arguments for . + + + + + Initializes a new instance of the class. + + command that was invoked. + + + + Initializes a new instance of the class. + + command that was invoked. + Command is being invoked asynchrounosly. + + + + Command that was invoked. + + + + + Abort the handled of this command. + + + The event can override this property. + + + + + Command is being invoked asynchrounosly. + + + + + Not equal condition + + + + + Returns SQL + + " <> " + + + + Used to determine the kind of this token + + + + + + >= + + + + + Returns SQL + + " >= " + + + + Used to determine the kind of this token + + + + + + Parsing a property + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + All tokens used during parsing + + + + + AND + + + + + OR + + + + + IN ( XXX ) + + + + + ( + + + + + ) + + + + + A generated tree with all tokens from the text + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Number of items to keep in the . + + + + Add a new token to the tree. + + + + + + Adds a child node. + + Token to be added as a child. + this method will also set the token as . + todo: remove this one and fix haml + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Next item is a child to the current node. + + + + + Go out of one level of nesting. + + + + + Back to root node. + + + + + Displays parse tree as a tree. + + + + + + Current node + + + + + Get one of the children + + + + + + + Number of root items. + + + + + The node that was inserted last. + + + + + A trail with the number of previously added nodes, independent of the tree/depth. + + + + + Number of items to keep in the trail. + + + Specified in the constructor, default value is 3. + + + + + Root in the tree. + + + + + OR condition ("||" in C#) + + + + + OR condition as string + + " || " + + + + Used to determine the kind of this token + + + + + + As the name implies the migrator uses sql specified for a certain driver to update the database. + The sql is loaded using manifest resource xml files named xxxxx.fdmig.xml (fadd data migration) + + + The fdmig file should look like the following + + + + + An optional description of the migration. + + + + alter table myTable rename column myColumn to myColumnValues; + + + + alter table myTable rename column myColumn to myColumnValues; + + + + + + + INSERT INTO myTable (myId, myValue) VALUES (13, '23123'); + + + + + ]]> + + + + + Inteface for a handler of database updating + + + + If changes has been made the migrator should update the database accordingly + Used for saving migration data to the database + + + Initializes the + Assemblies to look for fdmig.xml files in + + + Reads all manifest files ending with fdmig.xml and creates migrations from them + + + Parses the current 'migration' element in the reader and adds its value to the collection of migrations + The reader to parse the migration from + If is null + Throw if parsing failes due to invalid data in xml + + + Holds information about a specific migration + + + Sql for migration keyed by driver name (or default) + + + + Class to provide transparent retrieval of LCID for silverlight and normal .Net projects + + + + + Gets the LCID for the current thread + + + + + Makes sure that only digits have been entered. + + + Language file items: + + + ItemName + Language text + + + Digits + '{0}' may only contain digits. + + + DigitsExtra + '{0}' may only contain digits and "{1}". + + + + + + + Name used in language files. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + extra characters that are valid. + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is supported. + + + + General purpose arguments class for events containing only one item. + + Type of item + + + + Initializes a new instance of the class. + + The item. + + + + Gets or sets the item. + + The item. + + + + Class to generate readable names from arbitrary types + + + + + Removes any `X from generic type names, ie Dictionary`2. + If the name lacks any `X entry ie Int32 it will simply be left untouched + + The name to strip from generic parameter count + Number of arguments held + + + + Retrieves the name of the class, ie for => Dictionary + + The type to generate a name for + + + + + ]]> + + The type to generate a name for + + + + Retrieves a name of the type with any generic type arguments joined with name. + + The type to generate a name for + + => DictionaryInt32String. + Useful for naming ie arbitrary methods when building objects using reflection. + ]]> + + + + + Retrieves the full name of a class, ie System.Collections.Generic.Dictionary + + The type to return the full name for + + + + A object binding. Used to copy properties from one object to another. + + + + + Copies the specified from. + + object to copy from. + objec to copy to. + If either from or to are null + If "to" is not assignabled from "from". + + + + WHERE clause + + + + + Returns SQL + + " WHERE " + + + + Used to determine the kind of this token + + + + + Parse + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + >= + + + + + Used to determine the kind of this token + + + + + + Parsing a property + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parse >= + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parse 'AND' + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Used to parse and format date/times using the current language. + + todo: Copy latest documentation from IDateTimeHelper. + + + + Add a parser. + + + + + + + + Add default language parsers. + + + + + Will try to parse the date/time using the local parser. + Will also try the default DateTime.Parse method if date is in an unknown format. + + date/time string + A + If the date/time format is invalid. + If month/day/hour/minute/second are not within their ranges. + + + + Will try to parse the date/time using the local parser. + Will also try the default DateTime.Parse method if date is in an unknown format. + + date string (may be null/empty). + time string (may be null/empty). + A + If the date/time format is invalid. + If month/day/hour/minute/second are not within their ranges. + + + + Tries to parse a date string. + + Can contain a complete date or parts of it (which parts depends on the country). + A containing the date (time is 0) if parsed successfully; otherwise . + + + + Tries to parse a date string. + + Can contain a complete date or parts of it (which parts depends on the country). + array that parsed values are written to. + where in array to start write values + true if parsed successfully; otherwise false + + + + Tries to parse a time string. + + Can contain a complete time or parts of it (which parts depends on the country). + A containing the time (date is 0) if parsed successfully; otherwise . + + + + Tries to parse a time string. + + Can contain a complete time or parts of it (which parts depends on the country). + array that will be filled. Must contain three slots. + Where in the array to start write values + true if parsed successfully; otherwise false. + + + + Validate a date. + + year value + month value + day value + true if exceptions should be thrown on incorrect values. + true if specified values are a correct date; otherwise false. + + + + Validate + + hour + minute + second + true if exceptions should be thrown on incorrect values. + true if specified values are a correct date; otherwise false. + + + + Format a date as a string. + + A date/time + Examples: "Yesterday", "On monday" + + + + Format a date/time as a string. + + A date/time + Examples: "Yesterday at 12:20pm", "On monday at 11:38am" + + + + Get duration as a human friendly string. + + Start time of duration + End time of duration + The detail in which to display the duration + Number of time units to display + + A string like: 1 month, 2 weeks, and 3 days. + + + + + Get duration as a human friendly string. Displays all time unit durations. + + Start time of duration + End time of duration + + + + Get duration as a human friendly string. + + The timespan for which to output the duration + The detail in which to display the duration + /// Number of time measures to display + + A string like: 1 month, 2 weeks, and 3 days. + + cannot be used when using this method since counting of months + requires both to and from datetime information, in such a case user + + + + Get duration as a human friendly string. Displays all time unit durations. + + The timespan for which to output the duration + + + + Event arguments for transaction events. + + + + + Initializes a new instance of the class. + + Transaction. + The connection. + + + + Transaction that the event is for. + + + + + Connection that the transaction is being invoked in. + + + + + Main class in the data access layer. + + + + + Initializes a new instance of the class. + + The connection helper. + + + + Initializes a new instance of the class. + + The connection helper. + Assign logger to everything. + + + + Creates a connection, we use this method instead of the one in + the connection helper to be able to use transactions (with a single connection). + + A database connection. + Failed to create the connection. + + + + Create a command. + + + + + + Creates a new transaction. + + On of the s. + An object representing the new transaction. + + Once the transaction has completed, you must explicitly commit or roll back the transaction by using the Commit or Rollback methods. + + + + + Creates a new transaction. + + An object representing the new transaction. + + Once the transaction has completed, you must explicitly commit or roll back the transaction by using the Commit or Rollback methods. + + + + + Determines if we are a transaction. + + + + + An validation error. + + + + + + + Property/Argument that validation failed for. + Kind of validation that failed. + + + + Property/Argument that validation failed for + + + + + Kind of validation that failed + + + + + Delegate used to determine if the command propagation can be cancelled. + + Distlight that the command was going through. + Event information. + true of command can be cancelled. + + + + + Event arguments for . + + + + + Initializes a new instance of the class. + + Command that was cancelled. + Handler that cancelled the propagation + + + + Command that was cancelled by a handler + + + + + Handler that which to cancel the command. + + + + + Used to test inner classes. + + + + + Copy all stuff that have been modified by the command handler. + + Command to copy reply from. + + + + Transports commands in binary format. + + + + + Invoked when we have recieved a packet from the remote end. + + + + + Initializes a new instance of the class. + + The socket. + + + + Initializes a new instance of the class. + + + + + Releases unmanaged resources and performs other cleanup operations before the + is reclaimed by garbage collection. + + + + + Sends the specified value. + + object to serialize and send. + + + + Send a packet to the client. + + + + + + Goes through all incoming bytes and creates a packet. + One or more calls might be required to get a complete packet. + + buffer to process + where to start processing + total number of bytes in buffer. + number of bytes that are handled + + + + Called when a object buffer have been received completely. + + The buffer. + + + + Closes this instance. + + + + + Connect to an endpoint. + + Where to connect + if connection fails. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + true if we should reconnect when getting disconnected. + + + + + Invoked when channel is disconnected (except when are called). + + + + + Event args for + + + + + Initializes a new instance of the class. + + object received from remote end. + + + + Bytes received from remote end. + + + + + Invoked when an object have been received from the remote end. + + Client that received the object. + object received. + + + + A IN clause. + + + + + Returns SQL + + " IN" + + + + Used to determine the kind of this token + + + + + COUNT(*) SQL clause + + + + + Returns SQL + + " COUNT(*) " + + + + Used to determine the kind of this token + + + + + We are getting into a sub context (nested conditions) + + + + + Returns SQL + + ( + + + + Used to determine the kind of this token + + + + + + or != + ]]> + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + + + + + + Less tan condition + + + + + + + + Used to determine the kind of this token + + + + + + Parse + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Reads a mapping definition from an XML reader. + + + + + Initializes a new instance of the class. + + Reader containing mapping XML. + Type that the mapping is for. + + + + Read mapping. + + Mapping if found + If mapping is incorrect (syntax). + + + + Go through property attributes + + MappingException. + + + MappingException. + + + MappingException. + + + + Default mapping implementation + + + + + Initializes a new instance of the class. + + Type that the mapping is for. + Name of the database table. + + + + Get a column name from a property name. + + + + + + + Gets current primary key. + + The primary key if exactly ONE is defined; otherwise null. + + + + Add a property mapping + + Class property + Table column + + + + Add a property mapping + + Class property + Table column + True if property is a primary key. + Type of generator used. + + + + Name of database table. + + + + + Type that the mapping is for. + + + + + Gets all properties + + + + + Gets all primary keys + + + + + Attribute to specify that a property might only contain the specified letters (does not fail if the string is null or empty) + + + + + The language node item name for the attribute, should be in the form 'Parameter {0} has invalid characters, allowed characters are {1}' + + + + + Initializes a new instance of the class. + + The allowed letters + + + + Validate value + + Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. + value to validate + + true if value passed the validation; otherwise false. + + If a value not of type was supplied + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + + + + Determines if the validation class support the specified type. + + Property/Value type. + true if the type is a string + + + + General purpose class to get/set properties by specifying their name as text. + + + + User user = new User(); + Property.Set(user, "FirstName", "Jonas"); // same as user.FirstName = "Jonas"; + Property.Set(user, "CreatedAt", "2008-12-30 14:00"); // the CreatedAt property is of type DateTime, the Property class automatically converts it from string. + Property.Set(user, "Age", "20"); // age is int, which means that it will automatically be converted. + + + todo: Add the ability to extend the object with own additions. + + + + Assign a property value to the specified object. + + Object that has the property + Name of the property + Value, this method will try to cast incorrect types (and even try to parse certain types). + If value is not correct (i.e. null when null is not accepted etc) + If assigner object could not be generated. + If assigner object can't cast to the correct type. + values is null and it's not allowed for the specified type. + + + + Get a property value from the specified object. + + Object that has the property + Name of the property + property value + If value is not correct (i.e. null when null is not accepted etc) + If assigner object could not be generated. + If assigner object can't cast to the correct type. + + + + Base object for property assigner. + + + + + + + + + + + + + + + + + + + + + Used to determine + + + + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + or != + ]]> + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Tables and Classes are identical. + + + Since they are identical, we create a mapping which simply returns the + same values for the mapping. + + + + + Initializes a new instance of the class. + + Assembly that will be scanned after mappings. + "sequence" or "autoincrement" + + Specifying "sequence" means that the system will look for generators/sequences called "[tablename]_id_seq". + + + + + Gets the mapping. + + Name of the class to get mapping for. + if found; otherwise null. + + + Multiple classes found. + + + + Add an assembly in which we can look for mappings. + + An assembly + + + + Delegate used when a unhandled exception have been caught. + + + + + Arguments for + + + + + Initializes a new instance of the class. + + caught exception. + + + + Caught exception + + + + + Copies get/set properties from one object to another. + + + + + Releases unmanaged resources and performs other cleanup operations before the + is reclaimed by garbage collection. + + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Copies all get/set properties from one object to another. + + From. + To. + + + + Star * + + + + + SQL Star + + " * " + + + + Used to determine the kind of this token + + + + + A property name + + + + + Initializes a new instance of the class. + + Name of property. + + + + Returns SQL + + column name + + + + Used to determine the kind of this token + + + + + + Name of property + + + + + OR condition ("||" in C#) + + + + + Returns SQL + + " OR " + + + + Used to determine the kind of this token + + + + + + Parse (, which is start of one level nesting. + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Parse == or = + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Check if the current position is the start of this token + + + + true if our token is the next one. + + + + + + + + + Returns &&. + + " && " + + + + Used to determine the kind of this token + + + + + + Parse + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Arguments for + + Plugin type + + + + Initializes a new instance of the class. + + Plugin being started. + + + + Plugin being started + + + + + Application that the plugin should be started with. + + + + + A plugin is about to be started and it needs a interface to be passed to it. + + A type that implements . + + Arguments. + + + + INSERT INTO clause + + + + + returns SQL + + "INSERT INTO " + + + + Used to determine the kind of this token + + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + All tokens used during parsing + + + + + AND + + + + + OR + + + + + IN ( XXX ) + + + + + ( + + + + + ) + + + + + Query statement + + + + + Initializes a new instance of the class. + + Conditions (corresponds to the WHERE clause) using property names. + Argument values used in the condition. + + + + Initializes a new instance of the class. + + + + + Properties to sort by. + + properties separated by comma, with or without ASC/DESC. + the current statement + new Statement("FirstName = ?", firstName).OrderBy("LastName DESC, FirstName") + + + + Properties to group the statement by + + Properties to group by, separated by comma. + + new Statement(string.Empty).GroupBy("LastName, FirstName") + + + + Get a certain amount of entries. + + 0 based index. 0 = first page, 1 = second page.. + Number of entries per page. + + + + + Calculates hash code by concatenating the strings for all statement parts. + + + + + + Arguments being used in . + + + + + Conditions (corresponds to the WHERE clause) using property names + + + + + Property names + ASC/DESC + + + + + Property names to group by + + + + + 0 based index. 0 = first page, 1 = second page.. + + + + + Number of entries per page + + + + + Database connection configuration + + + + + Assembly qualified name of the .Net driver to use. + + + + + Connection string + + + + + Connection type. + + + + + Validates a string as http(s)/ftp url. + + + + + Name of the language item for this validation. + + + + + Localize error if validation failed. + + Localized field name. + Language node with all validation translations. + A localized error message if the validation failed; otherwise null. + + + attribute.Localize("FirstName", "'{0}' is required"); + // will return "'{0}' is required" if the validation failed, else null. + + + + + + Determines if the validation support the specified type. + + Property/Value type. + true if type is supported. + + Used when validation objects are generated. + + + + + Validate the URL + + Object instance (of the object being tested). + Value to test + true if value is an URL; otherwise false. + If type is not supported. + + + + Wrapper for the class adding support for tabbing easily + + "); + sb.AppendLine(@"); + sb.AppendLineDec(""); + + Would give the result: +
    + +
    + + Without having you worry about what tab indentation your on, neat! + ]]>
    +
    + + + Instances a blank + + + + + Instance the with a and a start intendation + + A to append text to + + Can be used to start writing with tabs using a set intendation when data has previously been written to the + with intendation. + + + + + The built string + + Generated string + + + + Changes the to contain the specified number of tab characters + + Number of tab characters to set + + + + Appends tabs followed by the specified value and a line termination to the string + + The value to add + + + + Appends tabs followed by the specified value and a line termination to the string + + The value to add + + + + Appends a empty line without tabs + + + + + Just appends plain string to the underlying without any tabs + + The value to add + + + + Appends tabs and value to the string + + The value to add + + + + Adds a new line and increases the tab indendation + + "); + sb.AppendLineInc(); + sb.AppendLine(""); + sb.AppendLineDec(""); + + => +
    + +
    + ]]>
    +
    + + + Appends tabs and value to the string after which the intendation is increased + + The value to append + The tab intendation is increased after adding the value + "); + sb.AppendLine("Example"); + + Would give: +
    + Example + ]]> + + + + Appends tabs and value to the string after which the intendation is increased + + The value to append + The tab intendation is increased after adding the value + "); + sb.AppendLine("Example"); + + Would give: +
    + Example + ]]> + + + + Decreases the intendation and appends tabs and value to the string + + The value to append + The tab intendation is decreased before adding the value + "); + sb.AppendLine("Example"); + sb.AppendLineDec("
    "); + + Would give: +
    + Example +
    + ]]> + + + + Decreases the intendation and appends tabs and value to the string + + The value to append + The tab intendation is decreased before adding the value + "); + sb.AppendLine("Example"); + sb.AppendLineDec("
    "); + + Would give: +
    + Example +
    + ]]> + + + + Retrieves the used by the class + + + + + Command sent by a TypeProxy + + + + + Initializes a new instance of the class. + + Type of object to execute method on. + Method to call. + Argumens that should be passed to the method. + + + + Return value from method call. + + + + + Type of object to execute method on. + + + + + Method to call. + + + + + Argumens that should be passed to the method call. + + + + + Exception thrown during method call + + + + + Class for building information strings about a proxy property + + + + + Instantiates and builds information about a property + + + + + + Builds a declaration string for the property proxy + + The property to build a proxy declaration for + + + + Retrieves a signature for the property, ie _propertyName + + + + + Retrieves the property name + + + + + Retrieves the return type for the property + + + + + Retrieves the property declaration string + + + + + Retrieves the property type + + + + + Returns true if the property has a get field + + + + + Returns true if the property has a set field + + + + + Invokes all handlers for a command. + + + + + Initializes a new instance of the class. + + used as "source" in the command event delegate. + command being executed. + Used to check if propagation may be cancelled. + callback when command have been executed.. + async result. + + + + + + + + + Returns SQL + + " <= " + + + + Used to determine the kind of this token + + + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Check if the current position is the start of this token + + true if our token is the next one. + + + + Parses the data in the specified . + + The containing the data to parse. + that is being built.. + true if more tokens can be parsed on the current leaf; false if we should continue to next leaf (parse no more children). + + + + Contains a value in a condition. + + + + + Initializes a new instance of the class. + + Property that this value belongs to. + + + + Question mark as string + + "?" + + + + Identifier for this token. + + + + + Property that this token belongs to. + + + + + Used to parse Swedish dates and times. + + + + + Static constructor setting up helping maps + + + + + Will try to parse the date/time using the local parser. + Will also try the default method if date is in an unknown format. + + date/time string + A if parsed successfully; otherwise . + If the date/time format is invalid. + If month/day/hour/minute/second are not within their ranges. + + Can parse one of the following formats:
    + YYYY-MM-DD HH:MM:SS
    + YYYY-MM-DD HH:MM
    + YYYYMMDDHHMM
    + YYYYMMDDHHMMSS
    + YYMMDDHHMM +
    +
    + + + Will try to parse the date/time using the local parser. + Will also try the default method if date is in an unknown format. + + date string. Date will be set to current if value is not specified. + time string. Time will be set to current if not specified. + A + If the date/time format is invalid. + If month/day/hour/minute/second are not within their ranges. + + + + Tries to parse a date string. + + Can contain a complete date or parts of it (which parts depends on the country). + + A containing the date (time is 0) if parsed successfully; otherwise . + + + YYYY-MM-DD + YYYYMMDD + YYMMDD + MMDD + + + + + Can parse one of the following formats: + YYYY-MM-DD + YYYYMMDD + YYMMDD + MMDD + + contains a date string. + array that parsed values are written to. + where in array to start write values + If value contains an unknown format. + If month/day are not within their ranges. + offset is out of range. + + + + Tries to parse a time string. + + Can contain a complete time or parts of it (which parts depends on the country). + A containing the time (date is 0) if parsed successfully; otherwise . + + + + Can parse one of the following formats: + HH:MM:SS + HH:MM + HHMM + HHMMSS + + a time value + array that will be filled. Must contain three slots. + Where in the array to start write values + true if parsed successfully; otherwise false. + offset is out of range. + Invalid time format. + + + + Validate a date + + year value + month value + day value + throw exceptions + true if specified values are a correct date; otherwise false. + If any of the values are not in the allowed ranges. + Month must be between 1 and 12. + + + + Validate a time value. + + hour + minute + throw exceptions + If any of the values are not in the allowed ranges. + + + + + + + + + + If any of the values are not in the allowed ranges. + + + + Format a date as a string. + + A date/time + Examples: "Yesterday", "On monday" + + + + Format a date as a string. + + A date/time + Examples: "Yesterday at 12:20pm", "On Monday at 11:38am" + + + + Get duration as a human friendly string. + + Start time of duration + End time of duration + The detail in which to display the duration + Number of time units to display + + A string like: 1 month, 2 weeks, and 3 days. + + + + + Get duration as a human friendly string. Displays all time unit durations. + + Start time of duration + End time of duration + + + + + Get duration as a human friendly string. + + The timespan for which to output the duration + The detail in which to display the duration + Number of time measures to display + + A string like: 1 month, 2 weeks, and 3 days. + + cannot be used when using this method since counting of months + requires both to and from date time information, in such a case user + Since is given as duration months cannot be calculated, try GetDuration(DateTime, DateTime, DurationDetail) instead. + + + + Get duration as a human friendly string. Displays all time unit durations. + + The timespan for which to output the duration + + + + + Displays a value defined by the either as a part or as a total + + Number of months and days + TimeSpan containing detailed times + The time unit to retrieve + True if the total amount of the time unit should be returned or just a portion of it + A string in the form 'amount timunitname, ' + + + + Retrieves a singular or plural name with amount and comma padded, ie '3 månader, ' or '1 månad, ' + + The name in plural (used to map for singular name) + The amount to display + + + + Mappings for properties. + + + + + Initializes a new instance of the class. + + Name of the class property. + Name of the database column. + + + + Gets or sets name in table + + + + + Gets or sets name in class. + + + + + Gets or sets whether this property is part of the primary key + + + + + Gets or sets how the value is generated. + + + + + sequence + Looks for a sequence named "[tableName]_id_seq" + + + autoincrement + Uses database specific code to fetch value after insert. + ONLY VALID FOR PRIMARY KEYS + + + + guid + generate a globally unique identifier. + + + any other value + specifies a sequence/generator name + + + + + + + Connection helper specialized for PostgreSQL database. + + + + + Initializes a new instance of the class. + + The connection string. + + + + Create a new connection to the database. + + An open database connection. + If connection fails. + + + + Try to get next sequence value. + + A command to perform actions with, we pass commands since they might be in a transaction. + Name of the sequence/generator. + A generated value. + If something failed + + + + Gets the latest auto incremented value from the database. + + A command to perform actions with, we pass commands since they might be in a transaction.. + Name of the column that the auto incremented value is for. + auto incremented value + If something failed + Not supported by PostgreSQL + + + + Modifies the SQL statement to include paging. + + Mapping used by certain implementations (but not by this one). + SQL statement generated by the DAL. + 0 based index + number of entries per page + SQL statement with paging + + + helper.Paging("SELECT * FROM users", 5, 10); // --> "SELECT * FROM users LIMIT 10 OFFSET 50" + + + + + + Connection string + + + + + diff --git a/thirdparty/HttpServer/Homepage.txt b/thirdparty/HttpServer/Homepage.txt new file mode 100644 index 000000000..c0d8fec2b --- /dev/null +++ b/thirdparty/HttpServer/Homepage.txt @@ -0,0 +1 @@ +http://webserver.codeplex.com/ \ No newline at end of file diff --git a/thirdparty/HttpServer/HttpServer.MVC.dll b/thirdparty/HttpServer/HttpServer.MVC.dll new file mode 100644 index 0000000000000000000000000000000000000000..0446bf95552e8725b2e25b89f05ea0d4a4b767f8 GIT binary patch literal 56320 zcmeZ`n!v!!z`(%5z`*eTKLf)K1_*F~PKqst z9Q2A(bMliJz;0zwfP?|VEev%|s3Hsu0ibYYfVho`ftBG-83V(PDh38lsKSg=28KdL z28I9y1_n@kLxpit;kmAV916F1#njr~KKJdyX|g|wb!Q(k*v@_qlm&nK>^bUl&BZL#fc^*g&sOvOSB3|zIK zkb*Knsf0;Gn1O+diMf`Afq_Mffq_BVfQiA4fq{XMfkBX|8l*a3gn@yJ3(6K{VBq4> z78GLA5MyBA;$~ydXJ=qwi{KJs(hz50;L?3|k57o{pBNJZgLJ+G0|VC`HZ2AQMgdUL zlVFfDW8eb?kQ~G?EjgxYW{|Z?Ow6@lh8$Bh$WdC8nDf~f7}#|9APSlDB^emF)U+V7 zFrFKPn=i${z?Cn}z`&(t1Qh`}7-TruPg+dOV&eIt3=C{qT1?C=Vi4vgCJjyo1~y#@ zCJlZN%_OD;VdaZ4FtCY7XhG!jWf>XRwCtFeHCP!K*qB%}BthoLF;%m|+zn=MiE9ZP zFoW|869a=Fi;g5~z9J(78y|~Tz6=8cm%M^8J0FXxmv}@73qnSgfq|=7oPmLji$#~6 zjWwT(0i**WpD)M2z!k!#mBb8Yi5c=Ti-C>OkO%oxOzRZHfjY`{3ZMuCMF*QaXTBnc z19qK;5(5L5hB8Ps)VU1O1}xyD&kTxNunsP;ZkR@Hh{7U928MznRtAQGd=*f17ppQb zaPcy`>GE?Haf3wFK(WCr9>k=b_k1;BVQe)8mbhO ze1uuGC52c))^iE7a0;?8vw%!sgQyo`g`}f<_Y8$tk<$^>yTUBG0-Wp|8XBNT2b-+T z0kf4eUlZh8SbD2rP+J5^Z;zmRn;>gnrqOM1VDo@UUN&KNF<}milMDXJ0V_B)6%{iu6mUS8?F&s;L^sT;Ruq# zq0I>-hs_~k8qT<+Snx@?;L;_g0hUU`5}q2axHPe7xZ{!%!!5<4;eksRi-spi3acx; zKr-0EftjNG6+sNoB$mHa?_9t7VX#OFou!SZ}y zegLTSWUdBjt_2ZH%+(-`wIG6txf-OY7DO;HSA#Uvf(Rz&e0K&0Hjt;;n3$^t7#LV; zK?D1S`sDzX2>yBOTh%d3@}Wdf%Zk$;S0{}{EzAoXztnw!K8*dfZG8qsW(U}9qzkH`l# zy)*(D7}&5nLWdU;TWsJEhsF`aMY>EPa6Tv&wWJN08A2i5F+nD9F367oHJ7xdg_t#B zLEd9y63LHaVBlJ6$H2g-%OcKmPfLhdBOcURzH^UHi20uwJG`|l#&eICyGV|Op@6+O z0TjC&pf)+945sup2j zV98HqVBop{YWsj2U&hW5VQ9dWfF!usbmW*cfze;AF&>pTWSu#h#zZz`%7+ znx|+93qt`1B;-(xP}2hSK^PdOF_@i!g&PY4I}5l!CkTmcRbfGmEKp$v&Z+s?3=CXi zhOBp=GK1QLpoZcFc@PWKIuy�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 T3=9R}`#}fPC8L%PKnMT;C6$sZ literal 0 HcmV?d00001 diff --git a/thirdparty/HttpServer/HttpServer.dll b/thirdparty/HttpServer/HttpServer.dll new file mode 100644 index 0000000000000000000000000000000000000000..593f8fa7cfbbb6fe4bf92a91c568970861ab4c98 GIT binary patch literal 127488 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 + + + HttpServer + + + +

    + Session store using memory for each session. + + + + + A session store is used to store and load sessions on a media. + The default implementation () saves/retrieves sessions from memory. + + + + + Creates a new http session with a generated id. + + A object + + + + Creates a new http session with a specific id + + Id used to identify the new cookie.. + A object. + + Id should be generated by the store implementation if it's null or . + + + + + Load an existing session. + + Session id (usually retrieved from a client side cookie). + A session if found; otherwise null. + + + + Save an updated session to the store. + + Session id (usually retrieved from a client side cookie). + If Id property have not been specified. + + + + We use the flyweight pattern which reuses small objects + instead of creating new each time. + + Unused session that should be reused next time Create is called. + + + + Remove expired sessions + + + + + Remove a session + + id of the session. + + + + Load a session from the store + + + null if session is not found. + + + + Number of minutes before a session expires. + + Default time is 20 minutes. + + + + Initializes the class setting the expirationtimer to clean the session every minute + + + + + Delegate for the cleanup timer + + + + + Creates a new http session + + + + + + Creates a new http session with a specific id + + Id used to identify the new cookie.. + A object. + + Id should be generated by the store implementation if it's null or . + + + + + Load an existing session. + + + + + + + Save an updated session to the store. + + + + + + We use the flyweight pattern which reuses small objects + instead of creating new each time. + + EmptyLanguageNode (unused) session that should be reused next time Create is called. + + + + Remove expired sessions + + + + + Remove a session + + id of the session. + + + + Load a session from the store + + + null if session is not found. + + + + Number of minutes before a session expires. + Default is 20 minutes. + + + + + Priority for log entries + + + + + + Very detailed logs to be able to follow the flow of the program. + + + + + Logs to help debug errors in the application + + + + + Information to be able to keep track of state changes etc. + + + + + Something did not go as we expected, but it's no problem. + + + + + Something that should not fail failed, but we can still keep + on going. + + + + + Something failed, and we cannot handle it properly. + + + + + Interface used to write to log files. + + + + + Write an entry to the log file. + + object that is writing to the log + importance of the log message + the message + + + + This class writes to the console. It colors the output depending on the logprio and includes a 3-level stacktrace (in debug mode) + + + + + + The actual instance of this class. + + + + + Logwriters the specified source. + + object that wrote the logentry. + Importance of the log message + The message. + + + + Get color for the specified logprio + + prio for the log entry + A for the prio + + + + Default log writer, writes everything to null (nowhere). + + + + + + The logging instance. + + + + + Writes everything to null + + object that wrote the log entry. + Importance of the log message + The message. + + + + PrototypeJS implementation of the javascript functions. + + + + + Purpose of this class is to create a javascript toolkit independent javascript helper. + + + + + Generates a list with JS options. + + StringBuilder that the options should be added to. + the javascript options. name, value pairs. each string value should be escaped by YOU! + true if we should start with a comma. + + + + Removes any javascript parameters from an array of parameters + + The array of parameters to remove javascript params from + An array of html parameters + + + + javascript action that should be added to the "onsubmit" event in the form tag. + + + All javascript option names should end with colon. + + + JSHelper.AjaxRequest("/user/show/1", "onsuccess:", "$('userInfo').update(result);"); + + + + + + Requests a url through ajax + + url to fetch + optional options in format "key, value, key, value", used in JS request object. + a link tag + All javascript option names should end with colon. + + + JSHelper.AjaxRequest("/user/show/1", "onsuccess:", "$('userInfo').update(result);"); + + + + + + Ajax requests that updates an element with + the fetched content + + Url to fetch content from + element to update + optional options in format "key, value, key, value", used in JS updater object. + A link tag. + All javascript option names should end with colon. + + + JSHelper.AjaxUpdater("/user/show/1", "userInfo", "onsuccess:", "alert('Successful!');"); + + + + + + A link that pop ups a Dialog (overlay div) + + url to contents of dialog + link title + A "a"-tag that popups a dialog when clicked + name/value of html attributes + + WebHelper.DialogLink("/user/show/1", "show user", "onmouseover", "alert('booh!');"); + + + + + Close a javascript dialog window/div. + + javascript for closing a dialog. + + + + + Creates a new modal dialog window + + url to open in window. + window title (may not be supported by all js implementations) + + + + + + Requests a url through ajax + + url to fetch. Url is NOT enclosed in quotes by the implementation. You need to do that yourself. + optional options in format "key, value, key, value", used in JS request object. All keys should end with colon. + a link tag + onclick attribute is used by this method. + + + // plain text + JSHelper.AjaxRequest("'/user/show/1'"); + + // ajax request using this.href + string link = "<a href=\"/user/call/1\" onclick=\"" + JSHelper.AjaxRequest("this.href") + "/<call user</a>"; + + + + + + Determins if a list of strings contains a specific value + + options to check in + value to find + true if value was found + case insensitive + + + + Ajax requests that updates an element with + the fetched content + + URL to fetch. URL is NOT enclosed in quotes by the implementation. You need to do that yourself. + element to update + options in format "key, value, key, value". All keys should end with colon. + A link tag. + + + JSHelper.AjaxUpdater("'/user/show/1'", "user", "onsuccess:", "alert('hello');", "asynchronous:", "true"); + + + + + + A link that pop ups a Dialog (overlay div) + + URL to contents of dialog + link title + name, value, name, value + + A "a"-tag that popups a dialog when clicked + + Requires Control.Modal found here: http://livepipe.net/projects/control_modal/ + And the following JavaScript (load it in application.js): + + Event.observe(window, 'load', + function() { + document.getElementsByClassName('modal').each(function(link){ new Control.Modal(link); }); + } + ); + + + + WebHelper.DialogLink("/user/show/1", "show user", "onmouseover", "alert('booh!');"); + + + + + create a modal dialog (usually using DIVs) + + url to fetch + dialog title + javascript/html attributes. javascript options ends with colon ':'. + + + + + Close a javascript dialog window/div. + + javascript for closing a dialog. + + + + + javascript action that should be added to the "onsubmit" event in the form tag. + + remember to encapsulate strings in '' + + All javascript option names should end with colon. + + + JSHelper.AjaxRequest("/user/show/1", "onsuccess:", "$('userInfo').update(result);"); + + + + + + Can handle application/x-www-form-urlencoded + + + + + Interface for form content decoders. + + + + + + + Stream containing the content + Content type (with any additional info like boundry). Content type is always supplied in lower case + Stream enconding + A http form, or null if content could not be parsed. + If contents in the stream is not valid input data. + + + + Checks if the decoder can handle the mime type + + Content type (with any additional info like boundry). Content type is always supplied in lower case. + True if the decoder can parse the specified content type + + + + + Stream containing the content + Content type (with any additional info like boundry). Content type is always supplied in lower case + Stream encoding + + A HTTP form, or null if content could not be parsed. + + If contents in the stream is not valid input data. + + + + Checks if the decoder can handle the mime type + + Content type (with any additional info like boundry). Content type is always supplied in lower case. + True if the decoder can parse the specified content type + + + + redirects from one URL to another. + + + + + Rules are used to perform operations before a request is being handled. + Rules can be used to create routing etc. + + + + + Process the incoming request. + + incoming HTTP request + outgoing HTTP response + true if response should be sent to the browser directly (no other rules or modules will be processed). + + returning true means that no modules will get the request. Returning true is typically being done + for redirects. + + If request or response is null. + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + true if request should be redirected, false if the request URI should be replaced. + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Process the incoming request. + + incoming HTTP request + outgoing HTTP response + true if response should be sent to the browser directly (no other rules or modules will be processed). + + returning true means that no modules will get the request. Returning true is typically being done + for redirects. + + + + + Gets string to match request URI with. + + Is compared to request.Uri.AbsolutePath + + + + Gets where to redirect. + + + + + Gets whether server should redirect client. + + + false means that the rule will replace + the current request URI with the new one from this class. + true means that a redirect response is sent to the client. + + + + + Contains a listener that doesn't do anything with the connections. + + + + + Listen for regular HTTP connections + + IP Address to accept connections on + TCP Port to listen on, default HTTP port is 80. + Factory used to create es. + address is null. + Port must be a positive number. + + + + Initializes a new instance of the class. + + IP Address to accept connections on + TCP Port to listen on, default HTTPS port is 443 + Factory used to create es. + Certificate to use + which HTTPS protocol to use, default is TLS. + + + Exception. + + + + Will try to accept connections one more time. + + If any exceptions is thrown. + + + + Can be used to create filtering of new connections. + + Accepted socket + true if connection can be accepted; otherwise false. + + + + Start listen for new connections + + Number of connections that can stand in a queue to be accepted. + Listener have already been started. + + + + Stop the listener + + + + + + Gives you a change to receive log entries for all internals of the HTTP library. + + + You may not switch log writer after starting the listener. + + + + + True if we should turn on trace logs. + + + + + Gets currently used port. + + + + + Catch exceptions not handled by the listener. + + + Exceptions will be thrown during debug mode if this event is not used, + exceptions will be printed to console and suppressed during release mode. + + + + + A request have been received from a . + + + + Class to handle loading of resource files + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + logger. + + + + Loads resources from a namespace in the given assembly to an URI + + The URI to map the resources to + The assembly in which the resources reside + The namespace from which to load the resources + + + resourceLoader.LoadResources("/user/", typeof(User).Assembly, "MyLib.Models.User.Views"); + + Will make the resource MyLib.Models.User.Views.list.Haml accessible via /user/list.haml or /user/list/ + + The amount of loaded files, giving you the possibility of making sure the resources needed gets loaded + If a resource has already been mapped to an uri + + + + Retrieves a stream for the specified resource path if loaded otherwise null + + Path to the resource to retrieve a stream for + A stream or null if the resource couldn't be found + + + + Fetch all files from the resource that matches the specified arguments. + + The path to the resource to extract + + a list of files if found; or an empty array if no files are found. + + Search path must end with an asterisk for finding arbitrary files + + + + Fetch all files from the resource that matches the specified arguments. + + Where the file should reside. + Files to check + + a list of files if found; or an empty array if no files are found. + + + + + Returns whether or not the loader has an instance of the file requested + + The name of the template/file + True if the loader can provide the file + + + + Helpers making it easier to work with forms. + + + + + + Used to let the website use different JavaScript libraries. + Default is + + + + + Create a <form> tag. + + name of form + action to invoke on submit + form should be posted as Ajax + HTML code + + + // without options + WebHelper.FormStart("frmLogin", "/user/login", Request.IsAjax); + + // with options + WebHelper.FormStart("frmLogin", "/user/login", Request.IsAjax, "style", "display:inline", "class", "greenForm"); + + + HTML attributes or JavaScript options. + Method will ALWAYS be POST. + options must consist of name, value, name, value + + + + Creates a select list with the values in a collection. + + Name of the SELECT-tag + collection used to generate options. + delegate used to return id and title from objects. + value that should be marked as selected. + First row should contain an empty value. + string containing a SELECT-tag. + + + + + Creates a select list with the values in a collection. + + Name of the SELECT-tag + Id of the SELECT-tag + collection used to generate options. + delegate used to return id and title from objects. + value that should be marked as selected. + First row should contain an empty value. + string containing a SELECT-tag. + + + + // Class that is going to be used in a SELECT-tag. + public class User + { + private readonly string _realName; + private readonly int _id; + public User(int id, string realName) + { + _id = id; + _realName = realName; + } + public string RealName + { + get { return _realName; } + } + + public int Id + { + get { return _id; } + } + } + + // Using an inline delegate to generate the select list + public void UserInlineDelegate() + { + List<User> items = new List<User>(); + items.Add(new User(1, "adam")); + items.Add(new User(2, "bertial")); + items.Add(new User(3, "david")); + string htmlSelect = Select("users", "users", items, delegate(object o, out object id, out object value) + { + User user = (User)o; + id = user.Id; + value = user.RealName; + }, 2, true); + } + + // Using an method as delegate to generate the select list. + public void UseExternalDelegate() + { + List<User> items = new List<User>(); + items.Add(new User(1, "adam")); + items.Add(new User(2, "bertial")); + items.Add(new User(3, "david")); + string htmlSelect = Select("users", "users", items, UserOptions, 1, true); + } + + // delegate returning id and title + public static void UserOptions(object o, out object id, out object title) + { + User user = (User)o; + id = user.Id; + value = user.RealName; + } + + + name, id, collection or getIdTitle is null. + + + + Creates a select list with the values in a collection. + + Name of the SELECT-tag + Id of the SELECT-tag + collection used to generate options. + delegate used to return id and title from objects. + value that should be marked as selected. + First row should contain an empty value. + name, value collection of extra HTML attributes. + string containing a SELECT-tag. + + name, id, collection or getIdTitle is null. + Invalid HTML attribute list. + + + + Generate a list of HTML options + + collection used to generate options. + delegate used to return id and title from objects. + value that should be marked as selected. + First row should contain an empty value. + + collection or getIdTitle is null. + + + sb is null. + + + + Creates a check box. + + element name + element value + determines if the check box is selected or not. This is done differently depending on the + type of variable. A boolean simply triggers checked or not, all other types are compared with "value" to determine if + the box is checked or not. + a list with additional attributes (name, value, name, value). + a generated radio button + + + + Creates a check box. + + element name + element id + element value + determines if the check box is selected or not. This is done differently depending on the + type of variable. A boolean simply triggers checked or not, all other types are compared with "value" to determine if + the box is checked or not. + a list with additional attributes (name, value, name, value). + a generated radio button + + value in your business object. (check box will be selected if it matches the element value) + + + + + Creates a check box. + + element name + element id + determines if the check box is selected or not. This is done differently depending on the + type of variable. A boolean simply triggers checked or not, all other types are compared with "value" to determine if + the box is checked or not. + a list with additional attributes (name, value, name, value). + a generated radio button + will set value to "1". + + + + Creates a RadioButton. + + element name + element value + determines if the radio button is selected or not. This is done differently depending on the + type of variable. A boolean simply triggers checked or not, all other types are compared with "value" to determine if + the box is checked or not. + a list with additional attributes (name, value, name, value). + a generated radio button + + + + Creates a RadioButton. + + element name + element id + element value + determines if the radio button is selected or not. This is done differently depending on the + type of variable. A boolean simply triggers checked or not, all other types are compared with "value" to determine if + the box is checked or not. + a list with additional attributes (name, value, name, value). + a generated radio button + + + + form close tag + + + + + + Implements HTTP Digest authentication. It's more secure than Basic auth since password is + encrypted with a "key" from the server. + + + Keep in mind that the password is encrypted with MD5. Use a combination of SSL and digest auth to be secure. + + + + + Authentication modules are used to implement different + kind of HTTP authentication. + + + + + Tag used for authentication. + + + + + Initializes a new instance of the class. + + Delegate used to provide information used during authentication. + Delegate used to determine if authentication is required (may be null). + + + + Initializes a new instance of the class. + + Delegate used to provide information used during authentication. + + + + Create a response that can be sent in the WWW-Authenticate header. + + Realm that the user should authenticate in + Array with optional options. + A correct authentication request. + If realm is empty or null. + + + + An authentication response have been received from the web browser. + Check if it's correct + + Contents from the Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + options to specific implementations + Authentication object that is stored for the request. A user class or something like that. + if is invalid + If any of the parameters is empty or null. + + + + Used to invoke the authentication delegate that is used to lookup the user name/realm. + + Realm (domain) that user want to authenticate in + User name + Password used for validation. Some implementations got password in clear text, they are then sent to client. + object that will be stored in the request to help you identify the user if authentication was successful. + true if authentication was successful + + + + Determines if authentication is required. + + HTTP request from browser + true if user should be authenticated. + throw from your delegate if no more attempts are allowed. + If no more attempts are allowed + + + + name used in HTTP request. + + + + + Initializes a new instance of the class. + + Delegate used to provide information used during authentication. + Delegate used to determine if authentication is required (may be null). + + + + Initializes a new instance of the class. + + Delegate used to provide information used during authentication. + + + + Used by test classes to be able to use hardcoded values + + + + + An authentication response have been received from the web browser. + Check if it's correct + + Contents from the Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + First option: true if username/password is correct but not cnonce + + Authentication object that is stored for the request. A user class or something like that. + + if authenticationHeader is invalid + If any of the paramters is empty or null. + + + + Encrypts parameters into a Digest string + + Realm that the user want to log into. + User logging in + Users password. + HTTP method. + Uri/domain that generated the login prompt. + Quality of Protection. + "Number used ONCE" + Hexadecimal request counter. + "Client Number used ONCE" + Digest encrypted string + + + + + + Md5 hex encoded "userName:realm:password", without the quotes. + Md5 hex encoded "method:uri", without the quotes + Quality of Protection + "Number used ONCE" + Hexadecimal request counter. + Client number used once + + + + + Create a response that can be sent in the WWW-Authenticate header. + + Realm that the user should authenticate in + First options specifies if true if username/password is correct but not cnonce. + A correct auth request. + If realm is empty or null. + + + + Decodes authorization header value + + header value + Encoding that the buffer is in + All headers and their values if successful; otherwise null + + NameValueCollection header = DigestAuthentication.Decode("response=\"6629fae49393a05397450978507c4ef1\",\r\nc=00001", Encoding.ASCII); + + Can handle lots of whitespaces and new lines without failing. + + + + Gets the current nonce. + + + + + + Gets the Md5 hash bin hex2. + + To be hashed. + + + + + determines if the nonce is valid or has expired. + + nonce value (check wikipedia for info) + true if the nonce has not expired. + + + + name used in http request. + + + + + Gets or sets whether the token supplied in is a + HA1 generated string. + + + + + cookie sent by the client/browser + + + + + + Constructor. + + cookie identifier + cookie content + id or content is null + id is empty + + + + Gets the cookie HTML representation. + + cookie string + + + + Gets the cookie identifier. + + + + + Cookie value. Set to null to remove cookie. + + + + + Contains server side HTTP request information. + + + + + Contains server side HTTP request information. + + + + + Called during parsing of a . + + Name of the header, should not be URL encoded + Value of the header, should not be URL encoded + If a header is incorrect. + + + + Add bytes to the body + + buffer to read bytes from + where to start read + number of bytes to read + Number of bytes actually read (same as length unless we got all body bytes). + If body is not writable + bytes is null. + offset is out of range. + + + + Clear everything in the request + + + + + Decode body into a form. + + A list with form decoders. + If body contents is not valid for the chosen decoder. + If body is still being transferred. + + + + Create a byte array from the body contents. + + Byte array containing the body contents + If body is still being transferred or request is + not using the POST or PUT verbs + + + + Sets the cookies. + + The cookies. + + + + Create a response object. + + Context for the connected client. + A new . + + + + Gets kind of types accepted by the client. + + + + + Gets or sets body stream. + + + + + Gets whether the body is complete. + + + + + Gets or sets kind of connection used for the session. + + + + + Gets or sets number of bytes in the body. + + + + + Gets cookies that was sent with the request. + + + + + Gets form parameters. + + + + + Gets headers sent by the client. + + + + + Gets or sets version of HTTP protocol that's used. + + + Probably or . + + + + + + Gets whether the request was made by Ajax (Asynchronous JavaScript) + + + + + Gets or sets requested method. + + + Will always be in upper case. + + + + + + Gets parameter from or . + + + + + Gets variables sent in the query string + + + + + Gets a value indicating whether this is secure. + + + + + Remote client's IP address and port + + + + + Gets or sets requested URI. + + + + + Gets URI absolute path divided into parts. + + + // URI is: http://gauffin.com/code/tiny/ + Console.WriteLine(request.UriParts[0]); // result: code + Console.WriteLine(request.UriParts[1]); // result: tiny + + + If you're using controllers than the first part is controller name, + the second part is method name and the third part is Id property. + + + + + + Gets or sets path and query. + + + + Are only used during request parsing. Cannot be set after "Host" header have been + added. + + + + + Chars used to split an URL path into multiple parts. + + + + + Assign a form. + + + + + + Creates a new object that is a copy of the current instance. + + + + A new object that is a copy of this instance. + + 2 + + + + Decode body into a form. + + A list with form decoders. + If body contents is not valid for the chosen decoder. + If body is still being transferred. + + + + Create a byte array from the body contents. + + Byte array containing the body contents + If body is still being transferred or request is + not using the POST or PUT verbs + + + + Cookies + + the cookies + + + + Create a response object. + + A new . + + + + Called during parsing of a . + + Name of the header, should not be URL encoded + Value of the header, should not be URL encoded + If a header is incorrect. + + + + Add bytes to the body + + buffer to read bytes from + where to start read + number of bytes to read + Number of bytes actually read (same as length unless we got all body bytes). + If body is not writable + bytes is null. + offset is out of range. + + + + Clear everything in the request + + + + + Gets or sets a value indicating whether this is secure. + + + + + Path and query (will be merged with the host header) and put in Uri + + + + + + Gets whether the body is complete. + + + + + Gets kind of types accepted by the client. + + + + + Gets or sets body stream. + + + + + Gets or sets kind of connection used for the session. + + + + + Gets or sets number of bytes in the body. + + + + + Gets headers sent by the client. + + + + + Gets or sets version of HTTP protocol that's used. + + + Probably or . + + + + + + Gets or sets requested method. + + + + Will always be in upper case. + + + + + + Gets variables sent in the query string + + + + + Remote client's IP address and port + + + + + Gets or sets requested URI. + + + + + Uri absolute path splitted into parts. + + + // uri is: http://gauffin.com/code/tiny/ + Console.WriteLine(request.UriParts[0]); // result: code + Console.WriteLine(request.UriParts[1]); // result: tiny + + + If you're using controllers than the first part is controller name, + the second part is method name and the third part is Id property. + + + + + + Gets parameter from or . + + + + + Gets form parameters. + + + + + Gets whether the request was made by Ajax (Asynchronous JavaScript) + + + + + Gets cookies that was sent with the request. + + + + + Creates request parsers when needed. + + + + + Creates request parsers when needed. + + + + + Create a new request parser. + + Used when logging should be enabled. + A new request parser. + + + + Create a new request parser. + + Used when logging should be enabled. + A new request parser. + + + + Class that receives Requests from a . + + + + + Client have been disconnected. + + Client that was disconnected. + Reason + + + + + Invoked when a client context have received a new HTTP request + + Client that received the request. + Request that was received. + + + + + Used to create and reuse contexts. + + + + + Used to create es. + + + + + Creates a that handles a connected client. + + Client socket (accepted by the ). + A creates . + + + + Create a secure . + + Client socket (accepted by the ). + HTTPS certificate to use. + Kind of HTTPS protocol. Usually TLS or SSL. + Require an SSL client certificate + A created . + + + + A request have been received from one of the contexts. + + + + + Initializes a new instance of the class. + + The writer. + Amount of bytes to read from the incoming socket stream. + Used to create a request parser. + + + + Create a new context. + + true if socket is running HTTPS. + Client that connected + Client security certificate + Network/SSL stream. + Client socket + A context. + + + + Create a new context. + + true if HTTPS is used. + Remote client + Client security certificate + Network stream, uses . + Client socket + A new context (always). + + + + Create a secure . + + Client socket (accepted by the ). + HTTPS certificate to use. + Kind of HTTPS protocol. Usually TLS or SSL. + Require an SSL client certificate + + A created . + + + + + Creates a that handles a connected client. + + Client socket (accepted by the ). + + A creates . + + + + + True if detailed trace logs should be written. + + + + + A request have been received from one of the contexts. + + + + + Custom network stream to mark sockets as reusable when disposing the stream. + + + + + Creates a new instance of the class for the specified . + + + The that the will use to send and receive data. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Initializes a new instance of the class for the specified with the specified ownership. + + + The that the will use to send and receive data. + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + the value of the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specify the type of access given to the over the provided . + + + The parameter is null. + + + The parameter is not connected. + -or- + the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights and the specified ownership. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specifies the type of access given to the over the provided . + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + + + + + Releases the unmanaged resources used by the and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Webhelper provides helpers for common tasks in HTML. + + + + + Used to let the website use different javascript libraries. + Default is + + + + + Creates a link that invokes through ajax. + + url to fetch + link title + + optional options in format "key, value, key, value". + Javascript options starts with ':'. + + a link tag + + WebHelper.AjaxRequest("/users/add/", "Add user", "method:", "post", "onclick", "validate('this');"); + + + + + Builds a link that updates an element with the fetched ajax content. + + Url to fetch content from + link title + html element to update with the results of the ajax request. + optional options in format "key, value, key, value" + A link tag. + + + + A link that pop ups a Dialog (overlay div) + + url to contents of dialog + link title + name/value of html attributes. + A "a"-tag that popups a dialog when clicked + + WebHelper.DialogLink("/user/show/1", "show user", "onmouseover", "alert('booh!');"); + + + + + Create/Open a dialog box using ajax + + + + + + + + + Close a javascript dialog window/div. + + javascript for closing a dialog. + + + + + Create a <form> tag. + + name of form + action to invoke on submit + form should be posted as ajax + html code + + WebHelper.FormStart("frmLogin", "/user/login", Request.IsAjax); + + + + + Create a link tag. + + url to go to + link title (text that is displayed) + html attributes, name, value, name, value + html code + + WebHelper.Link("/user/show/1", "Show user", "id", "showUser", "onclick", "return confirm('Are you shure?');"); + + + + + Build a link + + url to go to. + title of link (displayed text) + extra html attributes. + a complete link + + + + Build a link + + url to go to. + title of link (displayed text) + extra html attributes. + a complete link + more options + + + + Obsolete + + Obsolete + Obsolete + Obsolete + Obsolete + Obsolete + Obsolete + + + + Obsolete + + Obsolete + Obsolete + Obsolete + Obsolete + Obsolete + Obsolete + Obsolete + + + + Render errors into a UL with class "errors" + + class used by UL-tag. + items to list + an unordered html list. + + + + Render errors into a UL with class "errors" + + class used by UL-tag. + items to list + an unordered html list. + + + + Render errors into a UL with class "errors" + + + + + + + Generates a list with html attributes. + + StringBuilder that the options should be added to. + attributes set by user. + attributes set by any of the helper classes. + + + + Generates a list with html attributes. + + StringBuilder that the options should be added to. + + + + + Container to bind resource names to assemblies + + + + + Instantiates an instance of + + The dot seperated uri the resource maps to + The full resource name + The assembly the resource exists in + + + + Retrieves a stream to the resource + + Null if the resource couldn't be located somehow + + + + Retrieves the assembly the resource resides in + + + + + Retrieves the full name/path of the assembly + + + + + Retrieves the extension of the resource + + + + Returns the Uri without extension + + + Retrieves the full path name to the resource file + + + + All HTTP based exceptions will derive this class. + + + + + Create a new HttpException + + http status code (sent in the response) + error description + + + + Create a new HttpException + + http status code (sent in the response) + error description + inner exception + + + + status code to use in the response. + + + + + We dont want to let the server to die due to exceptions thrown in worker threads. + therefore we use this delegate to give you a change to handle uncaught exceptions. + + Class that the exception was thrown in. + Exception + + Server will throw a InternalServerException in release version if you dont + handle this delegate. + + + + + Delegate used to let authentication modules authenticate the user name and password. + + Realm that the user want to authenticate in + User name specified by client + Can either be user password or implementation specific token. + object that will be stored in a session variable called if authentication was successful. + throw forbidden exception if too many attempts have been made. + + + Use to specify that the token is a HA1 token. (MD5 generated + string from realm, user name and password); Md5String(userName + ":" + realm + ":" + password); + + + + + + Let's you decide on a system level if authentication is required. + + HTTP request from client + true if user should be authenticated. + throw if no more attempts are allowed. + If no more attempts are allowed + + + + New implementation of the HTTP listener. + + + Use the Create methods to create a default listener. + + + + + Initializes a new instance of the class. + + IP Address to accept connections on + TCP Port to listen on, default HTTP port is 80. + Factory used to create es. + address is null. + Port must be a positive number. + + + + Initializes a new instance of the class. + + The address. + The port. + The factory. + The certificate. + + + + Initializes a new instance of the class. + + The address. + The port. + The factory. + The certificate. + Callback to validate SSL client certificates. + The protocol. + True if client SSL certificates are required, otherwise false. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Certificate to use + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Certificate to use + Callback to validate SSL client certificates. + which HTTPS protocol to use, default is TLS. + True if client SSL certificates are required, otherwise false. + Created HTTP listener. + + + + Can be used to create filtering of new connections. + + Accepted socket + + true if connection can be accepted; otherwise false. + + + + + A client have been accepted, but not handled, by the listener. + + + + + Contains some kind of input from the browser/client. + can be QueryString, form data or any other request body content. + + + All names are converted into lower case. + + + + + Base class for request data containers + + + + + Adds a parameter mapped to the presented name + + The name to map the parameter to + The parameter value + + + + Returns true if the container contains the requested parameter + + Parameter id + True if parameter exists + + + + Returns a request parameter + + The name associated with the parameter + + + + Representation of a non-initialized class instance + + + Variable telling the class that it is non-initialized + + + + Initializes a new instance of the class. + + form name. + + + + Initializes a new instance of the class. + + form name. + if set to true all changes will be ignored. + this constructor should only be used by Empty + + + Creates a deep copy of the HttpInput class + The object to copy + The function makes a deep copy of quite a lot which can be slow + + + + Add a new element. Form array elements are parsed + and added in a correct hierarchy. + + Name is converted to lower case. + + name is null. + Cannot add stuff to . + + + + Returns true if the class contains a with the corresponding name. + + The field/query string name + True if the value exists + + + + Parses an item and returns it. + This function is primarily used to parse array items as in user[name]. + + + + + + + Outputs the instance representing all its values joined together + + + + Returns all items as an unescaped query string. + + + + + Extracts one parameter from an array + + Containing the string array + All but the first value + + string test1 = ExtractOne("system[user][extension][id]"); + string test2 = ExtractOne(test1); + string test3 = ExtractOne(test2); + // test1 = user[extension][id] + // test2 = extension[id] + // test3 = id + + + + Resets all data contained by class + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + + An object that can be used to iterate through the collection. + + 2 + + + + Form name as lower case + + + + + Get a form item. + + + Returns if item was not found. + + + + Interface for sessions + + + + + Remove everything from the session + + + + + Remove everything from the session + + True if the session is cleared due to expiration + + + + Session id + + + + + Should + + Name of the session variable + null if it's not set + If the object cant be serialized. + + + + When the session was last accessed. + This property is touched by the HTTP server each time the + session is requested. + + + + + Number of session variables. + + + + + Event triggered upon clearing the session + + + + + Gets keys for all values. + + + + + Arguments sent when a is cleared + + + + + Instantiates the arguments for the event + + True if the session is cleared due to expiration + + + + Gets if the session have expired. + + + + + Delegate for when a is cleared + + this is being cleared. + Arguments for the clearing + + + + Class to make dynamic binding of redirects. Instead of having to specify a number of similar redirect rules + a regular expression can be used to identify redirect URLs and their targets. + + + [a-z0-9]+)", "/users/${target}?find=true", RegexOptions.IgnoreCase) + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + + [a-zA-Z0-9]+)", "/user/${first}")); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to use, can be null + + [a-zA-Z0-9]+)", "/user/{first}", RegexOptions.IgnoreCase)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to apply + true if request should be redirected, false if the request URI should be replaced. + + [a-zA-Z0-9]+)", "/user/${first}", RegexOptions.None)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + Argument is null. + + + + + Process the incoming request. + + incoming HTTP request + outgoing HTTP response + true if response should be sent to the browser directly (no other rules or modules will be processed). + + returning true means that no modules will get the request. Returning true is typically being done + for redirects. + + If request or response is null + + + + Contains all HTTP Methods (according to the HTTP 1.1 specification) + + See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html + + + + + + The DELETE method requests that the origin server delete the resource identified by the Request-URI. + + + + This method MAY be overridden by human intervention (or other means) on the origin server. + The client cannot be guaranteed that the operation has been carried out, even if the status code + returned from the origin server indicates that the action has been completed successfully. + + + However, the server SHOULD NOT indicate success unless, at the time the response is given, + it intends to delete the resource or move it to an inaccessible location. + + + A successful response SHOULD be 200 (OK) if the response includes an entity describing the status, + 202 (Accepted) if the action has not yet been enacted, + or 204 (No Content) if the action has been enacted but the response does not include an entity. + + + If the request passes through a cache and the Request-URI identifies one or more currently cached entities, + those entries SHOULD be treated as stale. Responses to this method are not cacheable. + + + + + + The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI. + + + + If the Request-URI refers to a data-producing process, it is the produced data which shall be returned as the + entity in the response and not the source text of the process, unless that text happens to be the output of the process. + + + The semantics of the GET method change to a "conditional GET" if the request message includes an + If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, or If-Range header field. + A conditional GET method requests that the entity be transferred only under the circumstances described + by the conditional header field(s). The conditional GET method is intended to reduce unnecessary network + usage by allowing cached entities to be refreshed without requiring multiple requests or transferring + data already held by the client. + + + + + + The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. + + + The meta information contained in the HTTP headers in response to a HEAD request SHOULD be identical to the + information sent in response to a GET request. This method can be used for obtaining meta information about + the entity implied by the request without transferring the entity-body itself. + + This method is often used for testing hypertext links for validity, accessibility, and recent modification. + + + + + The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI. + + + This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval. + + + + + The POST method is used to request that the origin server accept the entity enclosed + in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. + + + POST is designed to allow a uniform method to cover the following functions: + + + Annotation of existing resources; + + Posting a message to a bulletin board, newsgroup, mailing list, or similar group of articles; + + Providing a block of data, such as the result of submitting a form, to a data-handling process; + + Extending a database through an append operation. + + + + If a resource has been created on the origin server, the response SHOULD be 201 (Created) and + contain an entity which describes the status of the request and refers to the new resource, and a + Location header (see section 14.30). + + + The action performed by the POST method might not result in a resource that can be identified by a URI. + In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on + whether or not the response includes an entity that describes the result. + + Responses to this method are not cacheable, unless the response includes appropriate Cache-Control + or Expires header fields. However, the 303 (See Other) response can be used to direct the user agent + to retrieve a cacheable resource. + + + + + + The PUT method requests that the enclosed entity be stored under the supplied Request-URI. + + + + + If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a + modified version of the one residing on the origin server. + + If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new + resource by the requesting user agent, the origin server can create the resource with that URI. + + If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response. + + If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to + indicate successful completion of the request. + + If the resource could not be created or modified with the Request-URI, an appropriate error response SHOULD be + given that reflects the nature of the problem. + + + + The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) headers that it does not + understand or implement and MUST return a 501 (Not Implemented) response in such cases. + + + + + + The TRACE method is used to invoke a remote, application-layer loop- back of the request message. + + + + + Contains all HTTP Methods (according to the HTTP 1.1 specification) + + See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html + + + + + + The DELETE method requests that the origin server delete the resource identified by the Request-URI. + + + + This method MAY be overridden by human intervention (or other means) on the origin server. + The client cannot be guaranteed that the operation has been carried out, even if the status code + returned from the origin server indicates that the action has been completed successfully. + + + However, the server SHOULD NOT indicate success unless, at the time the response is given, + it intends to delete the resource or move it to an inaccessible location. + + + A successful response SHOULD be 200 (OK) if the response includes an entity describing the status, + 202 (Accepted) if the action has not yet been enacted, + or 204 (No Content) if the action has been enacted but the response does not include an entity. + + + If the request passes through a cache and the Request-URI identifies one or more currently cached entities, + those entries SHOULD be treated as stale. Responses to this method are not cacheable. + + + + + + The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI. + + + + If the Request-URI refers to a data-producing process, it is the produced data which shall be returned as the + entity in the response and not the source text of the process, unless that text happens to be the output of the process. + + + The semantics of the GET method change to a "conditional GET" if the request message includes an + If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, or If-Range header field. + A conditional GET method requests that the entity be transferred only under the circumstances described + by the conditional header field(s). The conditional GET method is intended to reduce unnecessary network + usage by allowing cached entities to be refreshed without requiring multiple requests or transferring + data already held by the client. + + + + + + The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. + + + The meta information contained in the HTTP headers in response to a HEAD request SHOULD be identical to the + information sent in response to a GET request. This method can be used for obtaining meta information about + the entity implied by the request without transferring the entity-body itself. + + This method is often used for testing hypertext links for validity, accessibility, and recent modification. + + + + + The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI. + + + This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval. + + + + + The POST method is used to request that the origin server accept the entity enclosed + in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. + + + POST is designed to allow a uniform method to cover the following functions: + + + Annotation of existing resources; + + Posting a message to a bulletin board, newsgroup, mailing list, or similar group of articles; + + Providing a block of data, such as the result of submitting a form, to a data-handling process; + + Extending a database through an append operation. + + + + If a resource has been created on the origin server, the response SHOULD be 201 (Created) and + contain an entity which describes the status of the request and refers to the new resource, and a + Location header (see section 14.30). + + + The action performed by the POST method might not result in a resource that can be identified by a URI. + In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on + whether or not the response includes an entity that describes the result. + + Responses to this method are not cacheable, unless the response includes appropriate Cache-Control + or Expires header fields. However, the 303 (See Other) response can be used to direct the user agent + to retrieve a cacheable resource. + + + + + + The PUT method requests that the enclosed entity be stored under the supplied Request-URI. + + + + + If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a + modified version of the one residing on the origin server. + + If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new + resource by the requesting user agent, the origin server can create the resource with that URI. + + If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response. + + If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to + indicate successful completion of the request. + + If the resource could not be created or modified with the Request-URI, an appropriate error response SHOULD be + given that reflects the nature of the problem. + + + + The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) headers that it does not + understand or implement and MUST return a 501 (Not Implemented) response in such cases. + + + + + + The TRACE method is used to invoke a remote, application-layer loop- back of the request message. + + + + + Returns item either from a form or a query string (checks them in that order) + + + + Representation of a non-initialized HttpParam + + + Initialises the class to hold a value either from a post request or a querystring request + + + + The add method is not availible for HttpParam + since HttpParam checks both Request.Form and Request.QueryString + + name identifying the value + value to add + + + + + Checks whether the form or querystring has the specified value + + Name, case sensitive + true if found; otherwise false. + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + + An object that can be used to iterate through the collection. + + 2 + + + + Fetch an item from the form or querystring (in that order). + + + Item if found; otherwise HttpInputItem.EmptyLanguageNode + + + + Serves files that are stored in embedded resources. + + + + + A HttpModule can be used to serve Uri's. The module itself + decides if it should serve a Uri or not. In this way, you can + get a very flexible http application since you can let multiple modules + serve almost similar urls. + + + Throw if you are using a and want to prompt for user name/password. + + + + + Method that process the url + + Information sent by the browser about the request + Information that is being sent back to the client. + Session used to + true if this module handled the request. + + + + Set the log writer to use. + + logwriter to use. + + + + Log something. + + importance of log message + message + + + + If true specifies that the module doesn't consume the processing of a request so that subsequent modules + can continue processing afterwards. Default is false. + + + + + Initializes a new instance of the class. + Runs to make sure the basic mime types are available, they can be cleared later + through the use of if desired. + + + + + Initializes a new instance of the class. + Runs to make sure the basic mime types are available, they can be cleared later + through the use of if desired. + + The log writer to use when logging events + + + + Mimtypes that this class can handle per default + + + + + Loads resources from a namespace in the given assembly to an uri + + The uri to map the resources to + The assembly in which the resources reside + The namespace from which to load the resources + + resourceLoader.LoadResources("/user/", typeof(User).Assembly, "MyLib.Models.User.Views"); + + will make ie the resource MyLib.Models.User.Views.stylesheet.css accessible via /user/stylesheet.css + + The amount of loaded files, giving you the possibility of making sure the resources needed gets loaded + + + + Returns true if the module can handle the request + + + + + Method that process the url + + Information sent by the browser about the request + Information that is being sent back to the client. + Session used to + true if this module handled the request. + + + + List with all mime-type that are allowed. + + All other mime types will result in a Forbidden http status code. + + + + The request requires user authentication. The response MUST include a + WWW-Authenticate header field (section 14.47) containing a challenge + applicable to the requested resource. + + The client MAY repeat the request with a suitable Authorization header + field (section 14.8). If the request already included Authorization + credentials, then the 401 response indicates that authorization has been + refused for those credentials. If the 401 response contains the same challenge + as the prior response, and the user agent has already attempted authentication + at least once, then the user SHOULD be presented the entity that was given in the response, + since that entity might include relevant diagnostic information. + + HTTP access authentication is explained in rfc2617: + http://www.ietf.org/rfc/rfc2617.txt + + (description is taken from + http://www.submissionchamber.com/help-guides/error-codes.php#sec10.4.2) + + + + + Create a new unauhtorized exception. + + + + + + Create a new unauhtorized exception. + + reason to why the request was unauthorized. + inner exception + + + + Create a new unauhtorized exception. + + reason to why the request was unauthorized. + + + + Delegate used to find a realm/domain. + + + + + Realms are used during HTTP Authentication + + + + + + + A complete HTTP server, you need to add a module to it to be able to handle incoming requests. + + + + // this small example will add two web site modules, thus handling + // two different sites. In reality you should add Controller modules or something + // two the website modules to be able to handle different requests. + HttpServer server = new HttpServer(); + server.Add(new WebSiteModule("www.gauffin.com", "Gauffin Telecom AB")); + server.Add(new WebSiteModule("www.vapadi.se", "Remote PBX")); + + // start regular http + server.Start(IPAddress.Any, 80); + + // start https + server.Start(IPAddress.Any, 443, myCertificate); + + + + + + + + + Initializes a new instance of the class. + + Used to get all components used in the server.. + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Form decoders are used to convert different types of posted data to the object types. + + + + + + Initializes a new instance of the class. + + A session store is used to save and retrieve sessions + + + + + Initializes a new instance of the class. + + The log writer. + + + + + Initializes a new instance of the class. + + Form decoders are used to convert different types of posted data to the object types. + The log writer. + + + + + + + Initializes a new instance of the class. + + Form decoders are used to convert different types of posted data to the object types. + A session store is used to save and retrieve sessions + The log writer. + + + + + + + + Adds the specified rule. + + The rule. + + + + Add a to the server. + + module to add + + + + Removes a from the server. + + Module to remove. + + + + Decodes the request body. + + The request. + Failed to decode form data. + + + + Generate a HTTP error page (that will be added to the response body). + response status code is also set. + + Response that the page will be generated in. + . + response body contents. + + + + Generate a HTTP error page (that will be added to the response body). + response status code is also set. + + Response that the page will be generated in. + exception. + + + + Realms are used by the s. + + HTTP request + domain/realm. + + + + Process an incoming request. + + connection to client + request information + response that should be filled + session information + + + + Can be overloaded to implement stuff when a client have been connected. + + + Default implementation does nothing. + + client that disconnected + disconnect reason + + + + Handle authentication + + + + + true if request can be handled; false if not. + Invalid authorization header + + + + Will request authentication. + + + Sends respond to client, nothing else can be done with the response after this. + + + + + + + + Received from a when a request have been parsed successfully. + + that received the request. + The request. + + + + To be able to track request count. + + + + + + + Start the web server using regular HTTP. + + IP Address to listen on, use IpAddress.Any to accept connections on all IP addresses/network cards. + Port to listen on. 80 can be a good idea =) + address is null. + Port must be a positive number. + + + + Accept secure connections. + + IP Address to listen on, use to accept connections on all IP Addresses / network cards. + Port to listen on. 80 can be a good idea =) + Certificate to use + address is null. + Port must be a positive number. + + + + shut down the server and listeners + + + + + write an entry to the log file + + importance of the message + log message + + + + write an entry to the log file + + object that wrote the message + importance of the message + log message + + + + Server that is handling the current request. + + + Will be set as soon as a request arrives to the object. + + + + + Modules used for authentication. The module that is is added first is used as + the default authentication module. + + Use the corresponding property + in the if you are using multiple websites. + + + + Form decoder providers are used to decode request body (which normally contains form data). + + + + + Server name sent in HTTP responses. + + + Do NOT include version in name, since it makes it + easier for hackers. + + + + + Name of cookie where session id is stored. + + + + + Specified where logging should go. + + + + + + + + Number of connections that can wait to be accepted by the server. + + Default is 10. + + + + Gets or sets maximum number of allowed simultaneous requests. + + + + This property is useful in busy systems. The HTTP server + will start queuing new requests if this limit is hit, instead + of trying to process all incoming requests directly. + + + The default number if allowed simultaneous requests are 10. + + + + + + Gets or sets maximum number of requests queuing to be handled. + + + + The WebServer will start turning requests away if response code + to indicate that the server + is too busy to be able to handle the request. + + + + + + Realms are used during HTTP authentication. + Default realm is same as server name. + + + + + Let's to receive unhandled exceptions from the threads. + + + Exceptions will be thrown during debug mode if this event is not used, + exceptions will be printed to console and suppressed during release mode. + + + + Container for posted form data + + + Instance to help mark a non-initialized form + + + Initializes a form container with the specified name + + + + Makes a deep copy of the input + + The input to copy + + + + Adds a file to the collection of posted files + + The file to add + If the file is already added + If file is null + If the instance is HttpForm.EmptyForm which cannot be modified + + + + Checks if the form contains a specified file + + Field name of the file parameter + True if the file exists + If the instance is HttpForm.EmptyForm which cannot be modified + + + + Retrieves a file held by by the form + + The identifier of the file + The requested file or null if the file was not found + If name is null or empty + If the instance is HttpForm.EmptyForm which cannot be modified + + + Disposes all held HttpFile's and resets values + + + + Retrieves the number of files added to the + + 0 if no files are added + + + + The requested resource was not found in the web server. + + + + + Create a new exception + + message describing the error + inner exception + + + + Create a new exception + + message describing the error + + + + This class is created as a wrapper, since there are two different cookie types in .Net (Cookie and HttpCookie). + The framework might switch class in the future and we dont want to have to replace all instances + + + + + Let's copy all the cookies. + + value from cookie header. + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Remove all cookies. + + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Remove a cookie from the collection. + + Name of cookie. + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier (null if not existing). + + + + + The request could not be understood by the server due to malformed syntax. + The client SHOULD NOT repeat the request without modifications. + + Text taken from: http://www.submissionchamber.com/help-guides/error-codes.php + + + + + Create a new bad request exception. + + reason to why the request was bad. + + + + Create a new bad request exception. + + reason to why the request was bad. + inner exception + + + + A session stored in memory. + + + + + + + A unique id used by the sessions store to identify the session + + + + Id + + + + + + Remove everything from the session + + + + + Clears the specified expire. + + True if the session is cleared due to expiration + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Session id + + + + + Should + + Name of the session variable + null if it's not set + + + + when the session was last accessed. + + + Used to determine when the session should be removed. + + + + + Number of values in the session + + + + + Flag to indicate that the session have been changed + and should be saved into the session store. + + + + + Event triggered upon clearing the session + + + + + Gets keys for all values. + + + + + Small design by contract implementation. + + + + + Check whether a parameter is empty. + + Parameter value + Parameter name, or error description. + value is empty. + + + + Checks whether a parameter is null. + + Parameter value + Parameter name, or error description. + value is null. + + + + Checks whether a parameter is null. + + + Parameter value + Parameter name, or error description. + value is null. + + + + The server encountered an unexpected condition which prevented it from fulfilling the request. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + error message. + + + + Initializes a new instance of the class. + + error message. + inner exception. + + + + cookie being sent back to the browser. + + + + + + Constructor. + + cookie identifier + cookie content + cookie expiration date. Use DateTime.MinValue for session cookie. + id or content is null + id is empty + + + + Create a new cookie + + name identifying the cookie + cookie value + when the cookie expires. Setting DateTime.MinValue will delete the cookie when the session is closed. + Path to where the cookie is valid + Domain that the cookie is valid for. + + + + Create a new cookie + + Name and value will be used + when the cookie expires. + + + + Gets the cookie HTML representation. + + cookie string + + + + When the cookie expires. + DateTime.MinValue means that the cookie expires when the session do so. + + + + + Cookie is only valid under this path. + + + + + Event driven parser used to parse incoming HTTP requests. + + + The parser supports partial messages and keeps the states between + each parsed buffer. It's therefore important that the parser gets + ed if a client disconnects. + + + + + Parse partial or complete message. + + buffer containing incoming bytes + where in buffer that parsing should start + number of bytes to parse + Unparsed bytes left in buffer. + BadRequestException. + + + + Clear parser state. + + + + + Current state in parser. + + + + + A request have been successfully parsed. + + + + + More body bytes have been received. + + + + + Request line have been received. + + + + + A header have been received. + + + + + Gets or sets the log writer. + + + + + Current state in the parsing. + + + + + Should parse the request line + + + + + Searching for a complete header name + + + + + Searching for colon after header name (ignoring white spaces) + + + + + Searching for start of header value (ignoring white spaces) + + + + + Searching for a complete header value (can span over multiple lines, as long as they are prefixed with one/more whitespaces) + + + + + Adding bytes to body + + + + + The website module let's you handle multiple websites in the same server. + It uses the "Host" header to check which site you want. + + It's recommended that you do not + add any other modules to HttpServer if you are using the website module. Instead, + add all wanted modules to each website. + + + + + + domain name that should be handled. + + + + + Method that process the url + + Information sent by the browser about the request + Information that is being sent back to the client. + Session used to + + + + Name of site. + + + + + This decoder converts XML documents to form items. + Each element becomes a subitem in the form, and each attribute becomes an item. + + + // xml: somethingdata + // result: + // form["hello"].Value = "something" + // form["hello"]["id"].Value = 1 + // form["hello"]["world]["id"].Value = 1 + // form["hello"]["world"].Value = "data" + + + The original xml document is stored in form["__xml__"].Value. + + + + + + + Stream containing the content + Content type (with any additional info like boundry). Content type is always supplied in lower case + Stream encoding + Note: contentType and encoding are not used? + A http form, or null if content could not be parsed. + + + + + Recursive function that will go through an xml element and store it's content + to the form item. + + (parent) Item in form that content should be added to. + Node that should be parsed. + + + + Checks if the decoder can handle the mime type + + Content type (with any additional info like boundry). Content type is always supplied in lower case. + True if the decoder can parse the specified content type + + + + Used to handle INI files. + + + + + Add a new section. + + Name of section. + + + iniFile.Add("users"); + iniFile["users"].Add("Jonas"); + + + + + + Checks if ini file contains the specified section. + + Name of section + true if section exists; otherwise false. + + + + Load a INI file from a stream reader. + + StreamReader containing INI file data. + if sucessfully parsed. + If stream do not contain a valid INI file. + + + + Read ini file data from a stream. + + Stream to read from + if sucessfully parsed. + If stream do not contain a valid INI file. + + + + Read a ini file. + + Path and filename + if sucessfully parsed. + If stream do not contain a valid INI file. + + + + Load INI file from a string variable. + + Contains ini file contents. + A . + If stream do not contain a valid INI file. + + + + Write a INI file to disk. + + Path and filename + If file is not writable or path do not exist. + + + + Returns a that represents the current . + + + A that represents the current . + + + + + Gets a section. + + Name of section. + if found; otherwise null. + + + + A section in a INI file. + + + + + Initializes a new instance of the class. + + The name. + + + + Add a new parameter + + Name + Value + + + + Checks if section contains a parameter + + Name of parameter + true if found; otherwise false. + + + + Remove a parameter + + Name of parameter. + true if found and removed; otherwise false. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + + + + Gets or sets a parameter value. + + Name of parameter. + Value or null if parameter was not found. + + + + Gets or sets name of section. + + + + + Simple template engine. + This engine turns templates into C# code and compiles them at runtime + to .NET assemblies. This makes the templates blazing fast. The templates + are only recompiled if they have been changed on disk. + + + + + Interface for template rendering engines + + + + + Render the template + + Filename of the template to render + A list of key/value pairs to pass to the template + The rendered output + If template is not found. + + + + Used to get correct names for generics. + + + + + + + Response that is sent back to the web browser / client. + + + + A response can be sent if different ways. The easiest one is + to just fill the Body stream with content, everything else + will then be taken care of by the framework. The default content-type + is text/html, you should change it if you send anything else. + + The second and slightly more complex way is to send the response + as parts. Start with sending the header using the SendHeaders method and + then you can send the body using SendBody method, but do not forget + to set and before doing so. + + + + + // Example using response body. + class MyModule : HttpModule + { + public override bool Process(IHttpRequest request, IHttpResponse response, IHttpSession session) + { + StreamWriter writer = new StreamWriter(response.Body); + writer.WriteLine("Hello dear World!"); + writer.Flush(); + + // return true to tell webserver that we've handled the url + return true; + } + } + + + todo: add two examples, using SendHeaders/SendBody and just the Body stream. + + + + Response that is sent back to the web browser / client. + + A response can be sent if different ways. The easiest one is + to just fill the Body stream with content, everything else + will then be taken care of by the framework. The default content-type + is text/html, you should change it if you send anything else. + + The second and slighty more complex way is to send the response + as parts. Start with sending the header using the SendHeaders method and + then you can send the body using SendBody method, but do not forget + to set ContentType and ContentLength before doing so. + + + public void MyHandler(IHttpRequest request, IHttpResponse response) + { + + } + + + + + Add another header to the document. + + Name of the header, case sensitive, use lower cases. + Header values can span over multiple lines as long as each line starts with a white space. New line chars should be \r\n + If headers already been sent. + If value conditions have not been met. + Adding any header will override the default ones and those specified by properties. + + + + Send headers and body to the browser. + + If content have already been sent. + + + + Make sure that you have specified ContentLength and sent the headers first. + + + If headers have not been sent. + + offest of first byte to send + number of bytes to send. + + + This method can be used if you want to send body contents without caching them first. This + is recommended for larger files to keep the memory usage low. + + + + Make sure that you have specified ContentLength and sent the headers first. + + + If headers have not been sent. + + + + This method can be used if you want to send body contents without caching them first. This + is recommended for larger files to keep the memory usage low. + + + + Send headers to the client. + + If headers already been sent. + + + + + + + Redirect client to somewhere else using the 302 status code. + + Destination of the redirect + If headers already been sent. + You can not do anything more with the request when a redirect have been done. This should be your last + action. + + + + redirect to somewhere + + where the redirect should go + + No body are allowed when doing redirects. + + + + + The body stream is used to cache the body contents + before sending everything to the client. It's the simplest + way to serve documents. + + + + + Defines the version of the HTTP Response for applications where it's required + for this to be forced. + + + + + The chunked encoding modifies the body of a message in order to + transfer it as a series of chunks, each with its own size indicator, + followed by an OPTIONAL trailer containing entity-header fields. This + allows dynamically produced content to be transferred along with the + information necessary for the recipient to verify that it has + received the full message. + + + + + Kind of connection + + + + + Encoding to use when sending stuff to the client. + + Default is UTF8 + + + + Number of seconds to keep connection alive + + Only used if Connection property is set to ConnectionType.KeepAlive + + + + Status code that is sent to the client. + + Default is HttpStatusCode.Ok + + + + Information about why a specific status code was used. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + + + Kind of content in the body + + Default is text/html + + + + Headers have been sent to the client- + + You can not send any additional headers if they have already been sent. + + + + The whole response have been sent. + + + + + Cookies that should be created/changed. + + + + + Initializes a new instance of the class. + + Client that send the . + Contains information of what the client want to receive. + cannot be empty. + + + + Initializes a new instance of the class. + + Client that send the . + Version of HTTP protocol that the client uses. + Type of HTTP connection used. + + + + Add another header to the document. + + Name of the header, case sensitive, use lower cases. + Header values can span over multiple lines as long as each line starts with a white space. New line chars should be \r\n + If headers already been sent. + If value conditions have not been met. + Adding any header will override the default ones and those specified by properties. + + + + Send headers and body to the browser. + + If content have already been sent. + + + + Make sure that you have specified and sent the headers first. + + + If headers have not been sent. + + offset of first byte to send + number of bytes to send. + + + This method can be used if you want to send body contents without caching them first. This + is recommended for larger files to keep the memory usage low. + + + + Make sure that you have specified and sent the headers first. + + + If headers have not been sent. + + + + This method can be used if you want to send body contents without caching them first. This + is recommended for larger files to keep the memory usage low. + + + + Send headers to the client. + + If headers already been sent. + + + + + + + Redirect client to somewhere else using the 302 status code. + + Destination of the redirect + If headers already been sent. + You can not do anything more with the request when a redirect have been done. This should be your last + action. + + + + redirect to somewhere + + where the redirect should go + + No body are allowed when doing redirects. + + + + + The body stream is used to cache the body contents + before sending everything to the client. It's the simplest + way to serve documents. + + + + + The chunked encoding modifies the body of a message in order to + transfer it as a series of chunks, each with its own size indicator, + followed by an OPTIONAL trailer containing entity-header fields. This + allows dynamically produced content to be transferred along with the + information necessary for the recipient to verify that it has + received the full message. + + + + + Defines the version of the HTTP Response for applications where it's required + for this to be forced. + + + + + Kind of connection + + + + + Encoding to use when sending stuff to the client. + + Default is UTF8 + + + + Number of seconds to keep connection alive + + Only used if Connection property is set to . + + + + Status code that is sent to the client. + + Default is + + + + Information about why a specific status code was used. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + + + Kind of content in the body + + Default type is "text/html" + + + + Headers have been sent to the client- + + You can not send any additional headers if they have already been sent. + + + + The whole response have been sent. + + + + + Cookies that should be created/changed. + + + + + Will contain helper functions for javascript. + + + + + Requests a url through ajax + + url to fetch. Url is NOT enclosed in quotes by the implementation. You need to do that yourself. + optional options in format "key, value, key, value", used in JS request object. All keys should end with colon. + a link tag + onclick attribute is used by this method. + + + // plain text + JSHelper.AjaxRequest("'/user/show/1'"); + + // ajax request using this.href + string link = "<a href=\"/user/call/1\" onclick=\"" + JSHelper.AjaxRequest("this.href") + "/<call user</a>"; + + + + + + Ajax requests that updates an element with + the fetched content + + url to fetch. Url is NOT enclosed in quotes by the implementation. You need to do that yourself. + element to update + options in format "key, value, key, value". All keys should end with colon. + A link tag. + + + JSHelper.AjaxUpdater("'/user/show/1'", "user", "onsuccess:", "alert('hello');", "asynchronous:", "true"); + + + + + + Opens contents in a dialog window. + + url to contents of dialog + link title + name, value, name, value, all parameter names should end with colon. + + + + Close a javascript dialog window/div. + + javascript for closing a dialog. + + + + + Used to queue incoming requests. + + + + + Initializes a new instance of the class. + + Called when a request should be processed. + + + + Increment the by 1 in a thread safe manor. + + + + + Decrement the by 1 in a thread safe manor. + + + + + Used to process queued requests. + + + + + Gets or sets maximum number of allowed simultaneous requests. + + + + + Gets or sets maximum number of requests queuing to be handled. + + + + + Specifies how many requests the HTTP server is currently processing. + + + + + Used two queue incoming requests to avoid + thread starvation. + + + + + Method used to process a queued request + + Context that the request was received from. + Request to process. + + + + Event arguments used when a new header have been parsed. + + + + + Initializes a new instance of the class. + + Name of header. + Header value. + + + + Initializes a new instance of the class. + + + + + Gets or sets header name. + + + + + Gets or sets header value. + + + + + A reverse proxy are used to act as a bridge between local (protected/hidden) websites + and public clients. + + A typical usage is to allow web servers on non standard ports to still be available + to the public clients, or allow web servers on private ips to be available. + + + + + + + Base url requested from browser + Base url on private web server + + // this will return contents from http://192.168.1.128/view/jonas when client requests http://www.gauffin.com/user/view/jonas + _server.Add(new ReverseProxyModule("http://www.gauffin.com/user/", "http://192.168.1.128/"); + + + + + Method that determines if an url should be handled or not by the module + + Url requested by the client. + true if module should handle the url. + + + + Method that process the url + + Information sent by the browser about the request + Information that is being sent back to the client. + Session used to + + + + Generic helper functions for HTTP + + + + + Version string for HTTP v1.0 + + + + + Version string for HTTP v1.1 + + + + + Parses a query string. + + Query string (URI encoded) + A object if successful; otherwise + queryString is null. + If string cannot be parsed. + + + + If you string contains %2d instead of =, you have encoded your string + incorrectly. It's not a bug in the http server that it isn't decoded. + + + + + + + + + + + + + + + + + Represents a field in a multipart form + + + + Cookies that should be set. + + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + + + + Copy a request cookie + + + When the cookie should expire + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Remove all cookies + + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier (null if not existing). + + + + + Helpers to make XML handling easier + + + + + Serializes object to XML. + + object to serialize. + XML + + Removes name spaces and adds indentation + + + + + Create an object from a XML string + + Type of object + XML string + object + + + + Delegate used by to populate select options. + + current object (for instance a User). + Text that should be displayed in the value part of a <optiongt;-tag. + Text shown in the select list. + + // Class that is going to be used in a SELECT-tag. + public class User + { + private readonly string _realName; + private readonly int _id; + public User(int id, string realName) + { + _id = id; + _realName = realName; + } + public string RealName + { + get { return _realName; } + } + + public int Id + { + get { return _id; } + } + } + + // Using an inline delegate to generate the select list + public void UserInlineDelegate() + { + List<User> items = new List<User>(); + items.Add(new User(1, "adam")); + items.Add(new User(2, "bertial")); + items.Add(new User(3, "david")); + string htmlSelect = Select("users", "users", items, delegate(object o, out object id, out object value) + { + User user = (User)o; + id = user.Id; + value = user.RealName; + }, 2, true); + } + + // Using an method as delegate to generate the select list. + public void UseExternalDelegate() + { + List<User> items = new List<User>(); + items.Add(new User(1, "adam")); + items.Add(new User(2, "bertial")); + items.Add(new User(3, "david")); + string htmlSelect = Select("users", "users", items, UserOptions, 1, true); + } + + // delegate returning id and title + public static void UserOptions(object o, out object id, out object title) + { + User user = (User)o; + id = user.Id; + value = user.RealName; + } /// + + + + Parses a HTTP request directly from a stream + + + + + Create a new request parser + + delegate receiving log entries. + + + + Add a number of bytes to the body + + buffer containing more body bytes. + starting offset in buffer + number of bytes, from offset, to read. + offset to continue from. + + + + Remove all state information for the request. + + + + + Parse request line + + + If line is incorrect + Expects the following format: "Method SP Request-URI SP HTTP-Version CRLF" + + + + We've parsed a new header. + + Name in lower case + Value, unmodified. + If content length cannot be parsed. + + + + Parse a message + + bytes to parse. + where in buffer that parsing should start + number of bytes to parse, starting on . + offset (where to start parsing next). + BadRequestException. + + + + Gets or sets the log writer. + + + + + Current state in parser. + + + + + A request have been successfully parsed. + + + + + More body bytes have been received. + + + + + Request line have been received. + + + + + A header have been received. + + + + + Arguments used when more body bytes have come. + + + + + Initializes a new instance of the class. + + buffer that contains the received bytes. + offset in buffer where to start processing. + number of bytes from that should be parsed. + + + + Initializes a new instance of the class. + + + + + Gets or sets buffer that contains the received bytes. + + + + + Gets or sets number of bytes from that should be parsed. + + + + + Gets or sets offset in buffer where to start processing. + + + + + Contains a connection to a browser/client. + + + + + Disconnect from client + + error to report in the event. + + + + Send a response. + + Either or + HTTP status code + reason for the status code. + HTML body contents, can be null or empty. + A content type to return the body as, i.e. 'text/html' or 'text/plain', defaults to 'text/html' if null or empty + If is invalid. + + + + Send a response. + + Either or + HTTP status code + reason for the status code. + + + + Send a response. + + + + + + send a whole buffer + + buffer to send + + + + + Send data using the stream + + Contains data to send + Start position in buffer + number of bytes to send + + + + + + Closes the streams and disposes of the unmanaged resources + + + + + Using SSL or other encryption method. + + + + + Using SSL or other encryption method. + + + + + Gets the client's security certificate. + + + + + Gets or sets whether the context should not be reused when disconnected. + + + + + The context have been disconnected. + + + Event can be used to clean up a context, or to reuse it. + + + + + A request have been received in the context. + + + + + A have been disconnected. + + + + + Initializes a new instance of the class. + + Reason to disconnection. + + + + Gets reason to why client disconnected. + + + + + + + + + + Initializes a new instance of the class. + + The request. + + + + Gets received request. + + + + + Client X.509 certificate, X.509 chain, and any SSL policy errors encountered + during the SSL stream creation + + + + + Client security certificate + + + + + Client security certificate chain + + + + + Any SSL policy errors encountered during the SSL stream creation + + + + + Used to inform http server that + + + + + Eventarguments used when an exception is thrown by a module + + the exception + + + + Exception thrown in a module + + + + + Container class for posted files + + + + + Creates a container for a posted file + + The identifier of the post field + The file path + The content type of the file + The name of the file uploaded + If any parameter is null or empty + + + + Creates a container for a posted file + + If any parameter is null or empty + + + Destructor disposing the file + + + + Deletes the temporary file + + True if manual dispose + + + + Disposing interface, cleans up managed resources (the temporary file) and suppresses finalization + + + + + The name/id of the file + + + + + The full file path + + + + + The name of the uploaded file + + + + + The type of file + + + + + Contains a connection to a browser/client. + + + Remember to after you have hooked the event. + + TODO: Maybe this class should be broken up into HttpClientChannel and HttpClientContext? + + + + Initializes a new instance of the class. + + true if the connection is secured (SSL/TLS) + client that connected. + Stream used for communication + Client security certificate + Used to create a . + Size of buffer to use when reading data. Must be at least 4096 bytes. + Client socket + If fails + Stream must be writable and readable. + + + + Process incoming body bytes. + + + Bytes + + + + + + + + + + + Start reading content. + + + Make sure to call base.Start() if you override this method. + + + + + Clean up context. + + + Make sure to call base.Cleanup() if you override the method. + + + + + Disconnect from client + + error to report in the event. + + + BadRequestException. + + + + Send a response. + + Either or + HTTP status code + reason for the status code. + HTML body contents, can be null or empty. + A content type to return the body as, i.e. 'text/html' or 'text/plain', defaults to 'text/html' if null or empty + If is invalid. + + + + Send a response. + + Either or + HTTP status code + reason for the status code. + + + + Send a response. + + + + + + send a whole buffer + + buffer to send + + + + + Send data using the stream + + Contains data to send + Start position in buffer + number of bytes to send + + + + + + Gets or sets whether the context is available for re use. + + + + + This context have been cleaned, which means that it can be reused. + + + + + Context have been started (a new client have connected) + + + + + Gets or sets if + + + + + Overload to specify own type. + + + Must be specified before the context is being used. + + + + + Using SSL or other encryption method. + + + + + Using SSL or other encryption method. + + + + + Specify which logger to use. + + + + + Gets or sets the network stream. + + + + + Gets the client's security certificate. + + + + + Gets or sets IP address that the client connected from. + + + + + Gets or sets port that the client connected from. + + + + + The context have been disconnected. + + + Event can be used to clean up a context, or to reuse it. + + + + + A request have been received in the context. + + + + + Lists content type mime types. + + + + + text/plain + + + + + text/haml + + + + + content type for javascript documents = application/javascript + + + + RFC 4329 states that text/javascript have been superseeded by + application/javascript. You might still want to check browser versions + since older ones do not support application/javascript. + + Browser support: http://krijnhoetmer.nl/stuff/javascript/mime-types/ + + + + + text/xml + + + + + A list of content types + + + + + + + Semicolon separated content types. + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + + + + Searches for the specified type + + Can also be a part of a type (searching for "xml" would return true for "application/xml"). + true if type was found. + + + + Get this first content type. + + + + + Fetch a content type + + Part of type ("xml" would return "application/xml") + + All content types are in lower case. + + + + The "basic" authentication scheme is based on the model that the + client must authenticate itself with a user-ID and a password for + each realm. The realm value should be considered an opaque string + which can only be compared for equality with other realms on that + server. The server will service the request only if it can validate + the user-ID and password for the protection space of the Request-URI. + There are no optional authentication parameters. + + + + + Initializes a new instance of the class. + + Delegate used to provide information used during authentication. + Delegate used to determine if authentication is required (may be null). + + + + Initializes a new instance of the class. + + Delegate used to provide information used during authentication. + + + + Create a response that can be sent in the WWW-Authenticate header. + + Realm that the user should authenticate in + Not used in basic auth + A correct auth request. + + + + An authentication response have been received from the web browser. + Check if it's correct + + Contents from the Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + Not used in basic auth + Authentication object that is stored for the request. A user class or something like that. + if authenticationHeader is invalid + If any of the paramters is empty or null. + + + + name used in http request. + + + + + Type of HTTP connection + + + + + Connection is closed after each request-response + + + + + Connection is kept alive for X seconds (unless another request have been made) + + + + + Requests message-body be sent with an encoding to be specified in the "Transfer-Encoding" header. + + + + + The purpose of this module is to serve files. + + + + + Initializes a new instance of the class. + + Uri to serve, for instance "/files/" + Path on hard drive where we should start looking for files + If true a Last-Modifed header will be sent upon requests urging web browser to cache files + + + + Initializes a new instance of the class. + + Uri to serve, for instance "/files/" + Path on hard drive where we should start looking for files + + + + Mimtypes that this class can handle per default + + + + + Determines if the request should be handled by this module. + Invoked by the + + + true if this module should handle it. + + + Illegal path + + + + check if source contains any of the chars. + + + + + + + + Method that process the Uri. + + Information sent by the browser about the request + Information that is being sent back to the client. + Session used to + Failed to find file extension + File type is forbidden. + + + + return a file extension from an absolute Uri path (or plain filename) + + + + + + + List with all mime-type that are allowed. + + All other mime types will result in a Forbidden http status code. + + + + characters that may not exist in a path. + + + fileMod.ForbiddenChars = new string[]{ "\\", "..", ":" }; + + + + + represents a HTTP input item. Each item can have multiple sub items, a sub item + is made in a HTML form by using square brackets + + + // becomes: + Console.WriteLine("Value: {0}", form["user"]["FirstName"].Value); + + + All names in a form SHOULD be in lowercase. + + + + Representation of a non-initialized . + + + + Initializes an input item setting its name/identifier and value + + Parameter name/id + Parameter value + + + Creates a deep copy of the item specified + The item to copy + The function makes a deep copy of quite a lot which can be slow + + + + Add another value to this item + + Value to add. + Cannot add stuff to . + + + + checks if a sub-item exists (and has a value). + + name in lower case + true if the sub-item exists and has a value; otherwise false. + + + Returns a formatted representation of the instance with the values of all contained parameters + + + + Outputs the string in a formatted manner + + A prefix to append, used internally + produce a query string + + + + Add a sub item. + + Can contain array formatting, the item is then parsed and added in multiple levels + Value to add. + Argument is null. + Cannot add stuff to . + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + + An object that can be used to iterate through the collection. + + 2 + + + + Outputs the string in a formatted manner + + A prefix to append, used internally + + + + + Number of values + + + + + Get a sub item + + name in lower case. + if no item was found. + + + + Name of item (in lower case). + + + + + Returns the first value, or null if no value exist. + + + + + Returns the last value, or null if no value exist. + + + + + Returns the list with values. + + + + + + + name in lower case + + + + + The object form class takes an object and creates form items for it. + + + + + Initializes a new instance of the class. + + + form name *and* id. + action to do when form is posted. + + + + + Initializes a new instance of the class. + + form name *and* id. + action to do when form is posted. + object to get values from + + + + Initializes a new instance of the class. + + form action. + object to get values from. + + + + write out the FORM-tag. + + generated html code + + + + Writeout the form tag + + form should be posted through ajax. + generated html code + + + + Generates a text box. + + + + generated html code + + + + password box + + + + generated html code + + + + Hiddens the specified property name. + + Name of the property. + The options. + generated html code + + + + Labels the specified property name. + + property in object. + caption + generated html code + + + + Generate a checkbox + + property in object + checkbox value + additional html attributes. + generated html code + + + + Write a html select tag + + object property. + id column + The title column. + The options. + + + + + Selects the specified property name. + + Name of the property. + The items. + The id column. + The title column. + The options. + + + + + Write a submit tag. + + button caption + html submit tag + + + + html end form tag + + html + + + + The server understood the request, but is refusing to fulfill it. + Authorization will not help and the request SHOULD NOT be repeated. + If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, + it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information + available to the client, the status code 404 (Not Found) can be used instead. + + Text taken from: http://www.submissionchamber.com/help-guides/error-codes.php + + + + + Initializes a new instance of the class. + + error message + + + + Used when the request line have been successfully parsed. + + + + + Initializes a new instance of the class. + + The HTTP method. + The URI path. + The HTTP version. + + + + Initializes a new instance of the class. + + + + + Gets or sets http method. + + + Should be one of the methods declared in . + + + + + Gets or sets the version of the HTTP protocol that the client want to use. + + + + + Gets or sets requested URI path. + + + + + Inversion of control interface. + + + + + Add a component instance + + Interface type + Instance to add + + + + Get a component. + + Interface type + Component if registered, otherwise null. + + Component will get created if needed. + + + + + Checks if the specified component interface have been added. + + + true if found; otherwise false. + + + + Add a component. + + Type being requested. + Type being created. + + + + Implementation of the SCGI protocol. + + + The implementation reads configuration from an INI file called "scgi.ini", it should + be placed in the same folder as the server. The file should contain file mappings to + socket severs: + + [main] + php: localhost:4082 + py: 192.168.1.20:8037 + + + + + + + Method that process the url + + Information sent by the browser about the request + Information that is being sent back to the client. + Session used to + true if this module handled the request. + + + + Start module, will try to read the config file. + + + + + + + + http://www.faqs.org/rfcs/rfc1867.html + + + + + multipart/form-data + + + + + form-data + + + + + + + Stream containing the content + Content type (with any additional info like boundry). Content type is always supplied in lower case + Stream enconding + A http form, or null if content could not be parsed. + If contents in the stream is not valid input data. + If any parameter is null + + + + Checks if the decoder can handle the mime type + + Content type (with any additional info like boundry). Content type is always supplied in lower case. + True if the decoder can parse the specified content type + + + + This provider is used to let us implement any type of form decoding we want without + having to rewrite anything else in the server. + + + + + + + Should contain boundary and type, as in: multipart/form-data; boundary=---------------------------230051238959 + Stream containing form data. + Encoding used when decoding the stream + if no parser was found. + If stream is null or not readable. + If stream contents cannot be decoded properly. + + + + Add a decoder. + + + + + + + Number of added decoders. + + + + + Use with care. + + + + + Decoder used for unknown content types. + + + + + Add a component instance + + Interface type + Instance to add + + + + Get a component. + + Interface type + Component if registered, otherwise null. + + Component will get created if needed. + + + + If instance cannot be created. + + + + Checks if the specified component interface have been added. + + + true if found; otherwise false. + + + + Add a component. + + Type being requested. + Type being created. + Type have already been mapped. + + + + Invoked when a client have been accepted by the + + + Can be used to revoke incoming connections + + + + + Initializes a new instance of the class. + + The socket. + + + + Client may not be handled. + + + + + Accepted socket. + + + + + Client should be revoked. + + + + diff --git a/thirdparty/HttpServer/license.txt b/thirdparty/HttpServer/license.txt new file mode 100644 index 000000000..3668016fc --- /dev/null +++ b/thirdparty/HttpServer/license.txt @@ -0,0 +1,69 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +1. You must give any other recipients of the Work or Derivative Works a copy of this License; and + +2. You must cause any modified files to carry prominent notices stating that You changed the files; and + +3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + +4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. \ No newline at end of file diff --git a/thirdparty/HttpServer/xunit.dll b/thirdparty/HttpServer/xunit.dll new file mode 100644 index 0000000000000000000000000000000000000000..c02db484cc71f08df888f7bd1590ff1bd0a975cd GIT binary patch literal 65536 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 literal 0 HcmV?d00001