Browse Source

initial copy from zimbraEmail with replaced strings & filenames

andre 2 years ago
parent
commit
a4ed76be34
500 changed files with 44060 additions and 0 deletions
  1. 9 0
      app/Config/configuration.yml
  2. 1 0
      app/Config/cron.yml
  3. 1 0
      app/Config/di/buildWithDefaultMethod.yml
  4. 1 0
      app/Config/di/interface.yml
  5. 2 0
      app/Config/di/register.yml
  6. 9 0
      app/Config/di/rewrite.yml
  7. 1 0
      app/Config/di/services.yml
  8. 7 0
      app/Config/events.php
  9. 2 0
      app/Config/hooks.yml
  10. 7 0
      app/Config/menu/admin.yml
  11. 1 0
      app/Config/menu/client.yml
  12. 19 0
      app/Config/sidebars.yml
  13. 1 0
      app/Config/ui/admin/home/index.yml
  14. 23 0
      app/Configuration/Addon/Activate/After.php
  15. 23 0
      app/Configuration/Addon/Activate/Before.php
  16. 23 0
      app/Configuration/Addon/Config/After.php
  17. 23 0
      app/Configuration/Addon/Config/Before.php
  18. 23 0
      app/Configuration/Addon/Deactivate/After.php
  19. 23 0
      app/Configuration/Addon/Deactivate/Before.php
  20. 0 0
      app/Configuration/Addon/Others/.gitkeep
  21. 22 0
      app/Configuration/Addon/Update/After.php
  22. 22 0
      app/Configuration/Addon/Update/Before.php
  23. 1 0
      app/Configuration/Addon/Update/Patch/.gitkeep
  24. 100 0
      app/Cron/Migration.php
  25. 79 0
      app/Database/M2M0P0/data.sql
  26. 0 0
      app/Database/M2M0P0/schema.sql
  27. 11 0
      app/Database/data.sql
  28. 0 0
      app/Database/schema.sql
  29. 23 0
      app/Enums/ControllerEnums.php
  30. 100 0
      app/Enums/Kerio.php
  31. 31 0
      app/Enums/ProductParams.php
  32. 20 0
      app/Enums/Response.php
  33. 30 0
      app/Enums/Size.php
  34. 96 0
      app/Helpers/BuildUrlExtended.php
  35. 15 0
      app/Helpers/ErrorCodesLib.php
  36. 74 0
      app/Helpers/KerioManager.php
  37. 57 0
      app/Helpers/Storage.php
  38. 23 0
      app/Hooks/AdminAreaFooterOutput.php
  39. 57 0
      app/Hooks/ClientAreaPrimarySidebar.php
  40. 35 0
      app/Http/Actions/AdminLink.php
  41. 32 0
      app/Http/Actions/AdminServicesTabFields.php
  42. 78 0
      app/Http/Actions/AdminSingleSignOn.php
  43. 120 0
      app/Http/Actions/ChangePackage.php
  44. 148 0
      app/Http/Actions/ConfigOptions.php
  45. 111 0
      app/Http/Actions/CreateAccount.php
  46. 56 0
      app/Http/Actions/ListAccounts.php
  47. 37 0
      app/Http/Actions/MetaData.php
  48. 21 0
      app/Http/Actions/MetricProvider.php
  49. 46 0
      app/Http/Actions/ServiceSingleSignon.php
  50. 74 0
      app/Http/Actions/SuspendAccount.php
  51. 87 0
      app/Http/Actions/TerminateAccount.php
  52. 85 0
      app/Http/Actions/TestConnection.php
  53. 78 0
      app/Http/Actions/UnsuspendAccount.php
  54. 67 0
      app/Http/Actions/UsageUpdate.php
  55. 30 0
      app/Http/Admin/ProductConfiguration.php
  56. 42 0
      app/Http/Client/DistributionList.php
  57. 45 0
      app/Http/Client/DomainAlias.php
  58. 43 0
      app/Http/Client/EmailAccount.php
  59. 43 0
      app/Http/Client/EmailAlias.php
  60. 34 0
      app/Http/Client/Home.php
  61. 43 0
      app/Http/Client/Ressource.php
  62. 98 0
      app/Http/Client/Webmail.php
  63. 109 0
      app/Libs/Kerio/Api.php
  64. 26 0
      app/Libs/Kerio/Components/Api/Exceptions/KerioApiException.php
  65. 15 0
      app/Libs/Kerio/Components/Api/Exceptions/KerioServiceException.php
  66. 16 0
      app/Libs/Kerio/Components/Api/Interfaces/AbstractParser.php
  67. 29 0
      app/Libs/Kerio/Components/Api/Interfaces/ClientInterface.php
  68. 30 0
      app/Libs/Kerio/Components/Api/Interfaces/ConnectionInterface.php
  69. 322 0
      app/Libs/Kerio/Components/Api/Soap/Actions/Account.php
  70. 47 0
      app/Libs/Kerio/Components/Api/Soap/Actions/ClassOfServices.php
  71. 321 0
      app/Libs/Kerio/Components/Api/Soap/Actions/DistributionList.php
  72. 157 0
      app/Libs/Kerio/Components/Api/Soap/Actions/Domain.php
  73. 243 0
      app/Libs/Kerio/Components/Api/Soap/Actions/Ressource.php
  74. 20 0
      app/Libs/Kerio/Components/Api/Soap/Actions/Server.php
  75. 19 0
      app/Libs/Kerio/Components/Api/Soap/Actions/User.php
  76. 136 0
      app/Libs/Kerio/Components/Api/Soap/Client.php
  77. 412 0
      app/Libs/Kerio/Components/Api/Soap/Connection.php
  78. 16 0
      app/Libs/Kerio/Components/Api/Soap/Enums/ApiErrorCodes.php
  79. 46 0
      app/Libs/Kerio/Components/Api/Soap/Helpers/AccountHelper.php
  80. 36 0
      app/Libs/Kerio/Components/Api/Soap/Helpers/RessourceHelper.php
  81. 39 0
      app/Libs/Kerio/Components/Api/Soap/Helpers/ServiceFactory.php
  82. 133 0
      app/Libs/Kerio/Components/Api/Soap/Helpers/XmlParser.php
  83. 44 0
      app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractAction.php
  84. 51 0
      app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractApiClient.php
  85. 47 0
      app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractConnection.php
  86. 122 0
      app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractModel.php
  87. 19 0
      app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractRepository.php
  88. 130 0
      app/Libs/Kerio/Components/Api/Soap/Interfaces/ApiService.php
  89. 199 0
      app/Libs/Kerio/Components/Api/Soap/Models/Account.php
  90. 77 0
      app/Libs/Kerio/Components/Api/Soap/Models/AccountAlias.php
  91. 68 0
      app/Libs/Kerio/Components/Api/Soap/Models/ClassOfService.php
  92. 257 0
      app/Libs/Kerio/Components/Api/Soap/Models/DistributionList.php
  93. 118 0
      app/Libs/Kerio/Components/Api/Soap/Models/Domain.php
  94. 140 0
      app/Libs/Kerio/Components/Api/Soap/Models/Ressource.php
  95. 30 0
      app/Libs/Kerio/Components/Api/Soap/Models/Server.php
  96. 52 0
      app/Libs/Kerio/Components/Api/Soap/MySoapClient.php
  97. 102 0
      app/Libs/Kerio/Components/Api/Soap/Repository.php
  98. 233 0
      app/Libs/Kerio/Components/Api/Soap/Repository/Accounts.php
  99. 55 0
      app/Libs/Kerio/Components/Api/Soap/Repository/ClassOfServices.php
  100. 66 0
      app/Libs/Kerio/Components/Api/Soap/Repository/DistributionLists.php
  101. 122 0
      app/Libs/Kerio/Components/Api/Soap/Repository/Domains.php
  102. 136 0
      app/Libs/Kerio/Components/Api/Soap/Repository/Ressources.php
  103. 19 0
      app/Libs/Kerio/Components/Api/Soap/Repository/Server.php
  104. 205 0
      app/Libs/Kerio/Components/Api/Soap/Response.php
  105. 347 0
      app/Libs/Kerio/Components/Api/Soap/Services.php
  106. 163 0
      app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateAccount.php
  107. 70 0
      app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateAccountAlias.php
  108. 192 0
      app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateAccountCosQuota.php
  109. 250 0
      app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateDistributionList.php
  110. 106 0
      app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateDomain.php
  111. 99 0
      app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateDomainAlias.php
  112. 137 0
      app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateRessource.php
  113. 43 0
      app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteAccount.php
  114. 71 0
      app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteAccountAlias.php
  115. 54 0
      app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteDistributionList.php
  116. 173 0
      app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteDomain.php
  117. 37 0
      app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteDomainAlias.php
  118. 43 0
      app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteRessource.php
  119. 45 0
      app/Libs/Kerio/Components/Api/Soap/Services/Sso/ClientSingleSignOnToken.php
  120. 124 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackage.php
  121. 19 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackageConfigOptions.php
  122. 20 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackageCosQuota.php
  123. 119 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackageDedicatedCos.php
  124. 51 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/SuspendDomain.php
  125. 44 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UnsuspendDomain.php
  126. 77 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccount.php
  127. 107 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccountCosQuota.php
  128. 56 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccountPassword.php
  129. 39 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccountStatus.php
  130. 357 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateDistributionList.php
  131. 84 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateRessource.php
  132. 56 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateRessourcePassword.php
  133. 39 0
      app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateRessourceStatus.php
  134. 38 0
      app/Libs/Kerio/Components/Api/Soap/Traits/ApiClientHandler.php
  135. 30 0
      app/Libs/Kerio/Components/Api/Soap/Traits/ErrorHandler.php
  136. 70 0
      app/Libs/Kerio/Components/Api/Soap/Traits/FormDataHandler.php
  137. 119 0
      app/Libs/Kerio/Components/Api/Soap/Traits/ProcessStepHandler.php
  138. 35 0
      app/Libs/Kerio/Components/Api/Soap/Traits/ProductManagerHandler.php
  139. 35 0
      app/Libs/Kerio/Components/Filters/EmailAccounts/FilterByCosId.php
  140. 206 0
      app/Libs/Metrics/MyMetricProvider.php
  141. 190 0
      app/Libs/Migrations/Drivers/Version1To2/Settings.php
  142. 377 0
      app/Libs/Product/ProductManager.php
  143. 130 0
      app/Libs/Restrictions/Interfaces/AbstractRestriction.php
  144. 57 0
      app/Libs/Restrictions/Interfaces/AbstractRule.php
  145. 26 0
      app/Libs/Restrictions/Interfaces/RuleInterface.php
  146. 57 0
      app/Libs/Restrictions/Restriction.php
  147. 42 0
      app/Libs/Restrictions/Rules/ExtensionsValid.php
  148. 11308 0
      app/Libs/TLDList/tld.list
  149. 1 0
      app/Models/.gitkeep
  150. 27 0
      app/Models/ProductConfiguration.php
  151. 39 0
      app/Models/Whmcs/ProductConfigGroups.php
  152. 43 0
      app/Models/Whmcs/ProductConfigLinks.php
  153. 167 0
      app/Services/ClientAreaSidebarService.php
  154. 287 0
      app/Services/ConfigurableOptions/Abstracts/AbstractConfigurableOptions.php
  155. 46 0
      app/Services/ConfigurableOptions/Abstracts/AbstractSerialize.php
  156. 66 0
      app/Services/ConfigurableOptions/ConfigurableOptions.php
  157. 18 0
      app/Services/ConfigurableOptions/Helper/TypeConstans.php
  158. 195 0
      app/Services/ConfigurableOptions/Models/Option.php
  159. 101 0
      app/Services/ConfigurableOptions/Models/SubOption.php
  160. 100 0
      app/Services/ConfigurableOptions/Strategy/ConfigOptionsType.php
  161. 92 0
      app/Services/ConfigurableOptions/Strategy/Types/AbstractOptions.php
  162. 56 0
      app/Services/ConfigurableOptions/Strategy/Types/BasedOptions.php
  163. 50 0
      app/Services/ConfigurableOptions/Strategy/Types/ClassOfServicesOptions.php
  164. 46 0
      app/Services/ConfigurableOptions/Strategy/Types/ServiceConfigurableOptions.php
  165. 80 0
      app/Traits/ConfigTrait.php
  166. 32 0
      app/Traits/ExtensionsCheckerTrait.php
  167. 59 0
      app/Traits/FormExtendedTrait.php
  168. 89 0
      app/Traits/HostingService.php
  169. 31 0
      app/Traits/KerioApiHandler.php
  170. 37 0
      app/Traits/LangHandler.php
  171. 61 0
      app/Traits/ModuleConfigurationHandler.php
  172. 40 0
      app/Traits/ParamsHandler.php
  173. 38 0
      app/Traits/ProductService.php
  174. 78 0
      app/Traits/ServerParams.php
  175. 34 0
      app/Traits/StorageTrait.php
  176. 111 0
      app/UI/Admin/Custom/Fields/EnabledField.php
  177. 78 0
      app/UI/Admin/Custom/Fields/ExtendedInputField.php
  178. 56 0
      app/UI/Admin/Custom/Fields/ExtendedSelect.php
  179. 20 0
      app/UI/Admin/Custom/Forms/BaseFormExtended.php
  180. 112 0
      app/UI/Admin/Custom/Forms/SortedFieldForm.php
  181. 29 0
      app/UI/Admin/Custom/Modals/ModalExtendedTabsEdit.php
  182. 56 0
      app/UI/Admin/Custom/Pages/Description.php
  183. 18 0
      app/UI/Admin/Custom/Sections/BoxSectionExtended.php
  184. 18 0
      app/UI/Admin/Custom/Sections/FreeFieldsSection.php
  185. 41 0
      app/UI/Admin/Custom/Sections/HalfPageCustomCosSection.php
  186. 20 0
      app/UI/Admin/Custom/Sections/RowSection.php
  187. 14 0
      app/UI/Admin/Home/Pages/HomePage.php
  188. 27 0
      app/UI/Admin/LoggerManager/Buttons/DeleteAllLoggersButton.php
  189. 26 0
      app/UI/Admin/LoggerManager/Buttons/DeleteLoggerModalButton.php
  190. 25 0
      app/UI/Admin/LoggerManager/Buttons/MassDeleteLoggerButton.php
  191. 40 0
      app/UI/Admin/LoggerManager/Forms/DeleteAllLoggerForm.php
  192. 36 0
      app/UI/Admin/LoggerManager/Forms/DeleteLoggerForm.php
  193. 25 0
      app/UI/Admin/LoggerManager/Modals/DeleteAllLoggersModal.php
  194. 29 0
      app/UI/Admin/LoggerManager/Modals/DeleteLoggerModal.php
  195. 27 0
      app/UI/Admin/LoggerManager/Modals/MassDeleteLoggerModal.php
  196. 103 0
      app/UI/Admin/LoggerManager/Pages/LoggerPage.php
  197. 49 0
      app/UI/Admin/LoggerManager/Providers/LoggerDataProvider.php
  198. 29 0
      app/UI/Admin/ProductConfiguration/Buttons/CreateConfigurableOptionsBaseModalButton.php
  199. 44 0
      app/UI/Admin/ProductConfiguration/Forms/CreateConfigurableAction.php
  200. 76 0
      app/UI/Admin/ProductConfiguration/Helper/ConfigurableOptionsBuilder.php
  201. 27 0
      app/UI/Admin/ProductConfiguration/Modals/CreateConfigurableOptionsConfirm.php
  202. 74 0
      app/UI/Admin/ProductConfiguration/Pages/ConfigForm.php
  203. 61 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/CalendarFeatures.php
  204. 94 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/ClassOfServiceFeatures.php
  205. 73 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/ClientAreaFeatures.php
  206. 100 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/ConfigurableOptions.php
  207. 44 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/ContactFeatures.php
  208. 71 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/EssentialFeatures.php
  209. 102 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/GeneralFeatures.php
  210. 118 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/KerioSettings.php
  211. 87 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/MailServiceFeatures.php
  212. 47 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/MimeFeatures.php
  213. 65 0
      app/UI/Admin/ProductConfiguration/Pages/Sections/SearchFeatures.php
  214. 91 0
      app/UI/Admin/ProductConfiguration/Providers/ConfigurableOptionManager.php
  215. 237 0
      app/UI/Admin/ProductConfiguration/Providers/ProductConfigurationDataProvider.php
  216. 50 0
      app/UI/Admin/Templates/assets/css/integration.css
  217. 0 0
      app/UI/Admin/Templates/assets/css/module_styles.css
  218. 0 0
      app/UI/Admin/Templates/assets/js/.gitkeep
  219. 164 0
      app/UI/Admin/Templates/assets/js/productConfiguration/index.js
  220. 3 0
      app/UI/Admin/Templates/custom/fields/enabledField.tpl
  221. 16 0
      app/UI/Admin/Templates/custom/fields/extendedInputField.tpl
  222. 50 0
      app/UI/Admin/Templates/custom/fields/extendedSelect.tpl
  223. 32 0
      app/UI/Admin/Templates/custom/forms/baseFormExtended.tpl
  224. 32 0
      app/UI/Admin/Templates/custom/forms/sortedFieldForm.tpl
  225. 80 0
      app/UI/Admin/Templates/custom/modals/modalExtendedTabsEdit.tpl
  226. 21 0
      app/UI/Admin/Templates/custom/pages/description.tpl
  227. 33 0
      app/UI/Admin/Templates/custom/sections/boxSectionExtended.tpl
  228. 11 0
      app/UI/Admin/Templates/custom/sections/freeFieldsSection.tpl
  229. 8 0
      app/UI/Admin/Templates/custom/sections/rowSection.tpl
  230. 17 0
      app/UI/Admin/Templates/home/pages/homePage.tpl
  231. 32 0
      app/UI/Admin/Templates/loggerManager/buttons/deleteAllLoggersButton.tpl
  232. 48 0
      app/UI/Admin/Templates/productConfiguration/pages/sections/configurableOptions.tpl
  233. 27 0
      app/UI/Client/DistributionList/Buttons/AddListButton.php
  234. 27 0
      app/UI/Client/DistributionList/Buttons/DeleteListButton.php
  235. 26 0
      app/UI/Client/DistributionList/Buttons/EditListButton.php
  236. 28 0
      app/UI/Client/DistributionList/Buttons/MassDeleteListButton.php
  237. 49 0
      app/UI/Client/DistributionList/Forms/AddListForm.php
  238. 42 0
      app/UI/Client/DistributionList/Forms/DeleteListForm.php
  239. 54 0
      app/UI/Client/DistributionList/Forms/EditListForm.php
  240. 40 0
      app/UI/Client/DistributionList/Forms/MassDeleteListForm.php
  241. 28 0
      app/UI/Client/DistributionList/Modals/AddListModal.php
  242. 31 0
      app/UI/Client/DistributionList/Modals/DeleteListModal.php
  243. 28 0
      app/UI/Client/DistributionList/Modals/EditListModal.php
  244. 31 0
      app/UI/Client/DistributionList/Modals/MassDeleteListModal.php
  245. 116 0
      app/UI/Client/DistributionList/Pages/Lists.php
  246. 182 0
      app/UI/Client/DistributionList/Providers/AddListDataProvider.php
  247. 103 0
      app/UI/Client/DistributionList/Providers/DeleteListDataProvider.php
  248. 230 0
      app/UI/Client/DistributionList/Providers/EditListDataProvider.php
  249. 30 0
      app/UI/Client/DistributionList/Sections/AddAliasesDistribution.php
  250. 49 0
      app/UI/Client/DistributionList/Sections/AddMembersDistribution.php
  251. 32 0
      app/UI/Client/DistributionList/Sections/AddOwnersDistribution.php
  252. 39 0
      app/UI/Client/DistributionList/Sections/AddPreferencesDistribution.php
  253. 36 0
      app/UI/Client/DistributionList/Sections/AddPropertiesDistribution.php
  254. 72 0
      app/UI/Client/DistributionList/Sections/EditMembersDistribution.php
  255. 39 0
      app/UI/Client/DistributionList/Sections/EditPropertiesDistribution.php
  256. 26 0
      app/UI/Client/DomainAlias/Buttons/AddDomainAliasButton.php
  257. 28 0
      app/UI/Client/DomainAlias/Buttons/DeleteDomainAliasButton.php
  258. 29 0
      app/UI/Client/DomainAlias/Buttons/MassDeleteDomainAliasButton.php
  259. 50 0
      app/UI/Client/DomainAlias/Forms/AddDomainAliasForm.php
  260. 42 0
      app/UI/Client/DomainAlias/Forms/DeleteDomainAliasForm.php
  261. 41 0
      app/UI/Client/DomainAlias/Forms/MassDeleteDomainAliasForm.php
  262. 25 0
      app/UI/Client/DomainAlias/Modals/AddDomainAliasModals.php
  263. 33 0
      app/UI/Client/DomainAlias/Modals/DeleteDomainAliasModal.php
  264. 31 0
      app/UI/Client/DomainAlias/Modals/MassDeleteDomainAliasModal.php
  265. 99 0
      app/UI/Client/DomainAlias/Pages/DomainAliases.php
  266. 95 0
      app/UI/Client/DomainAlias/Providers/AddDomainAliasDataProvider.php
  267. 119 0
      app/UI/Client/DomainAlias/Providers/DeleteDomainAliasProvider.php
  268. 26 0
      app/UI/Client/EmailAccount/Buttons/AddAccountButton.php
  269. 30 0
      app/UI/Client/EmailAccount/Buttons/ChangePasswordButton.php
  270. 31 0
      app/UI/Client/EmailAccount/Buttons/ChangeStatusButton.php
  271. 31 0
      app/UI/Client/EmailAccount/Buttons/DeleteAccountButton.php
  272. 32 0
      app/UI/Client/EmailAccount/Buttons/EditAccountButton.php
  273. 103 0
      app/UI/Client/EmailAccount/Buttons/LoginToPanelButton.php
  274. 28 0
      app/UI/Client/EmailAccount/Buttons/MassChangeStatusButton.php
  275. 28 0
      app/UI/Client/EmailAccount/Buttons/MassDeleteAccountButton.php
  276. 19 0
      app/UI/Client/EmailAccount/Buttons/SpanDropdownButton.php
  277. 58 0
      app/UI/Client/EmailAccount/Forms/AddAccountForm.php
  278. 58 0
      app/UI/Client/EmailAccount/Forms/ChangePasswordForm.php
  279. 47 0
      app/UI/Client/EmailAccount/Forms/ChangeStatusForm.php
  280. 40 0
      app/UI/Client/EmailAccount/Forms/DeleteAccountForm.php
  281. 55 0
      app/UI/Client/EmailAccount/Forms/EditAccountForm.php
  282. 38 0
      app/UI/Client/EmailAccount/Forms/MassChangeStatusForm.php
  283. 42 0
      app/UI/Client/EmailAccount/Forms/MassDeleteAccountForm.php
  284. 26 0
      app/UI/Client/EmailAccount/Modals/AddAccountModal.php
  285. 29 0
      app/UI/Client/EmailAccount/Modals/ChangePasswordModal.php
  286. 29 0
      app/UI/Client/EmailAccount/Modals/ChangeStatusModal.php
  287. 34 0
      app/UI/Client/EmailAccount/Modals/DeleteAccountModal.php
  288. 30 0
      app/UI/Client/EmailAccount/Modals/EditAccountModal.php
  289. 30 0
      app/UI/Client/EmailAccount/Modals/MassChangeStatusModal.php
  290. 31 0
      app/UI/Client/EmailAccount/Modals/MassDeleteAccountModal.php
  291. 203 0
      app/UI/Client/EmailAccount/Pages/Accounts.php
  292. 307 0
      app/UI/Client/EmailAccount/Providers/AccountDataProvider.php
  293. 116 0
      app/UI/Client/EmailAccount/Providers/DeleteAccountDataProvider.php
  294. 354 0
      app/UI/Client/EmailAccount/Providers/EditAccountDataProvider.php
  295. 45 0
      app/UI/Client/EmailAccount/Sections/AdditionalSection.php
  296. 44 0
      app/UI/Client/EmailAccount/Sections/EditAdditionalSection.php
  297. 70 0
      app/UI/Client/EmailAccount/Sections/EditGeneralSection.php
  298. 83 0
      app/UI/Client/EmailAccount/Sections/GeneralSection.php
  299. 26 0
      app/UI/Client/EmailAlias/Buttons/AddEmailAliasButton.php
  300. 29 0
      app/UI/Client/EmailAlias/Buttons/DeleteEmailAliasButton.php
  301. 28 0
      app/UI/Client/EmailAlias/Buttons/MassDeleteEmailAliasButton.php
  302. 47 0
      app/UI/Client/EmailAlias/Forms/AddEmailAliasForm.php
  303. 41 0
      app/UI/Client/EmailAlias/Forms/DeleteEmailAliasForm.php
  304. 42 0
      app/UI/Client/EmailAlias/Forms/MassDeleteEmailAliasForm.php
  305. 25 0
      app/UI/Client/EmailAlias/Modals/AddEmailAliasModal.php
  306. 33 0
      app/UI/Client/EmailAlias/Modals/DeleteEmailAliasModal.php
  307. 31 0
      app/UI/Client/EmailAlias/Modals/MassDeleteEmailAliasModal.php
  308. 123 0
      app/UI/Client/EmailAlias/Pages/Aliases.php
  309. 109 0
      app/UI/Client/EmailAlias/Providers/AddEmailAliasDataProvider.php
  310. 115 0
      app/UI/Client/EmailAlias/Providers/DeleteEmailAliasDataProvider.php
  311. 69 0
      app/UI/Client/Home/Fields/FeatureField.php
  312. 128 0
      app/UI/Client/Home/Pages/Dashboard.php
  313. 26 0
      app/UI/Client/Ressource/Buttons/AddRessourceButton.php
  314. 30 0
      app/UI/Client/Ressource/Buttons/ChangePasswordButton.php
  315. 31 0
      app/UI/Client/Ressource/Buttons/ChangeStatusButton.php
  316. 31 0
      app/UI/Client/Ressource/Buttons/DeleteRessourceButton.php
  317. 32 0
      app/UI/Client/Ressource/Buttons/EditRessourceButton.php
  318. 103 0
      app/UI/Client/Ressource/Buttons/LoginToPanelButton.php
  319. 28 0
      app/UI/Client/Ressource/Buttons/MassChangeStatusButton.php
  320. 28 0
      app/UI/Client/Ressource/Buttons/MassDeleteRessourceButton.php
  321. 19 0
      app/UI/Client/Ressource/Buttons/SpanDropdownButton.php
  322. 58 0
      app/UI/Client/Ressource/Forms/AddRessourceForm.php
  323. 58 0
      app/UI/Client/Ressource/Forms/ChangePasswordForm.php
  324. 47 0
      app/UI/Client/Ressource/Forms/ChangeStatusForm.php
  325. 40 0
      app/UI/Client/Ressource/Forms/DeleteRessourceForm.php
  326. 55 0
      app/UI/Client/Ressource/Forms/EditRessourceForm.php
  327. 38 0
      app/UI/Client/Ressource/Forms/MassChangeStatusForm.php
  328. 42 0
      app/UI/Client/Ressource/Forms/MassDeleteRessourceForm.php
  329. 26 0
      app/UI/Client/Ressource/Modals/AddRessourceModal.php
  330. 29 0
      app/UI/Client/Ressource/Modals/ChangePasswordModal.php
  331. 29 0
      app/UI/Client/Ressource/Modals/ChangeStatusModal.php
  332. 34 0
      app/UI/Client/Ressource/Modals/DeleteRessourceModal.php
  333. 30 0
      app/UI/Client/Ressource/Modals/EditRessourceModal.php
  334. 30 0
      app/UI/Client/Ressource/Modals/MassChangeStatusModal.php
  335. 31 0
      app/UI/Client/Ressource/Modals/MassDeleteRessourceModal.php
  336. 200 0
      app/UI/Client/Ressource/Pages/Ressources.php
  337. 116 0
      app/UI/Client/Ressource/Providers/DeleteRessourceDataProvider.php
  338. 274 0
      app/UI/Client/Ressource/Providers/EditRessourceDataProvider.php
  339. 185 0
      app/UI/Client/Ressource/Providers/RessourceDataProvider.php
  340. 43 0
      app/UI/Client/Ressource/Sections/AdditionalSection.php
  341. 41 0
      app/UI/Client/Ressource/Sections/EditAdditionalSection.php
  342. 76 0
      app/UI/Client/Ressource/Sections/EditGeneralSection.php
  343. 81 0
      app/UI/Client/Ressource/Sections/GeneralSection.php
  344. 21 0
      app/UI/Client/Templates/assets/css/integration.css
  345. 5 0
      app/UI/Client/Templates/assets/css/module_styles.css
  346. BIN
      app/UI/Client/Templates/assets/icons/distributionList.png
  347. BIN
      app/UI/Client/Templates/assets/icons/domainAlias.png
  348. BIN
      app/UI/Client/Templates/assets/icons/emailAccount.png
  349. BIN
      app/UI/Client/Templates/assets/icons/emailAlias.png
  350. BIN
      app/UI/Client/Templates/assets/icons/goWebmail.png
  351. BIN
      app/UI/Client/Templates/assets/icons/ressource.png
  352. 0 0
      app/UI/Client/Templates/assets/js/.gitkeep
  353. 18 0
      app/UI/Client/Templates/assets/js/distributionList/index.js
  354. 18 0
      app/UI/Client/Templates/assets/js/emailAccount/index.js
  355. 18 0
      app/UI/Client/Templates/assets/js/ressource/index.js
  356. 5 0
      app/UI/Client/Templates/emailAccount/buttons/spanDropdownButton.tpl
  357. 30 0
      app/UI/Client/Templates/emailAccount/buttons/spanDropdownButton_components.tpl
  358. 8 0
      app/UI/Client/Templates/home/fields/featureField.tpl
  359. 15 0
      app/UI/Client/Templates/home/pages/dashboard.tpl
  360. 5 0
      app/UI/Client/Templates/ressource/buttons/spanDropdownButton.tpl
  361. 30 0
      app/UI/Client/Templates/ressource/buttons/spanDropdownButton_components.tpl
  362. 45 0
      app/Validators/EmailValidator.php
  363. 68 0
      app/Validators/IntegerValueValidator.php
  364. 58 0
      app/Validators/PasswordsValidator.php
  365. 39 0
      app/Validators/RepeatPasswordValidator.php
  366. 67 0
      app/Validators/TaggerEmailValidator.php
  367. 20 0
      commands/commands.php
  368. 43 0
      composer.json
  369. 851 0
      composer.lock
  370. 25 0
      core/Api/AbstractApi.php
  371. 158 0
      core/Api/AbstractApi/Curl.php
  372. 193 0
      core/Api/AbstractApi/Curl/Request.php
  373. 92 0
      core/Api/AbstractApi/Curl/Response.php
  374. 22 0
      core/Api/AbstractApi/Parser.php
  375. 186 0
      core/Api/Http.php
  376. 90 0
      core/Api/Whmcs.php
  377. 172 0
      core/App/AppContext.php
  378. 34 0
      core/App/AppParamsContainer.php
  379. 75 0
      core/App/Application.php
  380. 19 0
      core/App/Controllers/AppController.php
  381. 33 0
      core/App/Controllers/AppControllers/Addon.php
  382. 13 0
      core/App/Controllers/AppControllers/Api.php
  383. 13 0
      core/App/Controllers/AppControllers/Cron.php
  384. 13 0
      core/App/Controllers/AppControllers/Hooks.php
  385. 31 0
      core/App/Controllers/AppControllers/Http.php
  386. 71 0
      core/App/Controllers/Instances/Addon/Activate.php
  387. 149 0
      core/App/Controllers/Instances/Addon/Config.php
  388. 301 0
      core/App/Controllers/Instances/Addon/ConfigOptions.php
  389. 44 0
      core/App/Controllers/Instances/Addon/Deactivate.php
  390. 48 0
      core/App/Controllers/Instances/Addon/Upgrade.php
  391. 169 0
      core/App/Controllers/Instances/AddonController.php
  392. 11 0
      core/App/Controllers/Instances/Api/ApiController.php
  393. 39 0
      core/App/Controllers/Instances/Http/AddonIntegration.php
  394. 11 0
      core/App/Controllers/Instances/Http/AdminPageController.php
  395. 38 0
      core/App/Controllers/Instances/Http/AdminServicesTabFieldsIntegration.php
  396. 24 0
      core/App/Controllers/Instances/Http/ClientPageController.php
  397. 50 0
      core/App/Controllers/Instances/Http/ConfigOptionsIntegration.php
  398. 82 0
      core/App/Controllers/Instances/Http/ErrorPage.php
  399. 38 0
      core/App/Controllers/Instances/Http/Integration.php
  400. 31 0
      core/App/Controllers/Instances/Http/PageNotFound.php
  401. 179 0
      core/App/Controllers/Instances/HttpController.php
  402. 8 0
      core/App/Controllers/Interfaces/AddonController.php
  403. 8 0
      core/App/Controllers/Interfaces/AdminArea.php
  404. 8 0
      core/App/Controllers/Interfaces/AppController.php
  405. 8 0
      core/App/Controllers/Interfaces/ClientArea.php
  406. 10 0
      core/App/Controllers/Interfaces/DefaultController.php
  407. 137 0
      core/App/Controllers/ResponseResolver.php
  408. 103 0
      core/App/Controllers/Router.php
  409. 46 0
      core/App/ErrorHandler.php
  410. 104 0
      core/App/Installer/DatabaseInstaller.php
  411. 76 0
      core/App/Installer/ModuleInstaller.php
  412. 90 0
      core/App/LowLevelLog.php
  413. 21 0
      core/App/Packages/AppPackageConfiguration.php
  414. 76 0
      core/App/Packages/BasePackageConfiguration.php
  415. 9 0
      core/App/Packages/PackageConfigurationConst.php
  416. 103 0
      core/App/Packages/PackageManager.php
  417. 93 0
      core/App/Requirements/Checker.php
  418. 35 0
      core/App/Requirements/Handler.php
  419. 13 0
      core/App/Requirements/HandlerInterface.php
  420. 49 0
      core/App/Requirements/Handlers/Classes.php
  421. 114 0
      core/App/Requirements/Handlers/Files.php
  422. 47 0
      core/App/Requirements/Handlers/PhpExtensions.php
  423. 20 0
      core/App/Requirements/Instances/Classes.php
  424. 30 0
      core/App/Requirements/Instances/Files.php
  425. 21 0
      core/App/Requirements/Instances/PhpExtensions.php
  426. 13 0
      core/App/Requirements/RequirementInterface.php
  427. 26 0
      core/App/Requirements/RequirementsList.php
  428. 64 0
      core/App/TemplateDisplayWrapper.php
  429. 56 0
      core/Bootstrap.php
  430. 209 0
      core/Cache/CacheManager.php
  431. 107 0
      core/CommandLine/AbstractCommand.php
  432. 43 0
      core/CommandLine/AbstractCronController.php
  433. 218 0
      core/CommandLine/AbstractCronControllerWithoutThread.php
  434. 54 0
      core/CommandLine/Application.php
  435. 53 0
      core/CommandLine/Command.php
  436. 86 0
      core/CommandLine/CommandLoop.php
  437. 8 0
      core/CommandLine/CommandManager.php
  438. 8 0
      core/CommandLine/CronManager.php
  439. 253 0
      core/CommandLine/Hypervisor.php
  440. 8 0
      core/CommandLine/Job.php
  441. 86 0
      core/CommandLine/JobsLoop.php
  442. 64 0
      core/CommandLine/ReaderCronTask.php
  443. 68 0
      core/CommandLine/Tick.php
  444. 8 0
      core/Config/configuration.yml
  445. 1 0
      core/Config/cron.yml
  446. 5 0
      core/Config/di/buildWithDefaultMethod.yml
  447. 1 0
      core/Config/di/interface.yml
  448. 30 0
      core/Config/di/register.yml
  449. 8 0
      core/Config/di/services.php
  450. 5 0
      core/Config/di/services.yml
  451. 18 0
      core/Configuration/Addon/AbstractAfter.php
  452. 17 0
      core/Configuration/Addon/AbstractBefore.php
  453. 22 0
      core/Configuration/Addon/Activate/After.php
  454. 34 0
      core/Configuration/Addon/Activate/Before.php
  455. 24 0
      core/Configuration/Addon/Config/After.php
  456. 23 0
      core/Configuration/Addon/Config/Before.php
  457. 24 0
      core/Configuration/Addon/Deactivate/After.php
  458. 24 0
      core/Configuration/Addon/Deactivate/Before.php
  459. 24 0
      core/Configuration/Addon/Update/After.php
  460. 22 0
      core/Configuration/Addon/Update/Before.php
  461. 78 0
      core/Configuration/Addon/Update/Patch/AbstractPatch.php
  462. 105 0
      core/Configuration/Addon/Update/PatchManager.php
  463. 122 0
      core/Configuration/Data.php
  464. 13 0
      core/Configuration/Data/Version.php
  465. 30 0
      core/Configuration/Requirements/Files.php
  466. 0 0
      core/Database/data.sql
  467. 67 0
      core/Database/schema.sql
  468. 14 0
      core/DependencyInjection.php
  469. 76 0
      core/DependencyInjection/Builder.php
  470. 204 0
      core/DependencyInjection/Container.php
  471. 57 0
      core/DependencyInjection/DependencyInjection.php
  472. 63 0
      core/DependencyInjection/Services.php
  473. 34 0
      core/Enum/Enum.php
  474. 33 0
      core/Enum/Level.php
  475. 37 0
      core/Enum/Status.php
  476. 47 0
      core/Enum/StatusColor.php
  477. 80 0
      core/Events/Dispatcher.php
  478. 8 0
      core/Events/Event.php
  479. 8 0
      core/Events/Listener.php
  480. 41 0
      core/FileReader/Directory.php
  481. 68 0
      core/FileReader/File.php
  482. 85 0
      core/FileReader/PathValidator.php
  483. 84 0
      core/FileReader/Reader.php
  484. 49 0
      core/FileReader/Reader/AbstractType.php
  485. 36 0
      core/FileReader/Reader/Css.php
  486. 36 0
      core/FileReader/Reader/Html.php
  487. 35 0
      core/FileReader/Reader/Ini.php
  488. 36 0
      core/FileReader/Reader/Js.php
  489. 33 0
      core/FileReader/Reader/Json.php
  490. 36 0
      core/FileReader/Reader/Php.php
  491. 70 0
      core/FileReader/Reader/Sql.php
  492. 23 0
      core/FileReader/Reader/Xml.php
  493. 46 0
      core/FileReader/Reader/Yml.php
  494. 109 0
      core/HandlerError/ErrorCodes/ErrorCode.php
  495. 73 0
      core/HandlerError/ErrorCodes/ErrorCodes.php
  496. 109 0
      core/HandlerError/ErrorCodes/ErrorCodesLib.php
  497. 263 0
      core/HandlerError/ErrorManager.php
  498. 314 0
      core/HandlerError/Exceptions/Exception.php
  499. 243 0
      core/HandlerError/Logger.php
  500. 114 0
      core/HandlerError/Model/AbstractModel.php

+ 9 - 0
app/Config/configuration.yml

@@ -0,0 +1,9 @@
+version: '2.0.0'
+systemName: 'kerioEmail'
+name: 'kerioEmail'
+description: 'Kerio Email.<br>For more info visit our <a href="http://www.docs.modulesgarden.com/Kerio_Email_For_WHMCS" style="color: #4169E1;" target="_blank">Wiki</a>.'
+clientareaName: 'Kerio Email'
+author: '<a href="http://www.modulesgarden.com" targer="_blank">ModulesGarden</a>'
+moduleIcon: 'kerio_email'
+clienPortSecure: 8443
+clientPort: 443

+ 1 - 0
app/Config/cron.yml

@@ -0,0 +1 @@
+list:

+ 1 - 0
app/Config/di/buildWithDefaultMethod.yml

@@ -0,0 +1 @@
+class: []

+ 1 - 0
app/Config/di/interface.yml

@@ -0,0 +1 @@
+interface: []

+ 2 - 0
app/Config/di/register.yml

@@ -0,0 +1,2 @@
+class:
+  - {namespace: 'ModulesGarden\\Servers\\KerioEmail\\App\\Libs\\Kerio\\Api',            alias: "kerio", singleton: true , auto: false}

+ 9 - 0
app/Config/di/rewrite.yml

@@ -0,0 +1,9 @@
+class:
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Config\\After',     new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Config\\After'}
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Activate\\After',   new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Activate\\After'}
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Deactivate\\After', new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Deactivate\\After'}
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Update\\After',     new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Update\\After'}
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Config\\Before',    new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Config\\Before'}
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Activate\\Before',  new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Activate\\Before'}
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Deactivate\\Before',new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Deactivate\\Before'}
+    - {old: 'ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Update\\Before',    new: 'ModulesGarden\\Servers\\KerioEmail\\App\\Configuration\\Addon\\Update\\Before'}

+ 1 - 0
app/Config/di/services.yml

@@ -0,0 +1 @@
+- ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api

+ 7 - 0
app/Config/events.php

@@ -0,0 +1,7 @@
+<?php
+
+return [
+    \ModulesGarden\Servers\KerioEmail\App\Events\MyTestEvent::class    => [
+        \ModulesGarden\Servers\KerioEmail\App\Listeners\MyTestListener::class
+    ],
+];

+ 2 - 0
app/Config/hooks.yml

@@ -0,0 +1,2 @@
+name:
+    AdminAreaFooterOutput: true

+ 7 - 0
app/Config/menu/admin.yml

@@ -0,0 +1,7 @@
+home: 
+    icon: 'lu-nav__link-icon lu-zmdi lu-zmdi-home'
+LoggerManager:
+    icon: 'lu-nav__link-icon lu-zmdi lu-zmdi-assignment'
+documentation:
+    icon: 'lu-nav__link-icon lu-zmdi lu-zmdi-file-text'
+    externalUrl: "https://www.docs.modulesgarden.com/Domain_Orders_Extended_For_WHMCS"

+ 1 - 0
app/Config/menu/client.yml

@@ -0,0 +1 @@
+[]

+ 19 - 0
app/Config/sidebars.yml

@@ -0,0 +1,19 @@
+management:
+  emailAccount:
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=emailAccount'
+    order: 710
+  emailAlias:
+    order: 720
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=emailAlias'
+  distributionList:
+    order: 730
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=distributionList'
+  ressource:
+    order: 740
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=ressource'
+  domainAlias:
+    order: 750
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=domainAlias'
+  goWebmail:
+    order: 760
+    uri: 'clientarea.php?action=productdetails&id={$hostingId}&modop=custom&a=management&mg-page=webmail" target="_blank'

+ 1 - 0
app/Config/ui/admin/home/index.yml

@@ -0,0 +1 @@
+

+ 23 - 0
app/Configuration/Addon/Activate/After.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Activate;
+
+/**
+ * Runs after module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Activate\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+        
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Activate/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Activate;
+
+/**
+ * Runs before module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Activate\Before
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Config/After.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Config;
+
+/**
+ * Runs after loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Config\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+        
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Config/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Config;
+
+/**
+ * Runs before loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Config\Before
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Deactivate/After.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Deactivate;
+
+/**
+ * Runs after addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Deactivate\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+        
+        return $return;
+    }
+}

+ 23 - 0
app/Configuration/Addon/Deactivate/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Deactivate;
+
+/**
+ * Runs before addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Deactivate\Before
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+        
+        return $return;
+    }
+}

+ 0 - 0
app/Configuration/Addon/Others/.gitkeep


+ 22 - 0
app/Configuration/Addon/Update/After.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Update;
+
+/**
+ * runs after module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update\After
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $return = parent::execute($params);
+        return $return;
+    }
+}

+ 22 - 0
app/Configuration/Addon/Update/Before.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Configuration\Addon\Update;
+
+/**
+ * runs before module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update\Before
+{
+
+    /**
+     * @return array
+     */
+    public function execute($version)
+    {
+        $return = parent::execute($version);
+
+        return $return;
+    }
+}

+ 1 - 0
app/Configuration/Addon/Update/Patch/.gitkeep

@@ -0,0 +1 @@
+

+ 100 - 0
app/Cron/Migration.php

@@ -0,0 +1,100 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Cron;
+
+use ModulesGarden\Servers\KerioEmail\App\Models\ProductConfiguration;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use \Illuminate\Database\Capsule\Manager as DB;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Migrations\Drivers\Version1To2;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 13.11.19
+ * Time: 09:49
+ * Class Migration
+ */
+class Migration extends \ModulesGarden\Servers\KerioEmail\Core\CommandLine\AbstractCommand
+{
+    /**
+     * Command name
+     * @var string
+     */
+    protected $name = 'migration:v1_v2';
+
+    /**
+     * Command description
+     * @var string
+     */
+    protected $description = 'Migrate product settings from version 1.x to version 2.x';
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @param SymfonyStyle $io
+     */
+    protected function process(InputInterface $input, OutputInterface $output, SymfonyStyle $io)
+    {
+
+        $migration = new Version1To2\Settings();
+
+        $exists = DB::schema()->hasTable($migration->getFromTable());
+        if(!$exists)
+        {
+            $io->warning("Previous version of module can not be found.");
+        }
+
+        $previous = DB::table($migration->getFromTable())->get();
+
+        /**
+         *
+         */
+        $prodManager = new ProductConfiguration();
+
+        /**
+         *
+         * storage all params per product id
+         */
+        foreach($previous as $setting)
+        {
+            $settings[$setting->product_id][$setting->setting] = $setting->value;
+            $products[] = $setting->product_id;
+        }
+
+        /**
+         *
+         * update setting data & save
+         */
+        foreach($settings as $prodId => $settingsArray)
+        {
+            $attrs = $migration->updateValues($settingsArray, $prodId);
+
+            foreach($attrs as $key => $value)
+            {
+                $prodManager->updateOrCreate(['product_id' => $prodId, 'setting' => $key],['value' => $value]);
+            }
+        }
+
+
+        /**
+         *
+         * set new fields
+         */
+        foreach($migration->getNewFields() as $key => $value)
+        {
+            foreach($products as $id)
+            {
+                $prodManager->updateOrCreate(['product_id' => $id, 'setting' => $key],['value' => $value]);
+            }
+        }
+
+        /**
+         *
+         */
+        $io->success("Migration has been finished successfully.");
+    }
+}

+ 79 - 0
app/Database/M2M0P0/data.sql

@@ -0,0 +1,79 @@
+--
+-- `#prefix#Logger`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#Logger` (
+    `id`            int(10) unsigned NOT NULL AUTO_INCREMENT,
+    `id_ref`        int(10) NOT NULL,
+    `id_type`       VARCHAR(255) NOT NULL,
+    `type`          VARCHAR(255) NOT NULL,
+    `level`         VARCHAR(255) NOT NULL,
+    `date`          DATETIME DEFAULT null,
+    `request`       TEXT NOT NULL,
+    `response`      TEXT NOT NULL,
+    `before_vars`   TEXT NOT NULL,
+    `vars`          TEXT NOT NULL,
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+--
+-- `#prefix#ModuleSettings`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#ModuleSettings` (
+    `setting`              VARCHAR(64) NOT NULL UNIQUE,
+    `value`            TEXT NOT NULL,
+    PRIMARY KEY (`setting`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+--
+-- `#prefix#Commands`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#Commands` (
+    `name`             VARCHAR(64) NOT NULL UNIQUE,
+    `uuid`             VARCHAR(64) NOT NULL UNIQUE,
+    `parent_uuid`      VARCHAR(64) DEFAULT NULL,
+    `status`           enum('stopped', 'running', 'error') DEFAULT 'stopped',
+    `action`           enum('none', 'stop', 'reboot') DEFAULT 'none',
+    `params`           TEXT NOT NULL,
+    `created_at`       timestamp DEFAULT CURRENT_TIMESTAMP,
+    `updated_at`       timestamp,
+    PRIMARY KEY (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+
+CREATE TABLE IF NOT EXISTS `#prefix#Job` (
+    `id` int(10) unsigned  NOT NULL AUTO_INCREMENT,
+    `retry_after` datetime NOT NULL,
+    `retry_count` int(10) unsigned NOT NULL,
+    `job` varchar(255) NOT NULL,
+    `data` text,
+    `queue` varchar(32) DEFAULT 'default',
+    `status` varchar(32) NOT NULL,
+    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+CREATE TABLE IF NOT EXISTS `#prefix#JobLog` (
+    `id` int(10) unsigned  NOT NULL AUTO_INCREMENT,
+    `job_id` int(10) unsigned NOT NULL,
+    `type` varchar(32) NOT NULL,
+    `message` varchar(512) NOT NULL,
+    `additional` text,
+    `created_at` datetime NOT NULL,
+    `updated_at` datetime NOT NULL,
+    PRIMARY KEY (`id`),
+    KEY `job_id` (`job_id`),
+    KEY `type` (`type`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+--
+-- `#prefix#product_configuration`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#product_configuration` (
+    `id`                        INT(11)         NOT NULL AUTO_INCREMENT,
+    `product_id`                INT(11)         NOT NULL,
+    `setting`                   TEXT            NOT NULL,
+    `value`                     TEXT            NULL,
+    PRIMARY KEY (id)
+    )   ENGINE=InnoDB           DEFAULT
+        CHARSET=#charset#       DEFAULT     COLLATE #collation#;

+ 0 - 0
app/Database/M2M0P0/schema.sql


+ 11 - 0
app/Database/data.sql

@@ -0,0 +1,11 @@
+--
+-- `#prefix#product_configuration`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#product_configuration` (
+    `id`                        INT(11)         NOT NULL AUTO_INCREMENT,
+    `product_id`                INT(11)         NOT NULL,
+    `setting`                   TEXT            NOT NULL,
+    `value`                     TEXT            NULL,
+    PRIMARY KEY (id)
+    )   ENGINE=InnoDB           DEFAULT
+        CHARSET=#charset#       DEFAULT     COLLATE #collation#;

+ 0 - 0
app/Database/schema.sql


+ 23 - 0
app/Enums/ControllerEnums.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Enums;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.10.19
+ * Time: 10:20
+ * Class Controllers
+ */
+class ControllerEnums
+{
+    const EMAIL_ACCOUNT_PAGE        = 'ca_emailAccountPage';
+    const EMAIL_ALIAS_PAGE          = 'ca_emailAliasesPage';
+    const DOMAIN_ALIAS_PAGE         = 'ca_domainAliasesPage';
+    const WEBMAIL_PAGE              = 'ca_goToWebmailPage';
+    const DISTRIBUTION_MAIL_PAGE    = 'ca_distributionListPage';
+    const RESSOURCE_PAGE            = 'ca_ressourcePage';
+
+}

+ 100 - 0
app/Enums/Kerio.php

@@ -0,0 +1,100 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Enums;
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 14:10
+ * Class Kerio
+ */
+class Kerio
+{
+    /**
+     * attribute statuses
+     */
+    const ATTR_ENABLED      = 'TRUE';
+    const ATTR_DISABLED     = 'FALSE';
+    const ENABLED           = 'enabled';
+    const DISABLED          = 'disabled';
+    const ENABLED_AS_INT    = 1;
+
+    /**
+     * connection ports
+     */
+    const SECURE_PORT   = 7071;
+    const PORT          = 7072;
+
+    /**
+     *
+     */
+    const CLIENT_PORT   = 8443;
+
+    /**
+     * Kerio statuses
+     */
+    const STATUS_ACCEPT     = 'ACCEPT';
+    const STATUS_APPROVAL   = 'APPROVAL';
+    const STATUS_REJECT     = 'REJECT';
+
+    const ACC_STATUS_ACTIVE = 'active';
+    const ACC_STATUS_LOCKED = 'locked';
+    const ACC_STATUS_MAINTENANCE = 'maintenance';
+    const ACC_STATUS_CLOSED = 'closed';
+    const ACC_STATUS_LOCKOUT = 'lockout';
+    const ACC_STATUS_PENDING = 'pending';
+    const ACC_STATUS_SUSPEND = 'suspended';
+
+    const RES_TYPE_LOCATION  = 'Location';
+    const RES_TYPE_EQUIPMENT = 'Equipment';
+
+    const DEFAULT_LOGIN_LINK = 'https://kerio-server';
+
+    const BASE_ACCOUNT_CONFIG = [
+        'kerioFeatureMailEnabled',
+        'kerioFeatureCalendarEnabled',
+        'kerioFeatureBriefcasesEnabled',
+        'kerioFeatureContactsEnabled',
+        'kerioFeatureTasksEnabled',
+        'kerioFeatureOptionsEnabled',
+        'kerioFeatureTaggingEnabled',
+        'kerioFeatureChangePasswordEnabled',
+        'kerioFeatureManageZimlets',
+        'kerioFeatureGalEnabled',
+        'kerioFeatureWebClientOfflineAccessEnabled',
+        'kerioFeatureImportFolderEnabled',
+        'kerioDumpsterEnabled',
+        'kerioFeatureSharingEnabled',
+        'kerioFeatureSkinChangeEnabled',
+        'kerioFeatureHtmlComposeEnabled',
+        'kerioFeatureMAPIConnectorEnabled',
+        'kerioFeatureTouchClientEnabled',
+        'kerioFeatureGalAutoCompleteEnabled',
+        'kerioFeatureExportFolderEnabled',
+        'kerioDumpsterPurgeEnabled',
+        'kerioFeatureMailPriorityEnabled',
+        'kerioImapEnabled',
+        'kerioFeatureImapDataSourceEnabled',
+        'kerioFeatureMailSendLaterEnabled',
+        'kerioFeatureFiltersEnabled',
+        'kerioFeatureNewMailNotificationEnabled',
+        'kerioFeatureReadReceiptsEnabled',
+        'kerioFeatureFlaggingEnabled',
+        'kerioPop3Enabled',
+        'kerioFeaturePop3DataSourceEnabled',
+        'kerioFeatureConversationsEnabled',
+        'kerioFeatureOutOfOfficeReplyEnabled',
+        'kerioFeatureIdentitiesEnabled',
+        'kerioFeatureDistributionListFolderEnabled',
+        'kerioFeatureGroupCalendarEnabled',
+        'kerioFeatureCalendarReminderDeviceEmailEnabled',
+        'kerioFeatureAdvancedSearchEnabled',
+        'kerioFeatureInitialSearchPreferenceEnabled',
+        'kerioFeatureSavedSearchesEnabled',
+        'kerioFeaturePeopleSearchEnabled',
+        'kerioFeatureSMIMEEnabled',
+        'kerioFeatureEwsEnabled'
+    ];
+
+}

+ 31 - 0
app/Enums/ProductParams.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Enums;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 11.09.19
+ * Time: 15:13
+ * Class ProductConfig
+ */
+class ProductParams
+{
+    const CLASS_OF_SERVICE_NAME     = 'cos_name';
+    const FILTER_ACCOUNT_BY_COS     = 'filterAccountsByCOS';
+    const ACCOUNT_LIMIT             = 'acc_limit';
+    const ACCOUNT_SIZE              = 'acc_size';
+    const ACCOUNT_BASE              = 'acc_base';
+    const SIZE_UNLIMITED            = '-1';
+    const ZIMBRA_PREFIX_SETTINGS    = 'kerio';
+    const ALIAS_LIMIT               = 'alias_limit';
+    const DOMAIN_ALIAS_LIMIT        = 'domain_alias_limit';
+    const DOMAIN_LIST_LIMIT         = 'dist_list_limit';
+    const DOMAIN_MAX_SIZE           = 'domainMaxSize';
+    const DOMAIN_BASE_SIZE          = 'domainBaseSize';
+    const SWITCHER_ENABLED          = 'on';
+    const SWITCHER_DISABLED         = 'off';
+
+}

+ 20 - 0
app/Enums/Response.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Enums;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 14:22
+ * Class Response
+ */
+class Response
+{
+    const SUCCESS = 'success';
+    const FAILED = 'failed';
+    const ERROR  = 'error';
+
+}

+ 30 - 0
app/Enums/Size.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Enums;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 11.09.19
+ * Time: 11:55
+ * Class Size
+ */
+class Size
+{
+    const B_TO_GB = 1073741824;
+    const B_TO_MB = 1048576;
+    const B_TO_KB = 1024;
+
+    const DEFAULT_ACC_LIMIT          = 20;
+    const DEFAULT_ACC_BASE           = 1;
+    const DEFAULT_ACC_SIZE           = 100;
+    const DEFAULT_ALIAS_LIMIT        = 10;
+    const DEFAULT_DOMAIN_ALIAS_LIMIT = 10;
+    const DEFAULT_DIST_ALIAS_LIMIT   = 10;
+    const DEFAULT_NULL_VALUE         = 0;
+
+    const UNLIMITED = '-1';
+
+}

+ 96 - 0
app/Helpers/BuildUrlExtended.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Helpers;
+
+
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\BuildUrl;
+
+/**
+ *
+ * Extended BuildUrl class, allow to create url for provisioning
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 14:53
+ * Class BuildUrlExtended
+ */
+class BuildUrlExtended extends BuildUrl
+{
+
+    const FILE_URI = 'clientarea.php';
+
+    use RequestObjectHandler;
+
+    /**
+     * @param $controller
+     * @return string
+     */
+    public static function getProvisioningUrl($controller = 'home', $isModParam = true, $isAParam = true, $action = null)
+    {
+        /**
+         * uri params
+         */
+        $urlData = [
+            'action'  => 'productdetails',
+            'id'      => di('request')->get('id'),
+        ];
+
+        if($controller)
+        {
+            $urlData['mg-page'] = $controller;
+        }
+
+        if($isModParam)
+        {
+            $urlData['modop'] = 'custom';
+        }
+
+        if($isAParam)
+        {
+            $urlData['a'] = 'management';
+        }
+
+        if($action)
+        {
+            $urlData['mg-action'] = $action;
+        }
+
+        /**
+         * build uri
+         */
+        $url = BuildUrlExtended::FILE_URI.'?'.http_build_query($urlData);
+
+        /**
+         * get base URL
+         */
+        $baseUrl = self::baseUrl();
+
+        /**
+         * build full url
+         */
+        $url     = $baseUrl . $url;
+
+        return $url;
+    }
+
+    /**
+     * @return string
+     */
+    private static function baseUrl()
+    {
+        $protocol = 'https';
+        if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on')
+        {
+            $protocol = 'http';
+        }
+        $host   = $_SERVER['HTTP_HOST'];
+        $surfix = $_SERVER['PHP_SELF'];
+        $surfix = explode('/', $surfix);
+        array_pop($surfix);
+        $surfix = implode('/', $surfix);
+        return "{$protocol}://{$host}{$surfix}/";
+    }
+}

+ 15 - 0
app/Helpers/ErrorCodesLib.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Helpers;
+
+use \ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes\ErrorCodes;
+
+class ErrorCodesLib extends ErrorCodes
+{
+    const YOUR_APP_000001 = [
+        self::MESSAGE => 'Your error message',
+        self::CODE => 'YOUR_APP_000001',
+        self::DEV_MESSAGE => "Your error message left for other developers, the error genesis explanation...",
+        self::LOG => true //optional, determines if the error should be logged despite of inactive debug mode 
+    ];       
+}

+ 74 - 0
app/Helpers/KerioManager.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Helpers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Traits\ServerParams;
+use ModulesGarden\Servers\KerioEmail\App\Traits\KerioApiHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 07:21
+ * Class KerioManager
+ */
+class KerioManager
+{
+    use ServerParams;
+    use KerioApiHandler;
+
+    /**
+     * @param $id
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api
+     */
+    public function getApiByHosting($id)
+    {
+        $serverParams = $this->getServerParamsByHostingId($id);
+        $api = $this->getApi()->setParams($serverParams);
+
+        return $api;
+    }
+
+    /**
+     * @param $id
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api
+     */
+    public function getApiByProduct($id)
+    {
+        $serverParams = $this->getServerParamsByProductId($id);
+        $api = $this->getApi()->setParams($serverParams);
+        return $api;
+    }
+
+    /**
+     * @param $id
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api
+     */
+    public function getApiByServer($id)
+    {
+        $serverParams = $this->getServerParamsById($id);
+        $api = $this->getApi()->setParams($serverParams);
+        return $api;
+    }
+
+    /**
+     * @param $id
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository
+     */
+    public function getRepositoryByHosting($id)
+    {
+        return $this->getRepository($this->getApiByHosting($id)->soap);
+    }
+
+    /**
+     * @param $id
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository
+     */
+    public function getRepositoryByProduct($id)
+    {
+        return $this->getRepository($this->getApiByProduct($id)->soap);
+    }
+
+}

+ 57 - 0
app/Helpers/Storage.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Helpers;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 14:14
+ * Class Storage
+ */
+class Storage
+{
+    /**
+     * @var array
+     */
+    protected $data = [];
+
+    /**
+     * @param $key
+     * @param $value
+     * @return $this
+     */
+    public function set($key, $value)
+    {
+        $this->data[$key] = $value;
+        return $this;
+    }
+
+    /**
+     * @param $key
+     * @return bool
+     */
+    public function exists($key)
+    {
+        return isset($this->data[$key]);
+    }
+
+    /**
+     * @param $key
+     */
+    public function remove($key)
+    {
+        unset($this->data[$key]);
+    }
+
+    /**
+     * @param $key
+     * @return mixed
+     */
+    public function get($key)
+    {
+        return $this->data[$key];
+    }
+}

+ 23 - 0
app/Hooks/AdminAreaFooterOutput.php

@@ -0,0 +1,23 @@
+<?php
+
+use \ModulesGarden\Servers\KerioEmail\Core\Hook\HookIntegrator;
+
+$hookManager->register(
+    function ($args)
+    {
+        $hookIntegrator = new HookIntegrator($args);
+
+        /**
+         * @var $toReturn is a HTML integration code (or null if no integration was made)
+         * you can add your code to this var before returning its content,
+         * do not overwrite this var!
+         */
+        $toReturn = $hookIntegrator->getHtmlCode();
+
+        if ($toReturn)
+        {
+            return $toReturn;
+        }
+    },
+    100
+);

+ 57 - 0
app/Hooks/ClientAreaPrimarySidebar.php

@@ -0,0 +1,57 @@
+<?php
+
+$hookManager->register(
+    function (\WHMCS\View\Menu\Item $primarySidebar)
+    {
+
+        /**
+         * @var  \ModulesGarden\Servers\KerioEmail\Core\Http\Request $request
+         */
+        $request = \ModulesGarden\Servers\KerioEmail\Core\Helper\sl('request');
+
+        /**
+         * return if user is not logged
+         */
+        if(!$request->getSession('uid'))
+        {
+            return;
+        }
+
+        /**
+         * return if service id doesn't exists
+         */
+        if (!$request->get('id'))
+        {
+            return;
+        }
+
+        /**
+         *
+         */
+        $clientAreaSideBar = new \ModulesGarden\Servers\KerioEmail\App\Services\ClientAreaSidebarService($request->get("id"), $primarySidebar);
+        if (!$clientAreaSideBar->isActive() || !$clientAreaSideBar->isSupportedModule())
+        {
+            return;
+        }
+        if (!function_exists('ModuleBuildParams'))
+        {
+            require_once \ModulesGarden\Servers\KerioEmail\Core\ModuleConstants::getFullPathWhmcs('includes') . DIRECTORY_SEPARATOR . "modulefunctions.php";
+        }
+        $params = \ModuleBuildParams($request->get("id"));
+        \ModulesGarden\Servers\KerioEmail\Core\Helper\sl("whmcsParams")->setParams($params);
+
+        //Page Cancel
+        if ($request->get('action') == "cancel")
+        {
+            $clientAreaSideBar->informationReplaceUri();
+        } //Page Productdetails
+        else
+        {
+            if ($request->get('action') == "productdetails")
+            {
+                $clientAreaSideBar->informationReplaceUri();
+                $clientAreaSideBar->build();
+            }
+        }
+    }, 943
+);

+ 35 - 0
app/Http/Actions/AdminLink.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 15:03
+ * Class AdminLink
+ */
+class AdminLink extends AddonController
+{
+
+    public function execute($params = null)
+    {
+        //todo add if required -.-
+
+//        $lang = di('lang');
+//
+//        $code = '
+//        <form action="https://' . $host . ':' . $port . '/kerioAdmin/" method="post" target="_blank">
+//		<input type="hidden" name="ZLoginUserName" value="' . $params["serverusername"] . '" />
+//		<input type="hidden" name="ZLoginPassword" value="' . $params["serverpassword"] . '" />
+//		<input type="submit" value="' . $lang->absoluteT('loginToKerioPanel') . '" />
+//		</form>';
+//        return $code;
+    }
+}
+

+ 32 - 0
app/Http/Actions/AdminServicesTabFields.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 13.11.19
+ * Time: 13:45
+ * Class AdminServicesTabFields
+ */
+class AdminServicesTabFields extends AddonController
+{
+
+    public function execute($params = null)
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($params['serviceid']);
+
+        $webmail = $productManager->getClientUrl();
+        return [
+            'Login' => '<a class="btn" href="' . $webmail . '" target="_blank" style="color:#000000; text-decoration: none;">' .
+                       di('lang')->absoluteT('logInToWebmail') . '</a>'
+        ];
+    }
+}

+ 78 - 0
app/Http/Actions/AdminSingleSignOn.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 09:47
+ * Class AdminSingleSignOn
+ */
+class AdminSingleSignOn extends AddonController
+{
+
+    use ExtensionsCheckerTrait;
+    /**
+     *
+     *
+     * @param null $params
+     * @return array
+     */
+    public function execute($params = null)
+    {
+        try
+        {
+            /**
+             *
+             */
+            $this->checkExtensionOrThrowError();
+            /**
+             * kerio API manager
+             */
+            $manager = (new KerioManager());
+            $api = $manager->getApiByServer($params['serverid']);
+
+
+            /**
+             * API Connection
+             */
+            $connection = $api->soap->getConnection();
+
+
+            /**
+             * Build URL
+             */
+            $redirectTo = $connection->getServerUrl().'/service/preauth?'.http_build_query([
+                    'authtoken' => $connection->getAuthToken()
+            ]);
+
+            /**
+             *
+             * return connection error
+             */
+            return [
+                'success'       => true,
+                'redirectTo'    => $redirectTo
+            ];
+        }
+        catch (\Exception $ex)
+        {
+            /**
+             * return some crit error
+             */
+            return ['error' => $ex->getMessage()];
+        }
+    }
+}

+ 120 - 0
app/Http/Actions/ChangePackage.php

@@ -0,0 +1,120 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Response;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\KerioEmail\App\Models\ProductConfiguration;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 15:15
+ * Class ChangePackage
+ */
+class ChangePackage extends AddonController
+{
+    use ExtensionsCheckerTrait;
+
+    /**
+     * @param null $params
+     * @return string|void
+     */
+    public function execute($params = null)
+    {
+        try{
+
+            /**
+             * check if extensions are installed
+             */
+            $this->checkExtensionOrThrowError();
+
+            /**
+             * run kerio service
+             */
+            $result =  $this->kerioRunService($params);
+            return $result;
+        }catch (\Exception $ex)
+        {
+            /**
+             * return some crit error
+             */
+            return $ex->getMessage();
+        }
+
+    }
+
+    /**
+     * @param null $params
+     * @return string
+     */
+    protected function kerioRunService($params = null)
+    {
+
+        $productManager = new ProductManager();
+        $productManager->loadById($params['pid']);
+
+        $service = (new KerioManager())
+            ->getApiByServer($params['serverid'])
+            ->soap
+            ->service()
+            ->changePackages($productManager->get('cos_name'))
+            ->setProductManager($productManager)
+            ->setFormData($params)
+        ;
+
+        $result = $service->run();
+
+//        $configuration = ProductConfiguration::where('product_id', $params['pid'])->get();
+//        foreach($configuration as $cModel)
+//        {
+//            $config[$cModel->setting] = $cModel->value;
+//        }
+//
+//        $new_account_size = $config['acc_size'];
+//
+//        //todo mailboxes from API
+//
+//        $repository = (new KerioManager())
+//            ->getApiByServer($params['serverid'])
+//            ->soap
+//            ->repository();
+//
+//        $mailboxesApi = $repository->accounts->getByDomainName($params['domain']);
+//
+//        if ($config['coss_name'] == "customMGkerio")
+//        {
+//            $attr = $config;
+//            foreach ($attr as $key => &$item)
+//            {
+//                if (preg_match('/kerio.+/', $key))
+//                {
+//                    $item = $item == "on" ? "TRUE" : "FALSE";
+//                }
+//                else
+//                {
+//                    unset($attr[$key]);
+//                }
+//            }
+//
+//            $attr['kerioMailQuota'] = $new_account_size * 1048576;
+//        }elseif ($config['coss_name'] == 'cosQuota')
+//        {
+//            //todo
+//        }else{
+//
+//        }
+//
+//        foreach($mailboxesApi as $key => $value)
+//        {
+//            //todo
+//        }
+
+        return Response::SUCCESS;
+    }
+}

+ 148 - 0
app/Http/Actions/ConfigOptions.php

@@ -0,0 +1,148 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Http\Admin\ProductConfiguration;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Restriction;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\ConfigForm;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\Traits\OutputBuffer;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Product;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 09:07
+ * Class ConfigOptions
+ */
+class ConfigOptions extends AddonController
+{
+    use ExtensionsCheckerTrait;
+    use OutputBuffer;
+
+    /**
+     * @param null $params
+     * @return array
+     * @throws \Exception
+     */
+    public function execute($params = null)
+    {
+        try{
+
+            $this->throwErrorIfServerInvalid();
+            $this->throwErrorIfExtensionsInvalid();
+
+            if ($this->getRequestValue('action') === 'module-settings' && !$this->getRequestValue('loadData') )
+            {
+                if(empty($this->getRequestValue('magic')))
+                {
+                    return [
+                        "configoption" => [
+                            "Type" => "",
+                            "Description" => $this->getJsCode(),
+                        ],
+                    ];
+                }
+
+                if (isset($_REQUEST['magic']))
+                {
+                    $this->cleanOutputBuffer();
+
+                    return [ProductConfiguration::class, 'index'];
+                }
+
+                return [ProductConfiguration::class, 'index'];
+
+            }
+            elseif ($this->getRequestValue('action') === 'save')
+            {
+                $form = new ConfigForm();
+                $form->runInitContentProcess();
+                $form->returnAjaxData();
+            }
+            elseif (($this->getRequestValue('loadData') && $this->getRequestValue('ajax') == '1'))
+            {
+                return [ProductConfiguration::class, 'index'];
+            }
+
+        }catch (\Exception $e)
+        {
+            //todo log
+            throw new \Exception($e->getMessage());
+        }
+    }
+
+    /**
+     * check if server is configured properly
+     * @throws \Exception
+     */
+    protected function throwErrorIfServerInvalid()
+    {
+        $productId = di('request')->get('id');
+        $product = Product::where('id', $productId)->first();
+        if(!$product->servergroup)
+        {
+            throw new \Exception(di('lang')->absoluteT('error', 'invalidServer'));
+        }
+    }
+
+    /**
+     * check if extension is instlled
+     * @throws \Exception
+     */
+    protected function throwErrorIfExtensionsInvalid()
+    {
+        $extensions = [
+            \SoapClient::class => 'soap'
+        ];
+
+        foreach($extensions as $class => $extension)
+        {
+            if(!class_exists($class))
+            {
+                throw new \Exception(di('lang')->addReplacementConstant('extension', $extension)->absoluteT('error', 'extensionRequired'));
+            }
+        }
+
+    }
+    private function getJsCode()
+    {
+        $params = array_merge($this->request->request->all(), $this->request->query->all());
+        $dataQuery = http_build_query($params);
+
+        return "
+                <script>
+                    $('#layers').remove();
+                    $('.lu-alert').remove();
+                    $('#tblModuleSettings').addClass('hidden');
+                    $('#tblMetricSettings').before('<img style=\"margin-left: 50%; margin-top: 15px; margin-bottom: 15px; height: 20px\" id=\"mg-configoptionLoader\" src=\"images/loading.gif\">');
+                    $.post({
+                        url: '{$_SERVER['HTTP_ORIGIN']}{$_SERVER['PHP_SELF']}?$dataQuery&magic=1'
+                    })
+                    .done(function( data ){
+                        
+                        var json = JSON.parse(data);
+                       
+                        $('#mg-configoptionLoader').remove();
+                        if ({$this->getRequestValue('servergroup')} == 0)
+                        {
+                              $('#tblModuleSettings').html(json.content).removeClass('hidden');
+                        }
+                        else
+                        {
+                            $('#tblModuleSettings').html(json.content).removeClass('hidden');
+                        }
+//                        
+                    });
+                </script>";
+
+
+    }
+
+}

+ 111 - 0
app/Http/Actions/CreateAccount.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Response;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\KerioEmail\App\Traits\HostingService;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 15:14
+ * Class CreateAccount
+ */
+class CreateAccount extends AddonController
+{
+    use ExtensionsCheckerTrait;
+    use HostingService;
+    use WhmcsParams;
+    
+    /**
+     * create domain in kerio
+     *
+     * @param null $params
+     * @return string
+     */
+    public function execute($params = null)
+    {
+        try{
+
+            /**
+             * check if extensions are installed
+             */
+            $this->checkExtensionOrThrowError();
+
+            //update domain
+            if($params['customfields']['maildomain']){
+                $params['domain'] = $params['customfields']['maildomain'];
+                $this->hosting()->domain = $params['domain'];
+                $this->hosting()->save();
+            }
+
+            /**
+             * run kerio service
+             */
+            $result =  $this->kerioRunService($params);
+            return $result;
+        }catch (\Exception $ex)
+        {
+            /**
+             * return some crit error
+             */
+            return $ex->getMessage();
+        }
+
+    }
+
+    /**
+     * @param null $params
+     * @return mixed|string
+     */
+    protected function kerioRunService($params = null)
+    {
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByServer($params['serverid'])
+            ->soap
+            ->service()
+            ->createDomain();
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($params['serviceid']);
+
+        /**
+         *
+         * set params
+         * run service (Create domain in Kerio API)
+         */
+        $result = $service
+            ->setProductManager($productManager)
+            ->setFormData($params)
+            ->run();
+
+        /**
+         * check service result & return error
+         */
+        if(!$result)
+        {
+            return $service->getError();
+        }
+
+        /**
+         * return success response
+         */
+        return Response::SUCCESS;
+    }
+}

+ 56 - 0
app/Http/Actions/ListAccounts.php

@@ -0,0 +1,56 @@
+<?php
+
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+
+class ListAccounts extends AddonController
+{
+    use ExtensionsCheckerTrait;
+
+    public function execute($params = null)
+    {
+        try
+        {
+            $servers =(new KerioManager())
+                ->getApiByServer($params['serverid'])
+                ->soap
+                ->repository()
+                ->domains()
+                ->getAll();
+
+            $accounts = [];
+
+            foreach ($servers as $server)
+            {
+                $created = explode('.', $server->getAttr('kerioCreateTimestamp'));
+                $created = date( 'Y-m-d H:i:s', strtotime($created[0]));
+
+                $accounts[] = [
+                    'domain' => $server->getName(),
+                    'status' => 'Active',
+                    'created' => $created,
+                    'primaryip' => $params['serverip'],
+                    'uniqueIdentifier' => $server->getName(),
+                    'product' => '',
+                ];
+            }
+
+            return [
+                'success' => true,
+                'accounts' => $accounts
+            ];
+
+        }
+        catch (\Exception $ex)
+        {
+            return ['error' => $ex->getMessage()];
+        }
+
+    }
+}

+ 37 - 0
app/Http/Actions/MetaData.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 11:02
+ * Class MetaData
+ */
+class MetaData extends AddonController
+{
+    use ExtensionsCheckerTrait;
+
+    public function execute($params = null)
+    {
+        return [
+            'DefaultNonSSLPort' => Kerio::PORT,
+            'DefaultSSLPort'    => Kerio::SECURE_PORT,
+            'ListAccountsUniqueIdentifierDisplayName' => 'Domain',
+            'ListAccountsUniqueIdentifierField' => 'domain',
+            'ListAccountsProductField' => 'configoption1',
+        ];
+    }
+
+    protected function kerioRunService($params = null)
+    {
+
+    }
+}

+ 21 - 0
app/Http/Actions/MetricProvider.php

@@ -0,0 +1,21 @@
+<?php
+
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Metrics\MyMetricProvider;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+
+class MetricProvider extends AddonController
+{
+    use ExtensionsCheckerTrait;
+
+    public function execute($params = null)
+    {
+        return new MyMetricProvider($params);
+    }
+
+}

+ 46 - 0
app/Http/Actions/ServiceSingleSignon.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Connection;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ServerParams;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 09:47
+ * Class AdminSingleSignOn
+ */
+class ServiceSingleSignon extends AddonController
+{
+    use WhmcsParams;
+    use ServerParams;
+    public function execute($params = null)
+    {
+        try{
+
+            $productManager = new ProductManager();
+            $productManager->loadByHostingId($this->getRequestValue('id'));
+
+            return [
+                'success'    => true,
+                'redirectTo' => $productManager->getClientUrl()
+            ];
+
+        }catch (\Exception $e)
+        {
+            return ['error' => $e->getMessage()];
+        }
+    }
+}

+ 74 - 0
app/Http/Actions/SuspendAccount.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Response;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 15:15
+ * Class SuspendAccount
+ */
+class SuspendAccount extends AddonController
+{
+
+    use ExtensionsCheckerTrait;
+
+    public function execute($params = null)
+    {
+        try{
+
+            /**
+             * check if extensions are installed
+             */
+            $this->checkExtensionOrThrowError();
+
+            /**
+             * run kerio service
+             */
+            $result =  $this->kerioRunService($params);
+            return $result;
+        }catch (\Exception $ex)
+        {
+            /**
+             * return some crit error
+             */
+            return $ex->getMessage();
+        }
+
+    }
+
+    /**
+     * @param null $params
+     * @return mixed|string
+     */
+    protected function kerioRunService($params = null)
+    {
+        $service = (new KerioManager())
+            ->getApiByServer($params['serverid'])
+            ->soap
+            ->service()
+            ->suspendDomain()
+            ->setFormData($params)
+        ;
+
+        $result = $service->run();
+
+        if(!$result)
+        {
+            return $service->getError();
+        }
+
+        /**
+         * return success response
+         */
+        return Response::SUCCESS;
+    }
+}

+ 87 - 0
app/Http/Actions/TerminateAccount.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Response;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 15:14
+ * Class TerminateAccount
+ */
+class TerminateAccount extends AddonController
+{
+    use ExtensionsCheckerTrait;
+
+    public function execute($params = null)
+    {
+        try{
+
+            /**
+             * check if extensions are installed
+             */
+            $this->checkExtensionOrThrowError();
+
+            /**
+             * run kerio service
+             */
+            $result =  $this->kerioRunService($params);
+            return $result;
+        }catch (\Exception $ex)
+        {
+            /**
+             * return some crit error
+             */
+            return $ex->getMessage();
+        }
+
+    }
+
+    /**
+     * @param null $params
+     * @return mixed|string
+     */
+    protected function kerioRunService($params = null)
+    {
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByServer($params['serverid'])
+            ->soap
+            ->service()
+            ->deleteDomain()
+            ->setFormData($params)
+        ;
+
+        /**
+         *
+         * set params
+         * run service (Create domain in Kerio API)
+         */
+        $result = $service->run();
+
+        /**
+         * check service result & return error
+         */
+        if(!$result)
+        {
+            return $service->getError();
+        }
+
+        /**
+         * return success response
+         */
+        return Response::SUCCESS;
+    }
+}

+ 85 - 0
app/Http/Actions/TestConnection.php

@@ -0,0 +1,85 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Client;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 27.08.19
+ * Time: 14:54
+ * Class TestConnection
+ */
+class TestConnection extends AddonController
+{
+
+    use ExtensionsCheckerTrait;
+    /**
+     *
+     *
+     * @param null $params
+     * @return array
+     */
+    public function execute($params = null)
+    {
+        try{
+
+            /**
+             *
+             */
+            $this->checkExtensionOrThrowError();
+            /**
+             * kerio API manager
+             */
+            $manager = (new KerioManager());
+
+            /**
+             * set API params
+             */
+            if($params['serverusername'] )
+            {
+                /**
+                 *
+                 * override secure param
+                 */
+                $params['serversecure'] = $params['serversecure'] ? 'on' : 'off';
+
+                $api = $manager->getApi()->setParams($params);
+            }else{
+                $api = $manager->getApiByServer($params['serverid']);
+            }
+
+            /**
+             * API Connection
+             */
+            $connection = $api->soap->getConnection();
+
+            /**
+             * check if connected and return true
+             */
+            if($connection->isConnected())
+            {
+                return ['success' => true];
+            }
+
+            /**
+             *
+             * return connection error
+             */
+            return ['error' => $connection->getConnectionError()];
+        }
+        catch (\Exception $ex)
+        {
+            /**
+             * return some crit error
+             */
+            return ['error' => $ex->getMessage()];
+        }
+
+    }
+}

+ 78 - 0
app/Http/Actions/UnsuspendAccount.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Response;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ExtensionsCheckerTrait;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 15:15
+ * Class UnsuspendAccount
+ */
+class UnsuspendAccount extends AddonController
+{
+
+    use ExtensionsCheckerTrait;
+
+    public function execute($params = null)
+    {
+        try{
+
+            /**
+             * check if extensions are installed
+             */
+            $this->checkExtensionOrThrowError();
+
+            /**
+             * run kerio service
+             */
+            $result =  $this->kerioRunService($params);
+
+            /**
+             * return result
+             */
+            return $result;
+        }catch (\Exception $ex)
+        {
+            /**
+             * return some crit error
+             */
+            return $ex->getMessage();
+        }
+
+    }
+
+    /**
+     * @param null $params
+     * @return mixed|string
+     */
+    protected function kerioRunService($params = null)
+    {
+        $service = (new KerioManager())
+            ->getApiByServer($params['serverid'])
+            ->soap
+            ->service()
+            ->unsuspendDomain()
+            ->setFormData($params)
+        ;
+
+        $result = $service->run();
+
+        if(!$result)
+        {
+            return $service->getError();
+        }
+
+        /**
+         * return success response
+         */
+        return Response::SUCCESS;
+    }
+}

+ 67 - 0
app/Http/Actions/UsageUpdate.php

@@ -0,0 +1,67 @@
+<?php
+
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs;
+
+class UsageUpdate extends AddonController
+{
+    protected $moduleParams;
+
+    public function execute($params = null)
+    {
+        $this->moduleParams = $params;
+
+        $domains =(new KerioManager())
+            ->getApiByServer($this->moduleParams['serverid'])
+            ->soap
+            ->repository()
+            ->domains()
+            ->getAll();
+        foreach ($domains as $domain)
+        {
+            try
+            {
+                $domainName = $domain->getName();
+                $usage = $this->getDomainUsage($domainName);
+                $mailboxes = $usage['mailboxes'];
+                $storage = $usage['usage'];
+                $storage = $storage == 0 ? 0 : round($storage/1024/1024);
+                $serverId =$params['serverid'];
+
+                Whmcs\Hosting::where('server', $serverId)->where('domain', $domainName)->update(['bwusage' => $mailboxes]);
+                Whmcs\Hosting::where('server', $serverId)->where('domain', $domainName)->update(['diskusage' => $storage]);
+
+                usleep(5000);
+            }
+            catch (\Exception $ex)
+            {
+
+            }
+
+        }
+    }
+
+    private function getDomainUsage($tenant)
+    {
+        $client = (new KerioManager())
+            ->getApiByServer($this->moduleParams['serverid'])
+            ->soap
+            ->repository()
+            ->accounts;
+        $accounts = $client->getUsages($tenant);
+        $mailboxes = count($client->getMailboxes($tenant));
+        $totalUsage = 0;
+        foreach ($accounts as $account)
+        {
+            $usage = $account->getUsed();
+            $totalUsage += $usage;
+        }
+
+        return array('usage' => $totalUsage, 'mailboxes' => $mailboxes);
+    }
+}

+ 30 - 0
app/Http/Admin/ProductConfiguration.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Admin;
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\ConfigForm;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 09:10
+ * Class ProductConfiguration
+ */
+class ProductConfiguration extends AbstractClientController
+{
+
+    public function index()
+    {
+        $view = Helper\viewIntegrationAddon()
+            ->addElement(ConfigForm::class);
+
+        return $view;
+
+    }
+
+}

+ 42 - 0
app/Http/Client/DistributionList.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Client;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Pages\Description;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Pages\Lists;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Pages\Accounts;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:12
+ * Class DistributionList
+ */
+class DistributionList extends AbstractClientController
+{
+    use WhmcsParams;
+
+    public function index()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->request->get('id'));
+        if ($this->getWhmcsParamByKey('status') !== 'Active' || !$productManager->isControllerAccessible(ControllerEnums::DISTRIBUTION_MAIL_PAGE))
+        {
+            return Helper\redirectByUrl(BuildUrlExtended::getProvisioningUrl('',false,false));
+        }
+
+        return Helper\view()
+            ->addElement(new Description('distributionList'))
+            ->addElement(Lists::class)
+            ;
+    }
+}

+ 45 - 0
app/Http/Client/DomainAlias.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Client;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Pages\Description;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Pages\DomainAliases;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Pages\Accounts;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:13
+ * Class DomainAlias
+ */
+class DomainAlias extends AbstractClientController
+{
+    use WhmcsParams;
+
+    public function index()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->request->get('id'));
+
+        if ($this->getWhmcsParamByKey('status') !== 'Active' ||
+            $productManager->get(ControllerEnums::DOMAIN_ALIAS_PAGE) !== ProductParams::SWITCHER_ENABLED)
+        {
+            return Helper\redirectByUrl(BuildUrlExtended::getProvisioningUrl('',false,false));
+        }
+
+        return Helper\view()
+            ->addElement(new Description('domainAlias'))
+            ->addElement(DomainAliases::class)
+            ;
+
+    }
+}

+ 43 - 0
app/Http/Client/EmailAccount.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Client;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Pages\Description;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Pages\Accounts;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:12
+ * Class EmailAccount
+ */
+class EmailAccount extends AbstractClientController
+{
+    use WhmcsParams;
+
+    public function index()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->request->get('id'));
+
+        if ($this->getWhmcsParamByKey('status') !== 'Active' || !$productManager->isControllerAccessible(ControllerEnums::EMAIL_ACCOUNT_PAGE))
+        {
+            return Helper\redirectByUrl(BuildUrlExtended::getProvisioningUrl('',false,false));
+        }
+
+        return Helper\view()
+            ->addElement(new Description('emailAccount'))
+            ->addElement(Accounts::class)
+            ;
+
+    }
+}

+ 43 - 0
app/Http/Client/EmailAlias.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Client;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Pages\Description;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Pages\Accounts;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Pages\Aliases;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:12
+ * Class EmailAlias
+ */
+class EmailAlias extends AbstractClientController
+{
+    use WhmcsParams;
+
+    public function index()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->request->get('id'));
+        if ($this->getWhmcsParamByKey('status') !== 'Active' || !$productManager->isControllerAccessible(ControllerEnums::EMAIL_ALIAS_PAGE))
+        {
+            return Helper\redirectByUrl(BuildUrlExtended::getProvisioningUrl('',false,false));
+        }
+
+        return Helper\view()
+            ->addElement(new Description('emailAlias'))
+            ->addElement(Aliases::class)
+            ;
+
+    }
+}

+ 34 - 0
app/Http/Client/Home.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Client;
+
+use ModulesGarden\Servers\AwsEc2\App\UI\Client\Home\Pages\ScheduledTasks;
+use ModulesGarden\Servers\AwsEc2\App\UI\Client\Home\Pages\StatusWidget;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Home\Pages\Dashboard;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:13
+ * Class Home
+ */
+class Home extends AbstractClientController
+{
+    use WhmcsParams;
+
+    public function index()
+    {
+        if ($this->getWhmcsParamByKey('status') === 'Active')
+        {
+            return Helper\view()
+                ->addElement(Dashboard::class)
+                ;
+        }
+    }
+
+}

+ 43 - 0
app/Http/Client/Ressource.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Client;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Pages\Description;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Pages\Ressources;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:12
+ * Class Ressource
+ */
+class Ressource extends AbstractClientController
+{
+    use WhmcsParams;
+
+    public function index()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->request->get('id'));
+
+        if ($this->getWhmcsParamByKey('status') !== 'Active' || !$productManager->isControllerAccessible(ControllerEnums::RESSOURCE_PAGE))
+        {
+            return Helper\redirectByUrl(BuildUrlExtended::getProvisioningUrl('',false,false));
+        }
+
+        return Helper\view()
+            ->addElement(new Description('ressource'))
+            ->addElement(Ressources::class)
+            ;
+
+    }
+}

+ 98 - 0
app/Http/Client/Webmail.php

@@ -0,0 +1,98 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Http\Client;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\Core\Http\AbstractClientController;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:13
+ * Class Webmail
+ */
+class Webmail extends AbstractClientController
+{
+    use WhmcsParams;
+
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse
+     */
+    public function index()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->request->get('id'));
+        if ($this->getWhmcsParamByKey('status') !== 'Active' || !$productManager->isControllerAccessible(ControllerEnums::WEBMAIL_PAGE))
+        {
+            return Helper\redirectByUrl(BuildUrlExtended::getProvisioningUrl('',false,false));
+        }
+
+        $link = $productManager->get('login_link');
+
+        if(!$link)
+        {
+            $link = $productManager->getClientUrl();
+        }
+
+        return Helper\redirectByUrl($link, []);
+    }
+
+    /**
+     * @throws \Exception
+     */
+    public function clientSso()
+    {
+        /**
+         *
+         * product managet
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->request->get('id'));
+
+        /**
+         *
+         * load API
+         */
+        $api = (new KerioManager())
+            ->getApiByServer($productManager->getHosting()->server)
+            ->soap;
+
+        /**
+         *
+         * load sso service
+         */
+        $sso = $api
+            ->service()
+            ->clientSingleSignOnToken()
+            ->setFormData(['id' => $this->getRequestValue('actionElementId')]);
+
+        /**
+         *
+         * run service
+         */
+        $result = $sso->run();
+
+        /**
+         *
+         * throw error if without result
+         */
+        if(!$result)
+        {
+            throw new \Exception($sso->getError());
+        }
+
+        $url = $productManager->getClientUrl().'service/preauth';
+
+        return Helper\redirectByUrl($url, ['authtoken' => $result['authToken']]);
+    }
+}

+ 109 - 0
app/Libs/Kerio/Api.php

@@ -0,0 +1,109 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Exceptions\KerioApiException;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Interfaces\ClientInterface;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Client as SoapClient;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ParamsHandler;
+use ModulesGarden\Servers\KerioEmail\App\Traits\StorageTrait;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 27.08.19
+ * Time: 15:05
+ * Class KerioClientConnection
+ * @property SoapClient $soap
+ */
+class Api
+{
+
+    use StorageTrait;
+    use ParamsHandler;
+
+
+    /**
+     * Api constructor.
+     * @param array $params
+     */
+    public function __construct($params = [])
+    {
+       $this->setParams($params);
+    }
+
+    /**
+     * @param $name
+     * @return ClientInterface
+     * @throws \Exception
+     */
+    public function __get($name)
+    {
+        /**
+         * check if class is in storage
+         */
+        if(!$this->getStorage()->exists(strtolower($name)))
+        {
+            /**
+             * prepare class namespace
+             */
+            $class = '\\ModulesGarden\\Servers\\KerioEmail\\App\\Libs\\Kerio\\Components\\Api\\'.ucfirst($name).'\\Client';
+
+            /**
+             * check if class exists or throw error
+             */
+            if(!class_exists($class))
+            {
+                throw new KerioApiException([
+                    'message' => 'Class `'.$class.'`` does not exists',
+                    'debugCode' => KerioApiException::UNSUPORTED_CLIENT]);
+            }
+
+            /**
+             *
+             * create new client class
+             * prepare server parameters
+             */
+            $hostname = $this->params['serverhostname'] ? $this->params['serverhostname'] : $this->params['serverip'];
+            $port     = $this->params['serversecure'] === 'on' ? Kerio::SECURE_PORT : Kerio::PORT;
+            $port     = $this->params['serverport'] ? $this->params['serverport'] : $port;
+            $username = $this->params['serverusername'];
+            $pw       = html_entity_decode($this->params['serverpassword']);
+            $auth     = $this->params['authtype'] ? $this->params['authtype'] : 'admin';
+
+            $client = new $class($hostname, $port, $username, $pw, $auth);
+
+            /**
+             *
+             * throw exception if class is not implemented
+             */
+            if(!($client instanceof ClientInterface))
+            {
+                throw new KerioApiException([
+                    'message' => "Provided client type `{$class}` is not supported",
+                    'debugCode' => KerioApiException::UNSUPORTED_CLIENT]);
+            }
+
+            /**
+             *
+             * add class to storage
+             */
+            $this->getStorage()->set(strtolower($name), $client);
+
+        }else{
+            /**
+             *
+             * get client from storage
+             */
+            $client = $this->getStorage()->get(strtolower($name));
+        }
+
+        /**
+         *
+         */
+        return $client;
+    }
+
+
+
+}

+ 26 - 0
app/Libs/Kerio/Components/Api/Exceptions/KerioApiException.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Exceptions;
+use Throwable;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 11:09
+ * Class KerioApiException
+ */
+class KerioApiException extends \Exception
+{
+
+    const UNSUPORTED_CLASS  = 04001;
+    const UNSUPORTED_CLIENT = 04002;
+
+    public function __construct($params = [])
+    {
+        //todo debug log
+        //$params['']
+        parent::__construct($params['message'], $params['code'], $params['previous']);
+    }
+
+}

+ 15 - 0
app/Libs/Kerio/Components/Api/Exceptions/KerioServiceException.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Exceptions;
+
+/*
+File:   KerioServiceException.php
+Date:   14.08.2020
+Author: Tomasz Bielecki (tomasz.bi@modulesgarden.com)
+Class KerioServiceException
+*/
+
+class KerioServiceException extends \Exception
+{
+
+}

+ 16 - 0
app/Libs/Kerio/Components/Api/Interfaces/AbstractParser.php

@@ -0,0 +1,16 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Interfaces;
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 11:20
+ * Class AbstractParser
+ */
+abstract class AbstractParser
+{
+
+    public abstract function build();
+
+}

+ 29 - 0
app/Libs/Kerio/Components/Api/Interfaces/ClientInterface.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Interfaces;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 11:08
+ * Class ClientInterface
+ */
+interface ClientInterface
+{
+
+    /**
+     *
+     * return connection object
+     *
+     * @return ConnectionInterface
+     */
+    public function getConnection();
+
+    public function repository();
+//
+//    public function service();
+
+}

+ 30 - 0
app/Libs/Kerio/Components/Api/Interfaces/ConnectionInterface.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Interfaces;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 12:12
+ * Class ConnectionInterface
+ */
+interface ConnectionInterface
+{
+
+    /**
+     * check if connection has been established
+     *
+     * @return bool
+     */
+    public function isConnected();
+
+    /**
+     * return connection error message
+     *
+     * @return mixed
+     */
+    public function getConnectionError();
+}

+ 322 - 0
app/Libs/Kerio/Components/Api/Soap/Actions/Account.php

@@ -0,0 +1,322 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractAction;
+use SoapFault;
+use SoapParam;
+use SoapVar;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\XmlParser;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 13:46
+ * Class Account
+ */
+class Account extends AbstractAction
+{
+
+    public function read()
+    {
+
+    }
+
+    /**
+     * @description create account in Kerio API
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account
+     * @return bool|void
+     */
+    public function create(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account)
+    {
+        /**
+         *
+         */
+        $params = [
+            new SoapParam($account->getName(), "name"),
+            new SoapParam($account->getPassword(), "password"),
+        ];
+
+        /**
+         * add account params
+         */
+        foreach ($account->getAttrs() as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        /**
+         * run request
+         */
+        $result = $this->connection->request("CreateAccountRequest", $params);
+
+        $this->setLastResult($result);
+
+        /**
+         * load response to model
+         */
+        if($accountData = $result->getResponseBody()['CREATEACCOUNTRESPONSE']['ACCOUNT'])
+        {
+            $account->fill($accountData);
+            return $account;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias $alias
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias
+     */
+    public function createAlias(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias $alias)
+    {
+        $params = [
+            new SoapParam($alias->getAccountId(), "id"),
+            new SoapParam($alias->getAlias(), "alias"),
+        ];
+
+        $result = $this->connection->request("AddAccountAliasRequest", $params);
+        $this->setLastResult($result);
+
+        if(!$result->getLastError())
+        {
+            return $alias;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account
+     * @return bool|\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account
+     */
+    public function update(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account)
+    {
+        $params = [
+            new SoapParam($account->getId(), "id"),
+        ];
+
+        /**
+         * add account params
+         */
+        foreach ($account->getAttrs() as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        $result = $this->connection->request("ModifyAccountRequest", $params);
+        $this->setLastResult($result);
+
+        if($accountData = $result->getResponseBody()['MODIFYACCOUNTRESPONSE']['ACCOUNT'])
+        {
+            $account->fill($accountData);
+            return $account;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    public function setPassword(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account)
+    {
+        $params = [
+            new SoapParam($account->getId(), "id"),
+            new SoapParam($account->getPassword(), "newPassword"),
+        ];
+
+        $result = $this->connection->request("SetPasswordRequest", $params);
+        $this->setLastResult($result);
+
+        if($result->getLastError())
+        {
+            $this->setError($result->getLastError());
+            return false;
+        }
+
+        return true;
+
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account
+     * @return bool
+     */
+    public function delete(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account)
+    {
+        $params = [
+            new SoapParam($account->getId(), "id"),
+        ];
+
+        $result = $this->connection->request("DeleteAccountRequest", $params);
+        $this->setLastResult($result);
+
+        if($result->getLastError())
+        {
+            $this->setError($result->getLastError());
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias $alias
+     * @return bool
+     */
+    public function deleteAlias(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias $alias)
+    {
+        $params = [
+            new SoapParam($alias->getAccountId(), "id"),
+            new SoapParam($alias->getAlias(), "alias"),
+        ];
+
+        $result = $this->connection->request("RemoveAccountAliasRequest", $params);
+        $this->setLastResult($result);
+
+        if(!$result->getLastError())
+        {
+            return true;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+
+    }
+
+    /**
+     * @param $name
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getAccountId($name)
+    {
+        $params = [
+            new SoapVar('<ns1:account by="name">' . $name . '</ns1:account>', XSD_ANYXML),
+        ];
+
+        return $this->connection->cleanResponse()->request("GetAccountInfoRequest", $params);
+
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getAccountInfo(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account)
+    {
+        if($value = $account->getId())
+        {
+            $type = 'id';
+        }elseif($value =$account->getName())
+        {
+            $type = 'name';
+        }
+
+        $result = null;
+
+        $params = [
+            new SoapVar('<ns1:account by="' . $type . '">' . $value . '</ns1:account>', XSD_ANYXML),
+        ];
+
+        return $this->connection->request("GetAccountInfoRequest", $params);
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function delegateAuth(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account)
+    {
+        if($value = $account->getId())
+        {
+            $type = 'id';
+        }elseif($value =$account->getName())
+        {
+            $type = 'name';
+        }
+
+        $result = null;
+
+        $params = [
+            new SoapVar('<ns1:account by="' . $type . '">' . $value . '</ns1:account>', XSD_ANYXML),
+        ];
+
+        $result = $this->connection->cleanResponse()->request("DelegateAuthRequest", $params);
+        $this->setLastResult($result);
+
+        if($result->getLastError())
+        {
+            $this->setError($result->getLastError());
+            return false;
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getAccountOptions(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account $account)
+    {
+        if($value = $account->getId())
+        {
+            $type = 'id';
+        }elseif($value =$account->getName())
+        {
+            $type = 'name';
+        }
+
+        $params = [
+            new SoapVar('<ns1:account by="' . $type . '">' . $value . '</ns1:account>', XSD_ANYXML),
+        ];
+
+        return  $this->connection
+            ->cleanResponse()
+            ->request("GetAccountRequest", $params);
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getAllByDomain(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+        if($value = $domain->getId())
+        {
+            $type = 'id';
+        }elseif($value =$domain->getName())
+        {
+            $type = 'name';
+        }
+
+        $params = [
+            new SoapVar('<ns1:domain by="' . $type . '">' . $value . '</ns1:domain>', XSD_ANYXML),
+        ];
+        $result = $this->connection->request("GetAllAccountsRequest", $params);
+        return $result;
+    }
+
+    public function getAllAccounts($idOrNameDomain, $type = "auto")
+    {
+        if ($type == "auto")
+        {
+            //$realType = getDomainType($idOrNameDomain);
+        }
+        else
+        {
+            $realType = $type;
+        }
+
+        $result = null;
+
+        $params = [
+            new SoapVar('<ns1:domain by="' . $realType . '">' . $idOrNameDomain . '</ns1:domain>', XSD_ANYXML),
+        ];
+
+        return  $this->connection->request("GetAllAccountsRequest", $params);
+
+    }
+
+}

+ 47 - 0
app/Libs/Kerio/Components/Api/Soap/Actions/ClassOfServices.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractAction;
+use SoapVar;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 13:27
+ * Class ClassOfServices
+ */
+class ClassOfServices extends AbstractAction
+{
+
+    public function getAllCos()
+    {
+        $result = $this->connection->request("GetAllCosRequest");
+        $body = $result->getResponseBody();
+
+        return $body['GETALLCOSRESPONSE']['COS'];
+
+    }
+
+    public function getClassOfServiceName($id)
+    {
+        $params = [
+            new SoapVar('<ns1:cos by="id">' . $id . '</ns1:cos>', XSD_ANYXML),
+        ];
+
+        $this->connection->request("GetCosRequest", $params);
+
+    }
+
+    public function getCosId($name)
+    {
+        $params = [
+            new SoapVar('<ns1:cos by="name">' . $name . '</ns1:cos>', XSD_ANYXML),
+        ];
+
+        $this->connection->request("GetCosRequest", $params);
+    }
+}

+ 321 - 0
app/Libs/Kerio/Components/Api/Soap/Actions/DistributionList.php

@@ -0,0 +1,321 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractAction;
+use SoapFault;
+use SoapParam;
+use SoapVar;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 13:47
+ * Class DistributionList
+ */
+class DistributionList extends AbstractAction
+{
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response|null
+     */
+    function getAllDistributionLists(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+
+        $result = null;
+
+        $params = array(
+            new SoapVar('<ns1:domain by="name">'.$domain->getName().'</ns1:domain>', XSD_ANYXML),
+        );
+
+        $this->connection->cleanResponse();
+        $result = $this->connection
+            ->cleanResponse()
+            ->request("GetAllDistributionListsRequest", $params);
+
+        return $result;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list
+     * @return bool|\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList
+     */
+    public function read(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapVar('<ns1:dl by="id">'.$list->getId().'</ns1:dl>', XSD_ANYXML),
+        );
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("GetDistributionListRequest",$params);
+
+        if($data = $result->getResponseBody()['GETDISTRIBUTIONLISTRESPONSE']['DL'])
+        {
+            $list->fill($data);
+            return $list;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list
+     * @return bool|\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList
+     */
+    public function create(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapParam($list->getName(), "name"),
+        );
+
+
+        $attrs = $list->getAttrs();
+
+        if($list->isDynamic())
+        {
+            $params[] = new SoapParam(1, "dynamic");
+            unset($attrs['kerioDistributionListSendShareMessageToNewMembers']);
+        }
+
+        foreach($attrs as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("CreateDistributionListRequest",$params);
+        $this->setLastResult($result);
+
+        /**
+         * load response to model
+         */
+        if($accountData = $result->getResponseBody()['CREATEDISTRIBUTIONLISTRESPONSE']['DL'])
+        {
+            $list->fill($accountData);
+            return $list;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list
+     * @return bool|\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList
+     */
+    public function update(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = [
+            new SoapParam($list->getId(), 'id')
+        ];
+
+        $attrs = $list->getAttrs();
+
+        if($list->isDynamic())
+        {
+            $params[] = new SoapParam(1, "dynamic");
+            unset($attrs['kerioDistributionListSendShareMessageToNewMembers']);
+        }
+
+        foreach($attrs as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("ModifyDistributionListRequest",$params);
+        $this->setLastResult($result);
+
+            if($data = $result->getResponseBody()['MODIFYDISTRIBUTIONLISTRESPONSE']['DL'])
+        {
+            $list->fill($data);
+            return $list;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list
+     * @return bool
+     */
+    public function delete(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapParam($list->getId(), "id"),
+        );
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("DeleteDistributionListRequest",$params);
+        $this->setLastResult($result);
+
+        if($result->getResponseBody()['DELETEDISTRIBUTIONLISTRESPONSE'])
+        {
+            return true;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list
+     * @return bool
+     */
+    public function addMembers(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapParam($list->getId(), "id"),
+        );
+
+        foreach($list->getMembers() as $val)
+        {
+            $params[] = new SoapVar('<ns1:dlm>'.$val.'</ns1:dlm>', XSD_ANYXML);
+        }
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("AddDistributionListMemberRequest",$params);
+        $this->setLastResult($result);
+
+        if($result->getResponseBody()['ADDDISTRIBUTIONLISTMEMBERRESPONSE'])
+        {
+            return true;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    public function deleteMembers(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapParam($list->getId(), "id"),
+        );
+
+        foreach($list->getMembers() as $val)
+        {
+            $params[] = new SoapVar('<ns1:dlm>'.$val.'</ns1:dlm>', XSD_ANYXML);
+        }
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("RemoveDistributionListMemberRequest",$params);
+
+        return $result;
+    }
+
+
+    public function addOwners(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapVar('<ns1:dl by="id">'.$list->getId().'</ns1:dl>', XSD_ANYXML),
+            new SoapVar('<ns1:action op="addOwners">', XSD_ANYXML),
+        );
+
+        foreach($list->getOwners() as $owner)
+        {
+            $params[] = new SoapVar('<ns1:owner type="usr" by="name">'.$owner.'</ns1:owner>', XSD_ANYXML);
+        }
+
+        $params[] = new SoapVar('</ns1:action>', XSD_ANYXML);
+
+        $result = $this->connection
+            ->cleanResponse()
+            ->request("DistributionListActionRequest",$params);
+        $this->setLastResult($result);
+
+        if($result->getResponseBody()['DISTRIBUTIONLISTACTIONRESPONSE'])
+        {
+            return true;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+
+    }
+
+    public function deleteOwners(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapVar('<ns1:dl by="id">'.$id.'</ns1:dl>', XSD_ANYXML),
+            new SoapVar('<ns1:action op="removeOwners">', XSD_ANYXML),
+        );
+
+        foreach($list->getOwners() as $owner) {
+            $params[] = new SoapVar('<ns1:owner type="usr" by="name">'.$owner.'</ns1:owner>', XSD_ANYXML);
+        }
+        $params[] = new SoapVar('</ns1:action>', XSD_ANYXML);
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("DistributionListActionRequest",$params);
+        //todo
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list
+     * @return bool
+     */
+    public function addAlias(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapParam($list->getId(), 'id'),
+            new SoapParam($list->getAlias(), 'alias'),
+        );
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("AddDistributionListAliasRequest",$params);
+        $this->setLastResult($result);
+
+        if($result->getResponseBody()['ADDDISTRIBUTIONLISTALIASRESPONSE'])
+        {
+            return true;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list
+     * @return bool
+     */
+    public function deleteAlias(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList $list)
+    {
+        $params = array(
+            new SoapParam($list->getId(), 'id'),
+            new SoapParam($list->getAlias(), 'alias'),
+        );
+
+
+        $result = $result = $this->connection
+            ->cleanResponse()
+            ->request("RemoveDistributionListAliasRequest",$params);
+        $this->setLastResult($result);
+
+        if($result->getResponseBody()['REMOVEDISTRIBUTIONLISTALIASRESPONSE'])
+        {
+            return true;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+
+
+}

+ 157 - 0
app/Libs/Kerio/Components/Api/Soap/Actions/Domain.php

@@ -0,0 +1,157 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractAction;
+use SoapFault;
+use SoapParam;
+use SoapVar;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 13:46
+ * Class Domain
+ */
+class Domain extends AbstractAction
+{
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain|\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function create(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+        $params   = array(
+            new SoapParam($domain->getName(), "name"),
+        );
+
+        foreach ($domain->getAttrs() as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        $result = $this->connection->request("CreateDomainRequest", $params);
+        $this->setLastResult($result);
+        /**
+         * check data has been returned or return false
+         */
+        if($data = $result->getResponseBody()['CREATEDOMAINRESPONSE']['DOMAIN'])
+        {
+            $domain->fill($data);
+            return $domain;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function update(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+        $params   = array(
+            new SoapParam($domain->getId(), "id"),
+        );
+
+        foreach ($domain->getAttrs() as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        $result = $this->connection->request("ModifyDomainRequest", $params);
+        $this->setLastResult($result);
+        if($data = $result->getResponseBody()['MODIFYDOMAINRESPONSE']['DOMAIN'])
+        {
+            $domain->fill($data);
+            return $domain;
+        }
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return bool
+     */
+    public function delete(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+        $params   = array(
+            new SoapParam($domain->getId(), "id"),
+        );
+
+        $result = $this->connection->cleanResponse()->request("DeleteDomainRequest", $params);
+        $this->setLastResult($result);
+        if($result->getResponseBody()['DELETEDOMAINRESPONSE'])
+        {
+            return true;
+        }
+        $this->setError($result->getLastError());
+        return false;
+
+    }
+
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getAll()
+    {
+        $result = $this->connection->request("GetAllDomainsRequest", []);
+        return $result;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    function getDomainId(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+
+        $params = array(
+            new SoapVar('<ns1:domain by="name">' . $domain->getName() . '</ns1:domain>', XSD_ANYXML),
+        );
+
+        $result = $this->connection->cleanResponse()->request("GetDomainInfoRequest", $params);
+        $this->setLastResult($result);
+        return $result;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    function getDomain(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+
+        $params = array(
+            new SoapVar('<ns1:domain by="name">' . $domain->getName() . '</ns1:domain>', XSD_ANYXML),
+        );
+
+        $result = $this->connection->cleanResponse()->request("GetDomainRequest", $params);
+        $this->setLastResult($result);
+        return $result;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getDomainUsages(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+
+        $params = array(
+            new SoapVar('<ns1:GetQuotaUsageRequest />', XSD_ANYXML),
+            new SoapParam($domain->getName(), 'domain'),
+            new SoapParam("1", 'refresh')
+        );
+
+        $result = $this->connection->request("GetQuotaUsageRequest", $params);
+        $this->setLastResult($result);
+        return $result;
+    }
+
+}

+ 243 - 0
app/Libs/Kerio/Components/Api/Soap/Actions/Ressource.php

@@ -0,0 +1,243 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractAction;
+use SoapFault;
+use SoapParam;
+use SoapVar;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\XmlParser;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 13:46
+ * Class Account
+ */
+class Ressource extends AbstractAction
+{
+
+    public function read()
+    {
+
+    }
+
+    /**
+     * @description create ressource in Kerio API
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource
+     * @return bool|void
+     */
+    public function create(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource)
+    {
+        /**
+         *
+         */
+        $params = [
+            new SoapParam($ressource->getName(), "name"),
+            new SoapParam($ressource->getPassword(), "password"),
+        ];
+
+        /**
+         * add ressource params
+         */
+        foreach ($ressource->getAttrs() as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        /**
+         * run request
+         */
+        $result = $this->connection->request("CreateCalendarResourceRequest", $params);
+
+        $this->setLastResult($result);
+
+        /**
+         * load response to model
+         */
+        if($ressourceData = $result->getResponseBody()['CREATECALENDARRESOURCERESPONSE']['CALRESOURCE'])
+        {
+            $ressource->fill($ressourceData);
+            return $ressource;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource
+     * @return bool|\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource
+     */
+    public function update(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource)
+    {
+        $params = [
+            new SoapParam($ressource->getId(), "id"),
+        ];
+
+        /**
+         * add ressource params
+         */
+        foreach ($ressource->getAttrs() as $key => $value)
+        {
+            $params[] = new SoapVar('<ns1:a n="' . $key . '">' . $value . '</ns1:a>', XSD_ANYXML);
+        }
+
+        $result = $this->connection->request("ModifyCalendarResourceRequest", $params);
+        $this->setLastResult($result);
+
+        if($ressourceData = $result->getResponseBody()['MODIFYCALENDARRESOURCERESPONSE']['CALRESOURCE'])
+        {
+            $ressource->fill($ressourceData);
+            return $ressource;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    public function setPassword(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource)
+    {
+        $params = [
+            new SoapParam($ressource->getId(), "id"),
+            new SoapParam($ressource->getPassword(), "newPassword"),
+        ];
+
+        $result = $this->connection->request("SetPasswordRequest", $params);
+        $this->setLastResult($result);
+
+        if($result->getLastError())
+        {
+            $this->setError($result->getLastError());
+            return false;
+        }
+
+        return true;
+
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource
+     * @return bool
+     */
+    public function delete(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource)
+    {
+        $params = [
+            new SoapParam($ressource->getId(), "id"),
+        ];
+
+        $result = $this->connection->request("DeleteCalendarResourceRequest", $params);
+        $this->setLastResult($result);
+
+        if($result->getLastError())
+        {
+            $this->setError($result->getLastError());
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @param $name
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getRessourceId($name)
+    {
+        $params = [
+            new SoapVar('<ns1:calresource by="name">' . $name . '</ns1:calresource>', XSD_ANYXML),
+        ];
+
+        return $this->connection->cleanResponse()->request("GetCalendarResourceRequest", $params);
+
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getRessourceInfo(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource)
+    {
+        if($value = $ressource->getId())
+        {
+            $type = 'id';
+        }elseif($value =$ressource->getName())
+        {
+            $type = 'name';
+        }
+
+        $result = null;
+
+        $params = [
+            new SoapVar('<ns1:calresource by="' . $type . '">' . $value . '</ns1:calresource>', XSD_ANYXML),
+        ];
+
+        return $this->connection->request("GetCalendarResourceRequest", $params);
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getRessourceOptions(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource $ressource)
+    {
+        if($value = $ressource->getId())
+        {
+            $type = 'id';
+        }elseif($value =$ressource->getName())
+        {
+            $type = 'name';
+        }
+
+        $params = [
+            new SoapVar('<ns1:calresource by="' . $type . '">' . $value . '</ns1:calresource>', XSD_ANYXML),
+        ];
+
+        return  $this->connection
+            ->cleanResponse()
+            ->request("GetCalendarResourceRequest", $params);
+    }
+
+    /**
+     * @param \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function getAllByDomain(\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain $domain)
+    {
+        if($value = $domain->getId())
+        {
+            $type = 'id';
+        }elseif($value =$domain->getName())
+        {
+            $type = 'name';
+        }
+
+        $params = [
+            new SoapVar('<ns1:domain by="' . $type . '">' . $value . '</ns1:domain>', XSD_ANYXML),
+        ];
+        $result = $this->connection->request("GetAllCalendarResourcesRequest", $params);
+        return $result;
+    }
+
+    public function getAllRessources($idOrNameDomain, $type = "auto")
+    {
+        if ($type == "auto")
+        {
+            //$realType = getDomainType($idOrNameDomain);
+        }
+        else
+        {
+            $realType = $type;
+        }
+
+        $result = null;
+
+        $params = [
+            new SoapVar('<ns1:domain by="' . $realType . '">' . $idOrNameDomain . '</ns1:domain>', XSD_ANYXML),
+        ];
+
+        return  $this->connection->request("GetAllCalendarResourcesRequest", $params);
+
+    }
+
+}

+ 20 - 0
app/Libs/Kerio/Components/Api/Soap/Actions/Server.php

@@ -0,0 +1,20 @@
+<?php
+
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractAction;
+use SoapVar;
+
+class Server extends AbstractAction
+{
+    public function getAllServers()
+    {
+        $result = $this->connection->request("GetAllServersRequest");
+        $body = $result->getResponseBody();
+
+        return $body['GETALLSERVERSRESPONSE']['SERVER'];
+
+    }
+}

+ 19 - 0
app/Libs/Kerio/Components/Api/Soap/Actions/User.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractAction;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 13:46
+ * Class User
+ */
+class User extends AbstractAction
+{
+
+}

+ 136 - 0
app/Libs/Kerio/Components/Api/Soap/Client.php

@@ -0,0 +1,136 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Interfaces\ClientInterface;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions\Server;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Actions\User;
+use ModulesGarden\Servers\KerioEmail\App\Traits\StorageTrait;
+use MySoapClient;
+use SoapFault;
+use SoapHeader;
+use SoapParam;
+use SoapVar;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 27.08.19
+ * Time: 15:39
+ * Class SoapClient
+ * @property Account $account
+ * @property DistributionList $distributionList
+ * @property Domain $domain
+ * @property User $user
+ * @property ClassOfServices $classOfServices
+ * @property Server $server
+ * @property Connection $connection
+ *
+ */
+class Client implements ClientInterface
+{
+    use StorageTrait;
+
+    /**
+     * @var Connection
+     */
+    protected $connection;
+
+    /**
+     * @var Repository
+     */
+    protected $repository;
+
+    /**
+     * @var Services
+     */
+    protected $service;
+
+    /**
+     * Client constructor.
+     * @param $server
+     * @param int $port
+     * @param $username
+     * @param $password
+     * @param string $user
+     * @throws SoapFault
+     */
+    public function __construct($server, $port = 7071, $username, $password, $user = "admin")
+    {
+        $this->connection = new Connection($server, $port, $username, $password, $user);
+        $this->connection->login();
+    }
+
+    /**
+     * @param $conection
+     */
+    public function setConnection($conection)
+    {
+        $this->connection = $conection;
+    }
+
+    /**
+     * @return Connection
+     */
+    public function getConnection()
+    {
+        return $this->connection;
+    }
+
+    /**
+     *
+     * return repository manager
+     * @return Repository
+     */
+    public function repository()
+    {
+        if(!$this->repository)
+        {
+            $this->repository = new Repository($this);
+        }
+
+        return $this->repository;
+    }
+
+    /**
+     * @return Services
+     */
+    public function service()
+    {
+        if(!$this->service)
+        {
+            $this->service = new Services($this);
+        }
+        return $this->service;
+    }
+
+    /**
+     * @param $name
+     * @return mixed
+     * @throws \Exception
+     */
+    public function __get($name)
+    {
+        if(!$this->getStorage()->exists(strtolower($name)))
+        {
+            $class = '\\ModulesGarden\\Servers\\KerioEmail\\App\\Libs\\Kerio\\Components\\Api\\Soap\\Actions\\'.ucfirst($name);
+
+            if(!class_exists($class))
+            {
+                throw new \Exception('Action class '.$class.' does not exists');
+            }
+
+            $action = new $class($this->connection);
+
+            $this->getStorage()->set(strtolower($name), $action);
+        }else{
+
+            $action = $this->getStorage()->get(strtolower($name));
+        }
+
+        return $action;
+    }
+}

+ 412 - 0
app/Libs/Kerio/Components/Api/Soap/Connection.php

@@ -0,0 +1,412 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Interfaces\ConnectionInterface;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\XmlParser;
+use \SoapFault;
+use \SoapHeader;
+use \SoapParam;
+use \SoapVar;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 13:47
+ * Class Connection
+ */
+class Connection implements ConnectionInterface
+{
+    /**
+     * uri
+     */
+    const URI_ADMIN   = 'urn:kerioAdmin';
+    const URI_ACCOUNT = 'urn:kerioAccount';
+
+    /**
+     * protocol
+     */
+    const HTTPS_PROTOCOL = 'https://';
+
+    /**
+     * path
+     */
+    const ADMIN_PATH        = '/service/admin/soap/';
+    const ACCOUNT_PATH      = '/service/soap/';
+
+    /**
+     * ports
+     */
+    const CLIENT_PORT = '8443';
+
+    /**
+     * @var MySoapClient
+     */
+    protected $soapClient;
+    /**
+     * @var mixed
+     */
+    protected $params;
+    /**
+     * @var
+     */
+    protected $header;
+    /**
+     * @var
+     */
+    protected $responseModel;
+
+    /**
+     * @var bool
+     */
+    protected $connected = false;
+
+    /**
+     * @var null
+     */
+    protected $connectionError = null;
+
+    /**
+     * @var string
+     */
+    protected $authToken    = '';
+
+    /**
+     * @var string
+     */
+    protected $serverUrl = '';
+
+    protected $server;
+    protected $port;
+
+    /**
+     * Connection constructor.
+     * @param $server
+     * @param int $port
+     * @param $username
+     * @param $password
+     * @param string $user
+     * @throws SoapFault
+     */
+    public function __construct($server, $port = 7071, $username, $password = null, $user = "admin", $authToken = null , $preauth = null)
+    {
+        /**
+         * set params
+         */
+        $this->server = $server;
+        $this->port = $port;
+
+        /**
+         *
+         * get login credential by type
+         */
+        list($location, $uri, $params) = $this->getLoginDetails($server, $port, $username, $password, $user,$authToken, $preauth);
+
+        /**
+         *
+         * create new soap client with data
+         */
+        $this->soapClient = new \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\MySoapClient(null,
+            [
+                'location'       => $location,
+                'uri'            => $uri,
+                'trace'          => 1,
+                'exceptions'     => 1,
+                'soap_version'   => SOAP_1_2,
+                'style'          => SOAP_RPC,
+                'use'            => SOAP_LITERAL,
+                'stream_context' => stream_context_create(
+                    [
+                        'ssl' => [
+                            'verify_peer'      => false,
+                            'verify_peer_name' => false,
+                        ]])
+            ]
+        );
+
+        /**
+         * set credential params
+         */
+        $this->params = $params;
+    }
+
+    /**
+     * @param $server
+     * @param int $port
+     * @param $username
+     * @param $password
+     * @param $user
+     * @return array
+     */
+    protected function getLoginDetails($server, $port, $username, $password, $user, $authToken = null, $preauth = null)
+    {
+        $this->serverUrl    = self::HTTPS_PROTOCOL . $server . ":" . $port;
+
+        /**
+         *
+         * admin details
+         */
+        if ($user == "admin")
+        {
+            $location = self::HTTPS_PROTOCOL . $server . ":" . $port . self::ADMIN_PATH;
+
+            $uri = self::URI_ADMIN;
+
+            $params = [
+                new SoapParam($username, "name"),
+                new SoapParam($password, "password"),
+            ];
+        }
+
+        /**
+         *
+         * user details
+         */
+        if ($user == "user")
+        {
+            $location = self::HTTPS_PROTOCOL . $server . ":" . ($port ? $port : self::CLIENT_PORT)  . self::ACCOUNT_PATH;
+            $uri = self::URI_ACCOUNT;
+            $params = [
+                new SoapVar('<ns1:account by="name">' . $username . '</ns1:account>', XSD_ANYXML),
+            ];
+
+            if($authToken)
+            {
+                $params[] =  new SoapParam($authToken, "authToken");
+            }else{
+                $params[] =  new SoapParam($password, "password");
+            }
+
+        }
+
+        /**
+         *
+         * return data
+         */
+        return [$location, $uri, $params];
+    }
+    
+    /**
+     *
+     *
+     * @return \Exception|mixed|SoapFault|null
+     */
+    public function login()
+    {
+        try
+        {
+            /**
+             * set headers
+             */
+            $this->setSoapHeader();
+
+            /**
+             *
+             * authentication request
+             */
+            $result = $this->soapClient->__soapCall("AuthRequest", $this->params, null, $this->getSoapHeader());
+
+            /**
+             *
+             * Save the soapHeader with token
+             */
+            $this->authToken    = $result['authToken'];
+            $this->setSoapHeader($this->authToken);
+
+            /**
+             *
+             * set connected as true
+             */
+            $this->setConnected(true);
+        }
+        catch (SoapFault $exception)
+        {
+            $result = $exception;
+            /**
+             * set connected as false
+             */
+            $this->setConnected(false);
+            $this->setConnectionError($exception->getMessage());
+        }
+
+        return $result;
+    }
+
+    /**
+     * @return mixed
+     */
+    function getSoapHeader()
+    {
+        return $this->header;
+    }
+
+    /**
+     * @param null $authToken
+     */
+    function setSoapHeader($authToken = null)
+    {
+        if (!$authToken)
+        {
+            $this->header = new SoapHeader('urn:kerio', 'context');
+        }
+        else
+        {
+            $this->header = [
+                new SoapHeader(
+                    'urn:kerio',
+                    'context',
+                    new SoapVar('<ns2:context><ns2:authToken>' . $authToken . '</ns2:authToken></ns2:context>', XSD_ANYXML)
+                )
+            ];
+        }
+    }
+
+    /**
+     * @param $request
+     * @param array $params
+     * @param array $options
+     * @return Response
+     */
+    public function request($request, $params = [], $options = [])
+    {
+        /**
+         * headers
+         */
+        $soapHeader = $this->getSoapHeader();
+        /**
+         * response model
+         */
+        $response = $this->getResponseModel();
+
+        /**
+         * main request
+         */
+        try
+        {
+
+            /**
+             *
+             * request to api
+             */
+            $this->soapClient->__soapCall(
+                $request,
+                $params,
+                $options,
+                $soapHeader
+            );
+
+        }
+        catch (\SoapFault $ex)
+        {
+            $response->setLastError($ex->getMessage());
+        }
+        catch (\Exception $ex)
+        {
+            $response->setLastError($ex->getMessage());
+        }
+
+        /**
+         * Kerio api response
+         */
+        $soapRes = $this->soapClient->__getLastResponse();
+
+        /**
+         *
+         * set response model params
+         */
+        $response
+            ->setRequest($request)
+            ->setParams($params)
+            ->setOptions($options)
+            ->setHeaders($soapHeader)
+            ->setXmlResponse($soapRes)
+            ->response();
+
+        return $response;
+    }
+
+    /**
+     * @param $response
+     */
+    public function setResponseModel($response)
+    {
+        $this->responseModel = $response;
+    }
+
+    /**
+     * @return Response
+     */
+    public function getResponseModel()
+    {
+        if (!$this->responseModel)
+        {
+            $this->responseModel = new Response();
+        }
+
+        return $this->responseModel;
+    }
+
+    /**
+     * @return $this
+     */
+    public function cleanResponse()
+    {
+        $this->responseModel = null;
+        return $this;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isConnected()
+    {
+        return $this->connected;
+    }
+
+    /**
+     * @param $connected
+     * @return $this
+     */
+    public function setConnected($connected)
+    {
+        $this->connected = $connected;
+        return $this;
+    }
+
+    /**
+     * @return null
+     */
+    public function getConnectionError()
+    {
+        return $this->connectionError;
+    }
+
+    /**
+     * @param $connectionError
+     * @return $this
+     */
+    public function setConnectionError($connectionError)
+    {
+        $this->connectionError = $connectionError;
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAuthToken()
+    {
+        return $this->authToken;
+    }
+
+    /**
+     * @return string
+     */
+    public function getServerUrl()
+    {
+        return $this->serverUrl;
+    }
+}

+ 16 - 0
app/Libs/Kerio/Components/Api/Soap/Enums/ApiErrorCodes.php

@@ -0,0 +1,16 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Enums;
+
+/*
+File:   ErrorCodes.php
+Date:   13.08.2020
+Author: Tomasz Bielecki (tomasz.bi@modulesgarden.com)
+Class ErrorCodes
+*/
+
+class ApiErrorCodes
+{
+
+    const DOMAIN_DOES_NOT_EXISTS = 'account.NO_SUCH_DOMAIN';
+
+}

+ 46 - 0
app/Libs/Kerio/Components/Api/Soap/Helpers/AccountHelper.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:22
+ * Class AccountHelper
+ */
+class AccountHelper
+{
+
+    /**
+     * @description return formatted data per API data
+     * @param $date
+     * @return false|string|null
+     */
+    public static function getFormattedData($date, $format = 'd/m/Y')
+    {
+        if(!$date)
+        {
+            return null;
+        }
+        $tmpDate = strstr($date, '.', true);
+        $tmpDate = $tmpDate ? $tmpDate : $date;
+
+        return date($format, strtotime($tmpDate));
+    }
+
+    /**
+     * @param $quote
+     * @return float|int|string
+     */
+    public static function getQuotaAsMb($quote)
+    {
+        return isset($quote) ? ($quote / Size::B_TO_MB)  : ProductParams::SIZE_UNLIMITED;
+    }
+
+}

+ 36 - 0
app/Libs/Kerio/Components/Api/Soap/Helpers/RessourceHelper.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:22
+ * Class RessourceHelper
+ */
+class RessourceHelper
+{
+
+    /**
+     * @description return formatted data per API data
+     * @param $date
+     * @return false|string|null
+     */
+    public static function getFormattedData($date, $format = 'd/m/Y')
+    {
+        if(!$date)
+        {
+            return null;
+        }
+        $tmpDate = strstr($date, '.', true);
+        $tmpDate = $tmpDate ? $tmpDate : $date;
+
+        return date($format, strtotime($tmpDate));
+    }
+}

+ 39 - 0
app/Libs/Kerio/Components/Api/Soap/Helpers/ServiceFactory.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * Class ServiceFactory
+ * User: Nessandro
+ * Date: 2019-09-12
+ * Time: 10:21
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateConfigOptionAccountOld;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateCustomAccountOld;
+
+class ServiceFactory
+{
+
+    /**
+     * @param $type
+     * @return CreateCustomAccountOld
+     */
+    public static function createAccount($type)
+    {
+        switch ($type)
+        {
+            case ClassOfServices::CUSTOM_ZIMBRA:
+                $service = new CreateCustomAccountOld();
+                break;
+            case ClassOfServices::ZIMBRA_CONFIG_OPTIONS:
+                $service = new CreateConfigOptionAccountOld();
+                break;
+        }
+
+        return $service;
+    }
+
+}

+ 133 - 0
app/Libs/Kerio/Components/Api/Soap/Helpers/XmlParser.php

@@ -0,0 +1,133 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers;
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 14:42
+ * Class XmlParser
+ */
+class XmlParser
+{
+    /**
+     * @var array
+     */
+    var $stack=array();
+    /**
+     * @var
+     */
+    var $stack_ref;
+    /**
+     * @var array
+     */
+    var $arrOutput = array();
+    /**
+     * @var
+     */
+    var $resParser;
+    /**
+     * @var
+     */
+    var $strXmlData;
+
+    /**
+     * @param $pos
+     */
+    public function push_pos(&$pos)
+    {
+        $this->stack[count($this->stack)]=&$pos;
+        $this->stack_ref=&$pos;
+    }
+
+    /**
+     *
+     */
+    public function pop_pos()
+    {
+        unset($this->stack[count($this->stack)-1]);
+        $this->stack_ref=&$this->stack[count($this->stack)-1];
+    }
+
+    /**
+     * @param $strInputXML
+     * @return array
+     */
+    public function parse($strInputXML)
+    {
+        $this->resParser = xml_parser_create ();
+        xml_set_object($this->resParser,$this);
+        xml_set_element_handler($this->resParser, "tagOpen", "tagClosed");
+
+        xml_set_character_data_handler($this->resParser, "tagData");
+
+        $this->push_pos($this->arrOutput);
+
+        $this->strXmlData = xml_parse($this->resParser,$strInputXML );
+        if(!$this->strXmlData)
+        {
+            var_dump(sprintf("XML error: %s at line %d",
+                xml_error_string(xml_get_error_code($this->resParser)),
+                xml_get_current_line_number($this->resParser)));
+            die();
+        }
+
+        xml_parser_free($this->resParser);
+
+        return $this->arrOutput;
+    }
+
+    /**
+     * @param $parser
+     * @param $name
+     * @param $attrs
+     */
+    public function tagOpen($parser, $name, $attrs)
+    {
+        if (isset($this->stack_ref[$name]))
+        {
+            if (!isset($this->stack_ref[$name][0]))
+            {
+                $tmp=$this->stack_ref[$name];
+                unset($this->stack_ref[$name]);
+                $this->stack_ref[$name][0]=$tmp;
+            }
+            $cnt=count($this->stack_ref[$name]);
+            $this->stack_ref[$name][$cnt]=array();
+            if (isset($attrs))
+                $this->stack_ref[$name][$cnt]=$attrs;
+            $this->push_pos($this->stack_ref[$name][$cnt]);
+        }
+        else
+        {
+            $this->stack_ref[$name]=array();
+            if (isset($attrs))
+                $this->stack_ref[$name]=$attrs;
+            $this->push_pos($this->stack_ref[$name]);
+        }
+    }
+
+    /**
+     * @param $parser
+     * @param $tagData
+     */
+    public function tagData($parser, $tagData)
+    {
+        if(trim($tagData))
+        {
+            if(isset($this->stack_ref['DATA']))
+                $this->stack_ref['DATA'] .= $tagData;
+            else
+                $this->stack_ref['DATA'] = $tagData;
+        }
+    }
+
+    /**
+     * @param $parser
+     * @param $name
+     */
+    public function tagClosed($parser, $name)
+    {
+        $this->pop_pos();
+    }
+}

+ 44 - 0
app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractAction.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Connection;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ErrorHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 13:56
+ * Class AbstractAction
+ */
+abstract class AbstractAction extends AbstractConnection
+{
+    use ErrorHandler;
+
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    protected $lastResult = null;
+
+    /**
+     * @return |null
+     */
+    public function getLastResult()
+    {
+        return $this->lastResult;
+    }
+
+    /**
+     * @param $lastResult
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    public function setLastResult($lastResult)
+    {
+        $this->lastResult = $lastResult;
+        return $this;
+    }
+
+}

+ 51 - 0
app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractApiClient.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Client;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 10:05
+ * Class AbstractApiClient
+ */
+class AbstractApiClient
+{
+    /**
+     * @var Client
+     */
+    protected $client;
+
+    /**
+     * AbstractApiClient constructor.
+     * @param Client|null $client
+     */
+    public function __construct(Client $client = null)
+    {
+        $this->setClient($client);
+    }
+
+    /**
+     * @return Client
+     */
+    public function getClient()
+    {
+        return $this->client;
+    }
+
+    /**
+     * @param Client|null $client
+     * @return $this
+     */
+    public function setClient(Client $client = null)
+    {
+        $this->client = $client;
+        return $this;
+    }
+
+
+}

+ 47 - 0
app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractConnection.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Connection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 09:47
+ * Class AbstractConnection
+ */
+class AbstractConnection
+{
+    /**
+     * @var Connection
+     */
+    protected $connection;
+
+    /**
+     * AbstractAction constructor.
+     * @param Connection|null $connection
+     */
+    public function __construct(Connection $connection= null)
+    {
+        $this->setConnection($connection);
+    }
+
+    /**
+     * @param Connection|null $connection
+     */
+    public function setConnection(Connection $connection= null)
+    {
+        $this->connection = $connection;
+    }
+
+    /**
+     * @return Connection
+     */
+    public function getConnection()
+    {
+        return $this->connection;
+    }
+}

+ 122 - 0
app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractModel.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 13:34
+ * Class AbstractModel
+ */
+abstract class AbstractModel
+{
+    /**
+     * @description storage other resources
+     * @var array
+     */
+    protected $resources = [];
+
+    /**
+     * AbstractModel constructor.
+     * @param array $data
+     */
+    public function __construct($data = [])
+    {
+        $this->fill($data);
+    }
+
+    /**
+     * @param array $data
+     * @return $this
+     */
+    public function fill($data = [])
+    {
+
+        foreach ($data as $key => $row)
+        {
+            $property = strtolower($key);
+            /* method Name */
+            $method = 'set' . ucfirst($property);
+            /* property name */
+            if (method_exists($this, $method)) {
+                /**
+                 * set through method if exists
+                 *
+                 */
+                $this->$method($row);
+
+            } elseif (property_exists($this, $property)) {
+                /**
+                 * set as property if exists
+                 */
+                $this->{$property} = $row;
+            } else {
+                /**
+                 * add data to resources if property or methods doesnt exists
+                 */
+                $this->addResource($property, $row);
+            }
+
+        }
+
+        return $this;
+    }
+
+    /**
+     * @param $name
+     * @return |null
+     */
+    public function getDataResourceA($name)
+    {
+        foreach ($this->resources['a'] as $res) {
+            if ($res['N'] === $name) {
+                return $res['DATA'];
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @param $name
+     * @return array
+     */
+    public function getDataResourceACollection($name)
+    {
+        foreach ($this->resources['a'] as $res) {
+            if ($res['N'] === $name) {
+                $tmp[] = $res['DATA'];
+            }
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getAllDataResourcesAAttributes()
+    {
+        foreach ($this->resources['a'] as $res) {
+            $tmp[$res['N']] = $res['DATA'];
+
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @param $key
+     * @param array $data
+     * @return $this
+     */
+    public function addResource($key, $data = [])
+    {
+        $this->resources[$key] = $data;
+        return $this;
+    }
+
+}

+ 19 - 0
app/Libs/Kerio/Components/Api/Soap/Interfaces/AbstractRepository.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ErrorHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 14:44
+ * Class AbstractRepository
+ */
+class AbstractRepository extends AbstractApiClient
+{
+    use ErrorHandler;
+}

+ 130 - 0
app/Libs/Kerio/Components/Api/Soap/Interfaces/ApiService.php

@@ -0,0 +1,130 @@
+<?php
+/**
+ * Class ApiService
+ * User: Nessandro
+ * Date: 2019-09-12
+ * Time: 10:42
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Exceptions\KerioServiceException;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Client;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ApiClientHandler;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ErrorHandler;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\FormDataHandler;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProcessStepHandler;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\response;
+
+class ApiService
+{
+    use ApiClientHandler;
+    use FormDataHandler;
+    use ProcessStepHandler;
+    use ErrorHandler;
+
+    /**
+     * ApiService constructor.
+     * @param Client|null $api
+     */
+    public function __construct(Client $api = null )
+    {
+        if($api)
+        {
+            $this->setApi($api);
+        }
+    }
+
+    /**
+     * configure service
+     */
+    protected function config()
+    {
+        //todo
+    }
+
+    /**
+     * Check if service is valid
+     *
+     * @return bool
+     */
+    protected function isValid()
+    {
+        /**
+         * check if api is set
+         */
+        if(!$this->api)
+        {
+            $this->setError('API Not Found');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * main process of service
+     *
+     * @return mixed
+     */
+    protected function process()
+    {
+        //todo
+    }
+
+    /**
+     * clear data after service
+     */
+    protected function clear()
+    {
+
+    }
+
+    /**
+     * Run process of service
+     *
+     * @return bool|void
+     */
+    public function run()
+    {
+
+        $this->config();
+
+        if($result = $this->isValid())
+        {
+            $result = $this->process();
+        }
+
+        $this->clear();
+
+        return $result;
+    }
+
+    /**
+     *
+     * @description catch exceptions
+     * @return bool|string|void
+     */
+    public function safeRun()
+    {
+        try{
+            return $this->run();
+        }catch (\Exception $e){
+            return $e->getMessage();
+        }
+    }
+
+
+    /**
+     * @description run if you want to return some error
+     * @param string $message
+     * @param int $code
+     * @throws KerioServiceException
+     */
+    protected function throwError($message = 'Service error, contact ModulesGarden to investigate this problem.', $code = 0)
+    {
+        throw new KerioServiceException($message, $code);
+    }
+}

+ 199 - 0
app/Libs/Kerio/Components/Api/Soap/Models/Account.php

@@ -0,0 +1,199 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractModel;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 08:43
+ * Class Account
+ */
+class Account extends AbstractModel
+{
+    /**
+     * Account Attributes
+     */
+    const ATTR_FIRSTNAME        = 'givenName';
+    const ATTR_LASTNAME         = 'sn';
+    const ATTR_PHONE            = 'telephoneNumber';
+    const ATTR_MOBILE_PHONE     = 'mobile';
+    const ATTR_FAX              = 'facsimileTelephoneNumber';
+    const ATTR_PAGER            = 'pager';
+    const ATTR_HOME_PHONE       = 'homePhone';
+    const ATTR_COUNTRY          = 'co';
+    const ATTR_STATE            = 'st';
+    const ATTR_POSTAL_CODE      = 'postalCode';
+    const ATTR_CITY             = 'l';
+    const ATTR_STREET           = 'street';
+    const ATTR_COMPANY          = 'company';
+    const ATTR_PROF_TITLE       = 'title';
+    const ATTR_ACCOUNT_STATUS   = 'kerioAccountStatus';
+    const ATTR_DISPLAY_NAME     = 'displayName';
+    const ATTR_MAIL_QUOTA       = 'kerioMailQuota';
+    const ATTR_ALIAS            = 'kerioMailAlias';
+    const ATTR_CLASS_OF_SERVICE_ID = 'kerioCOSId';
+
+    protected $id;
+    protected $name;
+    protected $password;
+    protected $attrs;
+    protected $limit;
+    protected $used;
+
+    /**
+     * @return mixed
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param $name
+     * @return $this
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getPassword()
+    {
+        return $this->password;
+    }
+
+    /**
+     * @param $password
+     * @return $this
+     */
+    public function setPassword($password)
+    {
+        $this->password = $password;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param $id
+     * @return $this
+     */
+    public function setId($id)
+    {
+        $this->id = $id;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getLimit()
+    {
+        return $this->limit;
+    }
+
+    /**
+     * @param $limit
+     * @return $this
+     */
+    public function setLimit($limit = 0)
+    {
+        $this->limit = $limit;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getUsed()
+    {
+        return $this->used;
+    }
+
+    /**
+     * @param $used
+     * @return $this
+     */
+    public function setUsed($used = 0)
+    {
+        $this->used = $used;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getAttrs()
+    {
+        return $this->attrs;
+    }
+
+    /**
+     * @param $key
+     * @param null $value
+     * @return $this
+     */
+    public function setAttr($key, $value = null)
+    {
+        $this->attrs[$key] = $value;
+        return $this;
+    }
+
+    /**
+     * @param $key
+     * @return mixed
+     */
+    public function getAttr($key)
+    {
+        return $this->attrs[$key];
+    }
+
+    /**
+     * @param $attrs
+     * @return $this
+     */
+    public function setAttrs($attrs = [])
+    {
+        $this->attrs = $attrs;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getCosId()
+    {
+        return $this->getDataResourceA(self::ATTR_CLASS_OF_SERVICE_ID);
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getAliases()
+    {
+        foreach($this->resources['a'] as $res)
+        {
+            if($res['N'] === self::ATTR_ALIAS)
+            {
+                $tmp[$res['DATA']] =  $res['DATA'];
+            }
+        }
+        return $tmp;
+    }
+
+}

+ 77 - 0
app/Libs/Kerio/Components/Api/Soap/Models/AccountAlias.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 12:24
+ * Class Alias
+ */
+class AccountAlias
+{
+    protected $accountId;
+    protected $alias;
+    protected $accountName;
+
+    /**
+     * @return mixed
+     */
+    public function getAccountId()
+    {
+        return $this->accountId;
+    }
+
+    /**
+     * @param $accountId
+     * @return $this
+     */
+    public function setAccountId($accountId)
+    {
+        $this->accountId = $accountId;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getAlias()
+    {
+        return $this->alias;
+    }
+
+    /**
+     * @param $alias
+     * @return $this
+     */
+    public function setAlias($alias)
+    {
+        $this->alias = $alias;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getAccountName()
+    {
+        return $this->accountName;
+    }
+
+    /**
+     * @param $accountName
+     * @return $this
+     */
+    public function setAccountName($accountName)
+    {
+        $this->accountName = $accountName;
+        return $this;
+    }
+
+
+
+
+}

+ 68 - 0
app/Libs/Kerio/Components/Api/Soap/Models/ClassOfService.php

@@ -0,0 +1,68 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models  ;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractModel;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 13:34
+ * Class ClassOfService
+ */
+class ClassOfService extends AbstractModel
+{
+    protected $name;
+    protected $id;
+
+    /**
+     * @return mixed
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param mixed $name
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param mixed $id
+     */
+    public function setId($id)
+    {
+        $this->id = $id;
+    }
+
+    /**
+     * @return float|int
+     */
+    public function getMbMailQuote()
+    {
+        $quete = $this->getDataResourceA('kerioMailQuota');
+        return $quete / 1024 /1024;
+    }
+
+    /**
+     * @return float|int
+     */
+    public function getMailQuote()
+    {
+        $quete = $this->getDataResourceA('kerioMailQuota');
+        return $quete / 1024 /1024;
+    }
+
+}

+ 257 - 0
app/Libs/Kerio/Components/Api/Soap/Models/DistributionList.php

@@ -0,0 +1,257 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractModel;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 08:43
+ * Class DistributionList
+ */
+class DistributionList extends AbstractModel
+{
+    const ATTR_DISPLAY_NAME             = 'displayName';
+    const ATTR_DESCRIPTION              = 'description';
+    const ATTR_SUBSCRIPTION_REQUEST     = 'kerioDistributionListSubscriptionPolicy';
+    const ATTR_UNSUBSCRIPTION_REQUEST   = 'kerioDistributionListUnsubscriptionPolicy';
+    const ATTR_NOTIFY_SHARES            = 'kerioDistributionListSendShareMessageToNewMembers';
+    const ATTR_HIDE_IN_GAL              = 'kerioHideInGal';
+    const ATTR_MAIL_STATUS              = 'kerioMailStatus';
+    const REPLY_TO_ENABLED              = 'kerioPrefReplyToEnabled';
+    const REPLY_TO_DISPLAY              = 'kerioPrefReplyToDisplay';
+    const REPLY_TO_ADDRESS              = 'kerioPrefReplyToAddress';
+
+    protected $name;
+    protected $id;
+    protected $attrs;
+    protected $dynamic = false;
+    protected $members = [];
+    protected $owners  = [];
+    protected $alias   = null;
+
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param $id
+     * @return $this
+     */
+    public function setId($id)
+    {
+        $this->id = $id;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param $name
+     * @return $this
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+        return $this;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isDynamic()
+    {
+        return $this->dynamic;
+    }
+
+    /**
+     * @param bool $dynamic
+     */
+    public function setDynamic($dynamic)
+    {
+        $this->dynamic = $dynamic;
+    }
+
+
+
+    /**
+     * @return mixed
+     */
+    public function getAttrs()
+    {
+        return $this->attrs;
+    }
+
+    /**
+     * @param mixed $attrs
+     */
+    public function setAttrs($attrs)
+    {
+        $this->attrs = $attrs;
+    }
+
+    /**
+     * @param $key
+     * @param null $value
+     */
+    public function setAttr($key, $value = null)
+    {
+        $this->attrs[$key] = $value;
+    }
+
+    /**
+     * @param $member
+     * @return $this
+     */
+    public function addMember($member)
+    {
+        $this->members[$member] = $member;
+        return $this;
+    }
+
+    /**
+     * @param array $members
+     * @return $this
+     */
+    public function setMembers($members = [])
+    {
+        $this->members = $members;
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getMembers()
+    {
+        return $this->members;
+    }
+
+    /**
+     * @param array $owners
+     * @return $this
+     */
+    public function setOwners($owners = [])
+    {
+        $this->owners = $owners;
+        return $this;
+    }
+
+    /**
+     * @param $owner
+     * @return $this
+     */
+    public function addOwner($owner)
+    {
+        $this->owners[$owner] = $owner;
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getOwners()
+    {
+        return $this->owners;
+    }
+
+    /**
+     * @param $owner
+     * @return $this
+     */
+    public function setAlias($alias)
+    {
+        $this->alias = $alias;
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getAlias()
+    {
+        return $this->alias;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getResourceMembers()
+    {
+        if($this->resources['dlm']['DATA'])
+        {
+            $tmp[$this->resources['dlm']['DATA']] = $this->resources['dlm']['DATA'];
+            return $tmp;
+        }
+
+        foreach($this->resources['dlm'] as $owner)
+        {
+            $tmp[$owner['DATA']] = $owner['DATA'];
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getResourceOwners()
+    {
+        $owners = $this->resources['owners'] ? $this->resources['owners'] : $this->owners;
+
+        /**
+         *
+         */
+        if($owners['OWNER']['NAME'])
+        {
+            $tmp[$owners['OWNER']['NAME']] = $owners['OWNER']['NAME'];
+            return $tmp;
+        }
+
+        /**
+         *
+         */
+        foreach($owners['OWNER'] as $owner)
+        {
+
+            $tmp[$owner['NAME']] = $owner['NAME'];
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getResourceAliases()
+    {
+        foreach($this->getDataResourceACollection('kerioMailAlias') as $alias)
+        {
+            if(isset($alias['DATA']) && $this->getName() !== $alias['DATA'])
+            {
+                $tmp[$alias['DATA']] = $alias['DATA'];
+
+            }elseif($this->getName() !== $alias){
+                $tmp[$alias] =$alias;
+            }
+
+        }
+
+        return $tmp;
+    }
+
+}

+ 118 - 0
app/Libs/Kerio/Components/Api/Soap/Models/Domain.php

@@ -0,0 +1,118 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractModel;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 15:20
+ * Class Domain
+ */
+class Domain extends AbstractModel
+{
+    const ATTR_ALIAS_TARGET_ID      = 'kerioDomainAliasTargetId';
+    const ATTR_ALIAS_CATCHALL       = 'kerioMailCatchAllForwardingAddress';
+    const ATTR_DOMAIN_TYPE          = 'kerioDomainType';
+    const ATTR_DESCRIPTION          = 'description';
+    const ATTR_DOMAIN_STATUS        = 'kerioDomainStatus';
+    const ATTR_MAIL_STATUS          = 'kerioMailStatus';
+    const ATTR_MAIL_DOMAIN_QUOTA    = 'kerioMailDomainQuota';
+    const TYPE_ALIAS                = 'alias';
+
+    protected $id;
+    protected $name;
+    protected $attrs;
+
+    /**
+     * @return mixed
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param mixed $name
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getAttrs()
+    {
+        return $this->attrs;
+    }
+
+    /**
+     * @param mixed $attrs
+     */
+    public function setAttrs($attrs)
+    {
+        $this->attrs = $attrs;
+    }
+
+    /**
+     * @param $key
+     * @param null $value
+     */
+    public function setAttr($key, $value = null)
+    {
+        $this->attrs[$key] = $value;
+    }
+
+    /**
+     * @param $key
+     * @return mixed
+     */
+    public function getAttr($key)
+    {
+        return $this->attrs[$key];
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param mixed $id
+     */
+    public function setId($id)
+    {
+        $this->id = $id;
+    }
+
+    /**
+     * @param $attrs
+     */
+    public function setA($attrs)
+    {
+        foreach($attrs as $attr)
+        {
+            $this->setAttr($attr['N'], $attr['DATA']);
+        }
+
+    }
+
+    /**
+     * @return bool
+     */
+    public function isAlias()
+    {
+        $targetId = $this->getAttr(self::ATTR_ALIAS_TARGET_ID);
+        return $targetId ? true : false;
+    }
+
+}

+ 140 - 0
app/Libs/Kerio/Components/Api/Soap/Models/Ressource.php

@@ -0,0 +1,140 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractModel;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 08:43
+ * Class Ressource
+ */
+class Ressource extends AbstractModel
+{
+    /**
+     * Ressource Attributes
+     */
+    const ATTR_NAME         = 'name';
+    const ATTR_STATUS       = 'kerioAccountStatus';
+    const ATTR_TYPE         = 'kerioCalResType';
+    const ATTR_DISPLAY_NAME = 'displayName';
+    const ATTR_DESC         = 'description';
+    const ATTR_NOTE         = 'kerioNotes';
+    const ATTR_CONT         = 'kerioCalResContactName';
+    const ATTR_CONT_EMAIL   = 'kerioCalResContactEmail';
+    const ATTR_CONT_PHONE   = 'kerioCalResContactPhone';
+    const ATTR_SITE         = 'kerioCalResSite';
+    const ATTR_BUILDING     = 'kerioCalResBuilding';
+    const ATTR_FLOOR        = 'kerioCalResFloor';
+    const ATTR_ROOM         = 'kerioCalResRoom';
+    const ATTR_CAPACITY     = 'kerioCalResCapacity';
+    const ATTR_STREET       = 'street';
+    const ATTR_TOWN         = 'l';
+    const ATTR_POSTAL_CODE  = 'postalCode';
+    const ATTR_COUNTY       = 'st';
+    const ATTR_STATE        = 'co';
+    const ATTR_AUTO         = 'kerioCalResAutoAcceptDecline';
+    const ATTR_BUSY         = 'kerioCalResAutoDeclineIfBusy';
+
+    protected $id;
+    protected $name;
+    protected $password;
+    protected $attrs;
+
+    /**
+     * @return mixed
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param $name
+     * @return $this
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getPassword()
+    {
+        return $this->password;
+    }
+
+    /**
+     * @param $password
+     * @return $this
+     */
+    public function setPassword($password)
+    {
+        $this->password = $password;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param $id
+     * @return $this
+     */
+    public function setId($id)
+    {
+        $this->id = $id;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getAttrs()
+    {
+        return $this->attrs;
+    }
+
+    /**
+     * @param $key
+     * @param null $value
+     * @return $this
+     */
+    public function setAttr($key, $value = null)
+    {
+        $this->attrs[$key] = $value;
+        return $this;
+    }
+
+    /**
+     * @param $key
+     * @return mixed
+     */
+    public function getAttr($key)
+    {
+        return $this->attrs[$key];
+    }
+
+    /**
+     * @param $attrs
+     * @return $this
+     */
+    public function setAttrs($attrs = [])
+    {
+        $this->attrs = $attrs;
+        return $this;
+    }
+
+}

+ 30 - 0
app/Libs/Kerio/Components/Api/Soap/Models/Server.php

@@ -0,0 +1,30 @@
+<?php
+
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models;
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractModel;
+
+
+class Server extends AbstractModel
+{
+
+    protected $id;
+
+
+    /**
+     * @return mixed
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param mixed $id
+     */
+    public function setId($id)
+    {
+        $this->id = $id;
+    }
+}

+ 52 - 0
app/Libs/Kerio/Components/Api/Soap/MySoapClient.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap;
+
+
+use SoapClient;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 27.08.19
+ * Time: 15:47
+ * Class MySoapClient
+ */
+class MySoapClient extends SoapClient
+{
+
+    /**
+     * @param string $request
+     * @param string $location
+     * @param string $action
+     * @param int $version
+     * @return string
+     */
+    public function __doRequest($request, $location, $action, $version)
+    {
+
+        if(stripos($request, 'DistributionListActionRequest') !== false)
+        {
+            $request = str_replace(array('ns1:DistributionListActionRequest', 'xmlns:ns2="urn:kerio"'), array('ns2:DistributionListActionRequest', 'xmlns:ns2="urn:kerioAccount"'), $request);
+        }
+
+        return parent::__doRequest($request, $location, $action, $version);
+    }
+
+    /**
+     * @param string $function_name
+     * @param array $arguments
+     * @param array|null $options
+     * @param null $input_headers
+     * @param array|null $output_headers
+     * @return mixed|void
+     */
+    public function __soapCall($function_name, array $arguments, array $options = null, $input_headers = null, array &$output_headers = null)
+    {
+        //todo logg
+        return parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers); // TODO: Change the autogenerated stub
+    }
+
+
+}

+ 102 - 0
app/Libs/Kerio/Components/Api/Soap/Repository.php

@@ -0,0 +1,102 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractApiClient;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractConnection;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\Accounts;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\Ressources;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\Server;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\DistributionLists;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\Domains;
+use ModulesGarden\Servers\KerioEmail\App\Traits\StorageTrait;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 09:37
+ * Class Repository
+ * @property ClassOfServices $cos
+ * @property Domains $domains
+ * @property Accounts $accounts
+ * @property DistributionLists $lists
+ */
+class Repository extends AbstractApiClient
+{
+    use StorageTrait;
+
+    public function __get($name)
+    {
+        $name = strtolower($name);
+        $exists = $this->getStorage()->exists($name);
+
+        if(!$exists && method_exists($this, $name))
+        {
+            $action = $this->$name();
+            $this->getStorage()->set($name, $action);
+        }elseif(!$exists)
+        {
+
+        }elseif($exists){
+
+            $action = $this->getStorage()->get($name);
+        }else{
+            throw new \Exception("Repository `{$name}` not found");
+        }
+
+        return $action;
+    }
+
+    /**
+     * @return Server
+     */
+    public function server()
+    {
+        return new Server($this->getClient());
+    }
+
+    /**
+     * @return ClassOfServices
+     */
+    public function cos()
+    {
+        return new ClassOfServices($this->getClient());
+    }
+
+    /**
+     * @return Domains
+     */
+    public function domains()
+    {
+        return new Domains($this->getClient());
+
+    }
+
+    /**
+     * @return Accounts
+     */
+    public function accounts()
+    {
+        return new Accounts($this->getClient());
+    }
+
+    /**
+     * @return Ressources
+     */
+    public function ressources()
+    {
+        return new Ressources($this->getClient());
+    }
+
+    /**
+     *
+     */
+    public function lists()
+    {
+        return new DistributionLists($this->getClient());
+    }
+}

+ 233 - 0
app/Libs/Kerio/Components/Api/Soap/Repository/Accounts.php

@@ -0,0 +1,233 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractApiClient;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractRepository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 08:28
+ * Class Accounts
+ */
+class Accounts extends AbstractRepository
+{
+    const NO_COS_INDEX = 'default';
+
+    /**
+     * get all account for domain
+     * @param $name
+     * @return mixed
+     */
+    public function getByDomainName($name)
+    {
+        $domain = new Domain();
+        $domain->setName($name);
+
+        $result = $this->getClient()->account->getAllByDomain($domain);
+
+        $accounts = $result->getResponseBody()['GETALLACCOUNTSRESPONSE']['ACCOUNT'];
+        /**
+         * API return one or araay with accounts
+         */
+        $tmp = [];
+        if(isset($accounts['NAME']))
+        {
+            $tmpAccount =  new Account($accounts);
+
+            /**
+             * skip ZiImbra default account
+             */
+            if (strpos($tmpAccount->getName(), 'galsync@') !== false)
+            {
+                return [];
+            }
+            $tmp[$tmpAccount->getId()] = $tmpAccount;
+        }else{
+            foreach($accounts as $account)
+            {
+                $tmpAccount =  new Account($account);
+
+                /**
+                 * skip ZiImbra default account
+                 */
+                if (strpos($tmpAccount->getName(), 'galsync@') !== false)
+                {
+                    continue;
+                }
+
+
+                $tmp[$tmpAccount->getId()] = $tmpAccount;
+            }
+        }
+
+       return $tmp;
+    }
+
+    /**
+     * @param $name
+     * @return mixed
+     */
+    public function getGroupedByCos($name)
+    {
+        $accounts = $this->getByDomainName($name);
+        foreach($accounts as $account)
+        {
+            /* @var $account Account*/
+            $cosId = $account->getDataResourceA(Account::ATTR_CLASS_OF_SERVICE_ID);
+            $key = $cosId ? $cosId : self::NO_COS_INDEX;
+
+            $tmp[$key][] = $account;
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @param $name
+     * @return mixed
+     */
+    public function getMailboxes($name)
+    {
+        $accounts = $this->getByDomainName($name);
+
+        foreach($accounts as $key => $account)
+        {
+            /* @var $account Account*/
+            if (strpos($account->getName(), 'galsync@') !== false)
+            {
+                unset($accounts[$key]);
+                continue;
+            }
+
+        }
+
+        return $accounts;
+    }
+
+    /**
+     * @param $id
+     * @return Account
+     */
+    public function getAccountInfoById($id)
+    {
+        $account = new Account();
+        $account->setId($id);
+
+        $result = $this->getClient()->account->getAccountInfo($account);
+
+        if(!$result->getLastError())
+        {
+            $body = $result->getResponseBody();
+            $result =  $account->fill($body['GETACCOUNTINFORESPONSE']);
+            $result->setName($body['GETACCOUNTINFORESPONSE']['NAME']['DATA']);
+            return $result;
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param $id
+     * @return Account
+     */
+    public function getAccountOptionsById($id)
+    {
+        $account = new Account();
+        $account->setId($id);
+
+        $result = $this->getClient()->account->getAccountOptions($account);
+
+        if(!$result->getLastError())
+        {
+            $body = $result->getResponseBody();
+            return $account->fill($body['GETACCOUNTRESPONSE']['ACCOUNT']);
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param $name
+     * @return mixed
+     */
+    public function getUsages($name)
+    {
+        $domain = new Domain();
+        $domain->setName($name);
+
+        $result = $this->getClient()->domain->getDomainUsages($domain);
+
+        $accounts = $result->getResponseBody()['GETQUOTAUSAGERESPONSE']['ACCOUNT'];
+
+        /**
+         * API return one or araay with accounts
+         */
+        if(isset($accounts['NAME']))
+        {
+            $tmpAccount =  new Account($accounts);
+            $tmp[$tmpAccount->getId()] = $tmpAccount;
+        }else{
+            foreach($accounts as $account)
+            {
+                $tmpAccount =  new Account($account);
+                $tmp[$tmpAccount->getId()] = $tmpAccount;
+            }
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @description return usages of all accounts
+     * @param $name
+     * @return float
+     */
+    public function getFullUsages($name)
+    {
+        /**
+         * count Usages
+         */
+        foreach($this->getUsages($name) as $acc)
+        {
+            $used += (float) $acc->getUsed();
+        }
+        $used = round($used / Size::B_TO_MB, 2);
+
+        return $used;
+    }
+
+    /**
+     * @param $domain
+     * @return array
+     */
+    public function getAccountAliasesByDomainName($domain)
+    {
+        $accounts = $this->getByDomainName($domain);
+
+        foreach($accounts as $account)
+        {
+            /* @var $account Account */
+            foreach($account->getAliases() as $al)
+            {
+
+                $alias = new AccountAlias();
+                $alias->setAccountId($account->getId());
+                $alias->setAccountName($account->getName());
+                $alias->setAlias($al);
+                $data[] = $alias;
+            }
+
+        }
+        return $data;
+    }
+
+}

+ 55 - 0
app/Libs/Kerio/Components/Api/Soap/Repository/ClassOfServices.php

@@ -0,0 +1,55 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractApiClient;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractRepository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService as CosModel;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:27
+ * Class ClassOfServices
+ */
+class ClassOfServices extends AbstractRepository
+{
+    const CUSTOM_ZIMBRA          = 'customMGkerio';
+    const ZIMBRA_CONFIG_OPTIONS  = 'kerioConfigurableOptions';
+    const CLASS_OF_SERVICE_QUOTA = 'cosQuota';
+
+    public function all()
+    {
+        $result = $this->getClient()->classOfServices->getAllCos();
+        foreach ($result as $item)
+        {
+            $cos = new CosModel($item);
+            $tmp[$cos->getId()] = $cos;
+        }
+        return $tmp;
+    }
+
+    public function asArrayList()
+    {
+        $result = $this->getClient()->classOfServices->getAllCos();
+        foreach ($result as $item)
+        {
+            $tmp[] = $item['NAME'];
+        }
+
+        return $tmp;
+    }
+
+    public function byName($name)
+    {
+        //todo add support
+    }
+
+    public function byId($id)
+    {
+        //todo add support
+    }
+
+}

+ 66 - 0
app/Libs/Kerio/Components/Api/Soap/Repository/DistributionLists.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractApiClient;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractRepository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 08:40
+ * Class DistributionList
+ */
+class DistributionLists extends AbstractRepository
+{
+
+    /**
+     * @param $domainName
+     * @return mixed
+     */
+    public function getAllDistributionListsByDomain($domainName)
+    {
+        $domain = new Domain();
+        $domain->setName($domainName);
+
+        $result = $this->getClient()->distributionList->getAllDistributionLists($domain);
+
+        $accounts = $result->getResponseBody()['GETALLDISTRIBUTIONLISTSRESPONSE']['DL'];
+
+        /**
+         * API return one or araay with accounts
+         */
+        if(isset($accounts['NAME']))
+        {
+            $tmpAccount =  new DistributionList($accounts);
+            $tmp[$tmpAccount->getId()] = $tmpAccount;
+        }else{
+            foreach($accounts as $account)
+            {
+                $tmpAccount =  new DistributionList($account);
+                $tmp[$tmpAccount->getId()] = $tmpAccount;
+            }
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @param $id
+     * @return bool|DistributionList
+     */
+    public function getDistributionListBydId($id)
+    {
+        $list = new DistributionList();
+        $list->setId($id);
+
+        return $this->getClient()->distributionList->read($list);
+    }
+
+}

+ 122 - 0
app/Libs/Kerio/Components/Api/Soap/Repository/Domains.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractApiClient;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractRepository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 07:59
+ * Class Domains
+ */
+class Domains extends AbstractRepository
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+
+
+    /**
+     * @param $name
+     * @return Domain| null
+     */
+    public function getByName($name)
+    {
+        $domain = new Domain();
+        $domain->setName($name);
+
+        $result = $this->getClient()->domain->getDomainId($domain);
+
+        if(!$result->getLastError())
+        {
+            $domain = new Domain($result->getResponseBody()['GETDOMAININFORESPONSE']['DOMAIN']);
+            return $domain;
+        }
+
+        $this->setError($result->getLastError());
+        return false;
+    }
+
+    public function getAliases($name)
+    {
+        $mainDomain = $this->getByName($name);
+
+        if(!$mainDomain)
+        {
+            return false;
+        }
+
+        /**
+         *
+         * parse all domain & return aliasese
+         */
+        foreach($aliases = $this->getAll() as $key => $alias)
+        {
+            /**
+             *
+             * check if domain is alias
+             */
+            /* @var $alias Domain */
+            if(!$alias->isAlias())
+            {
+                unset($aliases[$key]);
+                continue;
+            }
+
+            /**
+             *
+             * check if alias belong to main domain
+             */
+            if($alias->getAttr(Domain::ATTR_ALIAS_TARGET_ID) !== $mainDomain->getId())
+            {
+                unset($aliases[$key]);
+                continue;
+            }
+        }
+
+        return $aliases;
+    }
+
+    public function getAll()
+    {
+        $result = $this->getClient()->domain->getAll();
+
+        $domains = $result->getResponseBody()['GETALLDOMAINSRESPONSE']['DOMAIN'];
+
+        /**
+         * API return one or araay with accounts
+         */
+        if(isset($domains['NAME']))
+        {
+            $tmpAccount =  new Domain($domains);
+            $tmp[$tmpAccount->getId()] = $tmpAccount;
+        }else{
+            foreach($domains as $account)
+            {
+                $tmpAccount =  new Domain($account);
+                $tmp[$tmpAccount->getId()] = $tmpAccount;
+            }
+        }
+
+        return $tmp;
+    }
+
+    public function getDomain()
+    {
+        $result = $this->getClient()->domain->getAll();
+        $domains = $result->getResponseBody()['GETALLDOMAINSRESPONSE']['DOMAIN'];
+
+        $domain = new Domain();
+
+        $result = $this->getClient()->domain->getDomain($domain);
+
+
+    }
+
+}

+ 136 - 0
app/Libs/Kerio/Components/Api/Soap/Repository/Ressources.php

@@ -0,0 +1,136 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractApiClient;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractRepository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\RessourceAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 08:28
+ * Class Ressources
+ */
+class Ressources extends AbstractRepository
+{
+    /**
+     * get all ressource for domain
+     * @param $name
+     * @return mixed
+     */
+    public function getByDomainName($name)
+    {
+        $domain = new Domain();
+        $domain->setName($name);
+
+        $result = $this->getClient()->ressource->getAllByDomain($domain);
+        $ressources = $result->getResponseBody()['GETALLCALENDARRESOURCESRESPONSE']['CALRESOURCE'];
+        /**
+         * API return one or araay with ressources
+         */
+        $tmp = [];
+        if(isset($ressources['NAME']))
+        {
+            $tmpRessource =  new Ressource($ressources);
+
+            /**
+             * skip ZiImbra default ressource
+             */
+            if (strpos($tmpRessource->getName(), 'galsync@') !== false)
+            {
+                return [];
+            }
+            $tmp[$tmpRessource->getId()] = $tmpRessource;
+        }else{
+            foreach($ressources as $ressource)
+            {
+                $tmpRessource =  new Ressource($ressource);
+
+                /**
+                 * skip ZiImbra default ressource
+                 */
+                if (strpos($tmpRessource->getName(), 'galsync@') !== false)
+                {
+                    continue;
+                }
+
+
+                $tmp[$tmpRessource->getId()] = $tmpRessource;
+            }
+        }
+
+       return $tmp;
+    }
+
+    /**
+     * @param $name
+     * @return mixed
+     */
+    public function getRessources($name)
+    {
+        $ressources = $this->getByDomainName($name);
+
+        foreach($ressources as $key => $ressource)
+        {
+            /* @var $ressource Ressource*/
+            if (strpos($ressource->getName(), 'galsync@') !== false)
+            {
+                unset($ressources[$key]);
+                continue;
+            }
+
+        }
+
+        return $ressources;
+    }
+
+    /**
+     * @param $id
+     * @return Ressource
+     */
+    public function getRessourceInfoById($id)
+    {
+        $ressource = new Ressource();
+        $ressource->setId($id);
+
+        $result = $this->getClient()->ressource->getRessourceInfo($ressource);
+
+        if(!$result->getLastError())
+        {
+            $body = $result->getResponseBody();
+            $result =  $ressource->fill($body['GETCALENDARRESOURCERESPONSE']);
+            $result->setName($body['GETCALENDARRESOURCERESPONSE']['NAME']['DATA']);
+            return $result;
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param $id
+     * @return Ressource
+     */
+    public function getRessourceOptionsById($id)
+    {
+        $ressource = new Ressource();
+        $ressource->setId($id);
+
+        $result = $this->getClient()->ressource->getRessourceOptions($ressource);
+
+        if(!$result->getLastError())
+        {
+            $body = $result->getResponseBody();
+            return $ressource->fill($body['GETCALENDARRESOURCERESPONSE']['CALRESOURCE']);
+        }
+
+        return $result;
+    }
+
+}

+ 19 - 0
app/Libs/Kerio/Components/Api/Soap/Repository/Server.php

@@ -0,0 +1,19 @@
+<?php
+
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractApiClient;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\AbstractRepository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Server as ServerModel;
+
+class Server extends AbstractRepository
+{
+    public function all()
+    {
+        $result = $this->getClient()->server->getAllServers();
+
+        return $result;
+    }
+}

+ 205 - 0
app/Libs/Kerio/Components/Api/Soap/Response.php

@@ -0,0 +1,205 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\XmlParser;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 10:51
+ * Class Response
+ */
+class Response
+{
+    protected $request;
+    protected $options;
+    protected $params;
+    protected $headers;
+    protected $xmlResponse;
+    protected $responseHead;
+    protected $responseBody;
+    protected $responseModel;
+    protected $lastError;
+    protected $errors = [];
+
+    /**
+     * @return mixed
+     */
+    public function getRequest()
+    {
+        return $this->request;
+    }
+
+    /**
+     * @param $request
+     * @return $this
+     */
+    public function setRequest($request)
+    {
+        $this->request = $request;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getOptions()
+    {
+        return $this->options;
+    }
+
+    /**
+     * @param $options
+     * @return $this
+     */
+    public function setOptions($options)
+    {
+        $this->options = $options;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getParams()
+    {
+        return $this->params;
+    }
+
+    /**
+     * @param $params
+     * @return $this
+     */
+    public function setParams($params)
+    {
+        $this->params = $params;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getHeaders()
+    {
+        return $this->headers;
+    }
+
+    /**
+     * @param $headers
+     * @return $this
+     */
+    public function setHeaders($headers)
+    {
+        $this->headers = $headers;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getXmlResponse()
+    {
+        return $this->xmlResponse;
+    }
+
+    /**
+     * @param $xmlResponse
+     * @return $this
+     */
+    public function setXmlResponse($xmlResponse)
+    {
+        $this->xmlResponse = $xmlResponse;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getResponseBody()
+    {
+        return $this->responseBody;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getResponseModel()
+    {
+        return $this->responseModel;
+    }
+
+    /**
+     * @param $responseModel
+     * @return $this
+     */
+    public function setResponseModel($responseModel)
+    {
+        $this->responseModel = $responseModel;
+        return $this;
+    }
+
+    /**
+     *
+     */
+    public function getLastError()
+    {
+        return $this->lastError;
+    }
+
+    /**
+     * @param $lastError
+     */
+    public function setLastError($lastError)
+    {
+        //todo save to file
+
+        $this->errors[] = $lastError;
+        $this->lastError = $lastError;
+    }
+
+    /**
+     * @return bool
+     */
+    public function getLastErrorCode()
+    {
+        if($code = $this->responseBody['SOAP:FAULT']['SOAP:DETAIL']['ERROR']['CODE']['DATA'])
+        {
+            return $code;
+        }
+
+        return false;
+    }
+
+    /**
+     * Parse response
+     *
+     * @return $this
+     */
+    public function response()
+    {
+
+        /**
+         * xml parse response
+         */
+        $xml = new XmlParser();
+        $array = $xml->parse($this->xmlResponse);
+
+        /**
+         * set response header
+         */
+        $this->responseHead = $array['SOAP:ENVELOPE']['SOAP:HEADER'];
+
+        /**
+         * set response body
+         */
+        $this->responseBody = $array['SOAP:ENVELOPE']['SOAP:BODY'];
+
+        return $this;
+
+    }
+
+}

+ 347 - 0
app/Libs/Kerio/Components/Api/Soap/Services.php

@@ -0,0 +1,347 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap;
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccount;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccountAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccountCos;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccountCosQuota;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDomain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDomainAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateRessource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteAccount;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteAccountAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteDistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteDomain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteDomainAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteRessource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Sso\ClientSingleSignOn;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Sso\ClientSingleSignOnToken;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\ChangePackage;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\ChangePackageConfigOptions;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\ChangePackageCosQuota;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\ChangePackageDedicatedCos;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\SuspendDomain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateDomain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UnsuspendDomain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateAccount;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateAccountCosQuota;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateAccountPassword;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateAccountStatus;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateDistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateRessource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateRessourceStatus;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateRessourcePassword;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ApiClientHandler;
+
+/**
+ *
+ * Class return supported services
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 13:15
+ * Class Services
+ */
+class Services
+{
+    /**
+     * API Client handler
+     */
+    use ApiClientHandler;
+
+    /**
+     * Services constructor.
+     * @param Client $api
+     */
+    public function __construct(Client $api)
+    {
+        $this->setApi($api);
+    }
+
+    /**
+     *
+     * create account in kerio, depends of product configuration
+     * @param string $type
+     * @return CreateAccount|CreateAccountCos|CreateAccountCosQuota
+     */
+    public function createAccount($type = ClassOfServices::CUSTOM_ZIMBRA)
+    {
+        switch ($type)
+        {
+            case ClassOfServices::CUSTOM_ZIMBRA:
+                $service = new CreateAccount($this->getApi());
+                break;
+            case ClassOfServices::ZIMBRA_CONFIG_OPTIONS:
+                $service = new CreateAccountCosQuota($this->getApi());
+                break;
+            case ClassOfServices::CLASS_OF_SERVICE_QUOTA:
+                $service = new CreateAccountCosQuota($this->getApi());
+                break;
+            default:
+                $service = new CreateAccountCosQuota($this->getApi());
+                break;
+        }
+
+        return $service;
+    }
+
+    /**
+     * create alias for account in kerio
+     *
+     * @return CreateAccountAlias
+     */
+    public function createAccountAlias()
+    {
+        return new CreateAccountAlias($this->getApi());
+    }
+
+    /**
+     * create distribution list (mailing list)
+     *
+     * @return CreateDistributionList
+     */
+    public function createDistributionList()
+    {
+        return new CreateDistributionList($this->getApi());
+    }
+
+    /**
+     * create domain in kerio (main domain for account)
+     *
+     *
+     * @return CreateDomain
+     */
+    public function createDomain()
+    {
+        return new CreateDomain($this->getApi());
+    }
+
+    /**
+     * create alias domain for account
+     *
+     * @return CreateDomainAlias
+     */
+    public function createDomainAlias()
+    {
+        return new CreateDomainAlias($this->getApi());
+    }
+
+    /**
+     * create ressource for account
+     *
+     * @return CreateRessource
+     */
+    public function createRessource()
+    {
+        return new CreateRessource($this->getApi());
+    }
+
+    /**
+     *
+     * change product package
+     *
+     * @return ChangePackage
+     */
+    public function changePackages($type = ClassOfServices::CUSTOM_ZIMBRA)
+    {
+        switch ($type)
+        {
+            case ClassOfServices::CUSTOM_ZIMBRA:
+                $service = new ChangePackage($this->getApi());
+                break;
+            case ClassOfServices::ZIMBRA_CONFIG_OPTIONS:
+                $service = new ChangePackageConfigOptions($this->getApi());
+                break;
+            case ClassOfServices::CLASS_OF_SERVICE_QUOTA:
+                $service = new ChangePackageCosQuota($this->getApi());
+                break;
+            default:
+                $service = new ChangePackageDedicatedCos($this->getApi());
+                break;
+        }
+
+        return $service;
+    }
+
+    /**
+     * update account in panel
+     *
+     * @param string $type
+     * @return UpdateAccount|UpdateAccountCosQuota
+     */
+    public function updateAccount($type = ClassOfServices::CUSTOM_ZIMBRA)
+    {
+        switch ($type)
+        {
+            case ClassOfServices::CUSTOM_ZIMBRA:
+                $service = new UpdateAccount($this->getApi());
+                break;
+            case ClassOfServices::ZIMBRA_CONFIG_OPTIONS:
+                $service = new UpdateAccount($this->getApi());
+                break;
+            case ClassOfServices::CLASS_OF_SERVICE_QUOTA:
+                $service = new UpdateAccountCosQuota($this->getApi());
+                break;
+            default:
+                $service = new UpdateAccount($this->getApi());
+                break;
+        }
+
+        return $service;
+    }
+
+    /**
+     * update account status
+     *
+     * @return UpdateAccountStatus
+     */
+    public function updateAccountStatus()
+    {
+        return new UpdateAccountStatus($this->getApi());
+    }
+
+    /**
+     * update ressource
+     *
+     * @return UpdateRessource
+     */
+    public function updateRessource()
+    {
+        return new UpdateRessource($this->getApi());
+    }
+
+    /**
+     * update ressource status
+     *
+     * @return UpdateRessourceStatus
+     */
+    public function updateRessourceStatus()
+    {
+        return new UpdateRessourceStatus($this->getApi());
+    }
+
+    /**
+     * change password service
+     *
+     * @return UpdateAccountPassword
+     */
+    public function updateAccountPassword()
+    {
+        return new UpdateAccountPassword($this->getApi());
+    }
+
+    /**
+     * change password service
+     *
+     * @return UpdateRessourcePassword
+     */
+    public function updateRessourcePassword()
+    {
+        return new UpdateRessourcePassword($this->getApi());
+    }
+
+    /**
+     * distribution (mailing) list update service
+     *
+     * @return UpdateDistributionList
+     */
+    public function updateDistributionList()
+    {
+        return new UpdateDistributionList($this->getApi());
+    }
+
+    /**
+     * suspend domain in kerio
+     *
+     * @return SuspendDomain
+     */
+    public function suspendDomain()
+    {
+        return new SuspendDomain($this->getApi());
+    }
+
+    /**
+     * unsuspend domain
+     *
+     * @return UnsuspendDomain
+     */
+    public function unsuspendDomain()
+    {
+        return new UnsuspendDomain($this->getApi());
+    }
+
+    /**
+     * delete account in panel
+     *
+     * @return DeleteAccount
+     */
+    public function deleteAccount()
+    {
+        return new DeleteAccount($this->getApi());
+    }
+
+    /**
+     * delete ressource in panel
+     *
+     * @return DeleteRessource
+     */
+    public function deleteRessource()
+    {
+        return new DeleteRessource($this->getApi());
+    }
+
+    /**
+     * delete domain & each related things
+     *
+     * @return DeleteDomain
+     */
+    public function deleteDomain()
+    {
+        return new DeleteDomain($this->getApi());
+    }
+
+    /**
+     * delete account alias
+     *
+     * @return DeleteAccountAlias
+     */
+    public function deleteAccountAlias()
+    {
+        return new DeleteAccountAlias($this->getApi());
+    }
+
+    /**
+     * delete distribution list (mailing list)
+     *
+     * @return DeleteDistributionList
+     */
+    public function deleteDistributionList()
+    {
+        return new DeleteDistributionList($this->getApi());
+    }
+
+    /**
+     * delete domain alias
+     *
+     * @return DeleteDomainAlias
+     */
+    public function deleteDomainAlias()
+    {
+        return new DeleteDomainAlias($this->getApi());
+    }
+
+    /**
+     *
+     * return sso token
+     * @return ClientSingleSignOnToken
+     */
+    public function clientSingleSignOnToken()
+    {
+        return new ClientSingleSignOnToken($this->getApi());
+    }
+
+}

+ 163 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateAccount.php

@@ -0,0 +1,163 @@
+<?php
+/**
+ * Class CreateAccount
+ * User: Nessandro
+ * Date: 2019-10-07
+ * Time: 10:41
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\ConfigOptionsHelper;
+
+class CreateAccount extends ApiService
+{
+    use ProductManagerHandler;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+
+    /**
+     * added more conditions
+     * @return bool
+     */
+    protected function isValid()
+    {
+        /**
+         * check if product manager is set
+         */
+        if(!$this->productManager)
+        {
+            $this->setError('Product Manager Not Found');
+            return false;
+        }
+
+        /**
+         * domain name
+         */
+        if(!$this->formData['domain'])
+        {
+            $this->setError('Domain name can not be found.');
+            return false;
+        }
+
+        /**
+         * check full usages of domains
+         */
+        $maxDomainQuota = $this->productManager->get('domainMaxSize') * Size::B_TO_GB;
+        $usages = $this->api->repository()->accounts->getFullUsages($this->formData['domain']);
+
+        if($maxDomainQuota !== Size::UNLIMITED && $usages >= $maxDomainQuota)
+        {
+            $this->setError("Domain size limit has been reached");
+            return false;
+        }
+
+        /**
+         *
+         * Check if accounts limit has been reached
+         */
+        $hosting = $this->productManager->getHosting();
+        $configOption = new ConfigOptionsHelper;
+        $acc_addObj = $configOption->getConfigurableOption($hosting->id, 'acc_add');
+        $acc_add = $acc_addObj->qty ? $acc_addObj->qty : 0;
+        $accountLimit = $this->productManager->get('acc_base') + $acc_add;
+        $mailBoxes = $this->getMailboxes();
+
+        if(count($mailBoxes) >= $accountLimit && $accountLimit !== ProductParams::SIZE_UNLIMITED && 'editAccountForm' !== $this->getRequestValue('loadData'))
+        {
+            $this->setError('There are too many mailboxes');
+            return false;
+        }
+
+        /**
+         *
+         */
+        return parent::isValid();
+    }
+
+    /**
+     * @return mixed
+     */
+    protected function getMailboxes()
+    {
+        $mailBoxes = $this->api->repository()->accounts->getMailboxes($this->formData['domain']);
+        return $mailBoxes;
+    }
+
+    /**
+     * @return Account
+     */
+    protected function getModel()
+    {
+        $accountSize = $this->productManager->get(ProductParams::ACCOUNT_SIZE);
+        /**
+         * create new account in kerio
+         */
+        $account = new Account();
+        $account->setName($this->formData['username'].'@'.$this->formData['domain']);
+        $account->setPassword(html_entity_decode($this->formData['password']), ENT_QUOTES);
+        /**
+         *  set account attributes
+         */
+        $account->setAttr(Account::ATTR_FIRSTNAME, $this->formData['firstname']);
+        $account->setAttr(Account::ATTR_LASTNAME, $this->formData['lastname']);
+        $account->setAttr(Account::ATTR_PHONE, $this->formData['phone']);
+        $account->setAttr(Account::ATTR_MOBILE_PHONE, $this->formData['mobile_phone']);
+        $account->setAttr(Account::ATTR_FAX, $this->formData['fax']);
+        $account->setAttr(Account::ATTR_PAGER, $this->formData['pager']);
+        $account->setAttr(Account::ATTR_HOME_PHONE, $this->formData['home_phone']);
+        $account->setAttr(Account::ATTR_COUNTRY, $this->formData['country']);
+        $account->setAttr(Account::ATTR_STATE, $this->formData['state']);
+        $account->setAttr(Account::ATTR_PROF_TITLE, $this->formData['title']);
+        $account->setAttr(Account::ATTR_POSTAL_CODE, $this->formData['post_code']);
+        $account->setAttr(Account::ATTR_CITY, $this->formData['city']);
+        $account->setAttr(Account::ATTR_STREET, $this->formData['street']);
+        $account->setAttr(Account::ATTR_COMPANY, $this->formData['company']);
+        $account->setAttr(Account::ATTR_ACCOUNT_STATUS, $this->formData['status']);
+        $account->setAttr(Account::ATTR_DISPLAY_NAME, $this->formData['display_name']);
+        $account->setAttr(Account::ATTR_MAIL_QUOTA, $accountSize * Size::B_TO_MB);
+
+        foreach($this->productManager->getKerioConfiguration() as $key => $value)
+        {
+            $value = $value === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+            $account->setAttr($key, $value);
+        }
+
+        return $account;
+    }
+
+    /**
+     * @return bool|mixed|Account|void
+     */
+    protected function process()
+    {
+        /**
+         *
+         */
+        $model = $this->getModel();
+
+        /**
+         * create account in ZIMBRA
+         */
+        $result = $this->api->account->create($model);
+
+        /**
+         * problem with create account
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+}

+ 70 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateAccountAlias.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.10.19
+ * Time: 09:08
+ * Class CreateAccountAlias
+ */
+class CreateAccountAlias extends ApiService
+{
+    use ProductManagerHandler;
+
+    /**
+     * @return bool|void
+     */
+    public function isValid()
+    {
+        $limit = $this->productManager->get(ProductParams::ALIAS_LIMIT);
+        $createdAlias = $this->api->repository()->accounts->getAccountAliasesByDomainName($this->formData['domain']);
+
+        if(count($createdAlias) >= $limit && $limit !== ProductParams::SIZE_UNLIMITED)
+        {
+            $this->setError('Account alias limit has been reached');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return mixed|void
+     */
+    public function process()
+    {
+        /**
+         * prepare model
+         */
+        $alias = $alias = $this->formData['aliasName'].'@'.$this->formData['domain'];
+        $aliasAccount = new AccountAlias();
+        $aliasAccount->setAlias($alias);
+        $aliasAccount->setAccountId($this->formData['mailbox']);
+
+        /**
+         * create account alias in API
+         */
+        $result = $this->api->account->createAlias($aliasAccount);
+
+        /**
+         * problem with create account
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+
+}

+ 192 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateAccountCosQuota.php

@@ -0,0 +1,192 @@
+<?php
+/**
+ * Class CreateAccountCosQuota
+ * User: Nessandro
+ * Date: 2019-10-07
+ * Time: 14:05
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+
+class CreateAccountCosQuota extends CreateAccount
+{
+    /**
+     * array with class of service models
+     * @var array
+     */
+    protected $cosModels = [];
+
+    /**
+     * configure service before will run
+     */
+    protected function config()
+    {
+        /**
+         *
+         * load class of service models
+         */
+        $this->cosModels = $this->api->repository()->cos->all();
+
+        /**
+         * parent configuration
+         */
+        parent::config();
+    }
+
+    /**
+     *
+     * @return bool
+     */
+    public function isValid()
+    {
+        /**
+         *
+         * if parent service is not valid, return false
+         */
+        if (!$result = parent::isValid())
+        {
+            return $result;
+        }
+        /**
+         * check limits for dedicated class of service
+         */
+        $groupedByCos = $this->api->repository()->accounts->getGroupedByCos($this->formData['domain']);
+        $cosLimits    = $this->productManager->getSettingCos();
+
+        /**
+         *
+         * if is configured one quote in product configuration and provided by client is not the same
+         */
+        if(is_string($cosLimits) &&  $cosLimits !== $this->formData['cosId'])
+        {
+            $this->setError('Quota id is not valid.');
+            return false;
+        }
+
+        /**
+         *
+         * if is configured one quote
+         */
+        if(is_string($cosLimits) &&  $cosLimits === $this->formData['cosId']){
+
+            return true;
+        }
+
+        /**
+         * check if type of quote is availabel for client
+         */
+        if(!array_key_exists($this->formData['cosId'], $cosLimits))
+        {
+            $this->setError('There is no quota available to use');
+            return false;
+        }
+
+        /**
+         * check if limit has been reached
+         */
+        if ($cosLimits[$this->formData['cosId']] !== Size::UNLIMITED && count($groupedByCos[$this->formData['cosId']]) >= $cosLimits[$this->formData['cosId']] && $this->formData['cosId'] !== $this->formData['currentCosId'])
+        {
+            $this->setError('There are too many mailboxes with selected quota limit');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return Account
+     */
+    protected function getModel()
+    {
+        /**
+         * create new account in kerio
+         */
+        $account = new Account();
+        $account->setName($this->formData['username'].'@'.$this->formData['domain']);
+        $account->setPassword(html_entity_decode($this->formData['password']), ENT_QUOTES);
+        /**
+         *  set account attributes
+         */
+        $account->setAttr(Account::ATTR_FIRSTNAME, $this->formData['firstname']);
+        $account->setAttr(Account::ATTR_LASTNAME, $this->formData['lastname']);
+        $account->setAttr(Account::ATTR_PHONE, $this->formData['phone']);
+        $account->setAttr(Account::ATTR_MOBILE_PHONE, $this->formData['mobile_phone']);
+        $account->setAttr(Account::ATTR_FAX, $this->formData['fax']);
+        $account->setAttr(Account::ATTR_PAGER, $this->formData['pager']);
+        $account->setAttr(Account::ATTR_HOME_PHONE, $this->formData['home_phone']);
+        $account->setAttr(Account::ATTR_COUNTRY, $this->formData['country']);
+        $account->setAttr(Account::ATTR_STATE, $this->formData['state']);
+        $account->setAttr(Account::ATTR_POSTAL_CODE, $this->formData['post_code']);
+        $account->setAttr(Account::ATTR_CITY, $this->formData['city']);
+        $account->setAttr(Account::ATTR_PROF_TITLE, $this->formData['title']);
+        $account->setAttr(Account::ATTR_STREET, $this->formData['street']);
+        $account->setAttr(Account::ATTR_COMPANY, $this->formData['company']);
+        $account->setAttr(Account::ATTR_ACCOUNT_STATUS, $this->formData['status']);
+        $account->setAttr(Account::ATTR_DISPLAY_NAME, $this->formData['display_name']);
+
+        /* @var $cos ClassOfService*/
+        $cos = $this->cosModels[$this->formData['cosId']];
+
+        /**
+         * set quota by class of service
+         */
+        $account->setAttr(Account::ATTR_MAIL_QUOTA, $cos->getDataResourceA(Account::ATTR_MAIL_QUOTA));
+
+        /**
+         * define class of services attribute for account
+         */
+        $cosAttrs = $cos->getAllDataResourcesAAttributes();
+
+        foreach(Kerio::BASE_ACCOUNT_CONFIG as $key)
+        {
+            $value = $cosAttrs[$key] ? $cosAttrs[$key] : Kerio::ATTR_DISABLED;
+            $account->setAttr($key, $value);
+        }
+
+        /**
+         *
+         * set class of service id as account attribute
+         */
+        $account->setAttr(Account::ATTR_CLASS_OF_SERVICE_ID, $cos->getId());
+
+        return $account;
+    }
+
+    /**
+     * @return mixed
+     */
+    protected function getMailboxes()
+    {
+        $mailBoxes = $this->api->repository()->accounts->getMailboxes($this->formData['domain']);
+
+        $filterbyCOS = $this->productManager->get('filterAccountsByCOS');
+
+        /**
+         * todo should be taken from option or from configurable options, is depend if from config option or dedicated class of service has been selected
+         */
+        $getConfigOptCos = $this->formData['cosId'];
+
+        /**
+         * filter mailboxes if required
+         */
+        if($getConfigOptCos && $filterbyCOS === ProductParams::SWITCHER_ENABLED)
+        {
+            $mailBoxes = array_filter($mailBoxes, function($row) use ($getConfigOptCos)
+            {
+                /* @var $row  Account*/
+                return $row->getDataResourceA(Account::ATTR_CLASS_OF_SERVICE_ID) == $getConfigOptCos;
+            });
+        }
+
+        return $mailBoxes;
+    }
+
+}

+ 250 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateDistributionList.php

@@ -0,0 +1,250 @@
+<?php
+/**
+ * Class DistributionList
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 08:45
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+use ModulesGarden\Servers\KerioEmail\Core\Http\Request;
+
+class CreateDistributionList extends ApiService
+{
+    use ProductManagerHandler;
+
+    public function isValid()
+    {
+        /**
+         *
+         * check that the owners are valid
+         */
+        foreach($this->formData['owners'] as $owner)
+        {
+            $result = $this->api->account->getAccountId($owner);
+            if($result->getLastError())
+            {
+                $this->setError($result->getLastError());
+                return false;
+            }
+        }
+
+        /**
+         *
+         * check that the domains from aliases are valid
+         */
+        foreach($this->formData['emailAliases'] as $alias)
+        {
+            $aliasParts = explode('@', $alias);
+            $domain = new Domain();
+            $domain->setName($aliasParts[1]);
+            $result = $this->api->domain->getDomain($domain);
+            if($result->getLastError())
+            {
+                $this->setError($result->getLastError());
+                return false;
+            }
+        }
+
+        $listLimit = $this->productManager->get('dist_list_limit');
+        $usages = $this->api->repository()->lists->getAllDistributionListsByDomain($this->formData['domain']);
+
+        if($listLimit !== Size::UNLIMITED && count($usages) >= $listLimit)
+        {
+            $this->setError("Distribution list limit has been reached");
+            return false;
+        }
+
+        return parent::isValid();
+    }
+
+    protected function process()
+    {
+        $list = $this->getModel();
+
+        /**
+         * create list
+         */
+        $distList = $this->api->distributionList->create($list);
+
+        if(!$distList)
+        {
+            $this->setError($this->api->distributionList->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        /**
+         *
+         * add members to distribution list
+         */
+        $this->addListMembers($distList, $this->formData['memberList']);
+
+        /**
+         *
+         * add owners to distribution list
+         */
+        $this->addListOwners($distList, $this->formData['owners']);
+
+        /**
+         *
+         * add aliases to list
+         */
+        $this->addListAliases($distList, $this->formData['emailAliases']);
+
+        return true;
+    }
+
+    /**
+     * @return DistributionList
+     */
+    protected function getModel()
+    {
+        $email = $this->formData['listmail'].'@'.$this->formData['domain'];
+        $list = new DistributionList();
+        $list->setName($email);
+        $list->setAttr(DistributionList::ATTR_DISPLAY_NAME,$this->formData['displayName']);
+        $list->setAttr(DistributionList::ATTR_DESCRIPTION,$this->formData['description']);
+        $list->setAttr(DistributionList::ATTR_SUBSCRIPTION_REQUEST,$this->formData['subscriptionRequest']);
+        $list->setAttr(DistributionList::ATTR_UNSUBSCRIPTION_REQUEST,$this->formData['unsubscriptionRequest']);
+        $list->setAttr(DistributionList::REPLY_TO_DISPLAY,$this->formData['replyDisplayName']);
+        $list->setAttr(DistributionList::REPLY_TO_ADDRESS,$this->formData['replyEmailAddress']);
+
+
+        $notify = $this->formData['sharesNotify'] === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+        $list->setAttr(DistributionList::ATTR_NOTIFY_SHARES,$notify);
+
+        $hideGal = $this->formData['hideGal'] === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+        $list->setAttr(DistributionList::ATTR_HIDE_IN_GAL,$hideGal);
+
+        $status = $this->formData['receiveMail'] === ProductParams::SWITCHER_ENABLED ? Kerio::ENABLED : Kerio::DISABLED;
+        $list->setAttr(DistributionList::ATTR_MAIL_STATUS,$status);
+
+        $replyEnabled = $this->formData['replyEmail'] === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+        $list->setAttr(DistributionList::REPLY_TO_ENABLED,$replyEnabled);
+
+
+        if($this->formData['dynamicGroup'] === ProductParams::SWITCHER_ENABLED)
+        {
+            $list->setDynamic(true);
+        }
+
+        return $list;
+    }
+
+    /**
+     *
+     * add members to existing list list
+     *
+     * @param DistributionList $distList
+     * @param array $members
+     * @return bool
+     */
+    public function addListMembers(DistributionList $distList, $members = [])
+    {
+        /**
+         * check if available some members
+         */
+        if(!$members)
+        {
+            return true;
+        }
+
+        /**
+         * update object by members
+         */
+        foreach ($members as $member)
+        {
+            if($member)
+            {
+                $distList->addMember($member);
+            }
+        }
+
+        /**
+         *
+         * add members to list
+         */
+        $result = $this->api->distributionList->addMembers($distList);
+        if(!$result)
+        {
+            //todo add some logg
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * add owners to existing list
+     *
+     * @param DistributionList $distList
+     * @param array $owners
+     * @return bool
+     */
+    public function addListOwners(DistributionList $distList, $owners = [])
+    {
+        /**
+         * check if available some owners
+         */
+        if(!$owners)
+        {
+            return true;
+        }
+
+        /**
+         * update list by owners
+         */
+        foreach ($owners as $owner)
+        {
+            $distList->addOwner($owner);
+        }
+
+        /**
+         * add owners to list
+         */
+        $result = $this->api->distributionList->addOwners($distList);
+
+        if(!$result)
+        {
+
+            //todo add some logg
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * add aliases to list
+     *
+     * @param DistributionList $distList
+     * @param array $aliases
+     * @return bool
+     */
+    public function addListAliases(DistributionList $distList, $aliases = [])
+    {
+        foreach ($aliases as $alias)
+        {
+            $distList->setAlias($alias);
+            $result = $this->api->distributionList->addAlias($distList);
+
+            if(!$result)
+            {
+                //todo logger
+            }
+        }
+
+        return true;
+    }
+
+}

+ 106 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateDomain.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\ConfigOptionsHelper;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\UpdateLimit;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 11:04
+ * Class CreateDomain
+ */
+class CreateDomain extends ApiService
+{
+    use ProductManagerHandler;
+    use \ModulesGarden\Servers\KerioEmail\App\Traits\HostingService;
+
+    /**
+     * @return mixed|void
+     */
+    public function process()
+    {
+        /**
+         * prepare model
+         */
+        $hosting = $this->productManager->getHosting();
+        $serviceID = $hosting->id;
+        $configOption = new ConfigOptionsHelper;
+        $acc_base = $this->productManager->get('acc_base') ? $this->productManager->get('acc_base') : 0;
+        if(isset($this->formData['configoptions']['acc_add']) && isset($this->formData['configoptions']['acc_new'])) {
+            $acc_add = $this->formData['configoptions']['acc_add'];
+            $acc_new = $this->formData['configoptions']['acc_new'];
+            $acc_add = $acc_add + $acc_new;
+            $acc_new = 0;
+            $accountLimit = $acc_base + $acc_add;
+            if (($this->productManager->get('acc_limit') > 0) && ($accountLimit > $this->productManager->get('acc_limit'))) {
+                $acc_add = $this->productManager->get('acc_limit') - $acc_base;
+                $accountLimit = $this->productManager->get('acc_limit');
+            }
+            $acc_addObj = $configOption->getConfigurableOption($serviceID, 'acc_add');
+            if(isset($acc_addObj->id)) {
+                $configOption->updateConfigurableOption($acc_addObj->id, ['qty' => $acc_add]);
+            }
+            $acc_newObj = $configOption->getConfigurableOption($serviceID, 'acc_new');
+            if(isset($acc_newObj->id)) {
+                $configOption->updateConfigurableOption($acc_newObj->id, ['qty' => $acc_new]);
+            }
+        } else {
+            $accountLimit = $acc_base;
+        }
+        $domain = new Domain();
+        $domain->setName($this->formData['domain']);
+        $domainBaseSize = $this->productManager->get('domainBaseSize') ? $this->productManager->get('domainBaseSize') : 0;
+        if(isset($this->formData['configoptions']['domainAddSize']) && isset($this->formData['configoptions']['domainNewSize'])) {
+            $domainAddSize = $this->formData['configoptions']['domainAddSize'];
+            $domainNewSize = $this->formData['configoptions']['domainNewSize'];
+            $domainAddSize = $domainAddSize + $domainNewSize;
+            $domainNewSize = 0;
+            $domainSize = $domainBaseSize + $domainAddSize;
+            if (($this->productManager->get('domainMaxSize') > 0) && ($domainSize > $this->productManager->get('domainMaxSize'))) {
+                $domainMaxSize = $this->productManager->get('domainMaxSize');
+                $domainAddSize = $domainMaxSize - $domainBaseSize;
+                $domainSize = $domainBaseSize + $domainAddSize;
+            }
+            $domainAddSizeObj = $configOption->getConfigurableOption($serviceID, 'domainAddSize');
+            if(isset($domainAddSizeObj->id)) {
+                $configOption->updateConfigurableOption($domainAddSizeObj->id, ['qty' => $domainAddSize]);
+            }
+            $domainNewSizeObj = $configOption->getConfigurableOption($serviceID, 'domainNewSize');
+            if(isset($domainNewSizeObj->id)) {
+                $configOption->updateConfigurableOption($domainNewSizeObj->id, ['qty' => $domainNewSize]);
+            }
+        } else {
+            $domainSize = $domainBaseSize;
+        }
+        $updateLimit = new UpdateLimit;
+        $updateLimit->updateDiskLimit($serviceID, $domainSize * 1024);
+        $updateLimit->updateBWLimit($serviceID, $accountLimit);
+        $domain->setAttrs([
+            Domain::ATTR_MAIL_DOMAIN_QUOTA  => $domainSize * Size::B_TO_GB,
+        ]);
+
+        /**
+         * API request
+         */
+        $result = $this->api->domain->create($domain);
+
+        /**
+         * check result
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->domain->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+}

+ 99 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateDomainAlias.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 13:05
+ * Class DomainAlias
+ */
+class CreateDomainAlias extends ApiService
+{
+    use ProductManagerHandler;
+
+    protected function isValid()
+    {
+        /**
+         * check if domain alias is provided
+         */
+        if(!$this->formData['alias'])
+        {
+            $this->setError('Domain alias can not been created. No alias found.');
+            return false;
+        }
+
+        /**
+         * check if domain alias is provided
+         */
+        if(!$this->formData['domainId'])
+        {
+            $this->setError('Domain alias can not been created. No domain ID found.');
+            return false;
+        }
+
+        /**
+         * check limits
+         */
+        $domainAliasesLimit = $this->productManager->get(ProductParams::DOMAIN_ALIAS_LIMIT);
+
+        /**
+         * get created domains
+         */
+        $domainAliases = $this->api->repository()->domains->getAliases($this->formData['domain']);
+
+        if(count($domainAliases) >= $domainAliasesLimit && $domainAliasesLimit !== ProductParams::SIZE_UNLIMITED)
+        {
+            $this->setError('Domain aliases limit has been reached');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return bool|mixed|Domain|\ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response
+     */
+    protected function process()
+    {
+        /**
+         *
+         * prepare alias model
+         */
+        $domain = new Domain();
+        $domain->setName($this->formData['alias']);
+        $domain->setAttr(Domain::ATTR_ALIAS_TARGET_ID, $this->formData['domainId']);
+        $domain->setAttr(Domain::ATTR_DOMAIN_TYPE, Domain::TYPE_ALIAS);
+        $domain->setAttr(Domain::ATTR_DESCRIPTION, $this->formData['description']);
+        $domain->setAttr(Domain::ATTR_ALIAS_CATCHALL, '@' . $this->formData['domain']);
+
+        /**
+         *
+         * send request to ZIMBRA
+         */
+        $result = $this->api->domain->create($domain);
+
+        /**
+         * check if error occurred
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->domain->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        /**
+         * return result
+         */
+        return $result;
+    }
+
+}

+ 137 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Create/CreateRessource.php

@@ -0,0 +1,137 @@
+<?php
+/**
+ * Class CreateRessource
+ * User: Nessandro
+ * Date: 2019-10-07
+ * Time: 10:41
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\ConfigOptionsHelper;
+
+class CreateRessource extends ApiService
+{
+    use ProductManagerHandler;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+
+    /**
+     * added more conditions
+     * @return bool
+     */
+    protected function isValid()
+    {
+        /**
+         * check if product manager is set
+         */
+        if(!$this->productManager)
+        {
+            $this->setError('Product Manager Not Found');
+            return false;
+        }
+
+        /**
+         * domain name
+         */
+        if(!$this->formData['domain'])
+        {
+            $this->setError('Domain name can not be found.');
+            return false;
+        }
+
+        /**
+         *
+         */
+        return parent::isValid();
+    }
+
+    /**
+     * @return mixed
+     */
+    protected function getRessources()
+    {
+        $ressources = $this->api->repository()->ressources->getRessources($this->formData['domain']);
+        return $ressources;
+    }
+
+    /**
+     * @return Ressource
+     */
+    protected function getModel()
+    {
+        /**
+         * create new ressource in kerio
+         */
+        $ressource = new Ressource();
+
+        $ressource->setName($this->formData['username'].'@'.$this->formData['domain']);
+        $ressource->setPassword(html_entity_decode($this->formData['password']), ENT_QUOTES);
+        /**
+         *  set ressource attributes
+         */
+        $ressource->setAttr(Ressource::ATTR_STATUS, $this->formData['status']);
+        $ressource->setAttr(Ressource::ATTR_TYPE, $this->formData['type']);
+        $ressource->setAttr(Ressource::ATTR_DISPLAY_NAME, $this->formData['display_name']);
+        $ressource->setAttr(Ressource::ATTR_DESC, $this->formData['description']);
+        $ressource->setAttr(Ressource::ATTR_NOTE, $this->formData['notes']);
+        $ressource->setAttr(Ressource::ATTR_CONT, $this->formData['contact']);
+        $ressource->setAttr(Ressource::ATTR_CONT_EMAIL, $this->formData['contact_mail']);
+        $ressource->setAttr(Ressource::ATTR_CONT_PHONE, $this->formData['contact_phone']);
+        $ressource->setAttr(Ressource::ATTR_SITE, $this->formData['site']);
+        $ressource->setAttr(Ressource::ATTR_BUILDING, $this->formData['building']);
+        $ressource->setAttr(Ressource::ATTR_FLOOR, $this->formData['floor']);
+        $ressource->setAttr(Ressource::ATTR_ROOM, $this->formData['room']);
+        $ressource->setAttr(Ressource::ATTR_CAPACITY, $this->formData['capacity']);
+        $ressource->setAttr(Ressource::ATTR_STREET, $this->formData['street']);
+        $ressource->setAttr(Ressource::ATTR_TOWN, $this->formData['town']);
+        $ressource->setAttr(Ressource::ATTR_POSTAL_CODE, $this->formData['post_code']);
+        $ressource->setAttr(Ressource::ATTR_COUNTY, $this->formData['county']);
+        $ressource->setAttr(Ressource::ATTR_STATE, $this->formData['state']);
+        $ressource->setAttr(Ressource::ATTR_AUTO, $this->formData['auto_accept'] == 'on' ? 'TRUE' : 'FALSE' );
+        $ressource->setAttr(Ressource::ATTR_BUSY, $this->formData['auto_busy'] == 'on' ? 'TRUE' : 'FALSE' );
+
+        foreach($this->productManager->getKerioConfiguration() as $key => $value)
+        {
+            $value = $value === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+            $ressource->setAttr($key, $value);
+        }
+
+        return $ressource;
+    }
+
+    /**
+     * @return bool|mixed|Ressource|void
+     */
+    protected function process()
+    {
+        /**
+         *
+         */
+        $model = $this->getModel();
+
+        /**
+         * create ressource in ZIMBRA
+         */
+        $result = $this->api->ressource->create($model);
+
+        /**
+         * problem with create ressource
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->ressource->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+}

+ 43 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteAccount.php

@@ -0,0 +1,43 @@
+<?php
+/**
+ * Class DeleteAccount
+ * User: Nessandro
+ * Date: 2019-09-17
+ * Time: 17:12
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+
+class DeleteAccount extends ApiService
+{
+
+    /**
+     * remove account in APi
+     *
+     * @return bool|mixed
+     */
+    public function process()
+    {
+        $account = new Account();
+        $account->setId($this->formData['id']);
+
+        $result = $this->api->account->delete($account);
+
+        /**
+         * problem with remove account
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+
+}

+ 71 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteAccountAlias.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:11
+ * Class DeleteAccountAlias
+ */
+class DeleteAccountAlias extends ApiService
+{
+    public function isValid()
+    {
+        /**
+         * check if alias is provided
+         */
+        if(!$this->formData['alias'])
+        {
+            $this->setError('Alias can not be deleted. Invalid alias.');
+            return false;
+        }
+
+        /**
+         * check if mailbox data is provided
+         */
+        if(!$this->formData['id'])
+        {
+            $this->setError('Alias can not be deleted. Invalid account.');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return bool|mixed
+     */
+    public function process()
+    {
+        /**
+         * prepare model
+         */
+        $aliasAccount = new AccountAlias();
+        $aliasAccount->setAlias($this->formData['alias']);
+        $aliasAccount->setAccountId($this->formData['id']);
+
+        /**
+         * delete alias from API
+         */
+        $result = $this->api->account->deleteAlias($aliasAccount);
+
+        /**
+         * problem with create account
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+
+    }
+}

+ 54 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteDistributionList.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 08:23
+ * Class DeleteDistributionList
+ */
+class DeleteDistributionList extends ApiService
+{
+
+    /**
+     *
+     * @return bool
+     */
+    public function isValid()
+    {
+        if(!$this->formData['id'])
+        {
+            $this->setError('Account Id name can not be found.');
+            return false;
+        }
+
+        return parent::isValid();
+    }
+
+    /**
+     *
+     * @return bool|mixed
+     */
+    public function process()
+    {
+        $list = new DistributionList();
+        $list->setId($this->formData['id']);
+
+        $result = $this->api->distributionList->delete($list);
+
+        if(!$result)
+        {
+            $this->setError($this->api->distributionList->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+}

+ 173 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteDomain.php

@@ -0,0 +1,173 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Exceptions\KerioApiException;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Exceptions\KerioServiceException;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Enums\ApiErrorCodes;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.10.19
+ * Time: 14:41
+ * Class DeleteDomain
+ */
+class DeleteDomain extends ApiService
+{
+
+    protected $domain;
+
+    /**
+     * @return bool
+     */
+    public function isValid()
+    {
+        if(!$this->formData['domain'])
+        {
+            $this->setError('Domain not found');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return mixed|void
+     */
+    public function process()
+    {
+        $this->setDomainAsActiveIfRequired();
+        $this->removeLists();
+        $this->removeAccounts();
+        $this->removeDomain();
+        if ($this->getError())
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    protected function setDomainAsActiveIfRequired()
+    {
+        $domain = $this->getOrLoadDomain();
+        $domain->setAttrs([
+            Domain::ATTR_DOMAIN_STATUS => Kerio::ACC_STATUS_ACTIVE,
+            Domain::ATTR_MAIL_STATUS    => Kerio::ENABLED,
+        ]);
+
+        $response = $this->api->domain->update($domain);
+
+        return $this;
+    }
+
+    /**
+     * remove distribution list
+     *
+     * @return bool
+     */
+    protected function removeLists()
+    {
+        /**
+         * get lists
+         */
+        $lists = $this->api->repository()->lists->getAllDistributionListsByDomain($this->formData['domain']);
+
+        /**
+         * remove each list
+         */
+        foreach($lists as $list)
+        {
+            /* @var $list DistributionList */
+            $result = $this->api->distributionList->delete($list);
+            if($this->api->distributionList->getError())
+            {
+                $this->throwError($this->api->distributionList->getError());
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     *
+     * @return bool
+     *
+     */
+    protected function removeAccounts()
+    {
+        /**
+         * get accounts from Kerio
+         */
+        $accounts = $this->api->repository()->accounts->getByDomainName($this->formData['domain']);
+        /**
+         * remove each account
+         */
+        foreach($accounts as $account)
+        {
+            $result = $this->api->account->delete($account);
+            if($this->api->account->getError())
+            {
+                $this->throwError($this->api->account->getError());
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * remove domain from API
+     *
+     * @return bool
+     */
+    protected function removeDomain()
+    {
+        /**
+         *
+         * get domain from kerio
+         */
+        $domain = $this->getOrLoadDomain();
+
+
+        /**
+         * remove domain
+         */
+        $result = $this->api->domain->delete($domain);
+
+        if(!$result && ApiErrorCodes::DOMAIN_DOES_NOT_EXISTS !== $this->api->domain->getLastResult()->getLastErrorCode())
+        {
+            $this->setError($this->api->domain->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     *
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain
+     */
+    protected function getOrLoadDomain()
+    {
+        if(!$this->domain)
+        {
+            $this->domain = $this->api->repository()->domains->getByName($this->formData['domain']);
+        }
+
+        if ($this->api->repository()->domains->getError())
+        {
+            $this->throwError($this->api->repository()->domains->getError());
+        }
+
+        return $this->domain;
+    }
+
+
+}

+ 37 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteDomainAlias.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 14:39
+ * Class DeleteDomainAlias
+ */
+class DeleteDomainAlias extends ApiService
+{
+
+    public function process()
+    {
+
+        $domain = new Domain();
+        $domain->setId($this->formData['id']);
+
+        $result = $this->api->domain->delete($domain);
+
+        if(!$result)
+        {
+            $this->setError($this->api->domain->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+
+}

+ 43 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Delete/DeleteRessource.php

@@ -0,0 +1,43 @@
+<?php
+/**
+ * Class DeleteRessource
+ * User: Nessandro
+ * Date: 2019-09-17
+ * Time: 17:12
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+
+class DeleteRessource extends ApiService
+{
+
+    /**
+     * remove ressource in APi
+     *
+     * @return bool|mixed
+     */
+    public function process()
+    {
+        $ressource = new Ressource();
+        $ressource->setId($this->formData['id']);
+
+        $result = $this->api->ressource->delete($ressource);
+
+        /**
+         * problem with remove ressource
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->ressource->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+
+}

+ 45 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Sso/ClientSingleSignOnToken.php

@@ -0,0 +1,45 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Sso;
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Connection;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 17:24
+ * Class ClientSingleSignOn
+ */
+class ClientSingleSignOnToken extends ApiService
+{
+
+    /**
+     *
+     * @return mixed|string
+     * @throws \SoapFault
+     */
+    public function process()
+    {
+        $account = new Account();
+        $account->setName($this->formData['mail']);
+        $account->setId($this->formData['id']);
+
+        $result = $this->api->account->delegateAuth($account);
+
+        if(!$result)
+        {
+            $this->setError($this->api->account->getError());
+            return false;
+
+        }
+
+        return [
+            'authToken' => $result->getResponseBody()['DELEGATEAUTHRESPONSE']['AUTHTOKEN']['DATA'],
+        '   lifeTime' =>$result->getResponseBody()['DELEGATEAUTHRESPONSE']['LIFETIME']['DATA']
+        ];
+    }
+
+}

+ 124 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackage.php

@@ -0,0 +1,124 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\ConfigOptionsHelper;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\UpdateLimit;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 13:03
+ * Class ChangePackage
+ */
+class ChangePackage extends ApiService
+{
+    use ProductManagerHandler;
+    use \ModulesGarden\Servers\KerioEmail\App\Traits\HostingService;
+
+    public function isValid()
+    {
+        if(!$this->formData['domain'])
+        {
+            $this->setError('Domain name can not be found.');
+            return false;
+        }
+
+        return parent::isValid(); // TODO: Change the autogenerated stub
+    }
+
+    public function process()
+    {
+        $serviceID = $this->formData['serviceid'];
+        $configOption = new ConfigOptionsHelper;
+        $accounts = $this->api->repository()->accounts->getByDomainName($this->formData['domain']);
+        $acc_base = $this->productManager->get('acc_base') ? $this->productManager->get('acc_base') : 0;
+        if(isset($this->formData['configoptions']['acc_add']) && isset($this->formData['configoptions']['acc_new'])) {
+            $acc_add = $this->formData['configoptions']['acc_add'];
+            $acc_new = $this->formData['configoptions']['acc_new'];
+            $acc_add = $acc_add + $acc_new;
+            $acc_new = 0;
+            $accountLimit = $acc_base + $acc_add;
+            if (($this->productManager->get('acc_limit') > 0) && ($accountLimit > $this->productManager->get('acc_limit'))) {
+                $acc_add = $this->productManager->get('acc_limit') - $acc_base;
+            }
+            $acc_addObj = $configOption->getConfigurableOption($serviceID, 'acc_add');
+            if(isset($acc_addObj->id)) {
+                $configOption->updateConfigurableOption($acc_addObj->id, ['qty' => $acc_add]);
+            }
+            $acc_newObj = $configOption->getConfigurableOption($serviceID, 'acc_new');
+            if(isset($acc_newObj->id)) {
+                $configOption->updateConfigurableOption($acc_newObj->id, ['qty' => $acc_new]);
+            }
+        } else {
+            $accountLimit = $this->productManager->get('acc_limit');
+        }
+        foreach($accounts as $account)
+        {
+            /* @var $account Account*/
+            foreach($this->productManager->getKerioConfiguration() as $key => $value)
+            {
+                $value = $value === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+                $account->setAttr($key, $value);
+                $result = $this->api->account->update($account);
+
+                if(!$result)
+                {
+                    //todo some logs
+                }
+            }
+        }
+        $domain = $this->api->repository()->domains->getByName($this->formData['domain']);
+        if(!$domain) {
+            throw new \Exception($this->api->repository()->domains->getError());
+            return false;
+        }
+        $domainBaseSize = $this->productManager->get('domainBaseSize') ? $this->productManager->get('domainBaseSize') : 0;
+        if(isset($this->formData['configoptions']['domainAddSize']) && isset($this->formData['configoptions']['domainNewSize'])) {
+            $domainAddSize = $this->formData['configoptions']['domainAddSize'];
+            $domainNewSize = $this->formData['configoptions']['domainNewSize'];
+            $domainAddSize = $domainAddSize + $domainNewSize;
+            $domainNewSize = 0;
+            $domainSize = $domainBaseSize + $domainAddSize;
+            if (($this->productManager->get('domainMaxSize') > 0) && ($domainSize > $this->productManager->get('domainMaxSize'))) {
+                $domainMaxSize = $this->productManager->get('domainMaxSize');
+                $domainAddSize = $domainMaxSize - $domainBaseSize;
+                $domainSize = $domainBaseSize + $domainAddSize;
+            }
+            $domainAddSizeObj = $configOption->getConfigurableOption($serviceID, 'domainAddSize');
+            if(isset($domainAddSizeObj->id)) {
+                $configOption->updateConfigurableOption($domainAddSizeObj->id, ['qty' => $domainAddSize]);
+            }
+            $domainNewSizeObj = $configOption->getConfigurableOption($serviceID, 'domainNewSize');
+            if(isset($domainNewSizeObj->id)) {
+                $configOption->updateConfigurableOption($domainNewSizeObj->id, ['qty' => $domainNewSize]);
+            }
+        } else {
+            $domainSize = $this->productManager->get('domainBaseSize');
+        }
+        $updateLimit = new UpdateLimit;
+        $updateLimit->updateDiskLimit($serviceID, $domainSize * 1024);
+        $updateLimit->updateBWLimit($serviceID, $accountLimit);
+        $domain->setAttrs([
+            Domain::ATTR_MAIL_DOMAIN_QUOTA  => $domainSize * Size::B_TO_GB,
+        ]);
+        $response = $this->api->domain->update($domain);
+        if(!$response)
+        {
+            throw new \Exception($this->api->domain->getError());
+            return false;
+        }
+
+        return true;
+    }
+}

+ 19 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackageConfigOptions.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 13:59
+ * Class ChangePackageConfigOptions
+ */
+class ChangePackageConfigOptions extends ChangePackage
+{
+
+}

+ 20 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackageCosQuota.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 13:59
+ * Class ChangePackageCosQuota
+ */
+class ChangePackageCosQuota extends ChangePackage
+{
+    
+
+}

+ 119 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/ChangePackageDedicatedCos.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 14:00
+ * Class ChangePackageDedicatedCos
+ */
+class ChangePackageDedicatedCos extends ChangePackage
+{
+
+    protected $cosModels = [];
+
+    /**
+     *
+     */
+    public function config()
+    {
+        $this->cosModels = $this->api->repository()->cos->all();
+
+        parent::config(); // TODO: Change the autogenerated stub
+    }
+
+    /**
+     * @return bool
+     */
+    public function isValid()
+    {
+        /**
+         *
+         */
+        if(!$this->formData['domain'])
+        {
+            $this->setError('Domain name can not be found.');
+            return false;
+        }
+
+        /**
+         * if cos doesn't exists
+         */
+        if(!$this->productManager->getSettingCos())
+        {
+            $this->setError('Can not found class of service Id');
+            return false;
+        }
+
+        /**
+         * invalid id format
+         */
+        if(!is_string($this->productManager->getSettingCos()))
+        {
+            $this->setError('Invalid class of service ID format');
+            return false;
+        }
+
+        return parent::isValid();
+    }
+
+    /**
+     * @return bool|mixed
+     */
+    public function process()
+    {
+        $accounts = $this->api->repository()->accounts->getByDomainName($this->formData['domain']);
+
+        foreach($accounts as $account)
+        {
+            /* @var $account Account*/
+            /* @var $cos ClassOfService*/
+            $cos = $this->cosModels[$this->productManager->getSettingCos()];
+
+            /**
+             * set quota by class of service
+             */
+            $account->setAttr(Account::ATTR_MAIL_QUOTA, $cos->getDataResourceA(Account::ATTR_MAIL_QUOTA));
+
+            /**
+             * define class of services attribute for account
+             */
+            $cosAttrs = $cos->getAllDataResourcesAAttributes();
+
+            foreach(Kerio::BASE_ACCOUNT_CONFIG as $key)
+            {
+                $value = $cosAttrs[$key] ? $cosAttrs[$key] : Kerio::ATTR_DISABLED;
+                $account->setAttr($key, $value);
+            }
+
+            /**
+             *
+             * set class of service id as account attribute
+             */
+            $account->setAttr(Account::ATTR_CLASS_OF_SERVICE_ID, $cos->getId());
+
+            /**
+             * update account
+             */
+            $result = $this->api->account->update($account);
+
+            if(!$result)
+            {
+                //todo
+            }
+        }
+
+        return true;
+
+    }
+}

+ 51 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/SuspendDomain.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.10.19
+ * Time: 15:20
+ * Class SuspendDomain
+ */
+class SuspendDomain extends ApiService
+{
+
+    public function isValid()
+    {
+
+        return parent::isValid();
+    }
+
+    public function process()
+    {
+        $domain = $this->api->repository()->domains->getByName($this->formData['domain']);
+        if(!$domain)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        $domain->setAttrs([
+            Domain::ATTR_DOMAIN_STATUS  => Kerio::ACC_STATUS_SUSPEND,
+            Domain::ATTR_MAIL_STATUS    => Kerio::DISABLED,
+
+        ]);
+
+        $response = $this->api->domain->update($domain);
+        if(!$response)
+        {
+            $this->setError($this->api->domain->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+}

+ 44 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UnsuspendDomain.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.10.19
+ * Time: 15:21
+ * Class UnsuspendDomain
+ */
+class UnsuspendDomain extends ApiService
+{
+
+    public function process()
+    {
+        $domain = $this->api->repository()->domains->getByName($this->formData['domain']);
+        if(!$domain)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        $domain->setAttrs([
+            Domain::ATTR_DOMAIN_STATUS => Kerio::ACC_STATUS_ACTIVE,
+            Domain::ATTR_MAIL_STATUS    => Kerio::ENABLED,
+            ]);
+
+        $response = $this->api->domain->update($domain);
+        if(!$response)
+        {
+            $this->setError($this->api->domain->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+}

+ 77 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccount.php

@@ -0,0 +1,77 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccount;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:09
+ * Class UpdateAccount
+ */
+class UpdateAccount extends CreateAccount
+{
+
+    /**
+     * @return bool|mixed|Account|void
+     */
+    protected function process()
+    {
+        /**
+         *
+         */
+        $model = $this->getModel();
+
+        /**
+         * update account in ZIMBRA
+         */
+        $result = $this->api->account->update($model);
+
+        /**
+         * problem with create account
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+
+    /**
+     * @return Account
+     */
+    public function getModel()
+    {
+        $account = new Account();
+        /**
+         *  set account attributes
+         */
+        $account->setId($this->formData['id']);
+
+        $account->setAttr(Account::ATTR_FIRSTNAME, $this->formData['firstname']);
+        $account->setAttr(Account::ATTR_LASTNAME, $this->formData['lastname']);
+        $account->setAttr(Account::ATTR_PHONE, $this->formData['phone']);
+        $account->setAttr(Account::ATTR_MOBILE_PHONE, $this->formData['mobile_phone']);
+        $account->setAttr(Account::ATTR_FAX, $this->formData['fax']);
+        $account->setAttr(Account::ATTR_PAGER, $this->formData['pager']);
+        $account->setAttr(Account::ATTR_HOME_PHONE, $this->formData['home_phone']);
+        $account->setAttr(Account::ATTR_COUNTRY, $this->formData['country']);
+        $account->setAttr(Account::ATTR_STATE, $this->formData['state']);
+        $account->setAttr(Account::ATTR_PROF_TITLE, $this->formData['title']);
+        $account->setAttr(Account::ATTR_POSTAL_CODE, $this->formData['post_code']);
+        $account->setAttr(Account::ATTR_CITY, $this->formData['city']);
+        $account->setAttr(Account::ATTR_STREET, $this->formData['street']);
+        $account->setAttr(Account::ATTR_COMPANY, $this->formData['company']);
+        $account->setAttr(Account::ATTR_ACCOUNT_STATUS, $this->formData['status']);
+        $account->setAttr(Account::ATTR_DISPLAY_NAME, $this->formData['display_name']);
+
+        return $account;
+
+    }
+}

+ 107 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccountCosQuota.php

@@ -0,0 +1,107 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccountCosQuota;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.10.19
+ * Time: 08:25
+ * Class UpdateAccountCosQuota
+ */
+class UpdateAccountCosQuota extends CreateAccountCosQuota
+{
+    /**
+     * @return bool|mixed|Account|void
+     */
+    protected function process()
+    {
+        /**
+         *
+         */
+        $model = $this->getModel();
+
+        /**
+         * update account in ZIMBRA
+         */
+        $result = $this->api->account->update($model);
+
+        /**
+         * problem with create account
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+
+    /**
+     * @return Account
+     */
+    public function getModel()
+    {
+        $account = new Account();
+        /**
+         *  set account attributes
+         */
+        $account->setId($this->formData['id']);
+
+        $account->setAttr(Account::ATTR_FIRSTNAME, $this->formData['firstname']);
+        $account->setAttr(Account::ATTR_LASTNAME, $this->formData['lastname']);
+        $account->setAttr(Account::ATTR_PHONE, $this->formData['phone']);
+        $account->setAttr(Account::ATTR_MOBILE_PHONE, $this->formData['mobile_phone']);
+        $account->setAttr(Account::ATTR_FAX, $this->formData['fax']);
+        $account->setAttr(Account::ATTR_PAGER, $this->formData['pager']);
+        $account->setAttr(Account::ATTR_HOME_PHONE, $this->formData['home_phone']);
+        $account->setAttr(Account::ATTR_COUNTRY, $this->formData['country']);
+        $account->setAttr(Account::ATTR_STATE, $this->formData['state']);
+        $account->setAttr(Account::ATTR_PROF_TITLE, $this->formData['title']);
+        $account->setAttr(Account::ATTR_POSTAL_CODE, $this->formData['post_code']);
+        $account->setAttr(Account::ATTR_CITY, $this->formData['city']);
+        $account->setAttr(Account::ATTR_STREET, $this->formData['street']);
+        $account->setAttr(Account::ATTR_COMPANY, $this->formData['company']);
+        $account->setAttr(Account::ATTR_ACCOUNT_STATUS, $this->formData['status']);
+        $account->setAttr(Account::ATTR_DISPLAY_NAME, $this->formData['display_name']);
+
+        /* @var $cos ClassOfService*/
+        $cos = $this->cosModels[$this->formData['cosId']];
+
+        /**
+         * set quota by class of service
+         */
+        $account->setAttr(Account::ATTR_MAIL_QUOTA, $cos->getDataResourceA(Account::ATTR_MAIL_QUOTA));
+
+        /**
+         * define class of services attribute for account
+         */
+        $cosAttrs = $cos->getAllDataResourcesAAttributes();
+
+        foreach(Kerio::BASE_ACCOUNT_CONFIG as $key)
+        {
+            $value = $cosAttrs[$key] ? $cosAttrs[$key] : Kerio::ATTR_DISABLED;
+            $account->setAttr($key, $value);
+        }
+
+        /**
+         *
+         * set class of service id as account attribute
+         */
+        $account->setAttr(Account::ATTR_CLASS_OF_SERVICE_ID, $cos->getId());
+
+
+        return $account;
+    }
+
+}

+ 56 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccountPassword.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccountCosQuota;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:15
+ * Class UpdateAccountPassword
+ */
+class UpdateAccountPassword extends ApiService
+{
+    use ProductManagerHandler;
+
+    /**
+     * @return bool
+     */
+    public function isValid()
+    {
+        if(!$this->formData['id'])
+        {
+            $this->setError('Account Id name can not be found.');
+            return false;
+        }
+
+        return parent::isValid(); // TODO: Change the autogenerated stub
+    }
+
+    /**
+     * @return bool|mixed
+     */
+    public function process()
+    {
+        $model = new Account();
+        $model->setId($this->formData['id']);
+        $model->setPassword($this->formData['password']);
+
+        $result = $this->api->account->setPassword($model);
+
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+}

+ 39 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateAccountStatus.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.10.19
+ * Time: 09:00
+ * Class UpdateAccountStatus
+ */
+class UpdateAccountStatus extends ApiService
+{
+    use ProductManagerHandler;
+
+    public function process()
+    {
+        $model = new Account();
+        $model->setId($this->formData['id']);
+        $model->setAttr(Account::ATTR_ACCOUNT_STATUS, $this->formData['status']);
+
+        $result = $this->api->account->update($model);
+
+        if(!$result)
+        {
+            $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+
+}

+ 357 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateDistributionList.php

@@ -0,0 +1,357 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDistributionList;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 09:42
+ * Class UpdateDistributionList
+ */
+class UpdateDistributionList extends CreateDistributionList
+{
+    public function isValid()
+    {
+        /**
+         *
+         * check that the owners are valid
+         */
+        foreach($this->formData['owners'] as $owner)
+        {
+            $result = $this->api->account->getAccountId($owner);
+            if($result->getLastError())
+            {
+                $this->setError($this->api->account->getLastResult()->getLastErrorCode());
+                return false;
+            }
+        }
+
+        /**
+         *
+         * check that the domains from aliases are valid
+         */
+        foreach($this->formData['emailAliases'] as $alias)
+        {
+            $aliasParts = explode('@', $alias);
+            $domain = new Domain();
+            $domain->setName($aliasParts[1]);
+            $result = $this->api->domain->getDomain($domain);
+            if($result->getLastError())
+            {
+                $this->setError($this->api->domain->getLastResult()->getLastErrorCode());
+                return false;
+            }
+        }
+
+        if(!$this->api)
+        {
+            $this->setError('API Not Found');
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * update aliases service
+     *
+     * @return bool|mixed
+     */
+    public function process()
+    {
+
+        $list = $this->getModel();
+        /**
+         * create list
+         */
+        $result = $this->api->distributionList->update($list);
+
+        if (!$result)
+        {
+            $this->setError($this->api->distributionList->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        /**
+         *
+         * update members list
+         */
+        $this->updateMembers($list, $this->formData['memberListActually'], $this->formData['memberList']);
+
+        /**
+         *
+         * update owners list
+         */
+        $this->updateOwners($list, $this->formData['ownersActually'], $this->formData['owners']);
+
+
+        /**
+         *
+         * update aliases
+         */
+        $this->updateListAliases($list, $this->formData['emailAliasesActually'], $this->formData['emailAliases']);
+
+
+        return true;
+    }
+
+    /**
+     * @return DistributionList
+     */
+    protected function getModel()
+    {
+        $list = new DistributionList();
+        $list->setId($this->formData['id']);
+        $list->setAttr(DistributionList::ATTR_DISPLAY_NAME, $this->formData['displayName']);
+        $list->setAttr(DistributionList::ATTR_DESCRIPTION, $this->formData['description']);
+        $list->setAttr(DistributionList::ATTR_SUBSCRIPTION_REQUEST, $this->formData['subscriptionRequest']);
+        $list->setAttr(DistributionList::ATTR_UNSUBSCRIPTION_REQUEST, $this->formData['unsubscriptionRequest']);
+        $list->setAttr(DistributionList::REPLY_TO_DISPLAY, $this->formData['replyDisplayName']);
+        $list->setAttr(DistributionList::REPLY_TO_ADDRESS, $this->formData['replyEmailAddress']);
+
+        $notify = $this->formData['sharesNotify'] === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+        $list->setAttr(DistributionList::ATTR_NOTIFY_SHARES, $notify);
+
+        $hideGal = $this->formData['hideGal'] === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+        $list->setAttr(DistributionList::ATTR_HIDE_IN_GAL, $hideGal);
+
+        $status = $this->formData['receiveMail'] === ProductParams::SWITCHER_ENABLED ? Kerio::ENABLED : Kerio::DISABLED;
+        $list->setAttr(DistributionList::ATTR_MAIL_STATUS, $status);
+
+        $replyEnabled = $this->formData['replyEmail'] === ProductParams::SWITCHER_ENABLED ? Kerio::ATTR_ENABLED : Kerio::ATTR_DISABLED;
+        $list->setAttr(DistributionList::REPLY_TO_ENABLED, $replyEnabled);
+
+
+        if ($this->formData['dynamicGroup'] === ProductParams::SWITCHER_ENABLED)
+        {
+            $list->setDynamic(true);
+        }
+
+        return $list;
+    }
+
+    /**
+     * @param DistributionList $list
+     * @param array $currentMembers
+     * @param array $newMembers
+     * @return bool
+     */
+    protected function updateMembers(DistributionList $list, $currentMembers = [], $newMembers = [])
+    {
+        /**
+         *
+         * get members which should be added
+         */
+        $add = array_diff((array) $newMembers,(array) $currentMembers);
+
+        /**
+         *
+         * add members to list
+         */
+        $this->addListMembers($list, $add);
+
+        /**
+         *
+         * get members which should be removed
+         */
+        $remove = array_diff((array)$currentMembers,(array) $newMembers);
+
+        /**
+         *
+         * remove members
+         */
+        $this->removeMembers($list, $remove);
+
+        /**
+         *
+         * return success
+         */
+        return true;
+    }
+
+    /**
+     * @param DistributionList $list
+     * @param array $members
+     * @return bool
+     */
+    protected function removeMembers(DistributionList $list, $members = [])
+    {
+        /**
+         *
+         * set member list as empty
+         */
+        $list->setMembers([]);
+
+        /**
+         *
+         * add members to remove
+         */
+        foreach ($members as $owner)
+        {
+            $list->addMember($owner);
+        }
+
+        /**
+         *
+         * remove old members
+         */
+        $result = $this->api->distributionList->deleteMembers($list);
+        if (!$result)
+        {
+            $this->setError($this->api->distributionList->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        /**
+         * return success
+         */
+        return true;
+    }
+
+    /**
+     *
+     * update owners list
+     *
+     * @param DistributionList $list
+     * @param array $currentOwners
+     * @param array $newOwners
+     * @return bool
+     */
+    protected function updateOwners(DistributionList $list, $currentOwners = [], $newOwners = [])
+    {
+        /**
+         *
+         * get owners which should be added
+         */
+        $add = array_diff((array) $newOwners, (array) $currentOwners);
+        /**
+         *
+         * add new owners
+         */
+        $this->addListOwners($list, $add);
+        /**
+         *
+         * get members which should be removed
+         */
+        $remove = array_diff((array) $currentOwners,(array) $newOwners);
+
+        /**
+         *
+         * remove other owners
+         */
+        $this->removeOwners($list, $remove);
+
+        /**
+         *
+         */
+        return true;
+
+    }
+
+    /**
+     *
+     * remove old owners
+     *
+     * @param DistributionList $list
+     * @param array $owners
+     * @return bool
+     */
+    protected function removeOwners(DistributionList $list, $owners = [])
+    {
+        /**
+         * set owner list as empty
+         */
+        $list->setOwners([]);
+
+        /**
+         * add owners which should be deleted
+         */
+        foreach ($owners as $owner)
+        {
+            $list->addOwner($owner);
+        }
+
+        /**
+         * delete owners from list
+         */
+        $result = $this->api->distributionList->deleteOwners($list);
+        if (!$result)
+        {
+            $this->setError($this->api->distributionList->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * update aliases list
+     *
+     * @param DistributionList $list
+     * @param array $currentAliases
+     * @param array $newAliases
+     * @return bool
+     */
+    protected function updateListAliases(DistributionList $list, $currentAliases = [], $newAliases = [])
+    {
+        /**
+         *
+         * get aliases to add
+         */
+        $add = array_diff((array) $newAliases,(array) $currentAliases);
+
+        /**
+         *
+         * add aliases
+         */
+        $this->addListAliases($list, $add);
+
+        /**
+         *
+         * get aliases to remove
+         */
+        $remove = array_diff((array) $currentAliases,(array) $newAliases);
+
+        /**
+         *
+         * remove aliases
+         */
+        $this->removeAliases($list, $remove);
+
+
+        return true;
+    }
+
+    /**
+     * remove aliases
+     *
+     * @param DistributionList $list
+     * @param array $aliases
+     * @return bool
+     */
+    public function removeAliases(DistributionList $list, $aliases = [])
+    {
+        /**
+         * remove each alias
+         */
+        foreach ($aliases as $alias)
+        {
+            $list->setAlias($alias);
+            $result = $this->api->distributionList->deleteAlias($list);
+        }
+
+        return true;
+    }
+
+
+}

+ 84 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateRessource.php

@@ -0,0 +1,84 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateRessource;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:09
+ * Class UpdateRessource
+ */
+class UpdateRessource extends CreateRessource
+{
+
+    /**
+     * @return bool|mixed|Ressource|void
+     */
+    protected function process()
+    {
+        /**
+         *
+         */
+        $model = $this->getModel();
+
+        /**
+         * update ressource in ZIMBRA
+         */
+        $result = $this->api->ressource->update($model);
+
+        /**
+         * problem with create ressource
+         */
+        if(!$result)
+        {
+            $this->setError($this->api->ressource->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return $result;
+    }
+
+    /**
+     * @return Ressource
+     */
+    public function getModel()
+    {
+        $ressource = new Ressource();
+        /**
+         *  set ressource attributes
+         */
+        $ressource->setId($this->formData['id']);
+
+        $ressource->setAttr(Ressource::ATTR_NAME, $this->formData['name']);
+        $ressource->setAttr(Ressource::ATTR_STATUS, $this->formData['status']);
+        $ressource->setAttr(Ressource::ATTR_TYPE, $this->formData['type']);
+        $ressource->setAttr(Ressource::ATTR_DISPLAY_NAME, $this->formData['display_name']);
+        $ressource->setAttr(Ressource::ATTR_DESC, $this->formData['description']);
+        $ressource->setAttr(Ressource::ATTR_NOTE, $this->formData['notes']);
+        $ressource->setAttr(Ressource::ATTR_CONT, $this->formData['contact']);
+        $ressource->setAttr(Ressource::ATTR_CONT_EMAIL, $this->formData['contact_mail']);
+        $ressource->setAttr(Ressource::ATTR_CONT_PHONE, $this->formData['contact_phone']);
+        $ressource->setAttr(Ressource::ATTR_SITE, $this->formData['site']);
+        $ressource->setAttr(Ressource::ATTR_BUILDING, $this->formData['building']);
+        $ressource->setAttr(Ressource::ATTR_FLOOR, $this->formData['floor']);
+        $ressource->setAttr(Ressource::ATTR_ROOM, $this->formData['room']);
+        $ressource->setAttr(Ressource::ATTR_CAPACITY, $this->formData['capacity']);
+        $ressource->setAttr(Ressource::ATTR_STREET, $this->formData['street']);
+        $ressource->setAttr(Ressource::ATTR_TOWN, $this->formData['town']);
+        $ressource->setAttr(Ressource::ATTR_POSTAL_CODE, $this->formData['post_code']);
+        $ressource->setAttr(Ressource::ATTR_COUNTY, $this->formData['county']);
+        $ressource->setAttr(Ressource::ATTR_STATE, $this->formData['state']);
+        $ressource->setAttr(Ressource::ATTR_AUTO, $this->formData['auto_accept'] == 'on' ? 'TRUE' : 'FALSE' );
+        $ressource->setAttr(Ressource::ATTR_BUSY, $this->formData['auto_busy'] == 'on' ? 'TRUE' : 'FALSE' );
+
+        return $ressource;
+
+    }
+}

+ 56 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateRessourcePassword.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateRessourceCosQuota;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:15
+ * Class UpdateRessourcePassword
+ */
+class UpdateRessourcePassword extends ApiService
+{
+    use ProductManagerHandler;
+
+    /**
+     * @return bool
+     */
+    public function isValid()
+    {
+        if(!$this->formData['id'])
+        {
+            $this->setError('Ressource Id name can not be found.');
+            return false;
+        }
+
+        return parent::isValid(); // TODO: Change the autogenerated stub
+    }
+
+    /**
+     * @return bool|mixed
+     */
+    public function process()
+    {
+        $ressource = new Ressource();
+        $ressource->setId($this->formData['id']);
+        $ressource->setPassword($this->formData['password']);
+
+        $result = $this->api->ressource->setPassword($ressource);
+
+        if(!$result)
+        {
+            $this->setError($this->api->ressource->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+}

+ 39 - 0
app/Libs/Kerio/Components/Api/Soap/Services/Update/UpdateRessourceStatus.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits\ProductManagerHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.10.19
+ * Time: 09:00
+ * Class UpdateRessourceStatus
+ */
+class UpdateRessourceStatus extends ApiService
+{
+    use ProductManagerHandler;
+
+    public function process()
+    {
+        $model = new Ressource();
+        $model->setId($this->formData['id']);
+        $model->setAttr(Ressource::ATTR_STATUS, $this->formData['status']);
+
+        $result = $this->api->ressource->update($model);
+
+        if(!$result)
+        {
+            $this->setError($this->api->ressource->getLastResult()->getLastErrorCode());
+            return false;
+        }
+
+        return true;
+    }
+
+}

+ 38 - 0
app/Libs/Kerio/Components/Api/Soap/Traits/ApiClientHandler.php

@@ -0,0 +1,38 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Client;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Interfaces\ApiService;
+
+/**
+ * Class ApiClientHandler
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 07:52
+ */
+
+trait ApiClientHandler
+{
+    /**
+     * @var Client
+     */
+    protected $api;
+
+    /**
+     * @param $api
+     * @return $this
+     */
+    public function setApi(Client $api)
+    {
+        $this->api = $api;
+        return $this;
+    }
+
+    /**
+     * @return Client
+     */
+    public function getApi()
+    {
+        return $this->api;
+    }
+
+}

+ 30 - 0
app/Libs/Kerio/Components/Api/Soap/Traits/ErrorHandler.php

@@ -0,0 +1,30 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits;
+
+trait ErrorHandler
+{
+
+    /**
+     * @var
+     */
+    protected $error;
+
+    /**
+     * @param null $error
+     * @return $this
+     */
+    public function setError($error = null)
+    {
+        $this->error = $error;
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getError()
+    {
+        return $this->error;
+    }
+
+}

+ 70 - 0
app/Libs/Kerio/Components/Api/Soap/Traits/FormDataHandler.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Class FormDataHandler
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 08:46
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits;
+
+
+/**
+ * Trait FormDataHandler
+ * @package ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits
+ */
+trait FormDataHandler
+{
+
+    /**
+     * @var array
+     */
+    protected $formData = [];
+
+    /**
+     * @return array
+     */
+    public function getFormData()
+    {
+        return $this->formData;
+    }
+
+    /**
+     * @param $formData
+     * @return $this
+     */
+    public function setFormData($formData)
+    {
+        foreach($formData as $key => &$value)
+        {
+            $this->updateEntity($value);
+        }
+
+        $this->formData = $formData;
+        return $this;
+    }
+
+    /**
+     * @param null $entity
+     */
+    public function updateEntity(&$entity = null)
+    {
+        if(is_array($entity))
+        {
+            foreach ($entity as $key => &$value)
+            {
+                $this->updateEntity($value);
+            }
+        }elseif(is_object($entity))
+        {
+
+        }else{
+            $entity = html_entity_decode($entity, ENT_QUOTES);
+        }
+
+    }
+
+
+
+}

+ 119 - 0
app/Libs/Kerio/Components/Api/Soap/Traits/ProcessStepHandler.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.10.19
+ * Time: 11:22
+ * Class ProcesStepHandler
+ */
+trait ProcessStepHandler
+{
+    /**
+     * array with process in progress
+     * @var array
+     */
+    protected $inProgressProcess = [];
+
+    /**
+     * array with completed process
+     * @var array
+     */
+    protected $completedProcess = [];
+
+    /**
+     * array with process finished with error status
+     * @var array
+     */
+    protected $errorProcess = [];
+
+    /**
+     * @var array
+     */
+    protected $allProcess = [];
+
+    /**
+     * @return array
+     */
+    public function getInProgress()
+    {
+        return $this->inProgressProcess;
+    }
+
+    /**
+     * @return array
+     */
+    public function getCompleted()
+    {
+        return $this->completedProcess;
+    }
+
+    /**
+     * @return array
+     */
+    public function getErrorProcess()
+    {
+        return $this->errorProcess;
+    }
+
+    /**
+     * @return array
+     */
+    public function getAllProcess()
+    {
+        return $this->allProcess;
+    }
+
+    /**
+     * @param $code
+     * @return $this
+     */
+    public function startProcess($code)
+    {
+        $this->inProgressProcess[$code] = $code;
+        $this->allProcess[]      = $code;
+        return $this;
+    }
+
+    /**
+     * @param $code
+     * @return $this
+     */
+    public function stopProcess($code)
+    {
+        unset($this->inProgressProcess[$code]);
+        $this->completedProcess[$code] = $code;
+        return $this;
+    }
+
+    /**
+     * @param $code
+     * @param $error
+     * @return $this
+     */
+    public function stopProcessWithError($code, $error)
+    {
+        unset($this->inProgressProcess[$code]);
+        $this->error[$code] = ['code' => $code, 'error' => $error];
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function info()
+    {
+        return [
+            'process'    => $this->getAllProcess(),
+            'inProgress' => $this->getInProgress(),
+            'finished'   => $this->getCompleted(),
+            'error'      => $this->getErrorProcess(),
+        ];
+
+    }
+
+}

+ 35 - 0
app/Libs/Kerio/Components/Api/Soap/Traits/ProductManagerHandler.php

@@ -0,0 +1,35 @@
+<?php
+
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Traits;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateAccount;
+
+trait ProductManagerHandler
+{
+
+    /**
+     * @var ProductManager
+     */
+    protected $productManager;
+
+    /**
+     * @return ProductManager
+     */
+    public function getProductManager()
+    {
+        return $this->productManager;
+    }
+
+    /**
+     * @param ProductManager $productManager
+     * @return $this
+     */
+    public function setProductManager(ProductManager $productManager)
+    {
+        $this->productManager = $productManager;
+        return $this;
+    }
+}

+ 35 - 0
app/Libs/Kerio/Components/Filters/EmailAccounts/FilterByCosId.php

@@ -0,0 +1,35 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Filters\EmailAccounts;
+
+/*
+File:   FilterByCosId.php
+Date:   06.05.2020
+Author: Tomasz Bielecki (tomasz.bi@modulesgarden.com)
+Class FilterByCosId
+*/
+
+class FilterByCosId
+{
+    protected $availableCos = [];
+
+    public function setAvailableCoses($availableCoses = [])
+    {
+        $this->availableCos = $availableCoses;
+        return $this;
+    }
+
+    public function filter($accounts = [])
+    {
+
+        foreach($accounts as $key => $account)
+        {
+            /* @var $account \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account */
+            if(!in_array($account->getCosId(), $this->availableCos)){
+                unset($accounts[$key]);
+            }
+        }
+
+        return $accounts;
+    }
+
+}

+ 206 - 0
app/Libs/Metrics/MyMetricProvider.php

@@ -0,0 +1,206 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Metrics;
+
+use ModulesGarden\Servers\HetznerVps\App\Libs\HetznerVps\Api;
+use ModulesGarden\Servers\HetznerVps\App\Libs\HetznerVps\Api\Constants;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use mysql_xdevapi\DocResult;
+use WHMCS\UsageBilling\Contracts\Metrics\MetricInterface;
+use WHMCS\UsageBilling\Contracts\Metrics\ProviderInterface;
+use WHMCS\UsageBilling\Metrics\Metric;
+use WHMCS\UsageBilling\Metrics\Units\WholeNumber;
+use WHMCS\UsageBilling\Metrics\Usage;
+use WHMCS\UsageBilling\Metrics\Units\GigaBytes;
+
+class MyMetricProvider implements ProviderInterface
+{
+    private $moduleParams = [];
+    public function __construct($moduleParams)
+    {
+        $this->moduleParams = $moduleParams;
+    }
+
+    public function metrics()
+    {
+        return [
+            new Metric(
+                'mailboxes',
+                'Email Accounts',
+                MetricInterface::TYPE_SNAPSHOT
+            ),
+            new Metric(
+                'aliases',
+                'Email Aliases',
+                MetricInterface::TYPE_SNAPSHOT
+            ),
+            new Metric(
+                'distributionLists',
+                'Distribution Lists',
+                MetricInterface::TYPE_SNAPSHOT
+            ),
+            new Metric(
+                'domainAliases',
+                'Domain Aliases',
+                MetricInterface::TYPE_SNAPSHOT
+            ),
+            new Metric(
+                'storage',
+                'Storage',
+                MetricInterface::TYPE_SNAPSHOT,
+                new GigaBytes()
+            )
+        ];
+    }
+
+    public function usage()
+    {
+        $domains =(new KerioManager())
+            ->getApiByServer($this->moduleParams['serverid'])
+            ->soap
+            ->repository()
+            ->domains()
+            ->getAll();
+
+        $usage = [];
+        foreach ($domains as $domain)
+        {
+            $domainName = $domain->getName();
+
+            $mailboxes = $this->getAccounts($domainName);
+            $countOfMailboxes = count($mailboxes);
+
+            $countOfDistributionList = count($this->getDistributionList($domainName));
+
+            $countOfEmailAliases = 0;
+
+            foreach ($mailboxes as $account)
+            {
+                $countOfEmailAliases += count($account->getAliases());
+            }
+
+            $domainAliases = $this->getDomainAliases($domainName);
+            $countOfDomainAliases = count($domainAliases);
+
+            $storage = $this->getDomainUsage($domainName);
+
+
+            $domainData = [
+                'mailboxes' => $countOfMailboxes,
+                'distributionLists' => $countOfDistributionList,
+                'aliases' => $countOfEmailAliases,
+                'domainAliases' => $countOfDomainAliases,
+                'storage' => round($storage / Size::B_TO_GB, 2),
+            ];
+
+            $usage[$domainName] = $this->wrapUserData($domainData);
+
+        }
+        return $usage;
+    }
+
+    public function tenantUsage($tenant)
+    {
+        $mailboxes = $this->getAccounts($tenant);
+        $countOfMailboxes = count($mailboxes);
+
+        $countOfEmailAliases = 0;
+
+        foreach ($mailboxes as $account)
+        {
+            $countOfEmailAliases += count($account->getAliases());
+        }
+
+        $countOfDistributionList = count($this->getDistributionList($tenant));
+
+        $domainAliases = $this->getDomainAliases($tenant);
+        $countOfDomainAliases = count($domainAliases);
+
+        $storage = $this->getDomainUsage($tenant);
+
+        $userData = [
+            'mailboxes' => $countOfMailboxes,
+            'distributionLists' => $countOfDistributionList,
+            'aliases' => $countOfEmailAliases,
+            'domainAliases' => $countOfDomainAliases,
+            'storage' => round($storage / Size::B_TO_GB, 2),
+        ];
+
+        return $this->wrapUserData($userData);
+    }
+
+    private function wrapUserData($data)
+    {
+        $wrapped = [];
+        foreach ($this->metrics() as $metric) {
+            $key = $metric->systemName();
+            if ($data[$key]) {
+                $value = $data[$key];
+                $metric = $metric->withUsage(
+                    new Usage($value)
+                );
+            }
+
+            $wrapped[] = $metric;
+        }
+
+        return $wrapped;
+    }
+
+    private function getAccounts($tenant)
+    {
+        $accounts =(new KerioManager())
+            ->getApiByServer($this->moduleParams['serverid'])
+            ->soap
+            ->repository()
+            ->accounts()
+            ->getByDomainName($tenant);
+
+        return $accounts;
+    }
+
+    private function getDomainAliases($tenant)
+    {
+        $domainAliases =(new KerioManager())
+            ->getApiByServer($this->moduleParams['serverid'])
+            ->soap
+            ->repository()
+            ->domains
+            ->getAliases($tenant);
+
+        return $domainAliases;
+    }
+
+    private function getDomainUsage($tenant)
+    {
+        $accounts =(new KerioManager())
+            ->getApiByServer($this->moduleParams['serverid'])
+            ->soap
+            ->repository()
+            ->accounts
+            ->getUsages($tenant);
+
+        $totalUsage = 0;
+        foreach ($accounts as $account)
+        {
+            $usage = $account->getUsed();
+            $totalUsage += $usage;
+        }
+
+        return $totalUsage;
+    }
+
+    private function getDistributionList($tenant)
+    {
+        $distributionList =(new KerioManager())
+            ->getApiByServer($this->moduleParams['serverid'])
+            ->soap
+            ->repository()
+            ->lists
+            ->getAllDistributionListsByDomain($tenant);
+
+        return $distributionList;
+    }
+
+}

+ 190 - 0
app/Libs/Migrations/Drivers/Version1To2/Settings.php

@@ -0,0 +1,190 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Migrations\Drivers\Version1To2;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+
+/**
+ * Class Settings
+ * User: Nessandro
+ * Date: 2019-11-12
+ * Time: 19:47
+ */
+
+class Settings
+{
+
+    /**
+     * @var string
+     */
+    protected $fromTable = 'mg_prodConfig';
+    /**
+     * @var string
+     */
+    protected $toTable   = '';
+
+    /**
+     * @return string
+     */
+    public function getFromTable()
+    {
+        return $this->fromTable;
+    }
+
+    /**
+     * @param $key
+     * @param $value
+     * @return array
+     */
+    public function unsupported($key, $value)
+    {
+        if(strpos($key, 'cos_') === 0)
+        {
+            $name = str_replace('cos_', 'cosQuota_', $key);
+            return [$name, $value];
+        }
+
+    }
+
+    /**
+     * @return array
+     */
+    public function getMapped()
+    {
+        return [
+            'acc_limit' => 'acc_limit',
+            'acc_size' => 'acc_size',
+            'alias_limit' => 'alias_limit',
+            'cos_name' => 'cos_name',
+            'dist_list_limit' => 'dist_list_limit',
+            'domainMaxSize' => 'domainMaxSize',
+            'domain_alias_limit' => 'domain_alias_limit',
+            'filterAccountsByCOS' => 'filterAccountsByCOS',
+            'login_link' => 'login_link',
+            'useCos', //todo ?
+            'kerioDumpsterEnabled' => 'kerioDumpsterEnabled',
+            'kerioDumpsterPurgeEnabled' => 'kerioDumpsterPurgeEnabled',
+            'kerioFeatureAdvancedSearchEnabled' => 'kerioFeatureAdvancedSearchEnabled',
+            'kerioFeatureBriefcasesEnabled' => 'kerioFeatureBriefcasesEnabled',
+            'kerioFeatureCalendarEnabled' => 'kerioFeatureCalendarEnabled',
+            'kerioFeatureCalendarReminderDeviceEmailEnabled' => 'kerioFeatureCalendarReminderDeviceEmailEnabled',
+            'kerioFeatureChangePasswordEnabled',
+            'kerioFeatureContactsEnabled',
+            'kerioFeatureConversationsEnabled',
+            'kerioFeatureDistributionListFolderEnabled',
+            'kerioFeatureEwsEnabled',
+            'kerioFeatureExportFolderEnabled',
+            'kerioFeatureFiltersEnabled',
+            'kerioFeatureFlaggingEnabled',
+            'kerioFeatureGalAutoCompleteEnabled',
+            'kerioFeatureGalEnabled',
+            'kerioFeatureGroupCalendarEnabled',
+            'kerioFeatureHtmlComposeEnabled',
+            'kerioFeatureIdentitiesEnabled',
+            'kerioFeatureImapDataSourceEnabled',
+            'kerioFeatureImportFolderEnabled',
+            'kerioFeatureInitialSearchPreferenceEnabled',
+            'kerioFeatureMailEnabled',
+            'kerioFeatureMailPriorityEnabled',
+            'kerioFeatureMailSendLaterEnabled',
+            'kerioFeatureManageZimlets',
+            'kerioFeatureMAPIConnectorEnabled',
+            'kerioFeatureNewMailNotificationEnabled',
+            'kerioFeatureOptionsEnabled',
+            'kerioFeatureOutOfOfficeReplyEnabled',
+            'kerioFeaturePeopleSearchEnabled',
+            'kerioFeaturePop3DataSourceEnabled',
+            'kerioFeatureReadReceiptsEnabled',
+            'kerioFeatureSavedSearchesEnabled',
+            'kerioFeatureSharingEnabled',
+            'kerioFeatureSkinChangeEnabled',
+            'kerioFeatureSMIMEEnabled',
+            'kerioFeatureTaggingEnabled',
+            'kerioFeatureTasksEnabled',
+            'kerioFeatureTouchClientEnabled',
+            'kerioFeatureWebClientOfflineAccessEnabled',
+            'kerioImapEnabled',
+            'kerioPop3Enabled',
+        ];
+    }
+
+    /**
+     * @param $params
+     * @return mixed
+     */
+    public function updateValues($params, $prodId)
+    {
+        foreach($params as $key => $value)
+        {
+            if(strpos($key, 'cos_') === 0 && $key !== 'cos_name')
+            {
+                $name = str_replace('cos_', '', $key);
+                $cos[$name] = $value;
+                unset($params[$key]);
+            }
+        }
+
+        if($cos)
+        {
+            $params['cos'] = json_encode($cos);
+        }
+
+        /**
+         * update cosName
+         *
+         */
+
+        $defaultTypes = [
+            ClassOfServices::CUSTOM_ZIMBRA,
+            ClassOfServices::ZIMBRA_CONFIG_OPTIONS,
+            ClassOfServices::CLASS_OF_SERVICE_QUOTA,
+        ];
+
+        /**
+         *
+         *
+         */
+        if(!in_array($params['cos_name'], $defaultTypes))
+        {
+            $manager    = new KerioManager();
+            $repository = $manager->getApiByProduct($prodId)->soap->repository();
+            $cosList        = $repository->cos->all();
+
+            /**
+             * class of services from API
+             */
+            foreach ($cosList as $cos)
+            {
+                /**
+                 * @var $cos \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService
+                 */
+                $cosList[$cos->getName()] = $cos->getId();
+            }
+
+            $params['cos_name'] = $cosList[$params['cos_name']];
+        }
+
+        return $params;
+    }
+
+    /**
+     *
+     * return new fields as name => default value
+     *
+     * @return array
+     */
+    public function getNewFields()
+    {
+        return [
+            'clientAreaFeaturesLeft'    => 'on',
+            'ca_emailAccountPage'       => 'on',
+            'ca_ressourcePage'          => 'on',
+            'ca_distributionListPage'   => 'on',
+            'ca_goToWebmailPage'        => 'on',
+            'clientAreaFeaturesRight'   => 'on',
+            'ca_emailAliasesPage'       => 'on',
+            'ca_domainAliasesPage'      => 'on',
+        ];
+
+    }
+
+}

+ 377 - 0
app/Libs/Product/ProductManager.php

@@ -0,0 +1,377 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Product;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Connection;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Helper\TypeConstans;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\ClassOfServicesOptions;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ConfigTrait;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ModuleConfigurationHandler;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\HostingConfigOption;
+use ModulesGarden\Servers\KerioEmail\App\Models\ProductConfiguration;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Server;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 11.09.19
+ * Time: 12:26
+ * Class ProductManager
+ */
+class ProductManager
+{
+
+    use ConfigTrait;
+    use ModuleConfigurationHandler;
+    /**
+     *
+     * @var array
+     */
+    protected $cos = [];
+
+    /**
+     * @var array
+     */
+    protected $configOptCosLimits = [];
+
+    /**
+     * @var bool
+     */
+    protected $cosConfigOptionEnabled = false;
+    /**
+     * @var Hosting
+     */
+    protected $hosting = null;
+    /**
+     * @param $id
+     * @return $this
+     */
+    public function loadByHostingId($id)
+    {
+        /**
+         *
+         * load hosting model
+         */
+        $this->hosting = Hosting::with('configOptions')->where('id', $id)->first();
+
+        /**
+         *
+         * load product configuration
+         */
+        $this->loadById($this->hosting->packageid);
+
+        /**
+         *
+         *
+         * load config options (e.g class of services)
+         */
+        $this->loadConfigOptions($this->hosting->configOptions);
+
+        /**
+         *
+         */
+        return $this;
+    }
+
+    /**
+     * @param $id
+     * @return $this
+     */
+    public function loadById($id)
+    {
+        $config = ProductConfiguration::where('product_id', $id)->get();
+        foreach ($config as $conf)
+        {
+            $this->set($conf->setting, $conf->value);
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return Hosting
+     */
+    public function getHosting()
+    {
+        return $this->hosting;
+    }
+
+    /**
+     * @param $configOpt
+     * @return $this
+     */
+    public function loadConfigOptions($configOpt)
+    {
+        /**
+         * configurable options to config array
+         */
+        foreach ($configOpt as $opt)
+        {
+            /**
+             *
+             * continue if conf opt is hidden
+             */
+            if((bool) $opt->configOption->hidden === true)
+            {
+                continue;
+            }
+
+            if(!$opt->configOption->isLinkedToProduct($this->hosting->packageid))
+            {
+                continue;
+            }
+            /* @var $opt HostingConfigOption */
+            $option = explode('|', $opt->configOption->optionname);
+
+            if (false !== strpos( $option[0], ClassOfServicesOptions::COS_CONFIG_OPT_PREFIX))
+            {
+                $this->addCosConfigOpt($option[0], $opt->qty);
+                continue;
+            }
+
+            /**
+             * base setting
+             */
+            if ((int) $opt->configOption->optiontype === TypeConstans::QUANTITY)
+            {
+                $this->set($option[0], $opt->qty);
+                continue;
+
+            }
+            elseif ((int) $opt->configOption->optiontype === TypeConstans::DROPDOWN)
+            {
+                /**
+                 * selected class of services
+                 */
+                $name = explode('|', $opt->subOption->optionname);
+                if($option[0] === 'cos')
+                {
+                    /**
+                     * add to available cos list
+                     */
+                    $this->addCosConfigOpt($name[0], Size::UNLIMITED);
+                }
+
+                $this->set($option[0], $name[0]);
+                continue;
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * @param $cosName
+     * @param int $quantity
+     * @return $this
+     */
+    public function addCosConfigOpt($cosName, $quantity= 0)
+    {
+        $cosName = str_replace(ClassOfServicesOptions::COS_CONFIG_OPT_PREFIX,'',$cosName);
+        $this->cos[$cosName] = $quantity;
+        $this->configOptCosLimits[$cosName] = $quantity;
+        $this->setCosConfigOptionEnabled(true);
+        return $this;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getKerioConfiguration()
+    {
+        foreach($this->config as $name => $value)
+        {
+            if(false !== strpos($name, ProductParams::ZIMBRA_PREFIX_SETTINGS))
+            {
+                $tmp[$name] = $value;
+            }
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getSettingCos()
+    {
+        /**
+         *
+         * if type is `cosQuota` return saved class of services list
+         */
+        if($this->get('cos_name') === ClassOfServices::CLASS_OF_SERVICE_QUOTA)
+        {
+
+            /**
+             *
+             * return cos from config opt or decoded from database
+             */
+            return $this->cos ? $this->cos : json_decode($this->get('cos'), true);
+        }
+
+        /**
+         *
+         * if type is `kerioConfigurableOptions` return choosed cos id
+         */
+        if($this->get('cos_name') === ClassOfServices::ZIMBRA_CONFIG_OPTIONS)
+        {
+            return $this->cos;
+        }
+
+        /**
+         *
+         * return cos name if is other type
+         */
+        if($this->get('cos_name') !== ClassOfServices::CUSTOM_ZIMBRA)
+        {
+            return $this->get('cos_name');
+        }
+
+        return null;
+    }
+
+    /**
+     *
+     * is available controller actions
+     * @param $controller
+     * @return bool
+     */
+    public function isControllerAccessible($controller)
+    {
+        return $this->get($controller) === ProductParams::SWITCHER_ENABLED;
+    }
+
+    /**
+     * @param $name
+     * @return bool
+     */
+    public function isSidebarEnabled($name)
+    {
+        switch ($name)
+        {
+            case 'emailAccount':
+                $controller = ControllerEnums::EMAIL_ACCOUNT_PAGE;
+                break;
+            case 'emailAlias':
+                $controller = ControllerEnums::EMAIL_ALIAS_PAGE;
+                break;
+            case 'ressource':
+                $controller = ControllerEnums::RESSOURCE_PAGE;
+                break;
+            case 'distributionList':
+                $controller = ControllerEnums::DISTRIBUTION_MAIL_PAGE;
+                break;
+            case 'domainAlias':
+                $controller = ControllerEnums::DOMAIN_ALIAS_PAGE;
+                break;
+            case 'goWebmail':
+                $controller = ControllerEnums::WEBMAIL_PAGE;
+                break;
+
+        }
+        return $this->isActionAccessible($controller);
+    }
+
+    /**
+     *
+     * @param $action
+     * @return bool
+     */
+    public function isActionAccessible($action)
+    {
+        return $this->get($action) === ProductParams::SWITCHER_ENABLED;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getServerUrl()
+    {
+        if($this->hosting)
+        {
+            $server = $this->hosting->server()->first();
+
+            $hostname = $server->hostname ? $server->hostname : $server->ipaddress;
+
+            $url = ($server->secure ? 'https://' : 'http://') . $hostname.($server->secure ? ':'.Kerio::SECURE_PORT: ':'.Kerio::PORT).'/';
+            return $url;
+        }
+        return null;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getClientUrl()
+    {
+        if($this->hosting)
+        {
+
+            /**
+             *
+             * load server
+             */
+            $server = $this->hosting->server()->first();
+
+            /**
+             * set hostname if exist or IP address
+             */
+            $hostname = $server->hostname ? $server->hostname : $server->ipaddress;
+
+            /**
+             *
+             * load port from configuration or set default port
+             */
+            $port = $server->secure === 'on' ? $this->loadModuleData()->getAll()['clienPortSecure'] : $this->loadModuleData()->getAll()['clienPort'];
+            $port = $port ? $port : Connection::CLIENT_PORT;
+
+            /**
+             *
+             * prepare url
+             */
+            $url = ($server->secure ? 'https://' : 'http://') . $hostname.':'.$port.'/';
+            return $url;
+        }
+        return null;
+    }
+
+    /**
+     * @return array
+     */
+    public function getConfigOptCosLimits()
+    {
+        return $this->configOptCosLimits;
+    }
+
+    /**
+     * @param array $configOptCosLimits
+     */
+    public function setConfigOptCosLimits($configOptCosLimits)
+    {
+        $this->configOptCosLimits = $configOptCosLimits;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isCosConfigOptionEnabled()
+    {
+        return $this->cosConfigOptionEnabled;
+    }
+
+    /**
+     * @param bool $cosConfigOptionEnabled
+     */
+    public function setCosConfigOptionEnabled($cosConfigOptionEnabled)
+    {
+        $this->cosConfigOptionEnabled = $cosConfigOptionEnabled;
+    }
+
+
+
+}

+ 130 - 0
app/Libs/Restrictions/Interfaces/AbstractRestriction.php

@@ -0,0 +1,130 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Interfaces;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Restriction;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 10:29
+ * Class AbstractRestriction
+ */
+abstract class AbstractRestriction
+{
+    const STATUS_VALID      = true;
+    const STATUS_INVALID    = false;
+
+    /**
+     * @var bool
+     */
+    protected $throwError = false;
+
+    /**
+     * @var RuleInterface
+     */
+    protected $rule;
+
+    /**
+     * @var
+     */
+    public $errorMessage;
+
+    /**
+     * @var bool
+     */
+    public $isValid = self::STATUS_VALID;
+
+    /**
+     * Restriction constructor.
+     * @param RuleInterface $rule
+     */
+    public function __construct(RuleInterface $rule)
+    {
+        $this->rule = $rule;
+    }
+
+    /**
+     *
+     * check restriction
+     * @return mixed
+     */
+    public abstract function check();
+
+    /**
+     * @return bool
+     */
+    public function isThrowErrorEnabled()
+    {
+        return $this->throwError === true;
+    }
+
+    /**
+     * @return $this
+     */
+    public function enableThrowError()
+    {
+        $this->throwError = true;
+        return $this;
+    }
+
+    /**
+     * @return $this
+     */
+    public function disableThrowError()
+    {
+        $this->throwError = true;
+        return $this;
+    }
+
+    /**
+     * @return RuleInterface
+     */
+    public function getRule()
+    {
+        return $this->rule;
+    }
+
+    /**
+     * @param RuleInterface $rule
+     */
+    public function setRule(RuleInterface $rule)
+    {
+        $this->rule = $rule;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getErrorMessage()
+    {
+        return $this->errorMessage;
+    }
+
+    /**
+     * @param mixed $errorMessage
+     */
+    public function setErrorMessage($errorMessage)
+    {
+        $this->errorMessage = $errorMessage;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isValid()
+    {
+        return $this->isValid;
+    }
+
+    /**
+     * @param bool $isValid
+     */
+    public function setIsValid($isValid)
+    {
+        $this->isValid = $isValid;
+    }
+}

+ 57 - 0
app/Libs/Restrictions/Interfaces/AbstractRule.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Interfaces;
+
+
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Lang\Lang;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 10:02
+ * Class AbstractRule
+ */
+abstract class AbstractRule implements RuleInterface
+{
+
+    /**
+     * @var string
+     */
+    protected $message = 'somethingWentWrong';
+
+    /**
+     * @var array
+     */
+    protected $replacements = [];
+
+    /**
+     * @param $key
+     * @param $value
+     * @return $this
+     */
+    protected function addReplacement($key, $value)
+    {
+        $this->replacements[$key] = $value;
+        return $this;
+    }
+    /**
+     *
+     * @return mixed|void
+     */
+    public function getMessage()
+    {
+        /* @var $lang Lang*/
+        $lang = di('lang');
+
+        foreach($this->replacements as $key => $repl)
+        {
+            $lang->addReplacementConstant($key, $repl);
+        }
+
+        return $lang->absoluteT('restrictions', 'error', $this->message);
+    }
+
+}

+ 26 - 0
app/Libs/Restrictions/Interfaces/RuleInterface.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Interfaces;
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 09:59
+ * Class RuleInterface
+ */
+interface RuleInterface
+{
+
+    /**
+     * check if rule is valid
+     * @return mixed
+     */
+    public function isValid();
+
+    /**
+     * return message if rule is invalid
+     * @return mixed
+     */
+    public function getMessage();
+
+}

+ 57 - 0
app/Libs/Restrictions/Restriction.php

@@ -0,0 +1,57 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Interfaces\AbstractRestriction;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Interfaces\RuleInterface;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 09:58
+ * Class Restriction
+ */
+class Restriction extends AbstractRestriction
+{
+
+    /**
+     * {@inheritDoc}
+     */
+    public function check()
+    {
+        /**
+         *
+         * check if rule is valid
+         */
+        if($this->rule->isValid() !== false)
+        {
+            return true;
+        }
+
+        /**
+         * set status as invalid
+         */
+        $this->setIsValid(self::STATUS_INVALID);
+
+        /**
+         *
+         * set error message
+         */
+        $this->setErrorMessage($this->rule->getMessage());
+
+        /**
+         *
+         * throw error if is enabled
+         */
+        if($this->isThrowErrorEnabled())
+        {
+            throw new \Exception($this->getErrorMessage());
+        }
+
+        /**
+         *
+         * return valid status
+         */
+        return $this->isValid();
+    }
+}

+ 42 - 0
app/Libs/Restrictions/Rules/ExtensionsValid.php

@@ -0,0 +1,42 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Rules;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Interfaces\AbstractRule;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 09:58
+ * Class ExtensionsValid
+ */
+class ExtensionsValid extends AbstractRule
+{
+
+    const EXTENSIONS = [
+        'soap' => \SoapClient::class
+    ];
+
+    /**
+     * @var string
+     */
+    protected $message = 'extensionRequired';
+
+    /**
+     * check if rule is valid
+     * @return mixed
+     */
+    public function isValid()
+    {
+        foreach (self::EXTENSIONS as $extension => $class)
+        {
+            if(!class_exists($class))
+            {
+                $this->addReplacement('extension', $extension);
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 11308 - 0
app/Libs/TLDList/tld.list

@@ -0,0 +1,11308 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// ===BEGIN ICANN DOMAINS===
+
+// ac : http://en.wikipedia.org/wiki/.ac
+ac
+com.ac
+edu.ac
+gov.ac
+net.ac
+mil.ac
+org.ac
+
+// ad : http://en.wikipedia.org/wiki/.ad
+ad
+nom.ad
+
+// ae : http://en.wikipedia.org/wiki/.ae
+// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php
+ae
+co.ae
+net.ae
+org.ae
+sch.ae
+ac.ae
+gov.ae
+mil.ae
+
+// aero : see http://www.information.aero/index.php?id=66
+aero
+accident-investigation.aero
+accident-prevention.aero
+aerobatic.aero
+aeroclub.aero
+aerodrome.aero
+agents.aero
+aircraft.aero
+airline.aero
+airport.aero
+air-surveillance.aero
+airtraffic.aero
+air-traffic-control.aero
+ambulance.aero
+amusement.aero
+association.aero
+author.aero
+ballooning.aero
+broker.aero
+caa.aero
+cargo.aero
+catering.aero
+certification.aero
+championship.aero
+charter.aero
+civilaviation.aero
+club.aero
+conference.aero
+consultant.aero
+consulting.aero
+control.aero
+council.aero
+crew.aero
+design.aero
+dgca.aero
+educator.aero
+emergency.aero
+engine.aero
+engineer.aero
+entertainment.aero
+equipment.aero
+exchange.aero
+express.aero
+federation.aero
+flight.aero
+freight.aero
+fuel.aero
+gliding.aero
+government.aero
+groundhandling.aero
+group.aero
+hanggliding.aero
+homebuilt.aero
+insurance.aero
+journal.aero
+journalist.aero
+leasing.aero
+logistics.aero
+magazine.aero
+maintenance.aero
+media.aero
+microlight.aero
+modelling.aero
+navigation.aero
+parachuting.aero
+paragliding.aero
+passenger-association.aero
+pilot.aero
+press.aero
+production.aero
+recreation.aero
+repbody.aero
+res.aero
+research.aero
+rotorcraft.aero
+safety.aero
+scientist.aero
+services.aero
+show.aero
+skydiving.aero
+software.aero
+student.aero
+trader.aero
+trading.aero
+trainer.aero
+union.aero
+workinggroup.aero
+works.aero
+
+// af : http://www.nic.af/help.jsp
+af
+gov.af
+com.af
+org.af
+net.af
+edu.af
+
+// ag : http://www.nic.ag/prices.htm
+ag
+com.ag
+org.ag
+net.ag
+co.ag
+nom.ag
+
+// ai : http://nic.com.ai/
+ai
+off.ai
+com.ai
+net.ai
+org.ai
+
+// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31
+al
+com.al
+edu.al
+gov.al
+mil.al
+net.al
+org.al
+
+// am : http://en.wikipedia.org/wiki/.am
+am
+
+// ao : http://en.wikipedia.org/wiki/.ao
+// http://www.dns.ao/REGISTR.DOC
+ao
+ed.ao
+gv.ao
+og.ao
+co.ao
+pb.ao
+it.ao
+
+// aq : http://en.wikipedia.org/wiki/.aq
+aq
+
+// ar : https://nic.ar/normativa-vigente.xhtml
+ar
+com.ar
+edu.ar
+gob.ar
+gov.ar
+int.ar
+mil.ar
+net.ar
+org.ar
+tur.ar
+
+// arpa : http://en.wikipedia.org/wiki/.arpa
+// Confirmed by registry <iana-questions@icann.org> 2008-06-18
+arpa
+e164.arpa
+in-addr.arpa
+ip6.arpa
+iris.arpa
+uri.arpa
+urn.arpa
+
+// as : http://en.wikipedia.org/wiki/.as
+as
+gov.as
+
+// asia : http://en.wikipedia.org/wiki/.asia
+asia
+
+// at : http://en.wikipedia.org/wiki/.at
+// Confirmed by registry <it@nic.at> 2008-06-17
+at
+ac.at
+co.at
+gv.at
+or.at
+
+// au : http://en.wikipedia.org/wiki/.au
+// http://www.auda.org.au/
+au
+// 2LDs
+com.au
+net.au
+org.au
+edu.au
+gov.au
+asn.au
+id.au
+// Historic 2LDs (closed to new registration, but sites still exist)
+info.au
+conf.au
+oz.au
+// CGDNs - http://www.cgdn.org.au/
+act.au
+nsw.au
+nt.au
+qld.au
+sa.au
+tas.au
+vic.au
+wa.au
+// 3LDs
+act.edu.au
+nsw.edu.au
+nt.edu.au
+qld.edu.au
+sa.edu.au
+tas.edu.au
+vic.edu.au
+wa.edu.au
+// act.gov.au  Bug 984824 - Removed at request of Greg Tankard
+// nsw.gov.au  Bug 547985 - Removed at request of <Shae.Donelan@services.nsw.gov.au>
+// nt.gov.au  Bug 940478 - Removed at request of Greg Connors <Greg.Connors@nt.gov.au>
+qld.gov.au
+sa.gov.au
+tas.gov.au
+vic.gov.au
+wa.gov.au
+
+// aw : http://en.wikipedia.org/wiki/.aw
+aw
+com.aw
+
+// ax : http://en.wikipedia.org/wiki/.ax
+ax
+
+// az : http://en.wikipedia.org/wiki/.az
+az
+com.az
+net.az
+int.az
+gov.az
+org.az
+edu.az
+info.az
+pp.az
+mil.az
+name.az
+pro.az
+biz.az
+
+// ba : http://en.wikipedia.org/wiki/.ba
+ba
+org.ba
+net.ba
+edu.ba
+gov.ba
+mil.ba
+unsa.ba
+unbi.ba
+co.ba
+com.ba
+rs.ba
+
+// bb : http://en.wikipedia.org/wiki/.bb
+bb
+biz.bb
+co.bb
+com.bb
+edu.bb
+gov.bb
+info.bb
+net.bb
+org.bb
+store.bb
+tv.bb
+
+// bd : http://en.wikipedia.org/wiki/.bd
+*.bd
+
+// be : http://en.wikipedia.org/wiki/.be
+// Confirmed by registry <tech@dns.be> 2008-06-08
+be
+ac.be
+
+// bf : http://en.wikipedia.org/wiki/.bf
+bf
+gov.bf
+
+// bg : http://en.wikipedia.org/wiki/.bg
+// https://www.register.bg/user/static/rules/en/index.html
+bg
+a.bg
+b.bg
+c.bg
+d.bg
+e.bg
+f.bg
+g.bg
+h.bg
+i.bg
+j.bg
+k.bg
+l.bg
+m.bg
+n.bg
+o.bg
+p.bg
+q.bg
+r.bg
+s.bg
+t.bg
+u.bg
+v.bg
+w.bg
+x.bg
+y.bg
+z.bg
+0.bg
+1.bg
+2.bg
+3.bg
+4.bg
+5.bg
+6.bg
+7.bg
+8.bg
+9.bg
+
+// bh : http://en.wikipedia.org/wiki/.bh
+bh
+com.bh
+edu.bh
+net.bh
+org.bh
+gov.bh
+
+// bi : http://en.wikipedia.org/wiki/.bi
+// http://whois.nic.bi/
+bi
+co.bi
+com.bi
+edu.bi
+or.bi
+org.bi
+
+// biz : http://en.wikipedia.org/wiki/.biz
+biz
+
+// bj : http://en.wikipedia.org/wiki/.bj
+bj
+asso.bj
+barreau.bj
+gouv.bj
+
+// bm : http://www.bermudanic.bm/dnr-text.txt
+bm
+com.bm
+edu.bm
+gov.bm
+net.bm
+org.bm
+
+// bn : http://en.wikipedia.org/wiki/.bn
+*.bn
+
+// bo : http://www.nic.bo/
+bo
+com.bo
+edu.bo
+gov.bo
+gob.bo
+int.bo
+org.bo
+net.bo
+mil.bo
+tv.bo
+
+// br : http://registro.br/dominio/categoria.html
+// Submitted by registry <fneves@registro.br> 2014-08-11
+br
+adm.br
+adv.br
+agr.br
+am.br
+arq.br
+art.br
+ato.br
+b.br
+bio.br
+blog.br
+bmd.br
+cim.br
+cng.br
+cnt.br
+com.br
+coop.br
+ecn.br
+eco.br
+edu.br
+emp.br
+eng.br
+esp.br
+etc.br
+eti.br
+far.br
+flog.br
+fm.br
+fnd.br
+fot.br
+fst.br
+g12.br
+ggf.br
+gov.br
+imb.br
+ind.br
+inf.br
+jor.br
+jus.br
+leg.br
+lel.br
+mat.br
+med.br
+mil.br
+mp.br
+mus.br
+net.br
+*.nom.br
+not.br
+ntr.br
+odo.br
+org.br
+ppg.br
+pro.br
+psc.br
+psi.br
+qsl.br
+radio.br
+rec.br
+slg.br
+srv.br
+taxi.br
+teo.br
+tmp.br
+trd.br
+tur.br
+tv.br
+vet.br
+vlog.br
+wiki.br
+zlg.br
+
+// bs : http://www.nic.bs/rules.html
+bs
+com.bs
+net.bs
+org.bs
+edu.bs
+gov.bs
+
+// bt : http://en.wikipedia.org/wiki/.bt
+bt
+com.bt
+edu.bt
+gov.bt
+net.bt
+org.bt
+
+// bv : No registrations at this time.
+// Submitted by registry <jarle@uninett.no> 2006-06-16
+bv
+
+// bw : http://en.wikipedia.org/wiki/.bw
+// http://www.gobin.info/domainname/bw.doc
+// list of other 2nd level tlds ?
+bw
+co.bw
+org.bw
+
+// by : http://en.wikipedia.org/wiki/.by
+// http://tld.by/rules_2006_en.html
+// list of other 2nd level tlds ?
+by
+gov.by
+mil.by
+// Official information does not indicate that com.by is a reserved
+// second-level domain, but it's being used as one (see www.google.com.by and
+// www.yahoo.com.by, for example), so we list it here for safety's sake.
+com.by
+
+// http://hoster.by/
+of.by
+
+// bz : http://en.wikipedia.org/wiki/.bz
+// http://www.belizenic.bz/
+bz
+com.bz
+net.bz
+org.bz
+edu.bz
+gov.bz
+
+// ca : http://en.wikipedia.org/wiki/.ca
+ca
+// ca geographical names
+ab.ca
+bc.ca
+mb.ca
+nb.ca
+nf.ca
+nl.ca
+ns.ca
+nt.ca
+nu.ca
+on.ca
+pe.ca
+qc.ca
+sk.ca
+yk.ca
+// gc.ca: http://en.wikipedia.org/wiki/.gc.ca
+// see also: http://registry.gc.ca/en/SubdomainFAQ
+gc.ca
+
+// cat : http://en.wikipedia.org/wiki/.cat
+cat
+
+// cc : http://en.wikipedia.org/wiki/.cc
+cc
+
+// cd : http://en.wikipedia.org/wiki/.cd
+// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1
+cd
+gov.cd
+
+// cf : http://en.wikipedia.org/wiki/.cf
+cf
+
+// cg : http://en.wikipedia.org/wiki/.cg
+cg
+
+// ch : http://en.wikipedia.org/wiki/.ch
+ch
+
+// ci : http://en.wikipedia.org/wiki/.ci
+// http://www.nic.ci/index.php?page=charte
+ci
+org.ci
+or.ci
+com.ci
+co.ci
+edu.ci
+ed.ci
+ac.ci
+net.ci
+go.ci
+asso.ci
+aéroport.ci
+int.ci
+presse.ci
+md.ci
+gouv.ci
+
+// ck : http://en.wikipedia.org/wiki/.ck
+*.ck
+!www.ck
+
+// cl : http://en.wikipedia.org/wiki/.cl
+cl
+gov.cl
+gob.cl
+co.cl
+mil.cl
+
+// cm : http://en.wikipedia.org/wiki/.cm plus bug 981927
+cm
+co.cm
+com.cm
+gov.cm
+net.cm
+
+// cn : http://en.wikipedia.org/wiki/.cn
+// Submitted by registry <tanyaling@cnnic.cn> 2008-06-11
+cn
+ac.cn
+com.cn
+edu.cn
+gov.cn
+net.cn
+org.cn
+mil.cn
+公司.cn
+网络.cn
+網絡.cn
+// cn geographic names
+ah.cn
+bj.cn
+cq.cn
+fj.cn
+gd.cn
+gs.cn
+gz.cn
+gx.cn
+ha.cn
+hb.cn
+he.cn
+hi.cn
+hl.cn
+hn.cn
+jl.cn
+js.cn
+jx.cn
+ln.cn
+nm.cn
+nx.cn
+qh.cn
+sc.cn
+sd.cn
+sh.cn
+sn.cn
+sx.cn
+tj.cn
+xj.cn
+xz.cn
+yn.cn
+zj.cn
+hk.cn
+mo.cn
+tw.cn
+
+// co : http://en.wikipedia.org/wiki/.co
+// Submitted by registry <tecnico@uniandes.edu.co> 2008-06-11
+co
+arts.co
+com.co
+edu.co
+firm.co
+gov.co
+info.co
+int.co
+mil.co
+net.co
+nom.co
+org.co
+rec.co
+web.co
+
+// com : http://en.wikipedia.org/wiki/.com
+com
+
+// coop : http://en.wikipedia.org/wiki/.coop
+coop
+
+// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do
+cr
+ac.cr
+co.cr
+ed.cr
+fi.cr
+go.cr
+or.cr
+sa.cr
+
+// cu : http://en.wikipedia.org/wiki/.cu
+cu
+com.cu
+edu.cu
+org.cu
+net.cu
+gov.cu
+inf.cu
+
+// cv : http://en.wikipedia.org/wiki/.cv
+cv
+
+// cw : http://www.una.cw/cw_registry/
+// Confirmed by registry <registry@una.net> 2013-03-26
+cw
+com.cw
+edu.cw
+net.cw
+org.cw
+
+// cx : http://en.wikipedia.org/wiki/.cx
+// list of other 2nd level tlds ?
+cx
+gov.cx
+
+// cy : http://en.wikipedia.org/wiki/.cy
+ac.cy
+biz.cy
+com.cy
+ekloges.cy
+gov.cy
+ltd.cy
+name.cy
+net.cy
+org.cy
+parliament.cy
+press.cy
+pro.cy
+tm.cy
+
+// cz : http://en.wikipedia.org/wiki/.cz
+cz
+
+// de : http://en.wikipedia.org/wiki/.de
+// Confirmed by registry <ops@denic.de> (with technical
+// reservations) 2008-07-01
+de
+
+// dj : http://en.wikipedia.org/wiki/.dj
+dj
+
+// dk : http://en.wikipedia.org/wiki/.dk
+// Confirmed by registry <robert@dk-hostmaster.dk> 2008-06-17
+dk
+
+// dm : http://en.wikipedia.org/wiki/.dm
+dm
+com.dm
+net.dm
+org.dm
+edu.dm
+gov.dm
+
+// do : http://en.wikipedia.org/wiki/.do
+do
+art.do
+com.do
+edu.do
+gob.do
+gov.do
+mil.do
+net.do
+org.do
+sld.do
+web.do
+
+// dz : http://en.wikipedia.org/wiki/.dz
+dz
+com.dz
+org.dz
+net.dz
+gov.dz
+edu.dz
+asso.dz
+pol.dz
+art.dz
+
+// ec : http://www.nic.ec/reg/paso1.asp
+// Submitted by registry <vabboud@nic.ec> 2008-07-04
+ec
+com.ec
+info.ec
+net.ec
+fin.ec
+k12.ec
+med.ec
+pro.ec
+org.ec
+edu.ec
+gov.ec
+gob.ec
+mil.ec
+
+// edu : http://en.wikipedia.org/wiki/.edu
+edu
+
+// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B
+ee
+edu.ee
+gov.ee
+riik.ee
+lib.ee
+med.ee
+com.ee
+pri.ee
+aip.ee
+org.ee
+fie.ee
+
+// eg : http://en.wikipedia.org/wiki/.eg
+eg
+com.eg
+edu.eg
+eun.eg
+gov.eg
+mil.eg
+name.eg
+net.eg
+org.eg
+sci.eg
+
+// er : http://en.wikipedia.org/wiki/.er
+*.er
+
+// es : https://www.nic.es/site_ingles/ingles/dominios/index.html
+es
+com.es
+nom.es
+org.es
+gob.es
+edu.es
+
+// et : http://en.wikipedia.org/wiki/.et
+et
+com.et
+gov.et
+org.et
+edu.et
+biz.et
+name.et
+info.et
+net.et
+
+// eu : http://en.wikipedia.org/wiki/.eu
+eu
+
+// fi : http://en.wikipedia.org/wiki/.fi
+fi
+// aland.fi : http://en.wikipedia.org/wiki/.ax
+// This domain is being phased out in favor of .ax. As there are still many
+// domains under aland.fi, we still keep it on the list until aland.fi is
+// completely removed.
+// TODO: Check for updates (expected to be phased out around Q1/2009)
+aland.fi
+
+// fj : http://en.wikipedia.org/wiki/.fj
+*.fj
+
+// fk : http://en.wikipedia.org/wiki/.fk
+*.fk
+
+// fm : http://en.wikipedia.org/wiki/.fm
+fm
+
+// fo : http://en.wikipedia.org/wiki/.fo
+fo
+
+// fr : http://www.afnic.fr/
+// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs
+fr
+com.fr
+asso.fr
+nom.fr
+prd.fr
+presse.fr
+tm.fr
+// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels
+aeroport.fr
+assedic.fr
+avocat.fr
+avoues.fr
+cci.fr
+chambagri.fr
+chirurgiens-dentistes.fr
+experts-comptables.fr
+geometre-expert.fr
+gouv.fr
+greta.fr
+huissier-justice.fr
+medecin.fr
+notaires.fr
+pharmacien.fr
+port.fr
+veterinaire.fr
+
+// ga : http://en.wikipedia.org/wiki/.ga
+ga
+
+// gb : This registry is effectively dormant
+// Submitted by registry <Damien.Shaw@ja.net> 2008-06-12
+gb
+
+// gd : http://en.wikipedia.org/wiki/.gd
+gd
+
+// ge : http://www.nic.net.ge/policy_en.pdf
+ge
+com.ge
+edu.ge
+gov.ge
+org.ge
+mil.ge
+net.ge
+pvt.ge
+
+// gf : http://en.wikipedia.org/wiki/.gf
+gf
+
+// gg : http://www.channelisles.net/register-domains/
+// Confirmed by registry <nigel@channelisles.net> 2013-11-28
+gg
+co.gg
+net.gg
+org.gg
+
+// gh : http://en.wikipedia.org/wiki/.gh
+// see also: http://www.nic.gh/reg_now.php
+// Although domains directly at second level are not possible at the moment,
+// they have been possible for some time and may come back.
+gh
+com.gh
+edu.gh
+gov.gh
+org.gh
+mil.gh
+
+// gi : http://www.nic.gi/rules.html
+gi
+com.gi
+ltd.gi
+gov.gi
+mod.gi
+edu.gi
+org.gi
+
+// gl : http://en.wikipedia.org/wiki/.gl
+// http://nic.gl
+gl
+co.gl
+com.gl
+edu.gl
+net.gl
+org.gl
+
+// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm
+gm
+
+// gn : http://psg.com/dns/gn/gn.txt
+// Submitted by registry <randy@psg.com> 2008-06-17
+gn
+ac.gn
+com.gn
+edu.gn
+gov.gn
+org.gn
+net.gn
+
+// gov : http://en.wikipedia.org/wiki/.gov
+gov
+
+// gp : http://www.nic.gp/index.php?lang=en
+gp
+com.gp
+net.gp
+mobi.gp
+edu.gp
+org.gp
+asso.gp
+
+// gq : http://en.wikipedia.org/wiki/.gq
+gq
+
+// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html
+// Submitted by registry <segred@ics.forth.gr> 2008-06-09
+gr
+com.gr
+edu.gr
+net.gr
+org.gr
+gov.gr
+
+// gs : http://en.wikipedia.org/wiki/.gs
+gs
+
+// gt : http://www.gt/politicas_de_registro.html
+gt
+com.gt
+edu.gt
+gob.gt
+ind.gt
+mil.gt
+net.gt
+org.gt
+
+// gu : http://gadao.gov.gu/registration.txt
+*.gu
+
+// gw : http://en.wikipedia.org/wiki/.gw
+gw
+
+// gy : http://en.wikipedia.org/wiki/.gy
+// http://registry.gy/
+gy
+co.gy
+com.gy
+net.gy
+
+// hk : https://www.hkdnr.hk
+// Submitted by registry <hk.tech@hkirc.hk> 2008-06-11
+hk
+com.hk
+edu.hk
+gov.hk
+idv.hk
+net.hk
+org.hk
+公司.hk
+教育.hk
+敎育.hk
+政府.hk
+個人.hk
+个人.hk
+箇人.hk
+網络.hk
+网络.hk
+组織.hk
+網絡.hk
+网絡.hk
+组织.hk
+組織.hk
+組织.hk
+
+// hm : http://en.wikipedia.org/wiki/.hm
+hm
+
+// hn : http://www.nic.hn/politicas/ps02,,05.html
+hn
+com.hn
+edu.hn
+org.hn
+net.hn
+mil.hn
+gob.hn
+
+// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf
+hr
+iz.hr
+from.hr
+name.hr
+com.hr
+
+// ht : http://www.nic.ht/info/charte.cfm
+ht
+com.ht
+shop.ht
+firm.ht
+info.ht
+adult.ht
+net.ht
+pro.ht
+org.ht
+med.ht
+art.ht
+coop.ht
+pol.ht
+asso.ht
+edu.ht
+rel.ht
+gouv.ht
+perso.ht
+
+// hu : http://www.domain.hu/domain/English/sld.html
+// Confirmed by registry <pasztor@iszt.hu> 2008-06-12
+hu
+co.hu
+info.hu
+org.hu
+priv.hu
+sport.hu
+tm.hu
+2000.hu
+agrar.hu
+bolt.hu
+casino.hu
+city.hu
+erotica.hu
+erotika.hu
+film.hu
+forum.hu
+games.hu
+hotel.hu
+ingatlan.hu
+jogasz.hu
+konyvelo.hu
+lakas.hu
+media.hu
+news.hu
+reklam.hu
+sex.hu
+shop.hu
+suli.hu
+szex.hu
+tozsde.hu
+utazas.hu
+video.hu
+
+// id : https://register.pandi.or.id/
+id
+ac.id
+biz.id
+co.id
+desa.id
+go.id
+mil.id
+my.id
+net.id
+or.id
+sch.id
+web.id
+
+// ie : http://en.wikipedia.org/wiki/.ie
+ie
+gov.ie
+
+// il : http://www.isoc.org.il/domains/
+il
+ac.il
+co.il
+gov.il
+idf.il
+k12.il
+muni.il
+net.il
+org.il
+
+// im : https://www.nic.im/
+// Submitted by registry <info@nic.im> 2013-11-15
+im
+ac.im
+co.im
+com.im
+ltd.co.im
+net.im
+org.im
+plc.co.im
+tt.im
+tv.im
+
+// in : http://en.wikipedia.org/wiki/.in
+// see also: https://registry.in/Policies
+// Please note, that nic.in is not an official eTLD, but used by most
+// government institutions.
+in
+co.in
+firm.in
+net.in
+org.in
+gen.in
+ind.in
+nic.in
+ac.in
+edu.in
+res.in
+gov.in
+mil.in
+
+// info : http://en.wikipedia.org/wiki/.info
+info
+
+// int : http://en.wikipedia.org/wiki/.int
+// Confirmed by registry <iana-questions@icann.org> 2008-06-18
+int
+eu.int
+
+// io : http://www.nic.io/rules.html
+// list of other 2nd level tlds ?
+io
+com.io
+
+// iq : http://www.cmc.iq/english/iq/iqregister1.htm
+iq
+gov.iq
+edu.iq
+mil.iq
+com.iq
+org.iq
+net.iq
+
+// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules
+// Also see http://www.nic.ir/Internationalized_Domain_Names
+// Two <iran>.ir entries added at request of <tech-team@nic.ir>, 2010-04-16
+ir
+ac.ir
+co.ir
+gov.ir
+id.ir
+net.ir
+org.ir
+sch.ir
+// xn--mgba3a4f16a.ir (<iran>.ir, Persian YEH)
+ایران.ir
+// xn--mgba3a4fra.ir (<iran>.ir, Arabic YEH)
+ايران.ir
+
+// is : http://www.isnic.is/domain/rules.php
+// Confirmed by registry <marius@isgate.is> 2008-12-06
+is
+net.is
+com.is
+edu.is
+gov.is
+org.is
+int.is
+
+// it : http://en.wikipedia.org/wiki/.it
+it
+gov.it
+edu.it
+// Reserved geo-names:
+// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf
+// There is also a list of reserved geo-names corresponding to Italian municipalities
+// http://www.nic.it/documenti/appendice-c.pdf, but it is not included here.
+// Regions
+abr.it
+abruzzo.it
+aosta-valley.it
+aostavalley.it
+bas.it
+basilicata.it
+cal.it
+calabria.it
+cam.it
+campania.it
+emilia-romagna.it
+emiliaromagna.it
+emr.it
+friuli-v-giulia.it
+friuli-ve-giulia.it
+friuli-vegiulia.it
+friuli-venezia-giulia.it
+friuli-veneziagiulia.it
+friuli-vgiulia.it
+friuliv-giulia.it
+friulive-giulia.it
+friulivegiulia.it
+friulivenezia-giulia.it
+friuliveneziagiulia.it
+friulivgiulia.it
+fvg.it
+laz.it
+lazio.it
+lig.it
+liguria.it
+lom.it
+lombardia.it
+lombardy.it
+lucania.it
+mar.it
+marche.it
+mol.it
+molise.it
+piedmont.it
+piemonte.it
+pmn.it
+pug.it
+puglia.it
+sar.it
+sardegna.it
+sardinia.it
+sic.it
+sicilia.it
+sicily.it
+taa.it
+tos.it
+toscana.it
+trentino-a-adige.it
+trentino-aadige.it
+trentino-alto-adige.it
+trentino-altoadige.it
+trentino-s-tirol.it
+trentino-stirol.it
+trentino-sud-tirol.it
+trentino-sudtirol.it
+trentino-sued-tirol.it
+trentino-suedtirol.it
+trentinoa-adige.it
+trentinoaadige.it
+trentinoalto-adige.it
+trentinoaltoadige.it
+trentinos-tirol.it
+trentinostirol.it
+trentinosud-tirol.it
+trentinosudtirol.it
+trentinosued-tirol.it
+trentinosuedtirol.it
+tuscany.it
+umb.it
+umbria.it
+val-d-aosta.it
+val-daosta.it
+vald-aosta.it
+valdaosta.it
+valle-aosta.it
+valle-d-aosta.it
+valle-daosta.it
+valleaosta.it
+valled-aosta.it
+valledaosta.it
+vallee-aoste.it
+valleeaoste.it
+vao.it
+vda.it
+ven.it
+veneto.it
+// Provinces
+ag.it
+agrigento.it
+al.it
+alessandria.it
+alto-adige.it
+altoadige.it
+an.it
+ancona.it
+andria-barletta-trani.it
+andria-trani-barletta.it
+andriabarlettatrani.it
+andriatranibarletta.it
+ao.it
+aosta.it
+aoste.it
+ap.it
+aq.it
+aquila.it
+ar.it
+arezzo.it
+ascoli-piceno.it
+ascolipiceno.it
+asti.it
+at.it
+av.it
+avellino.it
+ba.it
+balsan.it
+bari.it
+barletta-trani-andria.it
+barlettatraniandria.it
+belluno.it
+benevento.it
+bergamo.it
+bg.it
+bi.it
+biella.it
+bl.it
+bn.it
+bo.it
+bologna.it
+bolzano.it
+bozen.it
+br.it
+brescia.it
+brindisi.it
+bs.it
+bt.it
+bz.it
+ca.it
+cagliari.it
+caltanissetta.it
+campidano-medio.it
+campidanomedio.it
+campobasso.it
+carbonia-iglesias.it
+carboniaiglesias.it
+carrara-massa.it
+carraramassa.it
+caserta.it
+catania.it
+catanzaro.it
+cb.it
+ce.it
+cesena-forli.it
+cesenaforli.it
+ch.it
+chieti.it
+ci.it
+cl.it
+cn.it
+co.it
+como.it
+cosenza.it
+cr.it
+cremona.it
+crotone.it
+cs.it
+ct.it
+cuneo.it
+cz.it
+dell-ogliastra.it
+dellogliastra.it
+en.it
+enna.it
+fc.it
+fe.it
+fermo.it
+ferrara.it
+fg.it
+fi.it
+firenze.it
+florence.it
+fm.it
+foggia.it
+forli-cesena.it
+forlicesena.it
+fr.it
+frosinone.it
+ge.it
+genoa.it
+genova.it
+go.it
+gorizia.it
+gr.it
+grosseto.it
+iglesias-carbonia.it
+iglesiascarbonia.it
+im.it
+imperia.it
+is.it
+isernia.it
+kr.it
+la-spezia.it
+laquila.it
+laspezia.it
+latina.it
+lc.it
+le.it
+lecce.it
+lecco.it
+li.it
+livorno.it
+lo.it
+lodi.it
+lt.it
+lu.it
+lucca.it
+macerata.it
+mantova.it
+massa-carrara.it
+massacarrara.it
+matera.it
+mb.it
+mc.it
+me.it
+medio-campidano.it
+mediocampidano.it
+messina.it
+mi.it
+milan.it
+milano.it
+mn.it
+mo.it
+modena.it
+monza-brianza.it
+monza-e-della-brianza.it
+monza.it
+monzabrianza.it
+monzaebrianza.it
+monzaedellabrianza.it
+ms.it
+mt.it
+na.it
+naples.it
+napoli.it
+no.it
+novara.it
+nu.it
+nuoro.it
+og.it
+ogliastra.it
+olbia-tempio.it
+olbiatempio.it
+or.it
+oristano.it
+ot.it
+pa.it
+padova.it
+padua.it
+palermo.it
+parma.it
+pavia.it
+pc.it
+pd.it
+pe.it
+perugia.it
+pesaro-urbino.it
+pesarourbino.it
+pescara.it
+pg.it
+pi.it
+piacenza.it
+pisa.it
+pistoia.it
+pn.it
+po.it
+pordenone.it
+potenza.it
+pr.it
+prato.it
+pt.it
+pu.it
+pv.it
+pz.it
+ra.it
+ragusa.it
+ravenna.it
+rc.it
+re.it
+reggio-calabria.it
+reggio-emilia.it
+reggiocalabria.it
+reggioemilia.it
+rg.it
+ri.it
+rieti.it
+rimini.it
+rm.it
+rn.it
+ro.it
+roma.it
+rome.it
+rovigo.it
+sa.it
+salerno.it
+sassari.it
+savona.it
+si.it
+siena.it
+siracusa.it
+so.it
+sondrio.it
+sp.it
+sr.it
+ss.it
+suedtirol.it
+sv.it
+ta.it
+taranto.it
+te.it
+tempio-olbia.it
+tempioolbia.it
+teramo.it
+terni.it
+tn.it
+to.it
+torino.it
+tp.it
+tr.it
+trani-andria-barletta.it
+trani-barletta-andria.it
+traniandriabarletta.it
+tranibarlettaandria.it
+trapani.it
+trentino.it
+trento.it
+treviso.it
+trieste.it
+ts.it
+turin.it
+tv.it
+ud.it
+udine.it
+urbino-pesaro.it
+urbinopesaro.it
+va.it
+varese.it
+vb.it
+vc.it
+ve.it
+venezia.it
+venice.it
+verbania.it
+vercelli.it
+verona.it
+vi.it
+vibo-valentia.it
+vibovalentia.it
+vicenza.it
+viterbo.it
+vr.it
+vs.it
+vt.it
+vv.it
+
+// je : http://www.channelisles.net/register-domains/
+// Confirmed by registry <nigel@channelisles.net> 2013-11-28
+je
+co.je
+net.je
+org.je
+
+// jm : http://www.com.jm/register.html
+*.jm
+
+// jo : http://www.dns.jo/Registration_policy.aspx
+jo
+com.jo
+org.jo
+net.jo
+edu.jo
+sch.jo
+gov.jo
+mil.jo
+name.jo
+
+// jobs : http://en.wikipedia.org/wiki/.jobs
+jobs
+
+// jp : http://en.wikipedia.org/wiki/.jp
+// http://jprs.co.jp/en/jpdomain.html
+// Submitted by registry <info@jprs.jp> 2014-10-30
+jp
+// jp organizational type names
+ac.jp
+ad.jp
+co.jp
+ed.jp
+go.jp
+gr.jp
+lg.jp
+ne.jp
+or.jp
+// jp prefecture type names
+aichi.jp
+akita.jp
+aomori.jp
+chiba.jp
+ehime.jp
+fukui.jp
+fukuoka.jp
+fukushima.jp
+gifu.jp
+gunma.jp
+hiroshima.jp
+hokkaido.jp
+hyogo.jp
+ibaraki.jp
+ishikawa.jp
+iwate.jp
+kagawa.jp
+kagoshima.jp
+kanagawa.jp
+kochi.jp
+kumamoto.jp
+kyoto.jp
+mie.jp
+miyagi.jp
+miyazaki.jp
+nagano.jp
+nagasaki.jp
+nara.jp
+niigata.jp
+oita.jp
+okayama.jp
+okinawa.jp
+osaka.jp
+saga.jp
+saitama.jp
+shiga.jp
+shimane.jp
+shizuoka.jp
+tochigi.jp
+tokushima.jp
+tokyo.jp
+tottori.jp
+toyama.jp
+wakayama.jp
+yamagata.jp
+yamaguchi.jp
+yamanashi.jp
+栃木.jp
+愛知.jp
+愛媛.jp
+兵庫.jp
+熊本.jp
+茨城.jp
+北海道.jp
+千葉.jp
+和歌山.jp
+長崎.jp
+長野.jp
+新潟.jp
+青森.jp
+静岡.jp
+東京.jp
+石川.jp
+埼玉.jp
+三重.jp
+京都.jp
+佐賀.jp
+大分.jp
+大阪.jp
+奈良.jp
+宮城.jp
+宮崎.jp
+富山.jp
+山口.jp
+山形.jp
+山梨.jp
+岩手.jp
+岐阜.jp
+岡山.jp
+島根.jp
+広島.jp
+徳島.jp
+沖縄.jp
+滋賀.jp
+神奈川.jp
+福井.jp
+福岡.jp
+福島.jp
+秋田.jp
+群馬.jp
+香川.jp
+高知.jp
+鳥取.jp
+鹿児島.jp
+// jp geographic type names
+// http://jprs.jp/doc/rule/saisoku-1.html
+*.kawasaki.jp
+*.kitakyushu.jp
+*.kobe.jp
+*.nagoya.jp
+*.sapporo.jp
+*.sendai.jp
+*.yokohama.jp
+!city.kawasaki.jp
+!city.kitakyushu.jp
+!city.kobe.jp
+!city.nagoya.jp
+!city.sapporo.jp
+!city.sendai.jp
+!city.yokohama.jp
+// 4th level registration
+aisai.aichi.jp
+ama.aichi.jp
+anjo.aichi.jp
+asuke.aichi.jp
+chiryu.aichi.jp
+chita.aichi.jp
+fuso.aichi.jp
+gamagori.aichi.jp
+handa.aichi.jp
+hazu.aichi.jp
+hekinan.aichi.jp
+higashiura.aichi.jp
+ichinomiya.aichi.jp
+inazawa.aichi.jp
+inuyama.aichi.jp
+isshiki.aichi.jp
+iwakura.aichi.jp
+kanie.aichi.jp
+kariya.aichi.jp
+kasugai.aichi.jp
+kira.aichi.jp
+kiyosu.aichi.jp
+komaki.aichi.jp
+konan.aichi.jp
+kota.aichi.jp
+mihama.aichi.jp
+miyoshi.aichi.jp
+nishio.aichi.jp
+nisshin.aichi.jp
+obu.aichi.jp
+oguchi.aichi.jp
+oharu.aichi.jp
+okazaki.aichi.jp
+owariasahi.aichi.jp
+seto.aichi.jp
+shikatsu.aichi.jp
+shinshiro.aichi.jp
+shitara.aichi.jp
+tahara.aichi.jp
+takahama.aichi.jp
+tobishima.aichi.jp
+toei.aichi.jp
+togo.aichi.jp
+tokai.aichi.jp
+tokoname.aichi.jp
+toyoake.aichi.jp
+toyohashi.aichi.jp
+toyokawa.aichi.jp
+toyone.aichi.jp
+toyota.aichi.jp
+tsushima.aichi.jp
+yatomi.aichi.jp
+akita.akita.jp
+daisen.akita.jp
+fujisato.akita.jp
+gojome.akita.jp
+hachirogata.akita.jp
+happou.akita.jp
+higashinaruse.akita.jp
+honjo.akita.jp
+honjyo.akita.jp
+ikawa.akita.jp
+kamikoani.akita.jp
+kamioka.akita.jp
+katagami.akita.jp
+kazuno.akita.jp
+kitaakita.akita.jp
+kosaka.akita.jp
+kyowa.akita.jp
+misato.akita.jp
+mitane.akita.jp
+moriyoshi.akita.jp
+nikaho.akita.jp
+noshiro.akita.jp
+odate.akita.jp
+oga.akita.jp
+ogata.akita.jp
+semboku.akita.jp
+yokote.akita.jp
+yurihonjo.akita.jp
+aomori.aomori.jp
+gonohe.aomori.jp
+hachinohe.aomori.jp
+hashikami.aomori.jp
+hiranai.aomori.jp
+hirosaki.aomori.jp
+itayanagi.aomori.jp
+kuroishi.aomori.jp
+misawa.aomori.jp
+mutsu.aomori.jp
+nakadomari.aomori.jp
+noheji.aomori.jp
+oirase.aomori.jp
+owani.aomori.jp
+rokunohe.aomori.jp
+sannohe.aomori.jp
+shichinohe.aomori.jp
+shingo.aomori.jp
+takko.aomori.jp
+towada.aomori.jp
+tsugaru.aomori.jp
+tsuruta.aomori.jp
+abiko.chiba.jp
+asahi.chiba.jp
+chonan.chiba.jp
+chosei.chiba.jp
+choshi.chiba.jp
+chuo.chiba.jp
+funabashi.chiba.jp
+futtsu.chiba.jp
+hanamigawa.chiba.jp
+ichihara.chiba.jp
+ichikawa.chiba.jp
+ichinomiya.chiba.jp
+inzai.chiba.jp
+isumi.chiba.jp
+kamagaya.chiba.jp
+kamogawa.chiba.jp
+kashiwa.chiba.jp
+katori.chiba.jp
+katsuura.chiba.jp
+kimitsu.chiba.jp
+kisarazu.chiba.jp
+kozaki.chiba.jp
+kujukuri.chiba.jp
+kyonan.chiba.jp
+matsudo.chiba.jp
+midori.chiba.jp
+mihama.chiba.jp
+minamiboso.chiba.jp
+mobara.chiba.jp
+mutsuzawa.chiba.jp
+nagara.chiba.jp
+nagareyama.chiba.jp
+narashino.chiba.jp
+narita.chiba.jp
+noda.chiba.jp
+oamishirasato.chiba.jp
+omigawa.chiba.jp
+onjuku.chiba.jp
+otaki.chiba.jp
+sakae.chiba.jp
+sakura.chiba.jp
+shimofusa.chiba.jp
+shirako.chiba.jp
+shiroi.chiba.jp
+shisui.chiba.jp
+sodegaura.chiba.jp
+sosa.chiba.jp
+tako.chiba.jp
+tateyama.chiba.jp
+togane.chiba.jp
+tohnosho.chiba.jp
+tomisato.chiba.jp
+urayasu.chiba.jp
+yachimata.chiba.jp
+yachiyo.chiba.jp
+yokaichiba.chiba.jp
+yokoshibahikari.chiba.jp
+yotsukaido.chiba.jp
+ainan.ehime.jp
+honai.ehime.jp
+ikata.ehime.jp
+imabari.ehime.jp
+iyo.ehime.jp
+kamijima.ehime.jp
+kihoku.ehime.jp
+kumakogen.ehime.jp
+masaki.ehime.jp
+matsuno.ehime.jp
+matsuyama.ehime.jp
+namikata.ehime.jp
+niihama.ehime.jp
+ozu.ehime.jp
+saijo.ehime.jp
+seiyo.ehime.jp
+shikokuchuo.ehime.jp
+tobe.ehime.jp
+toon.ehime.jp
+uchiko.ehime.jp
+uwajima.ehime.jp
+yawatahama.ehime.jp
+echizen.fukui.jp
+eiheiji.fukui.jp
+fukui.fukui.jp
+ikeda.fukui.jp
+katsuyama.fukui.jp
+mihama.fukui.jp
+minamiechizen.fukui.jp
+obama.fukui.jp
+ohi.fukui.jp
+ono.fukui.jp
+sabae.fukui.jp
+sakai.fukui.jp
+takahama.fukui.jp
+tsuruga.fukui.jp
+wakasa.fukui.jp
+ashiya.fukuoka.jp
+buzen.fukuoka.jp
+chikugo.fukuoka.jp
+chikuho.fukuoka.jp
+chikujo.fukuoka.jp
+chikushino.fukuoka.jp
+chikuzen.fukuoka.jp
+chuo.fukuoka.jp
+dazaifu.fukuoka.jp
+fukuchi.fukuoka.jp
+hakata.fukuoka.jp
+higashi.fukuoka.jp
+hirokawa.fukuoka.jp
+hisayama.fukuoka.jp
+iizuka.fukuoka.jp
+inatsuki.fukuoka.jp
+kaho.fukuoka.jp
+kasuga.fukuoka.jp
+kasuya.fukuoka.jp
+kawara.fukuoka.jp
+keisen.fukuoka.jp
+koga.fukuoka.jp
+kurate.fukuoka.jp
+kurogi.fukuoka.jp
+kurume.fukuoka.jp
+minami.fukuoka.jp
+miyako.fukuoka.jp
+miyama.fukuoka.jp
+miyawaka.fukuoka.jp
+mizumaki.fukuoka.jp
+munakata.fukuoka.jp
+nakagawa.fukuoka.jp
+nakama.fukuoka.jp
+nishi.fukuoka.jp
+nogata.fukuoka.jp
+ogori.fukuoka.jp
+okagaki.fukuoka.jp
+okawa.fukuoka.jp
+oki.fukuoka.jp
+omuta.fukuoka.jp
+onga.fukuoka.jp
+onojo.fukuoka.jp
+oto.fukuoka.jp
+saigawa.fukuoka.jp
+sasaguri.fukuoka.jp
+shingu.fukuoka.jp
+shinyoshitomi.fukuoka.jp
+shonai.fukuoka.jp
+soeda.fukuoka.jp
+sue.fukuoka.jp
+tachiarai.fukuoka.jp
+tagawa.fukuoka.jp
+takata.fukuoka.jp
+toho.fukuoka.jp
+toyotsu.fukuoka.jp
+tsuiki.fukuoka.jp
+ukiha.fukuoka.jp
+umi.fukuoka.jp
+usui.fukuoka.jp
+yamada.fukuoka.jp
+yame.fukuoka.jp
+yanagawa.fukuoka.jp
+yukuhashi.fukuoka.jp
+aizubange.fukushima.jp
+aizumisato.fukushima.jp
+aizuwakamatsu.fukushima.jp
+asakawa.fukushima.jp
+bandai.fukushima.jp
+date.fukushima.jp
+fukushima.fukushima.jp
+furudono.fukushima.jp
+futaba.fukushima.jp
+hanawa.fukushima.jp
+higashi.fukushima.jp
+hirata.fukushima.jp
+hirono.fukushima.jp
+iitate.fukushima.jp
+inawashiro.fukushima.jp
+ishikawa.fukushima.jp
+iwaki.fukushima.jp
+izumizaki.fukushima.jp
+kagamiishi.fukushima.jp
+kaneyama.fukushima.jp
+kawamata.fukushima.jp
+kitakata.fukushima.jp
+kitashiobara.fukushima.jp
+koori.fukushima.jp
+koriyama.fukushima.jp
+kunimi.fukushima.jp
+miharu.fukushima.jp
+mishima.fukushima.jp
+namie.fukushima.jp
+nango.fukushima.jp
+nishiaizu.fukushima.jp
+nishigo.fukushima.jp
+okuma.fukushima.jp
+omotego.fukushima.jp
+ono.fukushima.jp
+otama.fukushima.jp
+samegawa.fukushima.jp
+shimogo.fukushima.jp
+shirakawa.fukushima.jp
+showa.fukushima.jp
+soma.fukushima.jp
+sukagawa.fukushima.jp
+taishin.fukushima.jp
+tamakawa.fukushima.jp
+tanagura.fukushima.jp
+tenei.fukushima.jp
+yabuki.fukushima.jp
+yamato.fukushima.jp
+yamatsuri.fukushima.jp
+yanaizu.fukushima.jp
+yugawa.fukushima.jp
+anpachi.gifu.jp
+ena.gifu.jp
+gifu.gifu.jp
+ginan.gifu.jp
+godo.gifu.jp
+gujo.gifu.jp
+hashima.gifu.jp
+hichiso.gifu.jp
+hida.gifu.jp
+higashishirakawa.gifu.jp
+ibigawa.gifu.jp
+ikeda.gifu.jp
+kakamigahara.gifu.jp
+kani.gifu.jp
+kasahara.gifu.jp
+kasamatsu.gifu.jp
+kawaue.gifu.jp
+kitagata.gifu.jp
+mino.gifu.jp
+minokamo.gifu.jp
+mitake.gifu.jp
+mizunami.gifu.jp
+motosu.gifu.jp
+nakatsugawa.gifu.jp
+ogaki.gifu.jp
+sakahogi.gifu.jp
+seki.gifu.jp
+sekigahara.gifu.jp
+shirakawa.gifu.jp
+tajimi.gifu.jp
+takayama.gifu.jp
+tarui.gifu.jp
+toki.gifu.jp
+tomika.gifu.jp
+wanouchi.gifu.jp
+yamagata.gifu.jp
+yaotsu.gifu.jp
+yoro.gifu.jp
+annaka.gunma.jp
+chiyoda.gunma.jp
+fujioka.gunma.jp
+higashiagatsuma.gunma.jp
+isesaki.gunma.jp
+itakura.gunma.jp
+kanna.gunma.jp
+kanra.gunma.jp
+katashina.gunma.jp
+kawaba.gunma.jp
+kiryu.gunma.jp
+kusatsu.gunma.jp
+maebashi.gunma.jp
+meiwa.gunma.jp
+midori.gunma.jp
+minakami.gunma.jp
+naganohara.gunma.jp
+nakanojo.gunma.jp
+nanmoku.gunma.jp
+numata.gunma.jp
+oizumi.gunma.jp
+ora.gunma.jp
+ota.gunma.jp
+shibukawa.gunma.jp
+shimonita.gunma.jp
+shinto.gunma.jp
+showa.gunma.jp
+takasaki.gunma.jp
+takayama.gunma.jp
+tamamura.gunma.jp
+tatebayashi.gunma.jp
+tomioka.gunma.jp
+tsukiyono.gunma.jp
+tsumagoi.gunma.jp
+ueno.gunma.jp
+yoshioka.gunma.jp
+asaminami.hiroshima.jp
+daiwa.hiroshima.jp
+etajima.hiroshima.jp
+fuchu.hiroshima.jp
+fukuyama.hiroshima.jp
+hatsukaichi.hiroshima.jp
+higashihiroshima.hiroshima.jp
+hongo.hiroshima.jp
+jinsekikogen.hiroshima.jp
+kaita.hiroshima.jp
+kui.hiroshima.jp
+kumano.hiroshima.jp
+kure.hiroshima.jp
+mihara.hiroshima.jp
+miyoshi.hiroshima.jp
+naka.hiroshima.jp
+onomichi.hiroshima.jp
+osakikamijima.hiroshima.jp
+otake.hiroshima.jp
+saka.hiroshima.jp
+sera.hiroshima.jp
+seranishi.hiroshima.jp
+shinichi.hiroshima.jp
+shobara.hiroshima.jp
+takehara.hiroshima.jp
+abashiri.hokkaido.jp
+abira.hokkaido.jp
+aibetsu.hokkaido.jp
+akabira.hokkaido.jp
+akkeshi.hokkaido.jp
+asahikawa.hokkaido.jp
+ashibetsu.hokkaido.jp
+ashoro.hokkaido.jp
+assabu.hokkaido.jp
+atsuma.hokkaido.jp
+bibai.hokkaido.jp
+biei.hokkaido.jp
+bifuka.hokkaido.jp
+bihoro.hokkaido.jp
+biratori.hokkaido.jp
+chippubetsu.hokkaido.jp
+chitose.hokkaido.jp
+date.hokkaido.jp
+ebetsu.hokkaido.jp
+embetsu.hokkaido.jp
+eniwa.hokkaido.jp
+erimo.hokkaido.jp
+esan.hokkaido.jp
+esashi.hokkaido.jp
+fukagawa.hokkaido.jp
+fukushima.hokkaido.jp
+furano.hokkaido.jp
+furubira.hokkaido.jp
+haboro.hokkaido.jp
+hakodate.hokkaido.jp
+hamatonbetsu.hokkaido.jp
+hidaka.hokkaido.jp
+higashikagura.hokkaido.jp
+higashikawa.hokkaido.jp
+hiroo.hokkaido.jp
+hokuryu.hokkaido.jp
+hokuto.hokkaido.jp
+honbetsu.hokkaido.jp
+horokanai.hokkaido.jp
+horonobe.hokkaido.jp
+ikeda.hokkaido.jp
+imakane.hokkaido.jp
+ishikari.hokkaido.jp
+iwamizawa.hokkaido.jp
+iwanai.hokkaido.jp
+kamifurano.hokkaido.jp
+kamikawa.hokkaido.jp
+kamishihoro.hokkaido.jp
+kamisunagawa.hokkaido.jp
+kamoenai.hokkaido.jp
+kayabe.hokkaido.jp
+kembuchi.hokkaido.jp
+kikonai.hokkaido.jp
+kimobetsu.hokkaido.jp
+kitahiroshima.hokkaido.jp
+kitami.hokkaido.jp
+kiyosato.hokkaido.jp
+koshimizu.hokkaido.jp
+kunneppu.hokkaido.jp
+kuriyama.hokkaido.jp
+kuromatsunai.hokkaido.jp
+kushiro.hokkaido.jp
+kutchan.hokkaido.jp
+kyowa.hokkaido.jp
+mashike.hokkaido.jp
+matsumae.hokkaido.jp
+mikasa.hokkaido.jp
+minamifurano.hokkaido.jp
+mombetsu.hokkaido.jp
+moseushi.hokkaido.jp
+mukawa.hokkaido.jp
+muroran.hokkaido.jp
+naie.hokkaido.jp
+nakagawa.hokkaido.jp
+nakasatsunai.hokkaido.jp
+nakatombetsu.hokkaido.jp
+nanae.hokkaido.jp
+nanporo.hokkaido.jp
+nayoro.hokkaido.jp
+nemuro.hokkaido.jp
+niikappu.hokkaido.jp
+niki.hokkaido.jp
+nishiokoppe.hokkaido.jp
+noboribetsu.hokkaido.jp
+numata.hokkaido.jp
+obihiro.hokkaido.jp
+obira.hokkaido.jp
+oketo.hokkaido.jp
+okoppe.hokkaido.jp
+otaru.hokkaido.jp
+otobe.hokkaido.jp
+otofuke.hokkaido.jp
+otoineppu.hokkaido.jp
+oumu.hokkaido.jp
+ozora.hokkaido.jp
+pippu.hokkaido.jp
+rankoshi.hokkaido.jp
+rebun.hokkaido.jp
+rikubetsu.hokkaido.jp
+rishiri.hokkaido.jp
+rishirifuji.hokkaido.jp
+saroma.hokkaido.jp
+sarufutsu.hokkaido.jp
+shakotan.hokkaido.jp
+shari.hokkaido.jp
+shibecha.hokkaido.jp
+shibetsu.hokkaido.jp
+shikabe.hokkaido.jp
+shikaoi.hokkaido.jp
+shimamaki.hokkaido.jp
+shimizu.hokkaido.jp
+shimokawa.hokkaido.jp
+shinshinotsu.hokkaido.jp
+shintoku.hokkaido.jp
+shiranuka.hokkaido.jp
+shiraoi.hokkaido.jp
+shiriuchi.hokkaido.jp
+sobetsu.hokkaido.jp
+sunagawa.hokkaido.jp
+taiki.hokkaido.jp
+takasu.hokkaido.jp
+takikawa.hokkaido.jp
+takinoue.hokkaido.jp
+teshikaga.hokkaido.jp
+tobetsu.hokkaido.jp
+tohma.hokkaido.jp
+tomakomai.hokkaido.jp
+tomari.hokkaido.jp
+toya.hokkaido.jp
+toyako.hokkaido.jp
+toyotomi.hokkaido.jp
+toyoura.hokkaido.jp
+tsubetsu.hokkaido.jp
+tsukigata.hokkaido.jp
+urakawa.hokkaido.jp
+urausu.hokkaido.jp
+uryu.hokkaido.jp
+utashinai.hokkaido.jp
+wakkanai.hokkaido.jp
+wassamu.hokkaido.jp
+yakumo.hokkaido.jp
+yoichi.hokkaido.jp
+aioi.hyogo.jp
+akashi.hyogo.jp
+ako.hyogo.jp
+amagasaki.hyogo.jp
+aogaki.hyogo.jp
+asago.hyogo.jp
+ashiya.hyogo.jp
+awaji.hyogo.jp
+fukusaki.hyogo.jp
+goshiki.hyogo.jp
+harima.hyogo.jp
+himeji.hyogo.jp
+ichikawa.hyogo.jp
+inagawa.hyogo.jp
+itami.hyogo.jp
+kakogawa.hyogo.jp
+kamigori.hyogo.jp
+kamikawa.hyogo.jp
+kasai.hyogo.jp
+kasuga.hyogo.jp
+kawanishi.hyogo.jp
+miki.hyogo.jp
+minamiawaji.hyogo.jp
+nishinomiya.hyogo.jp
+nishiwaki.hyogo.jp
+ono.hyogo.jp
+sanda.hyogo.jp
+sannan.hyogo.jp
+sasayama.hyogo.jp
+sayo.hyogo.jp
+shingu.hyogo.jp
+shinonsen.hyogo.jp
+shiso.hyogo.jp
+sumoto.hyogo.jp
+taishi.hyogo.jp
+taka.hyogo.jp
+takarazuka.hyogo.jp
+takasago.hyogo.jp
+takino.hyogo.jp
+tamba.hyogo.jp
+tatsuno.hyogo.jp
+toyooka.hyogo.jp
+yabu.hyogo.jp
+yashiro.hyogo.jp
+yoka.hyogo.jp
+yokawa.hyogo.jp
+ami.ibaraki.jp
+asahi.ibaraki.jp
+bando.ibaraki.jp
+chikusei.ibaraki.jp
+daigo.ibaraki.jp
+fujishiro.ibaraki.jp
+hitachi.ibaraki.jp
+hitachinaka.ibaraki.jp
+hitachiomiya.ibaraki.jp
+hitachiota.ibaraki.jp
+ibaraki.ibaraki.jp
+ina.ibaraki.jp
+inashiki.ibaraki.jp
+itako.ibaraki.jp
+iwama.ibaraki.jp
+joso.ibaraki.jp
+kamisu.ibaraki.jp
+kasama.ibaraki.jp
+kashima.ibaraki.jp
+kasumigaura.ibaraki.jp
+koga.ibaraki.jp
+miho.ibaraki.jp
+mito.ibaraki.jp
+moriya.ibaraki.jp
+naka.ibaraki.jp
+namegata.ibaraki.jp
+oarai.ibaraki.jp
+ogawa.ibaraki.jp
+omitama.ibaraki.jp
+ryugasaki.ibaraki.jp
+sakai.ibaraki.jp
+sakuragawa.ibaraki.jp
+shimodate.ibaraki.jp
+shimotsuma.ibaraki.jp
+shirosato.ibaraki.jp
+sowa.ibaraki.jp
+suifu.ibaraki.jp
+takahagi.ibaraki.jp
+tamatsukuri.ibaraki.jp
+tokai.ibaraki.jp
+tomobe.ibaraki.jp
+tone.ibaraki.jp
+toride.ibaraki.jp
+tsuchiura.ibaraki.jp
+tsukuba.ibaraki.jp
+uchihara.ibaraki.jp
+ushiku.ibaraki.jp
+yachiyo.ibaraki.jp
+yamagata.ibaraki.jp
+yawara.ibaraki.jp
+yuki.ibaraki.jp
+anamizu.ishikawa.jp
+hakui.ishikawa.jp
+hakusan.ishikawa.jp
+kaga.ishikawa.jp
+kahoku.ishikawa.jp
+kanazawa.ishikawa.jp
+kawakita.ishikawa.jp
+komatsu.ishikawa.jp
+nakanoto.ishikawa.jp
+nanao.ishikawa.jp
+nomi.ishikawa.jp
+nonoichi.ishikawa.jp
+noto.ishikawa.jp
+shika.ishikawa.jp
+suzu.ishikawa.jp
+tsubata.ishikawa.jp
+tsurugi.ishikawa.jp
+uchinada.ishikawa.jp
+wajima.ishikawa.jp
+fudai.iwate.jp
+fujisawa.iwate.jp
+hanamaki.iwate.jp
+hiraizumi.iwate.jp
+hirono.iwate.jp
+ichinohe.iwate.jp
+ichinoseki.iwate.jp
+iwaizumi.iwate.jp
+iwate.iwate.jp
+joboji.iwate.jp
+kamaishi.iwate.jp
+kanegasaki.iwate.jp
+karumai.iwate.jp
+kawai.iwate.jp
+kitakami.iwate.jp
+kuji.iwate.jp
+kunohe.iwate.jp
+kuzumaki.iwate.jp
+miyako.iwate.jp
+mizusawa.iwate.jp
+morioka.iwate.jp
+ninohe.iwate.jp
+noda.iwate.jp
+ofunato.iwate.jp
+oshu.iwate.jp
+otsuchi.iwate.jp
+rikuzentakata.iwate.jp
+shiwa.iwate.jp
+shizukuishi.iwate.jp
+sumita.iwate.jp
+tanohata.iwate.jp
+tono.iwate.jp
+yahaba.iwate.jp
+yamada.iwate.jp
+ayagawa.kagawa.jp
+higashikagawa.kagawa.jp
+kanonji.kagawa.jp
+kotohira.kagawa.jp
+manno.kagawa.jp
+marugame.kagawa.jp
+mitoyo.kagawa.jp
+naoshima.kagawa.jp
+sanuki.kagawa.jp
+tadotsu.kagawa.jp
+takamatsu.kagawa.jp
+tonosho.kagawa.jp
+uchinomi.kagawa.jp
+utazu.kagawa.jp
+zentsuji.kagawa.jp
+akune.kagoshima.jp
+amami.kagoshima.jp
+hioki.kagoshima.jp
+isa.kagoshima.jp
+isen.kagoshima.jp
+izumi.kagoshima.jp
+kagoshima.kagoshima.jp
+kanoya.kagoshima.jp
+kawanabe.kagoshima.jp
+kinko.kagoshima.jp
+kouyama.kagoshima.jp
+makurazaki.kagoshima.jp
+matsumoto.kagoshima.jp
+minamitane.kagoshima.jp
+nakatane.kagoshima.jp
+nishinoomote.kagoshima.jp
+satsumasendai.kagoshima.jp
+soo.kagoshima.jp
+tarumizu.kagoshima.jp
+yusui.kagoshima.jp
+aikawa.kanagawa.jp
+atsugi.kanagawa.jp
+ayase.kanagawa.jp
+chigasaki.kanagawa.jp
+ebina.kanagawa.jp
+fujisawa.kanagawa.jp
+hadano.kanagawa.jp
+hakone.kanagawa.jp
+hiratsuka.kanagawa.jp
+isehara.kanagawa.jp
+kaisei.kanagawa.jp
+kamakura.kanagawa.jp
+kiyokawa.kanagawa.jp
+matsuda.kanagawa.jp
+minamiashigara.kanagawa.jp
+miura.kanagawa.jp
+nakai.kanagawa.jp
+ninomiya.kanagawa.jp
+odawara.kanagawa.jp
+oi.kanagawa.jp
+oiso.kanagawa.jp
+sagamihara.kanagawa.jp
+samukawa.kanagawa.jp
+tsukui.kanagawa.jp
+yamakita.kanagawa.jp
+yamato.kanagawa.jp
+yokosuka.kanagawa.jp
+yugawara.kanagawa.jp
+zama.kanagawa.jp
+zushi.kanagawa.jp
+aki.kochi.jp
+geisei.kochi.jp
+hidaka.kochi.jp
+higashitsuno.kochi.jp
+ino.kochi.jp
+kagami.kochi.jp
+kami.kochi.jp
+kitagawa.kochi.jp
+kochi.kochi.jp
+mihara.kochi.jp
+motoyama.kochi.jp
+muroto.kochi.jp
+nahari.kochi.jp
+nakamura.kochi.jp
+nankoku.kochi.jp
+nishitosa.kochi.jp
+niyodogawa.kochi.jp
+ochi.kochi.jp
+okawa.kochi.jp
+otoyo.kochi.jp
+otsuki.kochi.jp
+sakawa.kochi.jp
+sukumo.kochi.jp
+susaki.kochi.jp
+tosa.kochi.jp
+tosashimizu.kochi.jp
+toyo.kochi.jp
+tsuno.kochi.jp
+umaji.kochi.jp
+yasuda.kochi.jp
+yusuhara.kochi.jp
+amakusa.kumamoto.jp
+arao.kumamoto.jp
+aso.kumamoto.jp
+choyo.kumamoto.jp
+gyokuto.kumamoto.jp
+hitoyoshi.kumamoto.jp
+kamiamakusa.kumamoto.jp
+kashima.kumamoto.jp
+kikuchi.kumamoto.jp
+kosa.kumamoto.jp
+kumamoto.kumamoto.jp
+mashiki.kumamoto.jp
+mifune.kumamoto.jp
+minamata.kumamoto.jp
+minamioguni.kumamoto.jp
+nagasu.kumamoto.jp
+nishihara.kumamoto.jp
+oguni.kumamoto.jp
+ozu.kumamoto.jp
+sumoto.kumamoto.jp
+takamori.kumamoto.jp
+uki.kumamoto.jp
+uto.kumamoto.jp
+yamaga.kumamoto.jp
+yamato.kumamoto.jp
+yatsushiro.kumamoto.jp
+ayabe.kyoto.jp
+fukuchiyama.kyoto.jp
+higashiyama.kyoto.jp
+ide.kyoto.jp
+ine.kyoto.jp
+joyo.kyoto.jp
+kameoka.kyoto.jp
+kamo.kyoto.jp
+kita.kyoto.jp
+kizu.kyoto.jp
+kumiyama.kyoto.jp
+kyotamba.kyoto.jp
+kyotanabe.kyoto.jp
+kyotango.kyoto.jp
+maizuru.kyoto.jp
+minami.kyoto.jp
+minamiyamashiro.kyoto.jp
+miyazu.kyoto.jp
+muko.kyoto.jp
+nagaokakyo.kyoto.jp
+nakagyo.kyoto.jp
+nantan.kyoto.jp
+oyamazaki.kyoto.jp
+sakyo.kyoto.jp
+seika.kyoto.jp
+tanabe.kyoto.jp
+uji.kyoto.jp
+ujitawara.kyoto.jp
+wazuka.kyoto.jp
+yamashina.kyoto.jp
+yawata.kyoto.jp
+asahi.mie.jp
+inabe.mie.jp
+ise.mie.jp
+kameyama.mie.jp
+kawagoe.mie.jp
+kiho.mie.jp
+kisosaki.mie.jp
+kiwa.mie.jp
+komono.mie.jp
+kumano.mie.jp
+kuwana.mie.jp
+matsusaka.mie.jp
+meiwa.mie.jp
+mihama.mie.jp
+minamiise.mie.jp
+misugi.mie.jp
+miyama.mie.jp
+nabari.mie.jp
+shima.mie.jp
+suzuka.mie.jp
+tado.mie.jp
+taiki.mie.jp
+taki.mie.jp
+tamaki.mie.jp
+toba.mie.jp
+tsu.mie.jp
+udono.mie.jp
+ureshino.mie.jp
+watarai.mie.jp
+yokkaichi.mie.jp
+furukawa.miyagi.jp
+higashimatsushima.miyagi.jp
+ishinomaki.miyagi.jp
+iwanuma.miyagi.jp
+kakuda.miyagi.jp
+kami.miyagi.jp
+kawasaki.miyagi.jp
+kesennuma.miyagi.jp
+marumori.miyagi.jp
+matsushima.miyagi.jp
+minamisanriku.miyagi.jp
+misato.miyagi.jp
+murata.miyagi.jp
+natori.miyagi.jp
+ogawara.miyagi.jp
+ohira.miyagi.jp
+onagawa.miyagi.jp
+osaki.miyagi.jp
+rifu.miyagi.jp
+semine.miyagi.jp
+shibata.miyagi.jp
+shichikashuku.miyagi.jp
+shikama.miyagi.jp
+shiogama.miyagi.jp
+shiroishi.miyagi.jp
+tagajo.miyagi.jp
+taiwa.miyagi.jp
+tome.miyagi.jp
+tomiya.miyagi.jp
+wakuya.miyagi.jp
+watari.miyagi.jp
+yamamoto.miyagi.jp
+zao.miyagi.jp
+aya.miyazaki.jp
+ebino.miyazaki.jp
+gokase.miyazaki.jp
+hyuga.miyazaki.jp
+kadogawa.miyazaki.jp
+kawaminami.miyazaki.jp
+kijo.miyazaki.jp
+kitagawa.miyazaki.jp
+kitakata.miyazaki.jp
+kitaura.miyazaki.jp
+kobayashi.miyazaki.jp
+kunitomi.miyazaki.jp
+kushima.miyazaki.jp
+mimata.miyazaki.jp
+miyakonojo.miyazaki.jp
+miyazaki.miyazaki.jp
+morotsuka.miyazaki.jp
+nichinan.miyazaki.jp
+nishimera.miyazaki.jp
+nobeoka.miyazaki.jp
+saito.miyazaki.jp
+shiiba.miyazaki.jp
+shintomi.miyazaki.jp
+takaharu.miyazaki.jp
+takanabe.miyazaki.jp
+takazaki.miyazaki.jp
+tsuno.miyazaki.jp
+achi.nagano.jp
+agematsu.nagano.jp
+anan.nagano.jp
+aoki.nagano.jp
+asahi.nagano.jp
+azumino.nagano.jp
+chikuhoku.nagano.jp
+chikuma.nagano.jp
+chino.nagano.jp
+fujimi.nagano.jp
+hakuba.nagano.jp
+hara.nagano.jp
+hiraya.nagano.jp
+iida.nagano.jp
+iijima.nagano.jp
+iiyama.nagano.jp
+iizuna.nagano.jp
+ikeda.nagano.jp
+ikusaka.nagano.jp
+ina.nagano.jp
+karuizawa.nagano.jp
+kawakami.nagano.jp
+kiso.nagano.jp
+kisofukushima.nagano.jp
+kitaaiki.nagano.jp
+komagane.nagano.jp
+komoro.nagano.jp
+matsukawa.nagano.jp
+matsumoto.nagano.jp
+miasa.nagano.jp
+minamiaiki.nagano.jp
+minamimaki.nagano.jp
+minamiminowa.nagano.jp
+minowa.nagano.jp
+miyada.nagano.jp
+miyota.nagano.jp
+mochizuki.nagano.jp
+nagano.nagano.jp
+nagawa.nagano.jp
+nagiso.nagano.jp
+nakagawa.nagano.jp
+nakano.nagano.jp
+nozawaonsen.nagano.jp
+obuse.nagano.jp
+ogawa.nagano.jp
+okaya.nagano.jp
+omachi.nagano.jp
+omi.nagano.jp
+ookuwa.nagano.jp
+ooshika.nagano.jp
+otaki.nagano.jp
+otari.nagano.jp
+sakae.nagano.jp
+sakaki.nagano.jp
+saku.nagano.jp
+sakuho.nagano.jp
+shimosuwa.nagano.jp
+shinanomachi.nagano.jp
+shiojiri.nagano.jp
+suwa.nagano.jp
+suzaka.nagano.jp
+takagi.nagano.jp
+takamori.nagano.jp
+takayama.nagano.jp
+tateshina.nagano.jp
+tatsuno.nagano.jp
+togakushi.nagano.jp
+togura.nagano.jp
+tomi.nagano.jp
+ueda.nagano.jp
+wada.nagano.jp
+yamagata.nagano.jp
+yamanouchi.nagano.jp
+yasaka.nagano.jp
+yasuoka.nagano.jp
+chijiwa.nagasaki.jp
+futsu.nagasaki.jp
+goto.nagasaki.jp
+hasami.nagasaki.jp
+hirado.nagasaki.jp
+iki.nagasaki.jp
+isahaya.nagasaki.jp
+kawatana.nagasaki.jp
+kuchinotsu.nagasaki.jp
+matsuura.nagasaki.jp
+nagasaki.nagasaki.jp
+obama.nagasaki.jp
+omura.nagasaki.jp
+oseto.nagasaki.jp
+saikai.nagasaki.jp
+sasebo.nagasaki.jp
+seihi.nagasaki.jp
+shimabara.nagasaki.jp
+shinkamigoto.nagasaki.jp
+togitsu.nagasaki.jp
+tsushima.nagasaki.jp
+unzen.nagasaki.jp
+ando.nara.jp
+gose.nara.jp
+heguri.nara.jp
+higashiyoshino.nara.jp
+ikaruga.nara.jp
+ikoma.nara.jp
+kamikitayama.nara.jp
+kanmaki.nara.jp
+kashiba.nara.jp
+kashihara.nara.jp
+katsuragi.nara.jp
+kawai.nara.jp
+kawakami.nara.jp
+kawanishi.nara.jp
+koryo.nara.jp
+kurotaki.nara.jp
+mitsue.nara.jp
+miyake.nara.jp
+nara.nara.jp
+nosegawa.nara.jp
+oji.nara.jp
+ouda.nara.jp
+oyodo.nara.jp
+sakurai.nara.jp
+sango.nara.jp
+shimoichi.nara.jp
+shimokitayama.nara.jp
+shinjo.nara.jp
+soni.nara.jp
+takatori.nara.jp
+tawaramoto.nara.jp
+tenkawa.nara.jp
+tenri.nara.jp
+uda.nara.jp
+yamatokoriyama.nara.jp
+yamatotakada.nara.jp
+yamazoe.nara.jp
+yoshino.nara.jp
+aga.niigata.jp
+agano.niigata.jp
+gosen.niigata.jp
+itoigawa.niigata.jp
+izumozaki.niigata.jp
+joetsu.niigata.jp
+kamo.niigata.jp
+kariwa.niigata.jp
+kashiwazaki.niigata.jp
+minamiuonuma.niigata.jp
+mitsuke.niigata.jp
+muika.niigata.jp
+murakami.niigata.jp
+myoko.niigata.jp
+nagaoka.niigata.jp
+niigata.niigata.jp
+ojiya.niigata.jp
+omi.niigata.jp
+sado.niigata.jp
+sanjo.niigata.jp
+seiro.niigata.jp
+seirou.niigata.jp
+sekikawa.niigata.jp
+shibata.niigata.jp
+tagami.niigata.jp
+tainai.niigata.jp
+tochio.niigata.jp
+tokamachi.niigata.jp
+tsubame.niigata.jp
+tsunan.niigata.jp
+uonuma.niigata.jp
+yahiko.niigata.jp
+yoita.niigata.jp
+yuzawa.niigata.jp
+beppu.oita.jp
+bungoono.oita.jp
+bungotakada.oita.jp
+hasama.oita.jp
+hiji.oita.jp
+himeshima.oita.jp
+hita.oita.jp
+kamitsue.oita.jp
+kokonoe.oita.jp
+kuju.oita.jp
+kunisaki.oita.jp
+kusu.oita.jp
+oita.oita.jp
+saiki.oita.jp
+taketa.oita.jp
+tsukumi.oita.jp
+usa.oita.jp
+usuki.oita.jp
+yufu.oita.jp
+akaiwa.okayama.jp
+asakuchi.okayama.jp
+bizen.okayama.jp
+hayashima.okayama.jp
+ibara.okayama.jp
+kagamino.okayama.jp
+kasaoka.okayama.jp
+kibichuo.okayama.jp
+kumenan.okayama.jp
+kurashiki.okayama.jp
+maniwa.okayama.jp
+misaki.okayama.jp
+nagi.okayama.jp
+niimi.okayama.jp
+nishiawakura.okayama.jp
+okayama.okayama.jp
+satosho.okayama.jp
+setouchi.okayama.jp
+shinjo.okayama.jp
+shoo.okayama.jp
+soja.okayama.jp
+takahashi.okayama.jp
+tamano.okayama.jp
+tsuyama.okayama.jp
+wake.okayama.jp
+yakage.okayama.jp
+aguni.okinawa.jp
+ginowan.okinawa.jp
+ginoza.okinawa.jp
+gushikami.okinawa.jp
+haebaru.okinawa.jp
+higashi.okinawa.jp
+hirara.okinawa.jp
+iheya.okinawa.jp
+ishigaki.okinawa.jp
+ishikawa.okinawa.jp
+itoman.okinawa.jp
+izena.okinawa.jp
+kadena.okinawa.jp
+kin.okinawa.jp
+kitadaito.okinawa.jp
+kitanakagusuku.okinawa.jp
+kumejima.okinawa.jp
+kunigami.okinawa.jp
+minamidaito.okinawa.jp
+motobu.okinawa.jp
+nago.okinawa.jp
+naha.okinawa.jp
+nakagusuku.okinawa.jp
+nakijin.okinawa.jp
+nanjo.okinawa.jp
+nishihara.okinawa.jp
+ogimi.okinawa.jp
+okinawa.okinawa.jp
+onna.okinawa.jp
+shimoji.okinawa.jp
+taketomi.okinawa.jp
+tarama.okinawa.jp
+tokashiki.okinawa.jp
+tomigusuku.okinawa.jp
+tonaki.okinawa.jp
+urasoe.okinawa.jp
+uruma.okinawa.jp
+yaese.okinawa.jp
+yomitan.okinawa.jp
+yonabaru.okinawa.jp
+yonaguni.okinawa.jp
+zamami.okinawa.jp
+abeno.osaka.jp
+chihayaakasaka.osaka.jp
+chuo.osaka.jp
+daito.osaka.jp
+fujiidera.osaka.jp
+habikino.osaka.jp
+hannan.osaka.jp
+higashiosaka.osaka.jp
+higashisumiyoshi.osaka.jp
+higashiyodogawa.osaka.jp
+hirakata.osaka.jp
+ibaraki.osaka.jp
+ikeda.osaka.jp
+izumi.osaka.jp
+izumiotsu.osaka.jp
+izumisano.osaka.jp
+kadoma.osaka.jp
+kaizuka.osaka.jp
+kanan.osaka.jp
+kashiwara.osaka.jp
+katano.osaka.jp
+kawachinagano.osaka.jp
+kishiwada.osaka.jp
+kita.osaka.jp
+kumatori.osaka.jp
+matsubara.osaka.jp
+minato.osaka.jp
+minoh.osaka.jp
+misaki.osaka.jp
+moriguchi.osaka.jp
+neyagawa.osaka.jp
+nishi.osaka.jp
+nose.osaka.jp
+osakasayama.osaka.jp
+sakai.osaka.jp
+sayama.osaka.jp
+sennan.osaka.jp
+settsu.osaka.jp
+shijonawate.osaka.jp
+shimamoto.osaka.jp
+suita.osaka.jp
+tadaoka.osaka.jp
+taishi.osaka.jp
+tajiri.osaka.jp
+takaishi.osaka.jp
+takatsuki.osaka.jp
+tondabayashi.osaka.jp
+toyonaka.osaka.jp
+toyono.osaka.jp
+yao.osaka.jp
+ariake.saga.jp
+arita.saga.jp
+fukudomi.saga.jp
+genkai.saga.jp
+hamatama.saga.jp
+hizen.saga.jp
+imari.saga.jp
+kamimine.saga.jp
+kanzaki.saga.jp
+karatsu.saga.jp
+kashima.saga.jp
+kitagata.saga.jp
+kitahata.saga.jp
+kiyama.saga.jp
+kouhoku.saga.jp
+kyuragi.saga.jp
+nishiarita.saga.jp
+ogi.saga.jp
+omachi.saga.jp
+ouchi.saga.jp
+saga.saga.jp
+shiroishi.saga.jp
+taku.saga.jp
+tara.saga.jp
+tosu.saga.jp
+yoshinogari.saga.jp
+arakawa.saitama.jp
+asaka.saitama.jp
+chichibu.saitama.jp
+fujimi.saitama.jp
+fujimino.saitama.jp
+fukaya.saitama.jp
+hanno.saitama.jp
+hanyu.saitama.jp
+hasuda.saitama.jp
+hatogaya.saitama.jp
+hatoyama.saitama.jp
+hidaka.saitama.jp
+higashichichibu.saitama.jp
+higashimatsuyama.saitama.jp
+honjo.saitama.jp
+ina.saitama.jp
+iruma.saitama.jp
+iwatsuki.saitama.jp
+kamiizumi.saitama.jp
+kamikawa.saitama.jp
+kamisato.saitama.jp
+kasukabe.saitama.jp
+kawagoe.saitama.jp
+kawaguchi.saitama.jp
+kawajima.saitama.jp
+kazo.saitama.jp
+kitamoto.saitama.jp
+koshigaya.saitama.jp
+kounosu.saitama.jp
+kuki.saitama.jp
+kumagaya.saitama.jp
+matsubushi.saitama.jp
+minano.saitama.jp
+misato.saitama.jp
+miyashiro.saitama.jp
+miyoshi.saitama.jp
+moroyama.saitama.jp
+nagatoro.saitama.jp
+namegawa.saitama.jp
+niiza.saitama.jp
+ogano.saitama.jp
+ogawa.saitama.jp
+ogose.saitama.jp
+okegawa.saitama.jp
+omiya.saitama.jp
+otaki.saitama.jp
+ranzan.saitama.jp
+ryokami.saitama.jp
+saitama.saitama.jp
+sakado.saitama.jp
+satte.saitama.jp
+sayama.saitama.jp
+shiki.saitama.jp
+shiraoka.saitama.jp
+soka.saitama.jp
+sugito.saitama.jp
+toda.saitama.jp
+tokigawa.saitama.jp
+tokorozawa.saitama.jp
+tsurugashima.saitama.jp
+urawa.saitama.jp
+warabi.saitama.jp
+yashio.saitama.jp
+yokoze.saitama.jp
+yono.saitama.jp
+yorii.saitama.jp
+yoshida.saitama.jp
+yoshikawa.saitama.jp
+yoshimi.saitama.jp
+aisho.shiga.jp
+gamo.shiga.jp
+higashiomi.shiga.jp
+hikone.shiga.jp
+koka.shiga.jp
+konan.shiga.jp
+kosei.shiga.jp
+koto.shiga.jp
+kusatsu.shiga.jp
+maibara.shiga.jp
+moriyama.shiga.jp
+nagahama.shiga.jp
+nishiazai.shiga.jp
+notogawa.shiga.jp
+omihachiman.shiga.jp
+otsu.shiga.jp
+ritto.shiga.jp
+ryuoh.shiga.jp
+takashima.shiga.jp
+takatsuki.shiga.jp
+torahime.shiga.jp
+toyosato.shiga.jp
+yasu.shiga.jp
+akagi.shimane.jp
+ama.shimane.jp
+gotsu.shimane.jp
+hamada.shimane.jp
+higashiizumo.shimane.jp
+hikawa.shimane.jp
+hikimi.shimane.jp
+izumo.shimane.jp
+kakinoki.shimane.jp
+masuda.shimane.jp
+matsue.shimane.jp
+misato.shimane.jp
+nishinoshima.shimane.jp
+ohda.shimane.jp
+okinoshima.shimane.jp
+okuizumo.shimane.jp
+shimane.shimane.jp
+tamayu.shimane.jp
+tsuwano.shimane.jp
+unnan.shimane.jp
+yakumo.shimane.jp
+yasugi.shimane.jp
+yatsuka.shimane.jp
+arai.shizuoka.jp
+atami.shizuoka.jp
+fuji.shizuoka.jp
+fujieda.shizuoka.jp
+fujikawa.shizuoka.jp
+fujinomiya.shizuoka.jp
+fukuroi.shizuoka.jp
+gotemba.shizuoka.jp
+haibara.shizuoka.jp
+hamamatsu.shizuoka.jp
+higashiizu.shizuoka.jp
+ito.shizuoka.jp
+iwata.shizuoka.jp
+izu.shizuoka.jp
+izunokuni.shizuoka.jp
+kakegawa.shizuoka.jp
+kannami.shizuoka.jp
+kawanehon.shizuoka.jp
+kawazu.shizuoka.jp
+kikugawa.shizuoka.jp
+kosai.shizuoka.jp
+makinohara.shizuoka.jp
+matsuzaki.shizuoka.jp
+minamiizu.shizuoka.jp
+mishima.shizuoka.jp
+morimachi.shizuoka.jp
+nishiizu.shizuoka.jp
+numazu.shizuoka.jp
+omaezaki.shizuoka.jp
+shimada.shizuoka.jp
+shimizu.shizuoka.jp
+shimoda.shizuoka.jp
+shizuoka.shizuoka.jp
+susono.shizuoka.jp
+yaizu.shizuoka.jp
+yoshida.shizuoka.jp
+ashikaga.tochigi.jp
+bato.tochigi.jp
+haga.tochigi.jp
+ichikai.tochigi.jp
+iwafune.tochigi.jp
+kaminokawa.tochigi.jp
+kanuma.tochigi.jp
+karasuyama.tochigi.jp
+kuroiso.tochigi.jp
+mashiko.tochigi.jp
+mibu.tochigi.jp
+moka.tochigi.jp
+motegi.tochigi.jp
+nasu.tochigi.jp
+nasushiobara.tochigi.jp
+nikko.tochigi.jp
+nishikata.tochigi.jp
+nogi.tochigi.jp
+ohira.tochigi.jp
+ohtawara.tochigi.jp
+oyama.tochigi.jp
+sakura.tochigi.jp
+sano.tochigi.jp
+shimotsuke.tochigi.jp
+shioya.tochigi.jp
+takanezawa.tochigi.jp
+tochigi.tochigi.jp
+tsuga.tochigi.jp
+ujiie.tochigi.jp
+utsunomiya.tochigi.jp
+yaita.tochigi.jp
+aizumi.tokushima.jp
+anan.tokushima.jp
+ichiba.tokushima.jp
+itano.tokushima.jp
+kainan.tokushima.jp
+komatsushima.tokushima.jp
+matsushige.tokushima.jp
+mima.tokushima.jp
+minami.tokushima.jp
+miyoshi.tokushima.jp
+mugi.tokushima.jp
+nakagawa.tokushima.jp
+naruto.tokushima.jp
+sanagochi.tokushima.jp
+shishikui.tokushima.jp
+tokushima.tokushima.jp
+wajiki.tokushima.jp
+adachi.tokyo.jp
+akiruno.tokyo.jp
+akishima.tokyo.jp
+aogashima.tokyo.jp
+arakawa.tokyo.jp
+bunkyo.tokyo.jp
+chiyoda.tokyo.jp
+chofu.tokyo.jp
+chuo.tokyo.jp
+edogawa.tokyo.jp
+fuchu.tokyo.jp
+fussa.tokyo.jp
+hachijo.tokyo.jp
+hachioji.tokyo.jp
+hamura.tokyo.jp
+higashikurume.tokyo.jp
+higashimurayama.tokyo.jp
+higashiyamato.tokyo.jp
+hino.tokyo.jp
+hinode.tokyo.jp
+hinohara.tokyo.jp
+inagi.tokyo.jp
+itabashi.tokyo.jp
+katsushika.tokyo.jp
+kita.tokyo.jp
+kiyose.tokyo.jp
+kodaira.tokyo.jp
+koganei.tokyo.jp
+kokubunji.tokyo.jp
+komae.tokyo.jp
+koto.tokyo.jp
+kouzushima.tokyo.jp
+kunitachi.tokyo.jp
+machida.tokyo.jp
+meguro.tokyo.jp
+minato.tokyo.jp
+mitaka.tokyo.jp
+mizuho.tokyo.jp
+musashimurayama.tokyo.jp
+musashino.tokyo.jp
+nakano.tokyo.jp
+nerima.tokyo.jp
+ogasawara.tokyo.jp
+okutama.tokyo.jp
+ome.tokyo.jp
+oshima.tokyo.jp
+ota.tokyo.jp
+setagaya.tokyo.jp
+shibuya.tokyo.jp
+shinagawa.tokyo.jp
+shinjuku.tokyo.jp
+suginami.tokyo.jp
+sumida.tokyo.jp
+tachikawa.tokyo.jp
+taito.tokyo.jp
+tama.tokyo.jp
+toshima.tokyo.jp
+chizu.tottori.jp
+hino.tottori.jp
+kawahara.tottori.jp
+koge.tottori.jp
+kotoura.tottori.jp
+misasa.tottori.jp
+nanbu.tottori.jp
+nichinan.tottori.jp
+sakaiminato.tottori.jp
+tottori.tottori.jp
+wakasa.tottori.jp
+yazu.tottori.jp
+yonago.tottori.jp
+asahi.toyama.jp
+fuchu.toyama.jp
+fukumitsu.toyama.jp
+funahashi.toyama.jp
+himi.toyama.jp
+imizu.toyama.jp
+inami.toyama.jp
+johana.toyama.jp
+kamiichi.toyama.jp
+kurobe.toyama.jp
+nakaniikawa.toyama.jp
+namerikawa.toyama.jp
+nanto.toyama.jp
+nyuzen.toyama.jp
+oyabe.toyama.jp
+taira.toyama.jp
+takaoka.toyama.jp
+tateyama.toyama.jp
+toga.toyama.jp
+tonami.toyama.jp
+toyama.toyama.jp
+unazuki.toyama.jp
+uozu.toyama.jp
+yamada.toyama.jp
+arida.wakayama.jp
+aridagawa.wakayama.jp
+gobo.wakayama.jp
+hashimoto.wakayama.jp
+hidaka.wakayama.jp
+hirogawa.wakayama.jp
+inami.wakayama.jp
+iwade.wakayama.jp
+kainan.wakayama.jp
+kamitonda.wakayama.jp
+katsuragi.wakayama.jp
+kimino.wakayama.jp
+kinokawa.wakayama.jp
+kitayama.wakayama.jp
+koya.wakayama.jp
+koza.wakayama.jp
+kozagawa.wakayama.jp
+kudoyama.wakayama.jp
+kushimoto.wakayama.jp
+mihama.wakayama.jp
+misato.wakayama.jp
+nachikatsuura.wakayama.jp
+shingu.wakayama.jp
+shirahama.wakayama.jp
+taiji.wakayama.jp
+tanabe.wakayama.jp
+wakayama.wakayama.jp
+yuasa.wakayama.jp
+yura.wakayama.jp
+asahi.yamagata.jp
+funagata.yamagata.jp
+higashine.yamagata.jp
+iide.yamagata.jp
+kahoku.yamagata.jp
+kaminoyama.yamagata.jp
+kaneyama.yamagata.jp
+kawanishi.yamagata.jp
+mamurogawa.yamagata.jp
+mikawa.yamagata.jp
+murayama.yamagata.jp
+nagai.yamagata.jp
+nakayama.yamagata.jp
+nanyo.yamagata.jp
+nishikawa.yamagata.jp
+obanazawa.yamagata.jp
+oe.yamagata.jp
+oguni.yamagata.jp
+ohkura.yamagata.jp
+oishida.yamagata.jp
+sagae.yamagata.jp
+sakata.yamagata.jp
+sakegawa.yamagata.jp
+shinjo.yamagata.jp
+shirataka.yamagata.jp
+shonai.yamagata.jp
+takahata.yamagata.jp
+tendo.yamagata.jp
+tozawa.yamagata.jp
+tsuruoka.yamagata.jp
+yamagata.yamagata.jp
+yamanobe.yamagata.jp
+yonezawa.yamagata.jp
+yuza.yamagata.jp
+abu.yamaguchi.jp
+hagi.yamaguchi.jp
+hikari.yamaguchi.jp
+hofu.yamaguchi.jp
+iwakuni.yamaguchi.jp
+kudamatsu.yamaguchi.jp
+mitou.yamaguchi.jp
+nagato.yamaguchi.jp
+oshima.yamaguchi.jp
+shimonoseki.yamaguchi.jp
+shunan.yamaguchi.jp
+tabuse.yamaguchi.jp
+tokuyama.yamaguchi.jp
+toyota.yamaguchi.jp
+ube.yamaguchi.jp
+yuu.yamaguchi.jp
+chuo.yamanashi.jp
+doshi.yamanashi.jp
+fuefuki.yamanashi.jp
+fujikawa.yamanashi.jp
+fujikawaguchiko.yamanashi.jp
+fujiyoshida.yamanashi.jp
+hayakawa.yamanashi.jp
+hokuto.yamanashi.jp
+ichikawamisato.yamanashi.jp
+kai.yamanashi.jp
+kofu.yamanashi.jp
+koshu.yamanashi.jp
+kosuge.yamanashi.jp
+minami-alps.yamanashi.jp
+minobu.yamanashi.jp
+nakamichi.yamanashi.jp
+nanbu.yamanashi.jp
+narusawa.yamanashi.jp
+nirasaki.yamanashi.jp
+nishikatsura.yamanashi.jp
+oshino.yamanashi.jp
+otsuki.yamanashi.jp
+showa.yamanashi.jp
+tabayama.yamanashi.jp
+tsuru.yamanashi.jp
+uenohara.yamanashi.jp
+yamanakako.yamanashi.jp
+yamanashi.yamanashi.jp
+
+// ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145
+*.ke
+
+// kg : http://www.domain.kg/dmn_n.html
+kg
+org.kg
+net.kg
+com.kg
+edu.kg
+gov.kg
+mil.kg
+
+// kh : http://www.mptc.gov.kh/dns_registration.htm
+*.kh
+
+// ki : http://www.ki/dns/index.html
+ki
+edu.ki
+biz.ki
+net.ki
+org.ki
+gov.ki
+info.ki
+com.ki
+
+// km : http://en.wikipedia.org/wiki/.km
+// http://www.domaine.km/documents/charte.doc
+km
+org.km
+nom.km
+gov.km
+prd.km
+tm.km
+edu.km
+mil.km
+ass.km
+com.km
+// These are only mentioned as proposed suggestions at domaine.km, but
+// http://en.wikipedia.org/wiki/.km says they're available for registration:
+coop.km
+asso.km
+presse.km
+medecin.km
+notaires.km
+pharmaciens.km
+veterinaire.km
+gouv.km
+
+// kn : http://en.wikipedia.org/wiki/.kn
+// http://www.dot.kn/domainRules.html
+kn
+net.kn
+org.kn
+edu.kn
+gov.kn
+
+// kp : http://www.kcce.kp/en_index.php
+kp
+com.kp
+edu.kp
+gov.kp
+org.kp
+rep.kp
+tra.kp
+
+// kr : http://en.wikipedia.org/wiki/.kr
+// see also: http://domain.nida.or.kr/eng/registration.jsp
+kr
+ac.kr
+co.kr
+es.kr
+go.kr
+hs.kr
+kg.kr
+mil.kr
+ms.kr
+ne.kr
+or.kr
+pe.kr
+re.kr
+sc.kr
+// kr geographical names
+busan.kr
+chungbuk.kr
+chungnam.kr
+daegu.kr
+daejeon.kr
+gangwon.kr
+gwangju.kr
+gyeongbuk.kr
+gyeonggi.kr
+gyeongnam.kr
+incheon.kr
+jeju.kr
+jeonbuk.kr
+jeonnam.kr
+seoul.kr
+ulsan.kr
+
+// kw : http://en.wikipedia.org/wiki/.kw
+*.kw
+
+// ky : http://www.icta.ky/da_ky_reg_dom.php
+// Confirmed by registry <kysupport@perimeterusa.com> 2008-06-17
+ky
+edu.ky
+gov.ky
+com.ky
+org.ky
+net.ky
+
+// kz : http://en.wikipedia.org/wiki/.kz
+// see also: http://www.nic.kz/rules/index.jsp
+kz
+org.kz
+edu.kz
+net.kz
+gov.kz
+mil.kz
+com.kz
+
+// la : http://en.wikipedia.org/wiki/.la
+// Submitted by registry <gavin.brown@nic.la> 2008-06-10
+la
+int.la
+net.la
+info.la
+edu.la
+gov.la
+per.la
+com.la
+org.la
+
+// lb : http://en.wikipedia.org/wiki/.lb
+// Submitted by registry <randy@psg.com> 2008-06-17
+lb
+com.lb
+edu.lb
+gov.lb
+net.lb
+org.lb
+
+// lc : http://en.wikipedia.org/wiki/.lc
+// see also: http://www.nic.lc/rules.htm
+lc
+com.lc
+net.lc
+co.lc
+org.lc
+edu.lc
+gov.lc
+
+// li : http://en.wikipedia.org/wiki/.li
+li
+
+// lk : http://www.nic.lk/seclevpr.html
+lk
+gov.lk
+sch.lk
+net.lk
+int.lk
+com.lk
+org.lk
+edu.lk
+ngo.lk
+soc.lk
+web.lk
+ltd.lk
+assn.lk
+grp.lk
+hotel.lk
+ac.lk
+
+// lr : http://psg.com/dns/lr/lr.txt
+// Submitted by registry <randy@psg.com> 2008-06-17
+lr
+com.lr
+edu.lr
+gov.lr
+org.lr
+net.lr
+
+// ls : http://en.wikipedia.org/wiki/.ls
+ls
+co.ls
+org.ls
+
+// lt : http://en.wikipedia.org/wiki/.lt
+lt
+// gov.lt : http://www.gov.lt/index_en.php
+gov.lt
+
+// lu : http://www.dns.lu/en/
+lu
+
+// lv : http://www.nic.lv/DNS/En/generic.php
+lv
+com.lv
+edu.lv
+gov.lv
+org.lv
+mil.lv
+id.lv
+net.lv
+asn.lv
+conf.lv
+
+// ly : http://www.nic.ly/regulations.php
+ly
+com.ly
+net.ly
+gov.ly
+plc.ly
+edu.ly
+sch.ly
+med.ly
+org.ly
+id.ly
+
+// ma : http://en.wikipedia.org/wiki/.ma
+// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf
+ma
+co.ma
+net.ma
+gov.ma
+org.ma
+ac.ma
+press.ma
+
+// mc : http://www.nic.mc/
+mc
+tm.mc
+asso.mc
+
+// md : http://en.wikipedia.org/wiki/.md
+md
+
+// me : http://en.wikipedia.org/wiki/.me
+me
+co.me
+net.me
+org.me
+edu.me
+ac.me
+gov.me
+its.me
+priv.me
+
+// mg : http://nic.mg/nicmg/?page_id=39
+mg
+org.mg
+nom.mg
+gov.mg
+prd.mg
+tm.mg
+edu.mg
+mil.mg
+com.mg
+co.mg
+
+// mh : http://en.wikipedia.org/wiki/.mh
+mh
+
+// mil : http://en.wikipedia.org/wiki/.mil
+mil
+
+// mk : http://en.wikipedia.org/wiki/.mk
+// see also: http://dns.marnet.net.mk/postapka.php
+mk
+com.mk
+org.mk
+net.mk
+edu.mk
+gov.mk
+inf.mk
+name.mk
+
+// ml : http://www.gobin.info/domainname/ml-template.doc
+// see also: http://en.wikipedia.org/wiki/.ml
+ml
+com.ml
+edu.ml
+gouv.ml
+gov.ml
+net.ml
+org.ml
+presse.ml
+
+// mm : http://en.wikipedia.org/wiki/.mm
+*.mm
+
+// mn : http://en.wikipedia.org/wiki/.mn
+mn
+gov.mn
+edu.mn
+org.mn
+
+// mo : http://www.monic.net.mo/
+mo
+com.mo
+net.mo
+org.mo
+edu.mo
+gov.mo
+
+// mobi : http://en.wikipedia.org/wiki/.mobi
+mobi
+
+// mp : http://www.dot.mp/
+// Confirmed by registry <dcamacho@saipan.com> 2008-06-17
+mp
+
+// mq : http://en.wikipedia.org/wiki/.mq
+mq
+
+// mr : http://en.wikipedia.org/wiki/.mr
+mr
+gov.mr
+
+// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf
+ms
+com.ms
+edu.ms
+gov.ms
+net.ms
+org.ms
+
+// mt : https://www.nic.org.mt/go/policy
+// Submitted by registry <help@nic.org.mt> 2013-11-19
+mt
+com.mt
+edu.mt
+net.mt
+org.mt
+
+// mu : http://en.wikipedia.org/wiki/.mu
+mu
+com.mu
+net.mu
+org.mu
+gov.mu
+ac.mu
+co.mu
+or.mu
+
+// museum : http://about.museum/naming/
+// http://index.museum/
+museum
+academy.museum
+agriculture.museum
+air.museum
+airguard.museum
+alabama.museum
+alaska.museum
+amber.museum
+ambulance.museum
+american.museum
+americana.museum
+americanantiques.museum
+americanart.museum
+amsterdam.museum
+and.museum
+annefrank.museum
+anthro.museum
+anthropology.museum
+antiques.museum
+aquarium.museum
+arboretum.museum
+archaeological.museum
+archaeology.museum
+architecture.museum
+art.museum
+artanddesign.museum
+artcenter.museum
+artdeco.museum
+arteducation.museum
+artgallery.museum
+arts.museum
+artsandcrafts.museum
+asmatart.museum
+assassination.museum
+assisi.museum
+association.museum
+astronomy.museum
+atlanta.museum
+austin.museum
+australia.museum
+automotive.museum
+aviation.museum
+axis.museum
+badajoz.museum
+baghdad.museum
+bahn.museum
+bale.museum
+baltimore.museum
+barcelona.museum
+baseball.museum
+basel.museum
+baths.museum
+bauern.museum
+beauxarts.museum
+beeldengeluid.museum
+bellevue.museum
+bergbau.museum
+berkeley.museum
+berlin.museum
+bern.museum
+bible.museum
+bilbao.museum
+bill.museum
+birdart.museum
+birthplace.museum
+bonn.museum
+boston.museum
+botanical.museum
+botanicalgarden.museum
+botanicgarden.museum
+botany.museum
+brandywinevalley.museum
+brasil.museum
+bristol.museum
+british.museum
+britishcolumbia.museum
+broadcast.museum
+brunel.museum
+brussel.museum
+brussels.museum
+bruxelles.museum
+building.museum
+burghof.museum
+bus.museum
+bushey.museum
+cadaques.museum
+california.museum
+cambridge.museum
+can.museum
+canada.museum
+capebreton.museum
+carrier.museum
+cartoonart.museum
+casadelamoneda.museum
+castle.museum
+castres.museum
+celtic.museum
+center.museum
+chattanooga.museum
+cheltenham.museum
+chesapeakebay.museum
+chicago.museum
+children.museum
+childrens.museum
+childrensgarden.museum
+chiropractic.museum
+chocolate.museum
+christiansburg.museum
+cincinnati.museum
+cinema.museum
+circus.museum
+civilisation.museum
+civilization.museum
+civilwar.museum
+clinton.museum
+clock.museum
+coal.museum
+coastaldefence.museum
+cody.museum
+coldwar.museum
+collection.museum
+colonialwilliamsburg.museum
+coloradoplateau.museum
+columbia.museum
+columbus.museum
+communication.museum
+communications.museum
+community.museum
+computer.museum
+computerhistory.museum
+comunicações.museum
+contemporary.museum
+contemporaryart.museum
+convent.museum
+copenhagen.museum
+corporation.museum
+correios-e-telecomunicações.museum
+corvette.museum
+costume.museum
+countryestate.museum
+county.museum
+crafts.museum
+cranbrook.museum
+creation.museum
+cultural.museum
+culturalcenter.museum
+culture.museum
+cyber.museum
+cymru.museum
+dali.museum
+dallas.museum
+database.museum
+ddr.museum
+decorativearts.museum
+delaware.museum
+delmenhorst.museum
+denmark.museum
+depot.museum
+design.museum
+detroit.museum
+dinosaur.museum
+discovery.museum
+dolls.museum
+donostia.museum
+durham.museum
+eastafrica.museum
+eastcoast.museum
+education.museum
+educational.museum
+egyptian.museum
+eisenbahn.museum
+elburg.museum
+elvendrell.museum
+embroidery.museum
+encyclopedic.museum
+england.museum
+entomology.museum
+environment.museum
+environmentalconservation.museum
+epilepsy.museum
+essex.museum
+estate.museum
+ethnology.museum
+exeter.museum
+exhibition.museum
+family.museum
+farm.museum
+farmequipment.museum
+farmers.museum
+farmstead.museum
+field.museum
+figueres.museum
+filatelia.museum
+film.museum
+fineart.museum
+finearts.museum
+finland.museum
+flanders.museum
+florida.museum
+force.museum
+fortmissoula.museum
+fortworth.museum
+foundation.museum
+francaise.museum
+frankfurt.museum
+franziskaner.museum
+freemasonry.museum
+freiburg.museum
+fribourg.museum
+frog.museum
+fundacio.museum
+furniture.museum
+gallery.museum
+garden.museum
+gateway.museum
+geelvinck.museum
+gemological.museum
+geology.museum
+georgia.museum
+giessen.museum
+glas.museum
+glass.museum
+gorge.museum
+grandrapids.museum
+graz.museum
+guernsey.museum
+halloffame.museum
+hamburg.museum
+handson.museum
+harvestcelebration.museum
+hawaii.museum
+health.museum
+heimatunduhren.museum
+hellas.museum
+helsinki.museum
+hembygdsforbund.museum
+heritage.museum
+histoire.museum
+historical.museum
+historicalsociety.museum
+historichouses.museum
+historisch.museum
+historisches.museum
+history.museum
+historyofscience.museum
+horology.museum
+house.museum
+humanities.museum
+illustration.museum
+imageandsound.museum
+indian.museum
+indiana.museum
+indianapolis.museum
+indianmarket.museum
+intelligence.museum
+interactive.museum
+iraq.museum
+iron.museum
+isleofman.museum
+jamison.museum
+jefferson.museum
+jerusalem.museum
+jewelry.museum
+jewish.museum
+jewishart.museum
+jfk.museum
+journalism.museum
+judaica.museum
+judygarland.museum
+juedisches.museum
+juif.museum
+karate.museum
+karikatur.museum
+kids.museum
+koebenhavn.museum
+koeln.museum
+kunst.museum
+kunstsammlung.museum
+kunstunddesign.museum
+labor.museum
+labour.museum
+lajolla.museum
+lancashire.museum
+landes.museum
+lans.museum
+läns.museum
+larsson.museum
+lewismiller.museum
+lincoln.museum
+linz.museum
+living.museum
+livinghistory.museum
+localhistory.museum
+london.museum
+losangeles.museum
+louvre.museum
+loyalist.museum
+lucerne.museum
+luxembourg.museum
+luzern.museum
+mad.museum
+madrid.museum
+mallorca.museum
+manchester.museum
+mansion.museum
+mansions.museum
+manx.museum
+marburg.museum
+maritime.museum
+maritimo.museum
+maryland.museum
+marylhurst.museum
+media.museum
+medical.museum
+medizinhistorisches.museum
+meeres.museum
+memorial.museum
+mesaverde.museum
+michigan.museum
+midatlantic.museum
+military.museum
+mill.museum
+miners.museum
+mining.museum
+minnesota.museum
+missile.museum
+missoula.museum
+modern.museum
+moma.museum
+money.museum
+monmouth.museum
+monticello.museum
+montreal.museum
+moscow.museum
+motorcycle.museum
+muenchen.museum
+muenster.museum
+mulhouse.museum
+muncie.museum
+museet.museum
+museumcenter.museum
+museumvereniging.museum
+music.museum
+national.museum
+nationalfirearms.museum
+nationalheritage.museum
+nativeamerican.museum
+naturalhistory.museum
+naturalhistorymuseum.museum
+naturalsciences.museum
+nature.museum
+naturhistorisches.museum
+natuurwetenschappen.museum
+naumburg.museum
+naval.museum
+nebraska.museum
+neues.museum
+newhampshire.museum
+newjersey.museum
+newmexico.museum
+newport.museum
+newspaper.museum
+newyork.museum
+niepce.museum
+norfolk.museum
+north.museum
+nrw.museum
+nuernberg.museum
+nuremberg.museum
+nyc.museum
+nyny.museum
+oceanographic.museum
+oceanographique.museum
+omaha.museum
+online.museum
+ontario.museum
+openair.museum
+oregon.museum
+oregontrail.museum
+otago.museum
+oxford.museum
+pacific.museum
+paderborn.museum
+palace.museum
+paleo.museum
+palmsprings.museum
+panama.museum
+paris.museum
+pasadena.museum
+pharmacy.museum
+philadelphia.museum
+philadelphiaarea.museum
+philately.museum
+phoenix.museum
+photography.museum
+pilots.museum
+pittsburgh.museum
+planetarium.museum
+plantation.museum
+plants.museum
+plaza.museum
+portal.museum
+portland.museum
+portlligat.museum
+posts-and-telecommunications.museum
+preservation.museum
+presidio.museum
+press.museum
+project.museum
+public.museum
+pubol.museum
+quebec.museum
+railroad.museum
+railway.museum
+research.museum
+resistance.museum
+riodejaneiro.museum
+rochester.museum
+rockart.museum
+roma.museum
+russia.museum
+saintlouis.museum
+salem.museum
+salvadordali.museum
+salzburg.museum
+sandiego.museum
+sanfrancisco.museum
+santabarbara.museum
+santacruz.museum
+santafe.museum
+saskatchewan.museum
+satx.museum
+savannahga.museum
+schlesisches.museum
+schoenbrunn.museum
+schokoladen.museum
+school.museum
+schweiz.museum
+science.museum
+scienceandhistory.museum
+scienceandindustry.museum
+sciencecenter.museum
+sciencecenters.museum
+science-fiction.museum
+sciencehistory.museum
+sciences.museum
+sciencesnaturelles.museum
+scotland.museum
+seaport.museum
+settlement.museum
+settlers.museum
+shell.museum
+sherbrooke.museum
+sibenik.museum
+silk.museum
+ski.museum
+skole.museum
+society.museum
+sologne.museum
+soundandvision.museum
+southcarolina.museum
+southwest.museum
+space.museum
+spy.museum
+square.museum
+stadt.museum
+stalbans.museum
+starnberg.museum
+state.museum
+stateofdelaware.museum
+station.museum
+steam.museum
+steiermark.museum
+stjohn.museum
+stockholm.museum
+stpetersburg.museum
+stuttgart.museum
+suisse.museum
+surgeonshall.museum
+surrey.museum
+svizzera.museum
+sweden.museum
+sydney.museum
+tank.museum
+tcm.museum
+technology.museum
+telekommunikation.museum
+television.museum
+texas.museum
+textile.museum
+theater.museum
+time.museum
+timekeeping.museum
+topology.museum
+torino.museum
+touch.museum
+town.museum
+transport.museum
+tree.museum
+trolley.museum
+trust.museum
+trustee.museum
+uhren.museum
+ulm.museum
+undersea.museum
+university.museum
+usa.museum
+usantiques.museum
+usarts.museum
+uscountryestate.museum
+usculture.museum
+usdecorativearts.museum
+usgarden.museum
+ushistory.museum
+ushuaia.museum
+uslivinghistory.museum
+utah.museum
+uvic.museum
+valley.museum
+vantaa.museum
+versailles.museum
+viking.museum
+village.museum
+virginia.museum
+virtual.museum
+virtuel.museum
+vlaanderen.museum
+volkenkunde.museum
+wales.museum
+wallonie.museum
+war.museum
+washingtondc.museum
+watchandclock.museum
+watch-and-clock.museum
+western.museum
+westfalen.museum
+whaling.museum
+wildlife.museum
+williamsburg.museum
+windmill.museum
+workshop.museum
+york.museum
+yorkshire.museum
+yosemite.museum
+youth.museum
+zoological.museum
+zoology.museum
+ירושלים.museum
+иком.museum
+
+// mv : http://en.wikipedia.org/wiki/.mv
+// "mv" included because, contra Wikipedia, google.mv exists.
+mv
+aero.mv
+biz.mv
+com.mv
+coop.mv
+edu.mv
+gov.mv
+info.mv
+int.mv
+mil.mv
+museum.mv
+name.mv
+net.mv
+org.mv
+pro.mv
+
+// mw : http://www.registrar.mw/
+mw
+ac.mw
+biz.mw
+co.mw
+com.mw
+coop.mw
+edu.mw
+gov.mw
+int.mw
+museum.mw
+net.mw
+org.mw
+
+// mx : http://www.nic.mx/
+// Submitted by registry <farias@nic.mx> 2008-06-19
+mx
+com.mx
+org.mx
+gob.mx
+edu.mx
+net.mx
+
+// my : http://www.mynic.net.my/
+my
+com.my
+net.my
+org.my
+gov.my
+edu.my
+mil.my
+name.my
+
+// mz : http://www.gobin.info/domainname/mz-template.doc
+*.mz
+!teledata.mz
+
+// na : http://www.na-nic.com.na/
+// http://www.info.na/domain/
+na
+info.na
+pro.na
+name.na
+school.na
+or.na
+dr.na
+us.na
+mx.na
+ca.na
+in.na
+cc.na
+tv.na
+ws.na
+mobi.na
+co.na
+com.na
+org.na
+
+// name : has 2nd-level tlds, but there's no list of them
+name
+
+// nc : http://www.cctld.nc/
+nc
+asso.nc
+
+// ne : http://en.wikipedia.org/wiki/.ne
+ne
+
+// net : http://en.wikipedia.org/wiki/.net
+net
+
+// nf : http://en.wikipedia.org/wiki/.nf
+nf
+com.nf
+net.nf
+per.nf
+rec.nf
+web.nf
+arts.nf
+firm.nf
+info.nf
+other.nf
+store.nf
+
+// ng : http://psg.com/dns/ng/
+ng
+com.ng
+edu.ng
+name.ng
+net.ng
+org.ng
+sch.ng
+gov.ng
+mil.ng
+mobi.ng
+
+// ni : http://www.nic.ni/
+com.ni
+gob.ni
+edu.ni
+org.ni
+nom.ni
+net.ni
+mil.ni
+co.ni
+biz.ni
+web.ni
+int.ni
+ac.ni
+in.ni
+info.ni
+
+// nl : http://en.wikipedia.org/wiki/.nl
+//      https://www.sidn.nl/
+//      ccTLD for the Netherlands
+nl
+
+// BV.nl will be a registry for dutch BV's (besloten vennootschap)
+bv.nl
+
+// no : http://www.norid.no/regelverk/index.en.html
+// The Norwegian registry has declined to notify us of updates. The web pages
+// referenced below are the official source of the data. There is also an
+// announce mailing list:
+// https://postlister.uninett.no/sympa/info/norid-diskusjon
+no
+// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html
+fhs.no
+vgs.no
+fylkesbibl.no
+folkebibl.no
+museum.no
+idrett.no
+priv.no
+// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html
+mil.no
+stat.no
+dep.no
+kommune.no
+herad.no
+// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html
+// counties
+aa.no
+ah.no
+bu.no
+fm.no
+hl.no
+hm.no
+jan-mayen.no
+mr.no
+nl.no
+nt.no
+of.no
+ol.no
+oslo.no
+rl.no
+sf.no
+st.no
+svalbard.no
+tm.no
+tr.no
+va.no
+vf.no
+// primary and lower secondary schools per county
+gs.aa.no
+gs.ah.no
+gs.bu.no
+gs.fm.no
+gs.hl.no
+gs.hm.no
+gs.jan-mayen.no
+gs.mr.no
+gs.nl.no
+gs.nt.no
+gs.of.no
+gs.ol.no
+gs.oslo.no
+gs.rl.no
+gs.sf.no
+gs.st.no
+gs.svalbard.no
+gs.tm.no
+gs.tr.no
+gs.va.no
+gs.vf.no
+// cities
+akrehamn.no
+åkrehamn.no
+algard.no
+ålgård.no
+arna.no
+brumunddal.no
+bryne.no
+bronnoysund.no
+brønnøysund.no
+drobak.no
+drøbak.no
+egersund.no
+fetsund.no
+floro.no
+florø.no
+fredrikstad.no
+hokksund.no
+honefoss.no
+hønefoss.no
+jessheim.no
+jorpeland.no
+jørpeland.no
+kirkenes.no
+kopervik.no
+krokstadelva.no
+langevag.no
+langevåg.no
+leirvik.no
+mjondalen.no
+mjøndalen.no
+mo-i-rana.no
+mosjoen.no
+mosjøen.no
+nesoddtangen.no
+orkanger.no
+osoyro.no
+osøyro.no
+raholt.no
+råholt.no
+sandnessjoen.no
+sandnessjøen.no
+skedsmokorset.no
+slattum.no
+spjelkavik.no
+stathelle.no
+stavern.no
+stjordalshalsen.no
+stjørdalshalsen.no
+tananger.no
+tranby.no
+vossevangen.no
+// communities
+afjord.no
+åfjord.no
+agdenes.no
+al.no
+ål.no
+alesund.no
+ålesund.no
+alstahaug.no
+alta.no
+áltá.no
+alaheadju.no
+álaheadju.no
+alvdal.no
+amli.no
+åmli.no
+amot.no
+åmot.no
+andebu.no
+andoy.no
+andøy.no
+andasuolo.no
+ardal.no
+årdal.no
+aremark.no
+arendal.no
+ås.no
+aseral.no
+åseral.no
+asker.no
+askim.no
+askvoll.no
+askoy.no
+askøy.no
+asnes.no
+åsnes.no
+audnedaln.no
+aukra.no
+aure.no
+aurland.no
+aurskog-holand.no
+aurskog-høland.no
+austevoll.no
+austrheim.no
+averoy.no
+averøy.no
+balestrand.no
+ballangen.no
+balat.no
+bálát.no
+balsfjord.no
+bahccavuotna.no
+báhccavuotna.no
+bamble.no
+bardu.no
+beardu.no
+beiarn.no
+bajddar.no
+bájddar.no
+baidar.no
+báidár.no
+berg.no
+bergen.no
+berlevag.no
+berlevåg.no
+bearalvahki.no
+bearalváhki.no
+bindal.no
+birkenes.no
+bjarkoy.no
+bjarkøy.no
+bjerkreim.no
+bjugn.no
+bodo.no
+bodø.no
+badaddja.no
+bådåddjå.no
+budejju.no
+bokn.no
+bremanger.no
+bronnoy.no
+brønnøy.no
+bygland.no
+bykle.no
+barum.no
+bærum.no
+bo.telemark.no
+bø.telemark.no
+bo.nordland.no
+bø.nordland.no
+bievat.no
+bievát.no
+bomlo.no
+bømlo.no
+batsfjord.no
+båtsfjord.no
+bahcavuotna.no
+báhcavuotna.no
+dovre.no
+drammen.no
+drangedal.no
+dyroy.no
+dyrøy.no
+donna.no
+dønna.no
+eid.no
+eidfjord.no
+eidsberg.no
+eidskog.no
+eidsvoll.no
+eigersund.no
+elverum.no
+enebakk.no
+engerdal.no
+etne.no
+etnedal.no
+evenes.no
+evenassi.no
+evenášši.no
+evje-og-hornnes.no
+farsund.no
+fauske.no
+fuossko.no
+fuoisku.no
+fedje.no
+fet.no
+finnoy.no
+finnøy.no
+fitjar.no
+fjaler.no
+fjell.no
+flakstad.no
+flatanger.no
+flekkefjord.no
+flesberg.no
+flora.no
+fla.no
+flå.no
+folldal.no
+forsand.no
+fosnes.no
+frei.no
+frogn.no
+froland.no
+frosta.no
+frana.no
+fræna.no
+froya.no
+frøya.no
+fusa.no
+fyresdal.no
+forde.no
+førde.no
+gamvik.no
+gangaviika.no
+gáŋgaviika.no
+gaular.no
+gausdal.no
+gildeskal.no
+gildeskål.no
+giske.no
+gjemnes.no
+gjerdrum.no
+gjerstad.no
+gjesdal.no
+gjovik.no
+gjøvik.no
+gloppen.no
+gol.no
+gran.no
+grane.no
+granvin.no
+gratangen.no
+grimstad.no
+grong.no
+kraanghke.no
+kråanghke.no
+grue.no
+gulen.no
+hadsel.no
+halden.no
+halsa.no
+hamar.no
+hamaroy.no
+habmer.no
+hábmer.no
+hapmir.no
+hápmir.no
+hammerfest.no
+hammarfeasta.no
+hámmárfeasta.no
+haram.no
+hareid.no
+harstad.no
+hasvik.no
+aknoluokta.no
+ákŋoluokta.no
+hattfjelldal.no
+aarborte.no
+haugesund.no
+hemne.no
+hemnes.no
+hemsedal.no
+heroy.more-og-romsdal.no
+herøy.møre-og-romsdal.no
+heroy.nordland.no
+herøy.nordland.no
+hitra.no
+hjartdal.no
+hjelmeland.no
+hobol.no
+hobøl.no
+hof.no
+hol.no
+hole.no
+holmestrand.no
+holtalen.no
+holtålen.no
+hornindal.no
+horten.no
+hurdal.no
+hurum.no
+hvaler.no
+hyllestad.no
+hagebostad.no
+hægebostad.no
+hoyanger.no
+høyanger.no
+hoylandet.no
+høylandet.no
+ha.no
+hå.no
+ibestad.no
+inderoy.no
+inderøy.no
+iveland.no
+jevnaker.no
+jondal.no
+jolster.no
+jølster.no
+karasjok.no
+karasjohka.no
+kárášjohka.no
+karlsoy.no
+galsa.no
+gálsá.no
+karmoy.no
+karmøy.no
+kautokeino.no
+guovdageaidnu.no
+klepp.no
+klabu.no
+klæbu.no
+kongsberg.no
+kongsvinger.no
+kragero.no
+kragerø.no
+kristiansand.no
+kristiansund.no
+krodsherad.no
+krødsherad.no
+kvalsund.no
+rahkkeravju.no
+ráhkkerávju.no
+kvam.no
+kvinesdal.no
+kvinnherad.no
+kviteseid.no
+kvitsoy.no
+kvitsøy.no
+kvafjord.no
+kvæfjord.no
+giehtavuoatna.no
+kvanangen.no
+kvænangen.no
+navuotna.no
+návuotna.no
+kafjord.no
+kåfjord.no
+gaivuotna.no
+gáivuotna.no
+larvik.no
+lavangen.no
+lavagis.no
+loabat.no
+loabát.no
+lebesby.no
+davvesiida.no
+leikanger.no
+leirfjord.no
+leka.no
+leksvik.no
+lenvik.no
+leangaviika.no
+leaŋgaviika.no
+lesja.no
+levanger.no
+lier.no
+lierne.no
+lillehammer.no
+lillesand.no
+lindesnes.no
+lindas.no
+lindås.no
+lom.no
+loppa.no
+lahppi.no
+láhppi.no
+lund.no
+lunner.no
+luroy.no
+lurøy.no
+luster.no
+lyngdal.no
+lyngen.no
+ivgu.no
+lardal.no
+lerdal.no
+lærdal.no
+lodingen.no
+lødingen.no
+lorenskog.no
+lørenskog.no
+loten.no
+løten.no
+malvik.no
+masoy.no
+måsøy.no
+muosat.no
+muosát.no
+mandal.no
+marker.no
+marnardal.no
+masfjorden.no
+meland.no
+meldal.no
+melhus.no
+meloy.no
+meløy.no
+meraker.no
+meråker.no
+moareke.no
+moåreke.no
+midsund.no
+midtre-gauldal.no
+modalen.no
+modum.no
+molde.no
+moskenes.no
+moss.no
+mosvik.no
+malselv.no
+målselv.no
+malatvuopmi.no
+málatvuopmi.no
+namdalseid.no
+aejrie.no
+namsos.no
+namsskogan.no
+naamesjevuemie.no
+nååmesjevuemie.no
+laakesvuemie.no
+nannestad.no
+narvik.no
+narviika.no
+naustdal.no
+nedre-eiker.no
+nes.akershus.no
+nes.buskerud.no
+nesna.no
+nesodden.no
+nesseby.no
+unjarga.no
+unjárga.no
+nesset.no
+nissedal.no
+nittedal.no
+nord-aurdal.no
+nord-fron.no
+nord-odal.no
+norddal.no
+nordkapp.no
+davvenjarga.no
+davvenjárga.no
+nordre-land.no
+nordreisa.no
+raisa.no
+ráisa.no
+nore-og-uvdal.no
+notodden.no
+naroy.no
+nærøy.no
+notteroy.no
+nøtterøy.no
+odda.no
+oksnes.no
+øksnes.no
+oppdal.no
+oppegard.no
+oppegård.no
+orkdal.no
+orland.no
+ørland.no
+orskog.no
+ørskog.no
+orsta.no
+ørsta.no
+os.hedmark.no
+os.hordaland.no
+osen.no
+osteroy.no
+osterøy.no
+ostre-toten.no
+østre-toten.no
+overhalla.no
+ovre-eiker.no
+øvre-eiker.no
+oyer.no
+øyer.no
+oygarden.no
+øygarden.no
+oystre-slidre.no
+øystre-slidre.no
+porsanger.no
+porsangu.no
+porsáŋgu.no
+porsgrunn.no
+radoy.no
+radøy.no
+rakkestad.no
+rana.no
+ruovat.no
+randaberg.no
+rauma.no
+rendalen.no
+rennebu.no
+rennesoy.no
+rennesøy.no
+rindal.no
+ringebu.no
+ringerike.no
+ringsaker.no
+rissa.no
+risor.no
+risør.no
+roan.no
+rollag.no
+rygge.no
+ralingen.no
+rælingen.no
+rodoy.no
+rødøy.no
+romskog.no
+rømskog.no
+roros.no
+røros.no
+rost.no
+røst.no
+royken.no
+røyken.no
+royrvik.no
+røyrvik.no
+rade.no
+råde.no
+salangen.no
+siellak.no
+saltdal.no
+salat.no
+sálát.no
+sálat.no
+samnanger.no
+sande.more-og-romsdal.no
+sande.møre-og-romsdal.no
+sande.vestfold.no
+sandefjord.no
+sandnes.no
+sandoy.no
+sandøy.no
+sarpsborg.no
+sauda.no
+sauherad.no
+sel.no
+selbu.no
+selje.no
+seljord.no
+sigdal.no
+siljan.no
+sirdal.no
+skaun.no
+skedsmo.no
+ski.no
+skien.no
+skiptvet.no
+skjervoy.no
+skjervøy.no
+skierva.no
+skiervá.no
+skjak.no
+skjåk.no
+skodje.no
+skanland.no
+skånland.no
+skanit.no
+skánit.no
+smola.no
+smøla.no
+snillfjord.no
+snasa.no
+snåsa.no
+snoasa.no
+snaase.no
+snåase.no
+sogndal.no
+sokndal.no
+sola.no
+solund.no
+songdalen.no
+sortland.no
+spydeberg.no
+stange.no
+stavanger.no
+steigen.no
+steinkjer.no
+stjordal.no
+stjørdal.no
+stokke.no
+stor-elvdal.no
+stord.no
+stordal.no
+storfjord.no
+omasvuotna.no
+strand.no
+stranda.no
+stryn.no
+sula.no
+suldal.no
+sund.no
+sunndal.no
+surnadal.no
+sveio.no
+svelvik.no
+sykkylven.no
+sogne.no
+søgne.no
+somna.no
+sømna.no
+sondre-land.no
+søndre-land.no
+sor-aurdal.no
+sør-aurdal.no
+sor-fron.no
+sør-fron.no
+sor-odal.no
+sør-odal.no
+sor-varanger.no
+sør-varanger.no
+matta-varjjat.no
+mátta-várjjat.no
+sorfold.no
+sørfold.no
+sorreisa.no
+sørreisa.no
+sorum.no
+sørum.no
+tana.no
+deatnu.no
+time.no
+tingvoll.no
+tinn.no
+tjeldsund.no
+dielddanuorri.no
+tjome.no
+tjøme.no
+tokke.no
+tolga.no
+torsken.no
+tranoy.no
+tranøy.no
+tromso.no
+tromsø.no
+tromsa.no
+romsa.no
+trondheim.no
+troandin.no
+trysil.no
+trana.no
+træna.no
+trogstad.no
+trøgstad.no
+tvedestrand.no
+tydal.no
+tynset.no
+tysfjord.no
+divtasvuodna.no
+divttasvuotna.no
+tysnes.no
+tysvar.no
+tysvær.no
+tonsberg.no
+tønsberg.no
+ullensaker.no
+ullensvang.no
+ulvik.no
+utsira.no
+vadso.no
+vadsø.no
+cahcesuolo.no
+čáhcesuolo.no
+vaksdal.no
+valle.no
+vang.no
+vanylven.no
+vardo.no
+vardø.no
+varggat.no
+várggát.no
+vefsn.no
+vaapste.no
+vega.no
+vegarshei.no
+vegårshei.no
+vennesla.no
+verdal.no
+verran.no
+vestby.no
+vestnes.no
+vestre-slidre.no
+vestre-toten.no
+vestvagoy.no
+vestvågøy.no
+vevelstad.no
+vik.no
+vikna.no
+vindafjord.no
+volda.no
+voss.no
+varoy.no
+værøy.no
+vagan.no
+vågan.no
+voagat.no
+vagsoy.no
+vågsøy.no
+vaga.no
+vågå.no
+valer.ostfold.no
+våler.østfold.no
+valer.hedmark.no
+våler.hedmark.no
+
+// np : http://www.mos.com.np/register.html
+*.np
+
+// nr : http://cenpac.net.nr/dns/index.html
+// Confirmed by registry <technician@cenpac.net.nr> 2008-06-17
+nr
+biz.nr
+info.nr
+gov.nr
+edu.nr
+org.nr
+net.nr
+com.nr
+
+// nu : http://en.wikipedia.org/wiki/.nu
+nu
+
+// nz : http://en.wikipedia.org/wiki/.nz
+// Confirmed by registry <jay@nzrs.net.nz> 2014-05-19
+nz
+ac.nz
+co.nz
+cri.nz
+geek.nz
+gen.nz
+govt.nz
+health.nz
+iwi.nz
+kiwi.nz
+maori.nz
+mil.nz
+māori.nz
+net.nz
+org.nz
+parliament.nz
+school.nz
+
+// om : http://en.wikipedia.org/wiki/.om
+om
+co.om
+com.om
+edu.om
+gov.om
+med.om
+museum.om
+net.om
+org.om
+pro.om
+
+// org : http://en.wikipedia.org/wiki/.org
+org
+
+// pa : http://www.nic.pa/
+// Some additional second level "domains" resolve directly as hostnames, such as
+// pannet.pa, so we add a rule for "pa".
+pa
+ac.pa
+gob.pa
+com.pa
+org.pa
+sld.pa
+edu.pa
+net.pa
+ing.pa
+abo.pa
+med.pa
+nom.pa
+
+// pe : https://www.nic.pe/InformeFinalComision.pdf
+pe
+edu.pe
+gob.pe
+nom.pe
+mil.pe
+org.pe
+com.pe
+net.pe
+
+// pf : http://www.gobin.info/domainname/formulaire-pf.pdf
+pf
+com.pf
+org.pf
+edu.pf
+
+// pg : http://en.wikipedia.org/wiki/.pg
+*.pg
+
+// ph : http://www.domains.ph/FAQ2.asp
+// Submitted by registry <jed@email.com.ph> 2008-06-13
+ph
+com.ph
+net.ph
+org.ph
+gov.ph
+edu.ph
+ngo.ph
+mil.ph
+i.ph
+
+// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK
+pk
+com.pk
+net.pk
+edu.pk
+org.pk
+fam.pk
+biz.pk
+web.pk
+gov.pk
+gob.pk
+gok.pk
+gon.pk
+gop.pk
+gos.pk
+info.pk
+
+// pl http://www.dns.pl/english/index.html
+// updated by .PL registry on 2015-04-28
+pl
+com.pl
+net.pl
+org.pl
+// pl functional domains (http://www.dns.pl/english/index.html)
+aid.pl
+agro.pl
+atm.pl
+auto.pl
+biz.pl
+edu.pl
+gmina.pl
+gsm.pl
+info.pl
+mail.pl
+miasta.pl
+media.pl
+mil.pl
+nieruchomosci.pl
+nom.pl
+pc.pl
+powiat.pl
+priv.pl
+realestate.pl
+rel.pl
+sex.pl
+shop.pl
+sklep.pl
+sos.pl
+szkola.pl
+targi.pl
+tm.pl
+tourism.pl
+travel.pl
+turystyka.pl
+// Government domains
+gov.pl
+ap.gov.pl
+ic.gov.pl
+is.gov.pl
+us.gov.pl
+kmpsp.gov.pl
+kppsp.gov.pl
+kwpsp.gov.pl
+psp.gov.pl
+wskr.gov.pl
+kwp.gov.pl
+mw.gov.pl
+ug.gov.pl
+um.gov.pl
+umig.gov.pl
+ugim.gov.pl
+upow.gov.pl
+uw.gov.pl
+starostwo.gov.pl
+pa.gov.pl
+po.gov.pl
+psse.gov.pl
+pup.gov.pl
+rzgw.gov.pl
+sa.gov.pl
+so.gov.pl
+sr.gov.pl
+wsa.gov.pl
+sko.gov.pl
+uzs.gov.pl
+wiih.gov.pl
+winb.gov.pl
+pinb.gov.pl
+wios.gov.pl
+witd.gov.pl
+wzmiuw.gov.pl
+piw.gov.pl
+wiw.gov.pl
+griw.gov.pl
+wif.gov.pl
+oum.gov.pl
+sdn.gov.pl
+zp.gov.pl
+uppo.gov.pl
+mup.gov.pl
+wuoz.gov.pl
+konsulat.gov.pl
+oirm.gov.pl
+// pl regional domains (http://www.dns.pl/english/index.html)
+augustow.pl
+babia-gora.pl
+bedzin.pl
+beskidy.pl
+bialowieza.pl
+bialystok.pl
+bielawa.pl
+bieszczady.pl
+boleslawiec.pl
+bydgoszcz.pl
+bytom.pl
+cieszyn.pl
+czeladz.pl
+czest.pl
+dlugoleka.pl
+elblag.pl
+elk.pl
+glogow.pl
+gniezno.pl
+gorlice.pl
+grajewo.pl
+ilawa.pl
+jaworzno.pl
+jelenia-gora.pl
+jgora.pl
+kalisz.pl
+kazimierz-dolny.pl
+karpacz.pl
+kartuzy.pl
+kaszuby.pl
+katowice.pl
+kepno.pl
+ketrzyn.pl
+klodzko.pl
+kobierzyce.pl
+kolobrzeg.pl
+konin.pl
+konskowola.pl
+kutno.pl
+lapy.pl
+lebork.pl
+legnica.pl
+lezajsk.pl
+limanowa.pl
+lomza.pl
+lowicz.pl
+lubin.pl
+lukow.pl
+malbork.pl
+malopolska.pl
+mazowsze.pl
+mazury.pl
+mielec.pl
+mielno.pl
+mragowo.pl
+naklo.pl
+nowaruda.pl
+nysa.pl
+olawa.pl
+olecko.pl
+olkusz.pl
+olsztyn.pl
+opoczno.pl
+opole.pl
+ostroda.pl
+ostroleka.pl
+ostrowiec.pl
+ostrowwlkp.pl
+pila.pl
+pisz.pl
+podhale.pl
+podlasie.pl
+polkowice.pl
+pomorze.pl
+pomorskie.pl
+prochowice.pl
+pruszkow.pl
+przeworsk.pl
+pulawy.pl
+radom.pl
+rawa-maz.pl
+rybnik.pl
+rzeszow.pl
+sanok.pl
+sejny.pl
+slask.pl
+slupsk.pl
+sosnowiec.pl
+stalowa-wola.pl
+skoczow.pl
+starachowice.pl
+stargard.pl
+suwalki.pl
+swidnica.pl
+swiebodzin.pl
+swinoujscie.pl
+szczecin.pl
+szczytno.pl
+tarnobrzeg.pl
+tgory.pl
+turek.pl
+tychy.pl
+ustka.pl
+walbrzych.pl
+warmia.pl
+warszawa.pl
+waw.pl
+wegrow.pl
+wielun.pl
+wlocl.pl
+wloclawek.pl
+wodzislaw.pl
+wolomin.pl
+wroclaw.pl
+zachpomor.pl
+zagan.pl
+zarow.pl
+zgora.pl
+zgorzelec.pl
+
+// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+pm
+
+// pn : http://www.government.pn/PnRegistry/policies.htm
+pn
+gov.pn
+co.pn
+org.pn
+edu.pn
+net.pn
+
+// post : http://en.wikipedia.org/wiki/.post
+post
+
+// pr : http://www.nic.pr/index.asp?f=1
+pr
+com.pr
+net.pr
+org.pr
+gov.pr
+edu.pr
+isla.pr
+pro.pr
+biz.pr
+info.pr
+name.pr
+// these aren't mentioned on nic.pr, but on http://en.wikipedia.org/wiki/.pr
+est.pr
+prof.pr
+ac.pr
+
+// pro : http://www.nic.pro/support_faq.htm
+pro
+aca.pro
+bar.pro
+cpa.pro
+jur.pro
+law.pro
+med.pro
+eng.pro
+
+// ps : http://en.wikipedia.org/wiki/.ps
+// http://www.nic.ps/registration/policy.html#reg
+ps
+edu.ps
+gov.ps
+sec.ps
+plo.ps
+com.ps
+org.ps
+net.ps
+
+// pt : http://online.dns.pt/dns/start_dns
+pt
+net.pt
+gov.pt
+org.pt
+edu.pt
+int.pt
+publ.pt
+com.pt
+nome.pt
+
+// pw : http://en.wikipedia.org/wiki/.pw
+pw
+co.pw
+ne.pw
+or.pw
+ed.pw
+go.pw
+belau.pw
+
+// py : http://www.nic.py/pautas.html#seccion_9
+// Confirmed by registry 2012-10-03
+py
+com.py
+coop.py
+edu.py
+gov.py
+mil.py
+net.py
+org.py
+
+// qa : http://domains.qa/en/
+qa
+com.qa
+edu.qa
+gov.qa
+mil.qa
+name.qa
+net.qa
+org.qa
+sch.qa
+
+// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs
+re
+com.re
+asso.re
+nom.re
+
+// ro : http://www.rotld.ro/
+ro
+com.ro
+org.ro
+tm.ro
+nt.ro
+nom.ro
+info.ro
+rec.ro
+arts.ro
+firm.ro
+store.ro
+www.ro
+
+// rs : http://en.wikipedia.org/wiki/.rs
+rs
+co.rs
+org.rs
+edu.rs
+ac.rs
+gov.rs
+in.rs
+
+// ru : http://www.cctld.ru/ru/docs/aktiv_8.php
+// Industry domains
+ru
+ac.ru
+com.ru
+edu.ru
+int.ru
+net.ru
+org.ru
+pp.ru
+// Geographical domains
+adygeya.ru
+altai.ru
+amur.ru
+arkhangelsk.ru
+astrakhan.ru
+bashkiria.ru
+belgorod.ru
+bir.ru
+bryansk.ru
+buryatia.ru
+cbg.ru
+chel.ru
+chelyabinsk.ru
+chita.ru
+chukotka.ru
+chuvashia.ru
+dagestan.ru
+dudinka.ru
+e-burg.ru
+grozny.ru
+irkutsk.ru
+ivanovo.ru
+izhevsk.ru
+jar.ru
+joshkar-ola.ru
+kalmykia.ru
+kaluga.ru
+kamchatka.ru
+karelia.ru
+kazan.ru
+kchr.ru
+kemerovo.ru
+khabarovsk.ru
+khakassia.ru
+khv.ru
+kirov.ru
+koenig.ru
+komi.ru
+kostroma.ru
+krasnoyarsk.ru
+kuban.ru
+kurgan.ru
+kursk.ru
+lipetsk.ru
+magadan.ru
+mari.ru
+mari-el.ru
+marine.ru
+mordovia.ru
+// mosreg.ru  Bug 1090800 - removed at request of Aleksey Konstantinov <konstantinovav@mosreg.ru>
+msk.ru
+murmansk.ru
+nalchik.ru
+nnov.ru
+nov.ru
+novosibirsk.ru
+nsk.ru
+omsk.ru
+orenburg.ru
+oryol.ru
+palana.ru
+penza.ru
+perm.ru
+ptz.ru
+rnd.ru
+ryazan.ru
+sakhalin.ru
+samara.ru
+saratov.ru
+simbirsk.ru
+smolensk.ru
+spb.ru
+stavropol.ru
+stv.ru
+surgut.ru
+tambov.ru
+tatarstan.ru
+tom.ru
+tomsk.ru
+tsaritsyn.ru
+tsk.ru
+tula.ru
+tuva.ru
+tver.ru
+tyumen.ru
+udm.ru
+udmurtia.ru
+ulan-ude.ru
+vladikavkaz.ru
+vladimir.ru
+vladivostok.ru
+volgograd.ru
+vologda.ru
+voronezh.ru
+vrn.ru
+vyatka.ru
+yakutia.ru
+yamal.ru
+yaroslavl.ru
+yekaterinburg.ru
+yuzhno-sakhalinsk.ru
+// More geographical domains
+amursk.ru
+baikal.ru
+cmw.ru
+fareast.ru
+jamal.ru
+kms.ru
+k-uralsk.ru
+kustanai.ru
+kuzbass.ru
+mytis.ru
+nakhodka.ru
+nkz.ru
+norilsk.ru
+oskol.ru
+pyatigorsk.ru
+rubtsovsk.ru
+snz.ru
+syzran.ru
+vdonsk.ru
+zgrad.ru
+// State domains
+gov.ru
+mil.ru
+// Technical domains
+test.ru
+
+// rw : http://www.nic.rw/cgi-bin/policy.pl
+rw
+gov.rw
+net.rw
+edu.rw
+ac.rw
+com.rw
+co.rw
+int.rw
+mil.rw
+gouv.rw
+
+// sa : http://www.nic.net.sa/
+sa
+com.sa
+net.sa
+org.sa
+gov.sa
+med.sa
+pub.sa
+edu.sa
+sch.sa
+
+// sb : http://www.sbnic.net.sb/
+// Submitted by registry <lee.humphries@telekom.com.sb> 2008-06-08
+sb
+com.sb
+edu.sb
+gov.sb
+net.sb
+org.sb
+
+// sc : http://www.nic.sc/
+sc
+com.sc
+gov.sc
+net.sc
+org.sc
+edu.sc
+
+// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm
+// Submitted by registry <admin@isoc.sd> 2008-06-17
+sd
+com.sd
+net.sd
+org.sd
+edu.sd
+med.sd
+tv.sd
+gov.sd
+info.sd
+
+// se : http://en.wikipedia.org/wiki/.se
+// Submitted by registry <patrik.wallstrom@iis.se> 2014-03-18
+se
+a.se
+ac.se
+b.se
+bd.se
+brand.se
+c.se
+d.se
+e.se
+f.se
+fh.se
+fhsk.se
+fhv.se
+g.se
+h.se
+i.se
+k.se
+komforb.se
+kommunalforbund.se
+komvux.se
+l.se
+lanbib.se
+m.se
+n.se
+naturbruksgymn.se
+o.se
+org.se
+p.se
+parti.se
+pp.se
+press.se
+r.se
+s.se
+t.se
+tm.se
+u.se
+w.se
+x.se
+y.se
+z.se
+
+// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines
+sg
+com.sg
+net.sg
+org.sg
+gov.sg
+edu.sg
+per.sg
+
+// sh : http://www.nic.sh/registrar.html
+sh
+com.sh
+net.sh
+gov.sh
+org.sh
+mil.sh
+
+// si : http://en.wikipedia.org/wiki/.si
+si
+
+// sj : No registrations at this time.
+// Submitted by registry <jarle@uninett.no> 2008-06-16
+sj
+
+// sk : http://en.wikipedia.org/wiki/.sk
+// list of 2nd level domains ?
+sk
+
+// sl : http://www.nic.sl
+// Submitted by registry <adam@neoip.com> 2008-06-12
+sl
+com.sl
+net.sl
+edu.sl
+gov.sl
+org.sl
+
+// sm : http://en.wikipedia.org/wiki/.sm
+sm
+
+// sn : http://en.wikipedia.org/wiki/.sn
+sn
+art.sn
+com.sn
+edu.sn
+gouv.sn
+org.sn
+perso.sn
+univ.sn
+
+// so : http://www.soregistry.com/
+so
+com.so
+net.so
+org.so
+
+// sr : http://en.wikipedia.org/wiki/.sr
+sr
+
+// st : http://www.nic.st/html/policyrules/
+st
+co.st
+com.st
+consulado.st
+edu.st
+embaixada.st
+gov.st
+mil.st
+net.st
+org.st
+principe.st
+saotome.st
+store.st
+
+// su : http://en.wikipedia.org/wiki/.su
+su
+adygeya.su
+arkhangelsk.su
+balashov.su
+bashkiria.su
+bryansk.su
+dagestan.su
+grozny.su
+ivanovo.su
+kalmykia.su
+kaluga.su
+karelia.su
+khakassia.su
+krasnodar.su
+kurgan.su
+lenug.su
+mordovia.su
+msk.su
+murmansk.su
+nalchik.su
+nov.su
+obninsk.su
+penza.su
+pokrovsk.su
+sochi.su
+spb.su
+togliatti.su
+troitsk.su
+tula.su
+tuva.su
+vladikavkaz.su
+vladimir.su
+vologda.su
+
+// sv : http://www.svnet.org.sv/niveldos.pdf
+sv
+com.sv
+edu.sv
+gob.sv
+org.sv
+red.sv
+
+// sx : http://en.wikipedia.org/wiki/.sx
+// Confirmed by registry <jcvignes@openregistry.com> 2012-05-31
+sx
+gov.sx
+
+// sy : http://en.wikipedia.org/wiki/.sy
+// see also: http://www.gobin.info/domainname/sy.doc
+sy
+edu.sy
+gov.sy
+net.sy
+mil.sy
+com.sy
+org.sy
+
+// sz : http://en.wikipedia.org/wiki/.sz
+// http://www.sispa.org.sz/
+sz
+co.sz
+ac.sz
+org.sz
+
+// tc : http://en.wikipedia.org/wiki/.tc
+tc
+
+// td : http://en.wikipedia.org/wiki/.td
+td
+
+// tel: http://en.wikipedia.org/wiki/.tel
+// http://www.telnic.org/
+tel
+
+// tf : http://en.wikipedia.org/wiki/.tf
+tf
+
+// tg : http://en.wikipedia.org/wiki/.tg
+// http://www.nic.tg/
+tg
+
+// th : http://en.wikipedia.org/wiki/.th
+// Submitted by registry <krit@thains.co.th> 2008-06-17
+th
+ac.th
+co.th
+go.th
+in.th
+mi.th
+net.th
+or.th
+
+// tj : http://www.nic.tj/policy.html
+tj
+ac.tj
+biz.tj
+co.tj
+com.tj
+edu.tj
+go.tj
+gov.tj
+int.tj
+mil.tj
+name.tj
+net.tj
+nic.tj
+org.tj
+test.tj
+web.tj
+
+// tk : http://en.wikipedia.org/wiki/.tk
+tk
+
+// tl : http://en.wikipedia.org/wiki/.tl
+tl
+gov.tl
+
+// tm : http://www.nic.tm/local.html
+tm
+com.tm
+co.tm
+org.tm
+net.tm
+nom.tm
+gov.tm
+mil.tm
+edu.tm
+
+// tn : http://en.wikipedia.org/wiki/.tn
+// http://whois.ati.tn/
+tn
+com.tn
+ens.tn
+fin.tn
+gov.tn
+ind.tn
+intl.tn
+nat.tn
+net.tn
+org.tn
+info.tn
+perso.tn
+tourism.tn
+edunet.tn
+rnrt.tn
+rns.tn
+rnu.tn
+mincom.tn
+agrinet.tn
+defense.tn
+turen.tn
+
+// to : http://en.wikipedia.org/wiki/.to
+// Submitted by registry <egullich@colo.to> 2008-06-17
+to
+com.to
+gov.to
+net.to
+org.to
+edu.to
+mil.to
+
+// tp : No registrations at this time.
+// Submitted by Ryan Sleevi <ryan.sleevi@gmail.com> 2014-01-03
+tp
+
+// subTLDs: https://www.nic.tr/forms/eng/policies.pdf
+//     and: https://www.nic.tr/forms/politikalar.pdf
+// Submitted by <mehmetgurevin@gmail.com> 2014-07-19
+tr
+com.tr
+info.tr
+biz.tr
+net.tr
+org.tr
+web.tr
+gen.tr
+tv.tr
+av.tr
+dr.tr
+bbs.tr
+name.tr
+tel.tr
+gov.tr
+bel.tr
+pol.tr
+mil.tr
+k12.tr
+edu.tr
+kep.tr
+
+// Used by Northern Cyprus
+nc.tr
+
+// Used by government agencies of Northern Cyprus
+gov.nc.tr
+
+// travel : http://en.wikipedia.org/wiki/.travel
+travel
+
+// tt : http://www.nic.tt/
+tt
+co.tt
+com.tt
+org.tt
+net.tt
+biz.tt
+info.tt
+pro.tt
+int.tt
+coop.tt
+jobs.tt
+mobi.tt
+travel.tt
+museum.tt
+aero.tt
+name.tt
+gov.tt
+edu.tt
+
+// tv : http://en.wikipedia.org/wiki/.tv
+// Not listing any 2LDs as reserved since none seem to exist in practice,
+// Wikipedia notwithstanding.
+tv
+
+// tw : http://en.wikipedia.org/wiki/.tw
+tw
+edu.tw
+gov.tw
+mil.tw
+com.tw
+net.tw
+org.tw
+idv.tw
+game.tw
+ebiz.tw
+club.tw
+網路.tw
+組織.tw
+商業.tw
+
+// tz : http://www.tznic.or.tz/index.php/domains
+// Confirmed by registry <manager@tznic.or.tz> 2013-01-22
+tz
+ac.tz
+co.tz
+go.tz
+hotel.tz
+info.tz
+me.tz
+mil.tz
+mobi.tz
+ne.tz
+or.tz
+sc.tz
+tv.tz
+
+// ua : https://hostmaster.ua/policy/?ua
+// Submitted by registry <dk@cctld.ua> 2012-04-27
+ua
+// ua 2LD
+com.ua
+edu.ua
+gov.ua
+in.ua
+net.ua
+org.ua
+// ua geographic names
+// https://hostmaster.ua/2ld/
+cherkassy.ua
+cherkasy.ua
+chernigov.ua
+chernihiv.ua
+chernivtsi.ua
+chernovtsy.ua
+ck.ua
+cn.ua
+cr.ua
+crimea.ua
+cv.ua
+dn.ua
+dnepropetrovsk.ua
+dnipropetrovsk.ua
+dominic.ua
+donetsk.ua
+dp.ua
+if.ua
+ivano-frankivsk.ua
+kh.ua
+kharkiv.ua
+kharkov.ua
+kherson.ua
+khmelnitskiy.ua
+khmelnytskyi.ua
+kiev.ua
+kirovograd.ua
+km.ua
+kr.ua
+krym.ua
+ks.ua
+kv.ua
+kyiv.ua
+lg.ua
+lt.ua
+lugansk.ua
+lutsk.ua
+lv.ua
+lviv.ua
+mk.ua
+mykolaiv.ua
+nikolaev.ua
+od.ua
+odesa.ua
+odessa.ua
+pl.ua
+poltava.ua
+rivne.ua
+rovno.ua
+rv.ua
+sb.ua
+sebastopol.ua
+sevastopol.ua
+sm.ua
+sumy.ua
+te.ua
+ternopil.ua
+uz.ua
+uzhgorod.ua
+vinnica.ua
+vinnytsia.ua
+vn.ua
+volyn.ua
+yalta.ua
+zaporizhzhe.ua
+zaporizhzhia.ua
+zhitomir.ua
+zhytomyr.ua
+zp.ua
+zt.ua
+
+// ug : https://www.registry.co.ug/
+ug
+co.ug
+or.ug
+ac.ug
+sc.ug
+go.ug
+ne.ug
+com.ug
+org.ug
+
+// uk : http://en.wikipedia.org/wiki/.uk
+// Submitted by registry <Michael.Daly@nominet.org.uk>
+uk
+ac.uk
+co.uk
+gov.uk
+ltd.uk
+me.uk
+net.uk
+nhs.uk
+org.uk
+plc.uk
+police.uk
+*.sch.uk
+
+// us : http://en.wikipedia.org/wiki/.us
+us
+dni.us
+fed.us
+isa.us
+kids.us
+nsn.us
+// us geographic names
+ak.us
+al.us
+ar.us
+as.us
+az.us
+ca.us
+co.us
+ct.us
+dc.us
+de.us
+fl.us
+ga.us
+gu.us
+hi.us
+ia.us
+id.us
+il.us
+in.us
+ks.us
+ky.us
+la.us
+ma.us
+md.us
+me.us
+mi.us
+mn.us
+mo.us
+ms.us
+mt.us
+nc.us
+nd.us
+ne.us
+nh.us
+nj.us
+nm.us
+nv.us
+ny.us
+oh.us
+ok.us
+or.us
+pa.us
+pr.us
+ri.us
+sc.us
+sd.us
+tn.us
+tx.us
+ut.us
+vi.us
+vt.us
+va.us
+wa.us
+wi.us
+wv.us
+wy.us
+// The registrar notes several more specific domains available in each state,
+// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat
+// haphazard; in some states these domains resolve as addresses, while in others
+// only subdomains are available, or even nothing at all. We include the
+// most common ones where it's clear that different sites are different
+// entities.
+k12.ak.us
+k12.al.us
+k12.ar.us
+k12.as.us
+k12.az.us
+k12.ca.us
+k12.co.us
+k12.ct.us
+k12.dc.us
+k12.de.us
+k12.fl.us
+k12.ga.us
+k12.gu.us
+// k12.hi.us  Bug 614565 - Hawaii has a state-wide DOE login
+k12.ia.us
+k12.id.us
+k12.il.us
+k12.in.us
+k12.ks.us
+k12.ky.us
+k12.la.us
+k12.ma.us
+k12.md.us
+k12.me.us
+k12.mi.us
+k12.mn.us
+k12.mo.us
+k12.ms.us
+k12.mt.us
+k12.nc.us
+// k12.nd.us  Bug 1028347 - Removed at request of Travis Rosso <trossow@nd.gov>
+k12.ne.us
+k12.nh.us
+k12.nj.us
+k12.nm.us
+k12.nv.us
+k12.ny.us
+k12.oh.us
+k12.ok.us
+k12.or.us
+k12.pa.us
+k12.pr.us
+k12.ri.us
+k12.sc.us
+// k12.sd.us  Bug 934131 - Removed at request of James Booze <James.Booze@k12.sd.us>
+k12.tn.us
+k12.tx.us
+k12.ut.us
+k12.vi.us
+k12.vt.us
+k12.va.us
+k12.wa.us
+k12.wi.us
+// k12.wv.us  Bug 947705 - Removed at request of Verne Britton <verne@wvnet.edu>
+k12.wy.us
+cc.ak.us
+cc.al.us
+cc.ar.us
+cc.as.us
+cc.az.us
+cc.ca.us
+cc.co.us
+cc.ct.us
+cc.dc.us
+cc.de.us
+cc.fl.us
+cc.ga.us
+cc.gu.us
+cc.hi.us
+cc.ia.us
+cc.id.us
+cc.il.us
+cc.in.us
+cc.ks.us
+cc.ky.us
+cc.la.us
+cc.ma.us
+cc.md.us
+cc.me.us
+cc.mi.us
+cc.mn.us
+cc.mo.us
+cc.ms.us
+cc.mt.us
+cc.nc.us
+cc.nd.us
+cc.ne.us
+cc.nh.us
+cc.nj.us
+cc.nm.us
+cc.nv.us
+cc.ny.us
+cc.oh.us
+cc.ok.us
+cc.or.us
+cc.pa.us
+cc.pr.us
+cc.ri.us
+cc.sc.us
+cc.sd.us
+cc.tn.us
+cc.tx.us
+cc.ut.us
+cc.vi.us
+cc.vt.us
+cc.va.us
+cc.wa.us
+cc.wi.us
+cc.wv.us
+cc.wy.us
+lib.ak.us
+lib.al.us
+lib.ar.us
+lib.as.us
+lib.az.us
+lib.ca.us
+lib.co.us
+lib.ct.us
+lib.dc.us
+lib.de.us
+lib.fl.us
+lib.ga.us
+lib.gu.us
+lib.hi.us
+lib.ia.us
+lib.id.us
+lib.il.us
+lib.in.us
+lib.ks.us
+lib.ky.us
+lib.la.us
+lib.ma.us
+lib.md.us
+lib.me.us
+lib.mi.us
+lib.mn.us
+lib.mo.us
+lib.ms.us
+lib.mt.us
+lib.nc.us
+lib.nd.us
+lib.ne.us
+lib.nh.us
+lib.nj.us
+lib.nm.us
+lib.nv.us
+lib.ny.us
+lib.oh.us
+lib.ok.us
+lib.or.us
+lib.pa.us
+lib.pr.us
+lib.ri.us
+lib.sc.us
+lib.sd.us
+lib.tn.us
+lib.tx.us
+lib.ut.us
+lib.vi.us
+lib.vt.us
+lib.va.us
+lib.wa.us
+lib.wi.us
+// lib.wv.us  Bug 941670 - Removed at request of Larry W Arnold <arnold@wvlc.lib.wv.us>
+lib.wy.us
+// k12.ma.us contains school districts in Massachusetts. The 4LDs are
+//  managed indepedently except for private (PVT), charter (CHTR) and
+//  parochial (PAROCH) schools.  Those are delegated dorectly to the
+//  5LD operators.   <k12-ma-hostmaster _ at _ rsuc.gweep.net>
+pvt.k12.ma.us
+chtr.k12.ma.us
+paroch.k12.ma.us
+
+// uy : http://www.nic.org.uy/
+uy
+com.uy
+edu.uy
+gub.uy
+mil.uy
+net.uy
+org.uy
+
+// uz : http://www.reg.uz/
+uz
+co.uz
+com.uz
+net.uz
+org.uz
+
+// va : http://en.wikipedia.org/wiki/.va
+va
+
+// vc : http://en.wikipedia.org/wiki/.vc
+// Submitted by registry <kshah@ca.afilias.info> 2008-06-13
+vc
+com.vc
+net.vc
+org.vc
+gov.vc
+mil.vc
+edu.vc
+
+// ve : https://registro.nic.ve/
+// Confirmed by registry 2012-10-04
+// Updated 2014-05-20 - Bug 940478
+ve
+arts.ve
+co.ve
+com.ve
+e12.ve
+edu.ve
+firm.ve
+gob.ve
+gov.ve
+info.ve
+int.ve
+mil.ve
+net.ve
+org.ve
+rec.ve
+store.ve
+tec.ve
+web.ve
+
+// vg : http://en.wikipedia.org/wiki/.vg
+vg
+
+// vi : http://www.nic.vi/newdomainform.htm
+// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other
+// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they
+// are available for registration (which they do not seem to be).
+vi
+co.vi
+com.vi
+k12.vi
+net.vi
+org.vi
+
+// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp
+vn
+com.vn
+net.vn
+org.vn
+edu.vn
+gov.vn
+int.vn
+ac.vn
+biz.vn
+info.vn
+name.vn
+pro.vn
+health.vn
+
+// vu : http://en.wikipedia.org/wiki/.vu
+// http://www.vunic.vu/
+vu
+com.vu
+edu.vu
+net.vu
+org.vu
+
+// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+wf
+
+// ws : http://en.wikipedia.org/wiki/.ws
+// http://samoanic.ws/index.dhtml
+ws
+com.ws
+net.ws
+org.ws
+gov.ws
+edu.ws
+
+// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+yt
+
+// IDN ccTLDs
+// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then
+// U-label, and follow this format:
+// // A-Label ("<Latin renderings>", <language name>[, variant info]) : <ISO 3166 ccTLD>
+// // [sponsoring org]
+// U-Label
+
+// xn--mgbaam7a8h ("Emerat", Arabic) : AE
+// http://nic.ae/english/arabicdomain/rules.jsp
+امارات
+
+// xn--y9a3aq ("hye", Armenian) : AM
+// ISOC AM (operated by .am Registry)
+հայ
+
+// xn--54b7fta0cc ("Bangla", Bangla) : BD
+বাংলা
+
+// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY
+// Operated by .by registry
+бел
+
+// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+中国
+
+// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+中國
+
+// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ
+الجزائر
+
+// xn--wgbh1c ("Egypt/Masr", Arabic) : EG
+// http://www.dotmasr.eg/
+مصر
+
+// xn--node ("ge", Georgian Mkhedruli) : GE
+გე
+
+// xn--qxam ("el", Greek) : GR
+// Hellenic Ministry of Infrastructure, Transport, and Networks
+ελ
+
+// xn--j6w193g ("Hong Kong", Chinese) : HK
+// https://www2.hkirc.hk/register/rules.jsp
+香港
+
+// xn--h2brj9c ("Bharat", Devanagari) : IN
+// India
+भारत
+
+// xn--mgbbh1a71e ("Bharat", Arabic) : IN
+// India
+بھارت
+
+// xn--fpcrj9c3d ("Bharat", Telugu) : IN
+// India
+భారత్
+
+// xn--gecrj9c ("Bharat", Gujarati) : IN
+// India
+ભારત
+
+// xn--s9brj9c ("Bharat", Gurmukhi) : IN
+// India
+ਭਾਰਤ
+
+// xn--45brj9c ("Bharat", Bengali) : IN
+// India
+ভারত
+
+// xn--xkc2dl3a5ee0h ("India", Tamil) : IN
+// India
+இந்தியா
+
+// xn--mgba3a4f16a ("Iran", Persian) : IR
+ایران
+
+// xn--mgba3a4fra ("Iran", Arabic) : IR
+ايران
+
+// xn--mgbtx2b ("Iraq", Arabic) : IQ
+// Communications and Media Commission
+عراق
+
+// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO
+// National Information Technology Center (NITC)
+// Royal Scientific Society, Al-Jubeiha
+الاردن
+
+// xn--3e0b707e ("Republic of Korea", Hangul) : KR
+한국
+
+// xn--80ao21a ("Kaz", Kazakh) : KZ
+қаз
+
+// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK
+// http://nic.lk
+ලංකා
+
+// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK
+// http://nic.lk
+இலங்கை
+
+// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA
+المغرب
+
+// xn--d1alf ("mkd", Macedonian) : MK
+// MARnet
+мкд
+
+// xn--l1acc ("mon", Mongolian) : MN
+мон
+
+// xn--mix891f ("Macao", Chinese, Traditional) : MO
+// MONIC / HNET Asia (Registry Operator for .mo)
+澳門
+
+// xn--mix082f ("Macao", Chinese, Simplified) : MO
+澳门
+
+// xn--mgbx4cd0ab ("Malaysia", Malay) : MY
+مليسيا
+
+// xn--mgb9awbf ("Oman", Arabic) : OM
+عمان
+
+// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK
+پاکستان
+
+// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK
+پاكستان
+
+// xn--ygbi2ammx ("Falasteen", Arabic) : PS
+// The Palestinian National Internet Naming Authority (PNINA)
+// http://www.pnina.ps
+فلسطين
+
+// xn--90a3ac ("srb", Cyrillic) : RS
+// http://www.rnids.rs/en/the-.срб-domain
+срб
+пр.срб
+орг.срб
+обр.срб
+од.срб
+упр.срб
+ак.срб
+
+// xn--p1ai ("rf", Russian-Cyrillic) : RU
+// http://www.cctld.ru/en/docs/rulesrf.php
+рф
+
+// xn--wgbl6a ("Qatar", Arabic) : QA
+// http://www.ict.gov.qa/
+قطر
+
+// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA
+// http://www.nic.net.sa/
+السعودية
+
+// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant)  : SA
+السعودیة
+
+// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA
+السعودیۃ
+
+// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA
+السعوديه
+
+// xn--mgbpl2fh ("sudan", Arabic) : SD
+// Operated by .sd registry
+سودان
+
+// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG
+新加坡
+
+// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG
+சிங்கப்பூர்
+
+// xn--ogbpf8fl ("Syria", Arabic) : SY
+سورية
+
+// xn--mgbtf8fl ("Syria", Arabic, variant) : SY
+سوريا
+
+// xn--o3cw4h ("Thai", Thai) : TH
+// http://www.thnic.co.th
+ไทย
+
+// xn--pgbs0dh ("Tunisia", Arabic) : TN
+// http://nic.tn
+تونس
+
+// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+台灣
+
+// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+台湾
+
+// xn--nnx388a ("Taiwan", Chinese, variant) : TW
+臺灣
+
+// xn--j1amh ("ukr", Cyrillic) : UA
+укр
+
+// xn--mgb2ddes ("AlYemen", Arabic) : YE
+اليمن
+
+// xxx : http://icmregistry.com
+xxx
+
+// ye : http://www.y.net.ye/services/domain_name.htm
+*.ye
+
+// za : http://www.zadna.org.za/content/page/domain-information
+ac.za
+agrica.za
+alt.za
+co.za
+edu.za
+gov.za
+grondar.za
+law.za
+mil.za
+net.za
+ngo.za
+nis.za
+nom.za
+org.za
+school.za
+tm.za
+web.za
+
+// zm : http://en.wikipedia.org/wiki/.zm
+*.zm
+
+// zw : http://en.wikipedia.org/wiki/.zw
+*.zw
+
+
+// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-11-12T22:43:48Z
+
+// aaa : 2015-02-26 American Automobile Association, Inc.
+aaa
+
+// aarp : 2015-05-21 AARP
+aarp
+
+// abarth : 2015-07-30 Fiat Chrysler Automobiles N.V.
+abarth
+
+// abb : 2014-10-24 ABB Ltd
+abb
+
+// abbott : 2014-07-24 Abbott Laboratories, Inc.
+abbott
+
+// abbvie : 2015-07-30 AbbVie Inc.
+abbvie
+
+// abc : 2015-07-30 Disney Enterprises, Inc.
+abc
+
+// able : 2015-06-25 Able Inc.
+able
+
+// abogado : 2014-04-24 Top Level Domain Holdings Limited
+abogado
+
+// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre
+abudhabi
+
+// academy : 2013-11-07 Half Oaks, LLC
+academy
+
+// accenture : 2014-08-15 Accenture plc
+accenture
+
+// accountant : 2014-11-20 dot Accountant Limited
+accountant
+
+// accountants : 2014-03-20 Knob Town, LLC
+accountants
+
+// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG
+aco
+
+// active : 2014-05-01 The Active Network, Inc
+active
+
+// actor : 2013-12-12 United TLD Holdco Ltd.
+actor
+
+// adac : 2015-07-16 Allgemeiner Deutscher Automobil-Club e.V. (ADAC)
+adac
+
+// ads : 2014-12-04 Charleston Road Registry Inc.
+ads
+
+// adult : 2014-10-16 ICM Registry AD LLC
+adult
+
+// aeg : 2015-03-19 Aktiebolaget Electrolux
+aeg
+
+// aetna : 2015-05-21 Aetna Life Insurance Company
+aetna
+
+// afamilycompany : 2015-07-23 Johnson Shareholdings, Inc.
+afamilycompany
+
+// afl : 2014-10-02 Australian Football League
+afl
+
+// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa
+africa
+
+// africamagic : 2015-03-05 Electronic Media Network (Pty) Ltd
+africamagic
+
+// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+agakhan
+
+// agency : 2013-11-14 Steel Falls, LLC
+agency
+
+// aig : 2014-12-18 American International Group, Inc.
+aig
+
+// aigo : 2015-08-06 aigo Digital Technology Co,Ltd.
+aigo
+
+// airbus : 2015-07-30 Airbus S.A.S.
+airbus
+
+// airforce : 2014-03-06 United TLD Holdco Ltd.
+airforce
+
+// airtel : 2014-10-24 Bharti Airtel Limited
+airtel
+
+// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+akdn
+
+// alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V.
+alfaromeo
+
+// alibaba : 2015-01-15 Alibaba Group Holding Limited
+alibaba
+
+// alipay : 2015-01-15 Alibaba Group Holding Limited
+alipay
+
+// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft
+allfinanz
+
+// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company
+allstate
+
+// ally : 2015-06-18 Ally Financial Inc.
+ally
+
+// alsace : 2014-07-02 REGION D ALSACE
+alsace
+
+// alstom : 2015-07-30 ALSTOM
+alstom
+
+// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc.
+americanexpress
+
+// americanfamily : 2015-07-23 AmFam, Inc.
+americanfamily
+
+// amex : 2015-07-31 American Express Travel Related Services Company, Inc.
+amex
+
+// amfam : 2015-07-23 AmFam, Inc.
+amfam
+
+// amica : 2015-05-28 Amica Mutual Insurance Company
+amica
+
+// amsterdam : 2014-07-24 Gemeente Amsterdam
+amsterdam
+
+// analytics : 2014-12-18 Campus IP LLC
+analytics
+
+// android : 2014-08-07 Charleston Road Registry Inc.
+android
+
+// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+anquan
+
+// anz : 2015-07-31 Australia and New Zealand Banking Group Limited
+anz
+
+// aol : 2015-09-17 AOL Inc.
+aol
+
+// apartments : 2014-12-11 June Maple, LLC
+apartments
+
+// app : 2015-05-14 Charleston Road Registry Inc.
+app
+
+// apple : 2015-05-14 Apple Inc.
+apple
+
+// aquarelle : 2014-07-24 Aquarelle.com
+aquarelle
+
+// aramco : 2014-11-20 Aramco Services Company
+aramco
+
+// archi : 2014-02-06 STARTING DOT LIMITED
+archi
+
+// army : 2014-03-06 United TLD Holdco Ltd.
+army
+
+// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E.
+arte
+
+// asda : 2015-07-31 Wal-Mart Stores, Inc.
+asda
+
+// associates : 2014-03-06 Baxter Hill, LLC
+associates
+
+// athleta : 2015-07-30 The Gap, Inc.
+athleta
+
+// attorney : 2014-03-20
+attorney
+
+// auction : 2014-03-20
+auction
+
+// audi : 2015-05-21 AUDI Aktiengesellschaft
+audi
+
+// audible : 2015-06-25 Amazon EU S.à r.l.
+audible
+
+// audio : 2014-03-20 Uniregistry, Corp.
+audio
+
+// auspost : 2015-08-13 Australian Postal Corporation
+auspost
+
+// author : 2014-12-18 Amazon EU S.à r.l.
+author
+
+// auto : 2014-11-13
+auto
+
+// autos : 2014-01-09 DERAutos, LLC
+autos
+
+// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca
+avianca
+
+// aws : 2015-06-25 Amazon EU S.à r.l.
+aws
+
+// axa : 2013-12-19 AXA SA
+axa
+
+// azure : 2014-12-18 Microsoft Corporation
+azure
+
+// baby : 2015-04-09 Johnson & Johnson Services, Inc.
+baby
+
+// baidu : 2015-01-08 Baidu, Inc.
+baidu
+
+// banamex : 2015-07-30 Citigroup Inc.
+banamex
+
+// bananarepublic : 2015-07-31 The Gap, Inc.
+bananarepublic
+
+// band : 2014-06-12
+band
+
+// bank : 2014-09-25 fTLD Registry Services LLC
+bank
+
+// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+bar
+
+// barcelona : 2014-07-24 Municipi de Barcelona
+barcelona
+
+// barclaycard : 2014-11-20 Barclays Bank PLC
+barclaycard
+
+// barclays : 2014-11-20 Barclays Bank PLC
+barclays
+
+// barefoot : 2015-06-11 Gallo Vineyards, Inc.
+barefoot
+
+// bargains : 2013-11-14 Half Hallow, LLC
+bargains
+
+// baseball : 2015-10-29 MLB Advanced Media DH, LLC
+baseball
+
+// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA)
+basketball
+
+// bauhaus : 2014-04-17 Werkhaus GmbH
+bauhaus
+
+// bayern : 2014-01-23 Bayern Connect GmbH
+bayern
+
+// bbc : 2014-12-18 British Broadcasting Corporation
+bbc
+
+// bbt : 2015-07-23 BB&T Corporation
+bbt
+
+// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+bbva
+
+// bcg : 2015-04-02 The Boston Consulting Group, Inc.
+bcg
+
+// bcn : 2014-07-24 Municipi de Barcelona
+bcn
+
+// beats : 2015-05-14 Beats Electronics, LLC
+beats
+
+// beer : 2014-01-09 Top Level Domain Holdings Limited
+beer
+
+// bentley : 2014-12-18 Bentley Motors Limited
+bentley
+
+// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG
+berlin
+
+// best : 2013-12-19 BestTLD Pty Ltd
+best
+
+// bestbuy : 2015-07-31 BBY Solutions, Inc.
+bestbuy
+
+// bet : 2015-05-07 Afilias plc
+bet
+
+// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited
+bharti
+
+// bible : 2014-06-19 American Bible Society
+bible
+
+// bid : 2013-12-19 dot Bid Limited
+bid
+
+// bike : 2013-08-27 Grand Hollow, LLC
+bike
+
+// bing : 2014-12-18 Microsoft Corporation
+bing
+
+// bingo : 2014-12-04 Sand Cedar, LLC
+bingo
+
+// bio : 2014-03-06 STARTING DOT LIMITED
+bio
+
+// black : 2014-01-16 Afilias Limited
+black
+
+// blackfriday : 2014-01-16 Uniregistry, Corp.
+blackfriday
+
+// blanco : 2015-07-16 BLANCO GmbH + Co KG
+blanco
+
+// blockbuster : 2015-07-30 Dish DBS Corporation
+blockbuster
+
+// blog : 2015-05-14 PRIMER NIVEL S.A.
+blog
+
+// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC
+bloomberg
+
+// blue : 2013-11-07 Afilias Limited
+blue
+
+// bms : 2014-10-30 Bristol-Myers Squibb Company
+bms
+
+// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+bmw
+
+// bnl : 2014-07-24 Banca Nazionale del Lavoro
+bnl
+
+// bnpparibas : 2014-05-29 BNP Paribas
+bnpparibas
+
+// boats : 2014-12-04 DERBoats, LLC
+boats
+
+// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH
+boehringer
+
+// bofa : 2015-07-31 NMS Services, Inc.
+bofa
+
+// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+bom
+
+// bond : 2014-06-05 Bond University Limited
+bond
+
+// boo : 2014-01-30 Charleston Road Registry Inc.
+boo
+
+// book : 2015-08-27 Amazon EU S.à r.l.
+book
+
+// booking : 2015-07-16 Booking.com B.V.
+booking
+
+// boots : 2015-01-08 THE BOOTS COMPANY PLC
+boots
+
+// bosch : 2015-06-18 Robert Bosch GMBH
+bosch
+
+// bostik : 2015-05-28 Bostik SA
+bostik
+
+// bot : 2014-12-18 Amazon EU S.à r.l.
+bot
+
+// boutique : 2013-11-14 Over Galley, LLC
+boutique
+
+// bradesco : 2014-12-18 Banco Bradesco S.A.
+bradesco
+
+// bridgestone : 2014-12-18 Bridgestone Corporation
+bridgestone
+
+// broadway : 2014-12-22 Celebrate Broadway, Inc.
+broadway
+
+// broker : 2014-12-11 IG Group Holdings PLC
+broker
+
+// brother : 2015-01-29 Brother Industries, Ltd.
+brother
+
+// brussels : 2014-02-06 DNS.be vzw
+brussels
+
+// budapest : 2013-11-21 Top Level Domain Holdings Limited
+budapest
+
+// bugatti : 2015-07-23 Bugatti International SA
+bugatti
+
+// build : 2013-11-07 Plan Bee LLC
+build
+
+// builders : 2013-11-07 Atomic Madison, LLC
+builders
+
+// business : 2013-11-07 Spring Cross, LLC
+business
+
+// buy : 2014-12-18 Amazon EU S.à r.l.
+buy
+
+// buzz : 2013-10-02 DOTSTRATEGY CO.
+buzz
+
+// bzh : 2014-02-27 Association www.bzh
+bzh
+
+// cab : 2013-10-24 Half Sunset, LLC
+cab
+
+// cafe : 2015-02-11 Pioneer Canyon, LLC
+cafe
+
+// cal : 2014-07-24 Charleston Road Registry Inc.
+cal
+
+// call : 2014-12-18 Amazon EU S.à r.l.
+call
+
+// calvinklein : 2015-07-30 PVH gTLD Holdings LLC
+calvinklein
+
+// camera : 2013-08-27 Atomic Maple, LLC
+camera
+
+// camp : 2013-11-07 Delta Dynamite, LLC
+camp
+
+// cancerresearch : 2014-05-15 Australian Cancer Research Foundation
+cancerresearch
+
+// canon : 2014-09-12 Canon Inc.
+canon
+
+// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+capetown
+
+// capital : 2014-03-06 Delta Mill, LLC
+capital
+
+// capitalone : 2015-08-06 Capital One Financial Corporation
+capitalone
+
+// car : 2015-01-22
+car
+
+// caravan : 2013-12-12 Caravan International, Inc.
+caravan
+
+// cards : 2013-12-05 Foggy Hollow, LLC
+cards
+
+// care : 2014-03-06 Goose Cross
+care
+
+// career : 2013-10-09 dotCareer LLC
+career
+
+// careers : 2013-10-02 Wild Corner, LLC
+careers
+
+// cars : 2014-11-13
+cars
+
+// cartier : 2014-06-23 Richemont DNS Inc.
+cartier
+
+// casa : 2013-11-21 Top Level Domain Holdings Limited
+casa
+
+// case : 2015-09-03 CNH Industrial N.V.
+case
+
+// caseih : 2015-09-03 CNH Industrial N.V.
+caseih
+
+// cash : 2014-03-06 Delta Lake, LLC
+cash
+
+// casino : 2014-12-18 Binky Sky, LLC
+casino
+
+// catering : 2013-12-05 New Falls. LLC
+catering
+
+// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+catholic
+
+// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+cba
+
+// cbn : 2014-08-22 The Christian Broadcasting Network, Inc.
+cbn
+
+// cbre : 2015-07-02 CBRE, Inc.
+cbre
+
+// cbs : 2015-08-06 CBS Domains Inc.
+cbs
+
+// ceb : 2015-04-09 The Corporate Executive Board Company
+ceb
+
+// center : 2013-11-07 Tin Mill, LLC
+center
+
+// ceo : 2013-11-07 CEOTLD Pty Ltd
+ceo
+
+// cern : 2014-06-05 European Organization for Nuclear Research ("CERN")
+cern
+
+// cfa : 2014-08-28 CFA Institute
+cfa
+
+// cfd : 2014-12-11 IG Group Holdings PLC
+cfd
+
+// chanel : 2015-04-09 Chanel International B.V.
+chanel
+
+// channel : 2014-05-08 Charleston Road Registry Inc.
+channel
+
+// chase : 2015-04-30 JPMorgan Chase & Co.
+chase
+
+// chat : 2014-12-04 Sand Fields, LLC
+chat
+
+// cheap : 2013-11-14 Sand Cover, LLC
+cheap
+
+// chintai : 2015-06-11 CHINTAI Corporation
+chintai
+
+// chloe : 2014-10-16 Richemont DNS Inc.
+chloe
+
+// christmas : 2013-11-21 Uniregistry, Corp.
+christmas
+
+// chrome : 2014-07-24 Charleston Road Registry Inc.
+chrome
+
+// chrysler : 2015-07-30 FCA US LLC.
+chrysler
+
+// church : 2014-02-06 Holly Fields, LLC
+church
+
+// cipriani : 2015-02-19 Hotel Cipriani Srl
+cipriani
+
+// circle : 2014-12-18 Amazon EU S.à r.l.
+circle
+
+// cisco : 2014-12-22 Cisco Technology, Inc.
+cisco
+
+// citadel : 2015-07-23 Citadel Domain LLC
+citadel
+
+// citi : 2015-07-30 Citigroup Inc.
+citi
+
+// citic : 2014-01-09 CITIC Group Corporation
+citic
+
+// city : 2014-05-29 Snow Sky, LLC
+city
+
+// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc.
+cityeats
+
+// claims : 2014-03-20 Black Corner, LLC
+claims
+
+// cleaning : 2013-12-05 Fox Shadow, LLC
+cleaning
+
+// click : 2014-06-05 Uniregistry, Corp.
+click
+
+// clinic : 2014-03-20 Goose Park, LLC
+clinic
+
+// clinique : 2015-10-01 The Estée Lauder Companies Inc.
+clinique
+
+// clothing : 2013-08-27 Steel Lake, LLC
+clothing
+
+// cloud : 2015-04-16 ARUBA S.p.A.
+cloud
+
+// club : 2013-11-08 .CLUB DOMAINS, LLC
+club
+
+// clubmed : 2015-06-25 Club Méditerranée S.A.
+clubmed
+
+// coach : 2014-10-09 Koko Island, LLC
+coach
+
+// codes : 2013-10-31 Puff Willow, LLC
+codes
+
+// coffee : 2013-10-17 Trixy Cover, LLC
+coffee
+
+// college : 2014-01-16 XYZ.COM LLC
+college
+
+// cologne : 2014-02-05 NetCologne Gesellschaft für Telekommunikation mbH
+cologne
+
+// comcast : 2015-07-23 Comcast IP Holdings I, LLC
+comcast
+
+// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+commbank
+
+// community : 2013-12-05 Fox Orchard, LLC
+community
+
+// company : 2013-11-07 Silver Avenue, LLC
+company
+
+// compare : 2015-10-08 iSelect Ltd
+compare
+
+// computer : 2013-10-24 Pine Mill, LLC
+computer
+
+// comsec : 2015-01-08 VeriSign, Inc.
+comsec
+
+// condos : 2013-12-05 Pine House, LLC
+condos
+
+// construction : 2013-09-16 Fox Dynamite, LLC
+construction
+
+// consulting : 2013-12-05
+consulting
+
+// contact : 2015-01-08 Top Level Spectrum, Inc.
+contact
+
+// contractors : 2013-09-10 Magic Woods, LLC
+contractors
+
+// cooking : 2013-11-21 Top Level Domain Holdings Limited
+cooking
+
+// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc.
+cookingchannel
+
+// cool : 2013-11-14 Koko Lake, LLC
+cool
+
+// corsica : 2014-09-25 Collectivité Territoriale de Corse
+corsica
+
+// country : 2013-12-19 Top Level Domain Holdings Limited
+country
+
+// coupon : 2015-02-26 Amazon EU S.à r.l.
+coupon
+
+// coupons : 2015-03-26 Black Island, LLC
+coupons
+
+// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+courses
+
+// credit : 2014-03-20 Snow Shadow, LLC
+credit
+
+// creditcard : 2014-03-20 Binky Frostbite, LLC
+creditcard
+
+// creditunion : 2015-01-22 CUNA Performance Resources, LLC
+creditunion
+
+// cricket : 2014-10-09 dot Cricket Limited
+cricket
+
+// crown : 2014-10-24 Crown Equipment Corporation
+crown
+
+// crs : 2014-04-03 Federated Co-operatives Limited
+crs
+
+// cruises : 2013-12-05 Spring Way, LLC
+cruises
+
+// csc : 2014-09-25 Alliance-One Services, Inc.
+csc
+
+// cuisinella : 2014-04-03 SALM S.A.S.
+cuisinella
+
+// cymru : 2014-05-08 Nominet UK
+cymru
+
+// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd.
+cyou
+
+// dabur : 2014-02-06 Dabur India Limited
+dabur
+
+// dad : 2014-01-23 Charleston Road Registry Inc.
+dad
+
+// dance : 2013-10-24 United TLD Holdco Ltd.
+dance
+
+// date : 2014-11-20 dot Date Limited
+date
+
+// dating : 2013-12-05 Pine Fest, LLC
+dating
+
+// datsun : 2014-03-27 NISSAN MOTOR CO., LTD.
+datsun
+
+// day : 2014-01-30 Charleston Road Registry Inc.
+day
+
+// dclk : 2014-11-20 Charleston Road Registry Inc.
+dclk
+
+// dds : 2015-05-07 Top Level Domain Holdings Limited
+dds
+
+// deal : 2015-06-25 Amazon EU S.à r.l.
+deal
+
+// dealer : 2014-12-22 Dealer Dot Com, Inc.
+dealer
+
+// deals : 2014-05-22 Sand Sunset, LLC
+deals
+
+// degree : 2014-03-06
+degree
+
+// delivery : 2014-09-11 Steel Station, LLC
+delivery
+
+// dell : 2014-10-24 Dell Inc.
+dell
+
+// deloitte : 2015-07-31 Deloitte Touche Tohmatsu
+deloitte
+
+// delta : 2015-02-19 Delta Air Lines, Inc.
+delta
+
+// democrat : 2013-10-24 United TLD Holdco Ltd.
+democrat
+
+// dental : 2014-03-20 Tin Birch, LLC
+dental
+
+// dentist : 2014-03-20
+dentist
+
+// desi : 2013-11-14 Desi Networks LLC
+desi
+
+// design : 2014-11-07 Top Level Design, LLC
+design
+
+// dev : 2014-10-16 Charleston Road Registry Inc.
+dev
+
+// dhl : 2015-07-23 Deutsche Post AG
+dhl
+
+// diamonds : 2013-09-22 John Edge, LLC
+diamonds
+
+// diet : 2014-06-26 Uniregistry, Corp.
+diet
+
+// digital : 2014-03-06 Dash Park, LLC
+digital
+
+// direct : 2014-04-10 Half Trail, LLC
+direct
+
+// directory : 2013-09-20 Extra Madison, LLC
+directory
+
+// discount : 2014-03-06 Holly Hill, LLC
+discount
+
+// discover : 2015-07-23 Discover Financial Services
+discover
+
+// dish : 2015-07-30 Dish DBS Corporation
+dish
+
+// diy : 2015-11-05 Lifestyle Domain Holdings, Inc.
+diy
+
+// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
+dnp
+
+// docs : 2014-10-16 Charleston Road Registry Inc.
+docs
+
+// dodge : 2015-07-30 FCA US LLC.
+dodge
+
+// dog : 2014-12-04 Koko Mill, LLC
+dog
+
+// doha : 2014-09-18 Communications Regulatory Authority (CRA)
+doha
+
+// domains : 2013-10-17 Sugar Cross, LLC
+domains
+
+// doosan : 2014-04-03 Doosan Corporation
+doosan
+
+// dot : 2015-05-21 Dish DBS Corporation
+dot
+
+// download : 2014-11-20 dot Support Limited
+download
+
+// drive : 2015-03-05 Charleston Road Registry Inc.
+drive
+
+// dstv : 2015-03-12 MultiChoice (Proprietary) Limited
+dstv
+
+// dtv : 2015-06-04 Dish DBS Corporation
+dtv
+
+// dubai : 2015-01-01 Dubai Smart Government Department
+dubai
+
+// duck : 2015-07-23 Johnson Shareholdings, Inc.
+duck
+
+// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company
+dunlop
+
+// duns : 2015-08-06 The Dun & Bradstreet Corporation
+duns
+
+// dupont : 2015-06-25 E.I. du Pont de Nemours and Company
+dupont
+
+// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+durban
+
+// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+dvag
+
+// dwg : 2015-07-23 Autodesk, Inc.
+dwg
+
+// earth : 2014-12-04 Interlink Co., Ltd.
+earth
+
+// eat : 2014-01-23 Charleston Road Registry Inc.
+eat
+
+// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V.
+edeka
+
+// education : 2013-11-07 Brice Way, LLC
+education
+
+// email : 2013-10-31 Spring Madison, LLC
+email
+
+// emerck : 2014-04-03 Merck KGaA
+emerck
+
+// emerson : 2015-07-23 Emerson Electric Co.
+emerson
+
+// energy : 2014-09-11 Binky Birch, LLC
+energy
+
+// engineer : 2014-03-06 United TLD Holdco Ltd.
+engineer
+
+// engineering : 2014-03-06 Romeo Canyon
+engineering
+
+// enterprises : 2013-09-20 Snow Oaks, LLC
+enterprises
+
+// epost : 2015-07-23 Deutsche Post AG
+epost
+
+// epson : 2014-12-04 Seiko Epson Corporation
+epson
+
+// equipment : 2013-08-27 Corn Station, LLC
+equipment
+
+// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson
+ericsson
+
+// erni : 2014-04-03 ERNI Group Holding AG
+erni
+
+// esq : 2014-05-08 Charleston Road Registry Inc.
+esq
+
+// estate : 2013-08-27 Trixy Park, LLC
+estate
+
+// esurance : 2015-07-23 Esurance Insurance Company
+esurance
+
+// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat)
+etisalat
+
+// eurovision : 2014-04-24 European Broadcasting Union (EBU)
+eurovision
+
+// eus : 2013-12-12 Puntueus Fundazioa
+eus
+
+// events : 2013-12-05 Pioneer Maple, LLC
+events
+
+// everbank : 2014-05-15 EverBank
+everbank
+
+// exchange : 2014-03-06 Spring Falls, LLC
+exchange
+
+// expert : 2013-11-21 Magic Pass, LLC
+expert
+
+// exposed : 2013-12-05 Victor Beach, LLC
+exposed
+
+// express : 2015-02-11 Sea Sunset, LLC
+express
+
+// extraspace : 2015-05-14 Extra Space Storage LLC
+extraspace
+
+// fage : 2014-12-18 Fage International S.A.
+fage
+
+// fail : 2014-03-06 Atomic Pipe, LLC
+fail
+
+// fairwinds : 2014-11-13 FairWinds Partners, LLC
+fairwinds
+
+// faith : 2014-11-20 dot Faith Limited
+faith
+
+// family : 2015-04-02
+family
+
+// fan : 2014-03-06
+fan
+
+// fans : 2014-11-07 Asiamix Digital Limited
+fans
+
+// farm : 2013-11-07 Just Maple, LLC
+farm
+
+// farmers : 2015-07-09 Farmers Insurance Exchange
+farmers
+
+// fashion : 2014-07-03 Top Level Domain Holdings Limited
+fashion
+
+// fast : 2014-12-18 Amazon EU S.à r.l.
+fast
+
+// fedex : 2015-08-06 Federal Express Corporation
+fedex
+
+// feedback : 2013-12-19 Top Level Spectrum, Inc.
+feedback
+
+// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V.
+ferrari
+
+// ferrero : 2014-12-18 Ferrero Trading Lux S.A.
+ferrero
+
+// fiat : 2015-07-31 Fiat Chrysler Automobiles N.V.
+fiat
+
+// fidelity : 2015-07-30 Fidelity Brokerage Services LLC
+fidelity
+
+// fido : 2015-08-06 Rogers Communications Partnership
+fido
+
+// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd
+film
+
+// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+final
+
+// finance : 2014-03-20 Cotton Cypress, LLC
+finance
+
+// financial : 2014-03-06 Just Cover, LLC
+financial
+
+// fire : 2015-06-25 Amazon EU S.à r.l.
+fire
+
+// firestone : 2014-12-18 Bridgestone Corporation
+firestone
+
+// firmdale : 2014-03-27 Firmdale Holdings Limited
+firmdale
+
+// fish : 2013-12-12 Fox Woods, LLC
+fish
+
+// fishing : 2013-11-21 Top Level Domain Holdings Limited
+fishing
+
+// fit : 2014-11-07 Top Level Domain Holdings Limited
+fit
+
+// fitness : 2014-03-06 Brice Orchard, LLC
+fitness
+
+// flickr : 2015-04-02 Yahoo! Domain Services Inc.
+flickr
+
+// flights : 2013-12-05 Fox Station, LLC
+flights
+
+// flir : 2015-07-23 FLIR Systems, Inc.
+flir
+
+// florist : 2013-11-07 Half Cypress, LLC
+florist
+
+// flowers : 2014-10-09 Uniregistry, Corp.
+flowers
+
+// flsmidth : 2014-07-24 FLSmidth A/S
+flsmidth
+
+// fly : 2014-05-08 Charleston Road Registry Inc.
+fly
+
+// foo : 2014-01-23 Charleston Road Registry Inc.
+foo
+
+// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc.
+foodnetwork
+
+// football : 2014-12-18 Foggy Farms, LLC
+football
+
+// ford : 2014-11-13 Ford Motor Company
+ford
+
+// forex : 2014-12-11 IG Group Holdings PLC
+forex
+
+// forsale : 2014-05-22
+forsale
+
+// forum : 2015-04-02 Fegistry, LLC
+forum
+
+// foundation : 2013-12-05 John Dale, LLC
+foundation
+
+// fox : 2015-09-11 FOX Registry, LLC
+fox
+
+// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH
+fresenius
+
+// frl : 2014-05-15 FRLregistry B.V.
+frl
+
+// frogans : 2013-12-19 OP3FT
+frogans
+
+// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc.
+frontdoor
+
+// frontier : 2015-02-05 Frontier Communications Corporation
+frontier
+
+// ftr : 2015-07-16 Frontier Communications Corporation
+ftr
+
+// fujitsu : 2015-07-30 Fujitsu Limited
+fujitsu
+
+// fujixerox : 2015-07-23 Xerox DNHC LLC
+fujixerox
+
+// fund : 2014-03-20 John Castle, LLC
+fund
+
+// furniture : 2014-03-20 Lone Fields, LLC
+furniture
+
+// futbol : 2013-09-20
+futbol
+
+// fyi : 2015-04-02 Silver Tigers, LLC
+fyi
+
+// gal : 2013-11-07 Asociación puntoGAL
+gal
+
+// gallery : 2013-09-13 Sugar House, LLC
+gallery
+
+// gallo : 2015-06-11 Gallo Vineyards, Inc.
+gallo
+
+// gallup : 2015-02-19 Gallup, Inc.
+gallup
+
+// game : 2015-05-28 Uniregistry, Corp.
+game
+
+// games : 2015-05-28 Foggy Beach, LLC
+games
+
+// gap : 2015-07-31 The Gap, Inc.
+gap
+
+// garden : 2014-06-26 Top Level Domain Holdings Limited
+garden
+
+// gbiz : 2014-07-17 Charleston Road Registry Inc.
+gbiz
+
+// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems"
+gdn
+
+// gea : 2014-12-04 GEA Group Aktiengesellschaft
+gea
+
+// gent : 2014-01-23 COMBELL GROUP NV/SA
+gent
+
+// genting : 2015-03-12 Resorts World Inc Pte. Ltd.
+genting
+
+// george : 2015-07-31 Wal-Mart Stores, Inc.
+george
+
+// ggee : 2014-01-09 GMO Internet, Inc.
+ggee
+
+// gift : 2013-10-17 Uniregistry, Corp.
+gift
+
+// gifts : 2014-07-03 Goose Sky, LLC
+gifts
+
+// gives : 2014-03-06 United TLD Holdco Ltd.
+gives
+
+// giving : 2014-11-13 Giving Limited
+giving
+
+// glade : 2015-07-23 Johnson Shareholdings, Inc.
+glade
+
+// glass : 2013-11-07 Black Cover, LLC
+glass
+
+// gle : 2014-07-24 Charleston Road Registry Inc.
+gle
+
+// global : 2014-04-17 Dot GLOBAL AS
+global
+
+// globo : 2013-12-19 Globo Comunicação e Participações S.A
+globo
+
+// gmail : 2014-05-01 Charleston Road Registry Inc.
+gmail
+
+// gmo : 2014-01-09 GMO Internet, Inc.
+gmo
+
+// gmx : 2014-04-24 1&1 Mail & Media GmbH
+gmx
+
+// godaddy : 2015-07-23 Go Daddy East, LLC
+godaddy
+
+// gold : 2015-01-22 June Edge, LLC
+gold
+
+// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+goldpoint
+
+// golf : 2014-12-18 Lone falls, LLC
+golf
+
+// goo : 2014-12-18 NTT Resonant Inc.
+goo
+
+// goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company
+goodhands
+
+// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company
+goodyear
+
+// goog : 2014-11-20 Charleston Road Registry Inc.
+goog
+
+// google : 2014-07-24 Charleston Road Registry Inc.
+google
+
+// gop : 2014-01-16 Republican State Leadership Committee, Inc.
+gop
+
+// got : 2014-12-18 Amazon EU S.à r.l.
+got
+
+// gotv : 2015-03-12 MultiChoice (Proprietary) Limited
+gotv
+
+// grainger : 2015-05-07 Grainger Registry Services, LLC
+grainger
+
+// graphics : 2013-09-13 Over Madison, LLC
+graphics
+
+// gratis : 2014-03-20 Pioneer Tigers, LLC
+gratis
+
+// green : 2014-05-08 Afilias Limited
+green
+
+// gripe : 2014-03-06 Corn Sunset, LLC
+gripe
+
+// group : 2014-08-15 Romeo Town, LLC
+group
+
+// guardian : 2015-07-30 The Guardian Life Insurance Company of America
+guardian
+
+// gucci : 2014-11-13 Guccio Gucci S.p.a.
+gucci
+
+// guge : 2014-08-28 Charleston Road Registry Inc.
+guge
+
+// guide : 2013-09-13 Snow Moon, LLC
+guide
+
+// guitars : 2013-11-14 Uniregistry, Corp.
+guitars
+
+// guru : 2013-08-27 Pioneer Cypress, LLC
+guru
+
+// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH
+hamburg
+
+// hangout : 2014-11-13 Charleston Road Registry Inc.
+hangout
+
+// haus : 2013-12-05
+haus
+
+// hbo : 2015-07-30 HBO Registry Services, Inc.
+hbo
+
+// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED
+hdfc
+
+// hdfcbank : 2015-02-12 HDFC Bank Limited
+hdfcbank
+
+// health : 2015-02-11 DotHealth, LLC
+health
+
+// healthcare : 2014-06-12 Silver Glen, LLC
+healthcare
+
+// help : 2014-06-26 Uniregistry, Corp.
+help
+
+// helsinki : 2015-02-05 City of Helsinki
+helsinki
+
+// here : 2014-02-06 Charleston Road Registry Inc.
+here
+
+// hermes : 2014-07-10 HERMES INTERNATIONAL
+hermes
+
+// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc.
+hgtv
+
+// hiphop : 2014-03-06 Uniregistry, Corp.
+hiphop
+
+// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc.
+hisamitsu
+
+// hitachi : 2014-10-31 Hitachi, Ltd.
+hitachi
+
+// hiv : 2014-03-13 dotHIV gemeinnuetziger e.V.
+hiv
+
+// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited
+hkt
+
+// hockey : 2015-03-19 Half Willow, LLC
+hockey
+
+// holdings : 2013-08-27 John Madison, LLC
+holdings
+
+// holiday : 2013-11-07 Goose Woods, LLC
+holiday
+
+// homedepot : 2015-04-02 Homer TLC, Inc.
+homedepot
+
+// homegoods : 2015-07-16 The TJX Companies, Inc.
+homegoods
+
+// homes : 2014-01-09 DERHomes, LLC
+homes
+
+// homesense : 2015-07-16 The TJX Companies, Inc.
+homesense
+
+// honda : 2014-12-18 Honda Motor Co., Ltd.
+honda
+
+// honeywell : 2015-07-23 Honeywell GTLD LLC
+honeywell
+
+// horse : 2013-11-21 Top Level Domain Holdings Limited
+horse
+
+// host : 2014-04-17 DotHost Inc.
+host
+
+// hosting : 2014-05-29 Uniregistry, Corp.
+hosting
+
+// hot : 2015-08-27 Amazon EU S.à r.l.
+hot
+
+// hoteles : 2015-03-05 Travel Reservations SRL
+hoteles
+
+// hotmail : 2014-12-18 Microsoft Corporation
+hotmail
+
+// house : 2013-11-07 Sugar Park, LLC
+house
+
+// how : 2014-01-23 Charleston Road Registry Inc.
+how
+
+// hsbc : 2014-10-24 HSBC Holdings PLC
+hsbc
+
+// htc : 2015-04-02 HTC corporation
+htc
+
+// hughes : 2015-07-30 Hughes Satellite Systems Corporation
+hughes
+
+// hyatt : 2015-07-30 Hyatt GTLD, L.L.C.
+hyatt
+
+// hyundai : 2015-07-09 Hyundai Motor Company
+hyundai
+
+// ibm : 2014-07-31 International Business Machines Corporation
+ibm
+
+// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited
+icbc
+
+// ice : 2014-10-30 IntercontinentalExchange, Inc.
+ice
+
+// icu : 2015-01-08 One.com A/S
+icu
+
+// ieee : 2015-07-23 IEEE Global LLC
+ieee
+
+// ifm : 2014-01-30 ifm electronic gmbh
+ifm
+
+// iinet : 2014-07-03 Connect West Pty. Ltd.
+iinet
+
+// ikano : 2015-07-09 Ikano S.A.
+ikano
+
+// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation)
+imamat
+
+// imdb : 2015-06-25 Amazon EU S.à r.l.
+imdb
+
+// immo : 2014-07-10 Auburn Bloom, LLC
+immo
+
+// immobilien : 2013-11-07 United TLD Holdco Ltd.
+immobilien
+
+// industries : 2013-12-05 Outer House, LLC
+industries
+
+// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD.
+infiniti
+
+// ing : 2014-01-23 Charleston Road Registry Inc.
+ing
+
+// ink : 2013-12-05 Top Level Design, LLC
+ink
+
+// institute : 2013-11-07 Outer Maple, LLC
+institute
+
+// insurance : 2015-02-19 fTLD Registry Services LLC
+insurance
+
+// insure : 2014-03-20 Pioneer Willow, LLC
+insure
+
+// intel : 2015-08-06 Intel Corporation
+intel
+
+// international : 2013-11-07 Wild Way, LLC
+international
+
+// intuit : 2015-07-30 Intuit Administrative Services, Inc.
+intuit
+
+// investments : 2014-03-20 Holly Glen, LLC
+investments
+
+// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A.
+ipiranga
+
+// irish : 2014-08-07 Dot-Irish LLC
+irish
+
+// iselect : 2015-02-11 iSelect Ltd
+iselect
+
+// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation)
+ismaili
+
+// ist : 2014-08-28 Istanbul Metropolitan Municipality
+ist
+
+// istanbul : 2014-08-28 Istanbul Metropolitan Municipality
+istanbul
+
+// itau : 2014-10-02 Itau Unibanco Holding S.A.
+itau
+
+// itv : 2015-07-09 ITV Services Limited
+itv
+
+// iveco : 2015-09-03 CNH Industrial N.V.
+iveco
+
+// iwc : 2014-06-23 Richemont DNS Inc.
+iwc
+
+// jaguar : 2014-11-13 Jaguar Land Rover Ltd
+jaguar
+
+// java : 2014-06-19 Oracle Corporation
+java
+
+// jcb : 2014-11-20 JCB Co., Ltd.
+jcb
+
+// jcp : 2015-04-23 JCP Media, Inc.
+jcp
+
+// jeep : 2015-07-30 FCA US LLC.
+jeep
+
+// jetzt : 2014-01-09 New TLD Company AB
+jetzt
+
+// jewelry : 2015-03-05 Wild Bloom, LLC
+jewelry
+
+// jio : 2015-04-02 Affinity Names, Inc.
+jio
+
+// jlc : 2014-12-04 Richemont DNS Inc.
+jlc
+
+// jll : 2015-04-02 Jones Lang LaSalle Incorporated
+jll
+
+// jmp : 2015-03-26 Matrix IP LLC
+jmp
+
+// jnj : 2015-06-18 Johnson & Johnson Services, Inc.
+jnj
+
+// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+joburg
+
+// jot : 2014-12-18 Amazon EU S.à r.l.
+jot
+
+// joy : 2014-12-18 Amazon EU S.à r.l.
+joy
+
+// jpmorgan : 2015-04-30 JPMorgan Chase & Co.
+jpmorgan
+
+// jprs : 2014-09-18 Japan Registry Services Co., Ltd.
+jprs
+
+// juegos : 2014-03-20 Uniregistry, Corp.
+juegos
+
+// juniper : 2015-07-30 JUNIPER NETWORKS, INC.
+juniper
+
+// kaufen : 2013-11-07 United TLD Holdco Ltd.
+kaufen
+
+// kddi : 2014-09-12 KDDI CORPORATION
+kddi
+
+// kerryhotels : 2015-04-30 Kerry Trading Co. Limited
+kerryhotels
+
+// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited
+kerrylogistics
+
+// kerryproperties : 2015-04-09 Kerry Trading Co. Limited
+kerryproperties
+
+// kfh : 2014-12-04 Kuwait Finance House
+kfh
+
+// kia : 2015-07-09 KIA MOTORS CORPORATION
+kia
+
+// kim : 2013-09-23 Afilias Limited
+kim
+
+// kinder : 2014-11-07 Ferrero Trading Lux S.A.
+kinder
+
+// kindle : 2015-06-25 Amazon EU S.à r.l.
+kindle
+
+// kitchen : 2013-09-20 Just Goodbye, LLC
+kitchen
+
+// kiwi : 2013-09-20 DOT KIWI LIMITED
+kiwi
+
+// koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH
+koeln
+
+// komatsu : 2015-01-08 Komatsu Ltd.
+komatsu
+
+// kosher : 2015-08-20 Kosher Marketing Assets LLC
+kosher
+
+// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft)
+kpmg
+
+// kpn : 2015-01-08 Koninklijke KPN N.V.
+kpn
+
+// krd : 2013-12-05 KRG Department of Information Technology
+krd
+
+// kred : 2013-12-19 KredTLD Pty Ltd
+kred
+
+// kuokgroup : 2015-04-09 Kerry Trading Co. Limited
+kuokgroup
+
+// kyknet : 2015-03-05 Electronic Media Network (Pty) Ltd
+kyknet
+
+// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen
+kyoto
+
+// lacaixa : 2014-01-09 CAIXA D'ESTALVIS I PENSIONS DE BARCELONA
+lacaixa
+
+// ladbrokes : 2015-08-06 LADBROKES INTERNATIONAL PLC
+ladbrokes
+
+// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A.
+lamborghini
+
+// lamer : 2015-10-01 The Estée Lauder Companies Inc.
+lamer
+
+// lancaster : 2015-02-12 LANCASTER
+lancaster
+
+// lancia : 2015-07-31 Fiat Chrysler Automobiles N.V.
+lancia
+
+// lancome : 2015-07-23 L'Oréal
+lancome
+
+// land : 2013-09-10 Pine Moon, LLC
+land
+
+// landrover : 2014-11-13 Jaguar Land Rover Ltd
+landrover
+
+// lanxess : 2015-07-30 LANXESS Corporation
+lanxess
+
+// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated
+lasalle
+
+// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico
+lat
+
+// latino : 2015-07-30 Dish DBS Corporation
+latino
+
+// latrobe : 2014-06-16 La Trobe University
+latrobe
+
+// law : 2015-01-22 Minds + Machines Group Limited
+law
+
+// lawyer : 2014-03-20
+lawyer
+
+// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant")
+lds
+
+// lease : 2014-03-06 Victor Trail, LLC
+lease
+
+// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
+leclerc
+
+// lefrak : 2015-07-16 LeFrak Organization, Inc.
+lefrak
+
+// legal : 2014-10-16 Blue Falls, LLC
+legal
+
+// lego : 2015-07-16 LEGO Juris A/S
+lego
+
+// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION
+lexus
+
+// lgbt : 2014-05-08 Afilias Limited
+lgbt
+
+// liaison : 2014-10-02 Liaison Technologies, Incorporated
+liaison
+
+// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+lidl
+
+// life : 2014-02-06 Trixy Oaks, LLC
+life
+
+// lifeinsurance : 2015-01-15 American Council of Life Insurers
+lifeinsurance
+
+// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc.
+lifestyle
+
+// lighting : 2013-08-27 John McCook, LLC
+lighting
+
+// like : 2014-12-18 Amazon EU S.à r.l.
+like
+
+// lilly : 2015-07-31 Eli Lilly and Company
+lilly
+
+// limited : 2014-03-06 Big Fest, LLC
+limited
+
+// limo : 2013-10-17 Hidden Frostbite, LLC
+limo
+
+// lincoln : 2014-11-13 Ford Motor Company
+lincoln
+
+// linde : 2014-12-04 Linde Aktiengesellschaft
+linde
+
+// link : 2013-11-14 Uniregistry, Corp.
+link
+
+// lipsy : 2015-06-25 Lipsy Ltd
+lipsy
+
+// live : 2014-12-04
+live
+
+// living : 2015-07-30 Lifestyle Domain Holdings, Inc.
+living
+
+// lixil : 2015-03-19 LIXIL Group Corporation
+lixil
+
+// loan : 2014-11-20 dot Loan Limited
+loan
+
+// loans : 2014-03-20 June Woods, LLC
+loans
+
+// locker : 2015-06-04 Dish DBS Corporation
+locker
+
+// locus : 2015-06-25 Locus Analytics LLC
+locus
+
+// loft : 2015-07-30 Annco, Inc.
+loft
+
+// lol : 2015-01-30 Uniregistry, Corp.
+lol
+
+// london : 2013-11-14 Dot London Domains Limited
+london
+
+// lotte : 2014-11-07 Lotte Holdings Co., Ltd.
+lotte
+
+// lotto : 2014-04-10 Afilias Limited
+lotto
+
+// love : 2014-12-22 Merchant Law Group LLP
+love
+
+// lpl : 2015-07-30 LPL Holdings, Inc.
+lpl
+
+// lplfinancial : 2015-07-30 LPL Holdings, Inc.
+lplfinancial
+
+// ltd : 2014-09-25 Over Corner, LLC
+ltd
+
+// ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA
+ltda
+
+// lundbeck : 2015-08-06 H. Lundbeck A/S
+lundbeck
+
+// lupin : 2014-11-07 LUPIN LIMITED
+lupin
+
+// luxe : 2014-01-09 Top Level Domain Holdings Limited
+luxe
+
+// luxury : 2013-10-17 Luxury Partners, LLC
+luxury
+
+// macys : 2015-07-31 Macys, Inc.
+macys
+
+// madrid : 2014-05-01 Comunidad de Madrid
+madrid
+
+// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF)
+maif
+
+// maison : 2013-12-05 Victor Frostbite, LLC
+maison
+
+// makeup : 2015-01-15 L'Oréal
+makeup
+
+// man : 2014-12-04 MAN SE
+man
+
+// management : 2013-11-07 John Goodbye, LLC
+management
+
+// mango : 2013-10-24 PUNTO FA S.L.
+mango
+
+// market : 2014-03-06
+market
+
+// marketing : 2013-11-07 Fern Pass, LLC
+marketing
+
+// markets : 2014-12-11 IG Group Holdings PLC
+markets
+
+// marriott : 2014-10-09 Marriott Worldwide Corporation
+marriott
+
+// marshalls : 2015-07-16 The TJX Companies, Inc.
+marshalls
+
+// maserati : 2015-07-31 Fiat Chrysler Automobiles N.V.
+maserati
+
+// mattel : 2015-08-06 Mattel Sites, Inc.
+mattel
+
+// mba : 2015-04-02 Lone Hollow, LLC
+mba
+
+// mcd : 2015-07-30 McDonald’s Corporation
+mcd
+
+// mcdonalds : 2015-07-30 McDonald’s Corporation
+mcdonalds
+
+// mckinsey : 2015-07-31 McKinsey Holdings, Inc.
+mckinsey
+
+// med : 2015-08-06 Medistry LLC
+med
+
+// media : 2014-03-06 Grand Glen, LLC
+media
+
+// meet : 2014-01-16
+meet
+
+// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation
+melbourne
+
+// meme : 2014-01-30 Charleston Road Registry Inc.
+meme
+
+// memorial : 2014-10-16 Dog Beach, LLC
+memorial
+
+// men : 2015-02-26 Exclusive Registry Limited
+men
+
+// menu : 2013-09-11 Wedding TLD2, LLC
+menu
+
+// meo : 2014-11-07 PT Comunicacoes S.A.
+meo
+
+// metlife : 2015-05-07 MetLife Services and Solutions, LLC
+metlife
+
+// miami : 2013-12-19 Top Level Domain Holdings Limited
+miami
+
+// microsoft : 2014-12-18 Microsoft Corporation
+microsoft
+
+// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+mini
+
+// mint : 2015-07-30 Intuit Administrative Services, Inc.
+mint
+
+// mit : 2015-07-02 Massachusetts Institute of Technology
+mit
+
+// mitsubishi : 2015-07-23 Mitsubishi Corporation
+mitsubishi
+
+// mlb : 2015-05-21 MLB Advanced Media DH, LLC
+mlb
+
+// mls : 2015-04-23 The Canadian Real Estate Association
+mls
+
+// mma : 2014-11-07 MMA IARD
+mma
+
+// mnet : 2015-03-05 Electronic Media Network (Pty) Ltd
+mnet
+
+// mobily : 2014-12-18 GreenTech Consultancy Company W.L.L.
+mobily
+
+// moda : 2013-11-07 United TLD Holdco Ltd.
+moda
+
+// moe : 2013-11-13 Interlink Co., Ltd.
+moe
+
+// moi : 2014-12-18 Amazon EU S.à r.l.
+moi
+
+// mom : 2015-04-16 Uniregistry, Corp.
+mom
+
+// monash : 2013-09-30 Monash University
+monash
+
+// money : 2014-10-16 Outer McCook, LLC
+money
+
+// monster : 2015-09-11 Monster Worldwide, Inc.
+monster
+
+// montblanc : 2014-06-23 Richemont DNS Inc.
+montblanc
+
+// mopar : 2015-07-30 FCA US LLC.
+mopar
+
+// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant")
+mormon
+
+// mortgage : 2014-03-20
+mortgage
+
+// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+moscow
+
+// moto : 2015-06-04 Charleston Road Registry Inc.
+moto
+
+// motorcycles : 2014-01-09 DERMotorcycles, LLC
+motorcycles
+
+// mov : 2014-01-30 Charleston Road Registry Inc.
+mov
+
+// movie : 2015-02-05 New Frostbite, LLC
+movie
+
+// movistar : 2014-10-16 Telefónica S.A.
+movistar
+
+// msd : 2015-07-23 MSD Registry Holdings, Inc.
+msd
+
+// mtn : 2014-12-04 MTN Dubai Limited
+mtn
+
+// mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation
+mtpc
+
+// mtr : 2015-03-12 MTR Corporation Limited
+mtr
+
+// multichoice : 2015-03-12 MultiChoice (Proprietary) Limited
+multichoice
+
+// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC
+mutual
+
+// mutuelle : 2015-06-18 Fédération Nationale de la Mutualité Française
+mutuelle
+
+// mzansimagic : 2015-03-05 Electronic Media Network (Pty) Ltd
+mzansimagic
+
+// nab : 2015-08-20 National Australia Bank Limited
+nab
+
+// nadex : 2014-12-11 IG Group Holdings PLC
+nadex
+
+// nagoya : 2013-10-24 GMO Registry, Inc.
+nagoya
+
+// naspers : 2015-02-12 Intelprop (Proprietary) Limited
+naspers
+
+// nationwide : 2015-07-23 Nationwide Mutual Insurance Company
+nationwide
+
+// natura : 2015-03-12 NATURA COSMÉTICOS S.A.
+natura
+
+// navy : 2014-03-06 United TLD Holdco Ltd.
+navy
+
+// nba : 2015-07-31 NBA REGISTRY, LLC
+nba
+
+// nec : 2015-01-08 NEC Corporation
+nec
+
+// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+netbank
+
+// netflix : 2015-06-18 Netflix, Inc.
+netflix
+
+// network : 2013-11-14 Trixy Manor, LLC
+network
+
+// neustar : 2013-12-05 NeuStar, Inc.
+neustar
+
+// new : 2014-01-30 Charleston Road Registry Inc.
+new
+
+// newholland : 2015-09-03 CNH Industrial N.V.
+newholland
+
+// news : 2014-12-18
+news
+
+// next : 2015-06-18 Next plc
+next
+
+// nextdirect : 2015-06-18 Next plc
+nextdirect
+
+// nexus : 2014-07-24 Charleston Road Registry Inc.
+nexus
+
+// nfl : 2015-07-23 NFL Reg Ops LLC
+nfl
+
+// ngo : 2014-03-06 Public Interest Registry
+ngo
+
+// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK)
+nhk
+
+// nico : 2014-12-04 DWANGO Co., Ltd.
+nico
+
+// nike : 2015-07-23 NIKE, Inc.
+nike
+
+// nikon : 2015-05-21 NIKON CORPORATION
+nikon
+
+// ninja : 2013-11-07 United TLD Holdco Ltd.
+ninja
+
+// nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
+nissan
+
+// nissay : 2015-10-29 Nippon Life Insurance Company
+nissay
+
+// nokia : 2015-01-08 Nokia Corporation
+nokia
+
+// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC
+northwesternmutual
+
+// norton : 2014-12-04 Symantec Corporation
+norton
+
+// now : 2015-06-25 Amazon EU S.à r.l.
+now
+
+// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+nowruz
+
+// nowtv : 2015-05-14 Starbucks (HK) Limited
+nowtv
+
+// nra : 2014-05-22 NRA Holdings Company, INC.
+nra
+
+// nrw : 2013-11-21 Minds + Machines GmbH
+nrw
+
+// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+ntt
+
+// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications
+nyc
+
+// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA
+obi
+
+// observer : 2015-04-30 Guardian News and Media Limited
+observer
+
+// off : 2015-07-23 Johnson Shareholdings, Inc.
+off
+
+// office : 2015-03-12 Microsoft Corporation
+office
+
+// okinawa : 2013-12-05 BusinessRalliart Inc.
+okinawa
+
+// olayan : 2015-05-14 Crescent Holding GmbH
+olayan
+
+// olayangroup : 2015-05-14 Crescent Holding GmbH
+olayangroup
+
+// oldnavy : 2015-07-31 The Gap, Inc.
+oldnavy
+
+// ollo : 2015-06-04 Dish DBS Corporation
+ollo
+
+// omega : 2015-01-08 The Swatch Group Ltd
+omega
+
+// one : 2014-11-07 One.com A/S
+one
+
+// ong : 2014-03-06 Public Interest Registry
+ong
+
+// onl : 2013-09-16 I-Registry Ltd.
+onl
+
+// online : 2015-01-15 DotOnline Inc.
+online
+
+// onyourside : 2015-07-23 Nationwide Mutual Insurance Company
+onyourside
+
+// ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED
+ooo
+
+// open : 2015-07-31 American Express Travel Related Services Company, Inc.
+open
+
+// oracle : 2014-06-19 Oracle Corporation
+oracle
+
+// orange : 2015-03-12 Orange Brand Services Limited
+orange
+
+// organic : 2014-03-27 Afilias Limited
+organic
+
+// orientexpress : 2015-02-05 Belmond Ltd.
+orientexpress
+
+// origins : 2015-10-01 The Estée Lauder Companies Inc.
+origins
+
+// osaka : 2014-09-04 Interlink Co., Ltd.
+osaka
+
+// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd.
+otsuka
+
+// ott : 2015-06-04 Dish DBS Corporation
+ott
+
+// ovh : 2014-01-16 OVH SAS
+ovh
+
+// page : 2014-12-04 Charleston Road Registry Inc.
+page
+
+// pamperedchef : 2015-02-05 The Pampered Chef, Ltd.
+pamperedchef
+
+// panasonic : 2015-07-30 Panasonic Corporation
+panasonic
+
+// panerai : 2014-11-07 Richemont DNS Inc.
+panerai
+
+// paris : 2014-01-30 City of Paris
+paris
+
+// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+pars
+
+// partners : 2013-12-05 Magic Glen, LLC
+partners
+
+// parts : 2013-12-05 Sea Goodbye, LLC
+parts
+
+// party : 2014-09-11 Blue Sky Registry Limited
+party
+
+// passagens : 2015-03-05 Travel Reservations SRL
+passagens
+
+// pay : 2015-08-27 Amazon EU S.à r.l.
+pay
+
+// payu : 2015-02-12 MIH PayU B.V.
+payu
+
+// pccw : 2015-05-14 PCCW Enterprises Limited
+pccw
+
+// pet : 2015-05-07 Afilias plc
+pet
+
+// pfizer : 2015-09-11 Pfizer Inc.
+pfizer
+
+// pharmacy : 2014-06-19 National Association of Boards of Pharmacy
+pharmacy
+
+// philips : 2014-11-07 Koninklijke Philips N.V.
+philips
+
+// photo : 2013-11-14 Uniregistry, Corp.
+photo
+
+// photography : 2013-09-20 Sugar Glen, LLC
+photography
+
+// photos : 2013-10-17 Sea Corner, LLC
+photos
+
+// physio : 2014-05-01 PhysBiz Pty Ltd
+physio
+
+// piaget : 2014-10-16 Richemont DNS Inc.
+piaget
+
+// pics : 2013-11-14 Uniregistry, Corp.
+pics
+
+// pictet : 2014-06-26 Pictet Europe S.A.
+pictet
+
+// pictures : 2014-03-06 Foggy Sky, LLC
+pictures
+
+// pid : 2015-01-08 Top Level Spectrum, Inc.
+pid
+
+// pin : 2014-12-18 Amazon EU S.à r.l.
+pin
+
+// ping : 2015-06-11 Ping Registry Provider, Inc.
+ping
+
+// pink : 2013-10-01 Afilias Limited
+pink
+
+// pioneer : 2015-07-16 Pioneer Corporation
+pioneer
+
+// pizza : 2014-06-26 Foggy Moon, LLC
+pizza
+
+// place : 2014-04-24 Snow Galley, LLC
+place
+
+// play : 2015-03-05 Charleston Road Registry Inc.
+play
+
+// playstation : 2015-07-02 Sony Computer Entertainment Inc.
+playstation
+
+// plumbing : 2013-09-10 Spring Tigers, LLC
+plumbing
+
+// plus : 2015-02-05 Sugar Mill, LLC
+plus
+
+// pnc : 2015-07-02 PNC Domain Co., LLC
+pnc
+
+// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+pohl
+
+// poker : 2014-07-03 Afilias Domains No. 5 Limited
+poker
+
+// politie : 2015-08-20 Politie Nederland
+politie
+
+// porn : 2014-10-16 ICM Registry PN LLC
+porn
+
+// pramerica : 2015-07-30 Prudential Financial, Inc.
+pramerica
+
+// praxi : 2013-12-05 Praxi S.p.A.
+praxi
+
+// press : 2014-04-03 DotPress Inc.
+press
+
+// prime : 2015-06-25 Amazon EU S.à r.l.
+prime
+
+// prod : 2014-01-23 Charleston Road Registry Inc.
+prod
+
+// productions : 2013-12-05 Magic Birch, LLC
+productions
+
+// prof : 2014-07-24 Charleston Road Registry Inc.
+prof
+
+// progressive : 2015-07-23 Progressive Casualty Insurance Company
+progressive
+
+// promo : 2014-12-18 Play.PROMO Oy
+promo
+
+// properties : 2013-12-05 Big Pass, LLC
+properties
+
+// property : 2014-05-22 Uniregistry, Corp.
+property
+
+// protection : 2015-04-23
+protection
+
+// pru : 2015-07-30 Prudential Financial, Inc.
+pru
+
+// prudential : 2015-07-30 Prudential Financial, Inc.
+prudential
+
+// pub : 2013-12-12 United TLD Holdco Ltd.
+pub
+
+// pwc : 2015-10-29 PricewaterhouseCoopers LLP
+pwc
+
+// qpon : 2013-11-14 dotCOOL, Inc.
+qpon
+
+// quebec : 2013-12-19 PointQuébec Inc
+quebec
+
+// quest : 2015-03-26 Quest ION Limited
+quest
+
+// qvc : 2015-07-30 QVC, Inc.
+qvc
+
+// racing : 2014-12-04 Premier Registry Limited
+racing
+
+// raid : 2015-07-23 Johnson Shareholdings, Inc.
+raid
+
+// read : 2014-12-18 Amazon EU S.à r.l.
+read
+
+// realestate : 2015-09-11 dotRealEstate LLC
+realestate
+
+// realtor : 2014-05-29 Real Estate Domains LLC
+realtor
+
+// realty : 2015-03-19 Fegistry, LLC
+realty
+
+// recipes : 2013-10-17 Grand Island, LLC
+recipes
+
+// red : 2013-11-07 Afilias Limited
+red
+
+// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd.
+redstone
+
+// redumbrella : 2015-03-26 Travelers TLD, LLC
+redumbrella
+
+// rehab : 2014-03-06 United TLD Holdco Ltd.
+rehab
+
+// reise : 2014-03-13
+reise
+
+// reisen : 2014-03-06 New Cypress, LLC
+reisen
+
+// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc.
+reit
+
+// reliance : 2015-04-02 Reliance Industries Limited
+reliance
+
+// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd.
+ren
+
+// rent : 2014-12-04 DERRent, LLC
+rent
+
+// rentals : 2013-12-05 Big Hollow,LLC
+rentals
+
+// repair : 2013-11-07 Lone Sunset, LLC
+repair
+
+// report : 2013-12-05 Binky Glen, LLC
+report
+
+// republican : 2014-03-20 United TLD Holdco Ltd.
+republican
+
+// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+rest
+
+// restaurant : 2014-07-03 Snow Avenue, LLC
+restaurant
+
+// review : 2014-11-20 dot Review Limited
+review
+
+// reviews : 2013-09-13
+reviews
+
+// rexroth : 2015-06-18 Robert Bosch GMBH
+rexroth
+
+// rich : 2013-11-21 I-Registry Ltd.
+rich
+
+// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited
+richardli
+
+// ricoh : 2014-11-20 Ricoh Company, Ltd.
+ricoh
+
+// rightathome : 2015-07-23 Johnson Shareholdings, Inc.
+rightathome
+
+// ril : 2015-04-02 Reliance Industries Limited
+ril
+
+// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO
+rio
+
+// rip : 2014-07-10 United TLD Holdco Ltd.
+rip
+
+// rocher : 2014-12-18 Ferrero Trading Lux S.A.
+rocher
+
+// rocks : 2013-11-14
+rocks
+
+// rodeo : 2013-12-19 Top Level Domain Holdings Limited
+rodeo
+
+// rogers : 2015-08-06 Rogers Communications Partnership
+rogers
+
+// room : 2014-12-18 Amazon EU S.à r.l.
+room
+
+// rsvp : 2014-05-08 Charleston Road Registry Inc.
+rsvp
+
+// ruhr : 2013-10-02 regiodot GmbH & Co. KG
+ruhr
+
+// run : 2015-03-19 Snow Park, LLC
+run
+
+// rwe : 2015-04-02 RWE AG
+rwe
+
+// ryukyu : 2014-01-09 BusinessRalliart Inc.
+ryukyu
+
+// saarland : 2013-12-12 dotSaarland GmbH
+saarland
+
+// safe : 2014-12-18 Amazon EU S.à r.l.
+safe
+
+// safety : 2015-01-08 Safety Registry Services, LLC.
+safety
+
+// sakura : 2014-12-18 SAKURA Internet Inc.
+sakura
+
+// sale : 2014-10-16
+sale
+
+// salon : 2014-12-11 Outer Orchard, LLC
+salon
+
+// samsclub : 2015-07-31 Wal-Mart Stores, Inc.
+samsclub
+
+// samsung : 2014-04-03 SAMSUNG SDS CO., LTD
+samsung
+
+// sandvik : 2014-11-13 Sandvik AB
+sandvik
+
+// sandvikcoromant : 2014-11-07 Sandvik AB
+sandvikcoromant
+
+// sanofi : 2014-10-09 Sanofi
+sanofi
+
+// sap : 2014-03-27 SAP AG
+sap
+
+// sapo : 2014-11-07 PT Comunicacoes S.A.
+sapo
+
+// sarl : 2014-07-03 Delta Orchard, LLC
+sarl
+
+// sas : 2015-04-02 Research IP LLC
+sas
+
+// save : 2015-06-25 Amazon EU S.à r.l.
+save
+
+// saxo : 2014-10-31 Saxo Bank A/S
+saxo
+
+// sbi : 2015-03-12 STATE BANK OF INDIA
+sbi
+
+// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION
+sbs
+
+// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ)
+sca
+
+// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB")
+scb
+
+// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG
+schaeffler
+
+// schmidt : 2014-04-03 SALM S.A.S.
+schmidt
+
+// scholarships : 2014-04-24 Scholarships.com, LLC
+scholarships
+
+// school : 2014-12-18 Little Galley, LLC
+school
+
+// schule : 2014-03-06 Outer Moon, LLC
+schule
+
+// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+schwarz
+
+// science : 2014-09-11 dot Science Limited
+science
+
+// scjohnson : 2015-07-23 Johnson Shareholdings, Inc.
+scjohnson
+
+// scor : 2014-10-31 SCOR SE
+scor
+
+// scot : 2014-01-23 Dot Scot Registry Limited
+scot
+
+// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal)
+seat
+
+// secure : 2015-08-27 Amazon EU S.à r.l.
+secure
+
+// security : 2015-05-14
+security
+
+// seek : 2014-12-04 Seek Limited
+seek
+
+// select : 2015-10-08 iSelect Ltd
+select
+
+// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A.
+sener
+
+// services : 2014-02-27 Fox Castle, LLC
+services
+
+// ses : 2015-07-23 SES
+ses
+
+// seven : 2015-08-06 Seven West Media Ltd
+seven
+
+// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG
+sew
+
+// sex : 2014-11-13 ICM Registry SX LLC
+sex
+
+// sexy : 2013-09-11 Uniregistry, Corp.
+sexy
+
+// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR
+sfr
+
+// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited
+shangrila
+
+// sharp : 2014-05-01 Sharp Corporation
+sharp
+
+// shaw : 2015-04-23 Shaw Cablesystems G.P.
+shaw
+
+// shell : 2015-07-30 Shell Information Technology International Inc
+shell
+
+// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+shia
+
+// shiksha : 2013-11-14 Afilias Limited
+shiksha
+
+// shoes : 2013-10-02 Binky Galley, LLC
+shoes
+
+// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+shouji
+
+// show : 2015-03-05 Snow Beach, LLC
+show
+
+// showtime : 2015-08-06 CBS Domains Inc.
+showtime
+
+// shriram : 2014-01-23 Shriram Capital Ltd.
+shriram
+
+// silk : 2015-06-25 Amazon EU S.à r.l.
+silk
+
+// sina : 2015-03-12 Sina Corporation
+sina
+
+// singles : 2013-08-27 Fern Madison, LLC
+singles
+
+// site : 2015-01-15 DotSite Inc.
+site
+
+// ski : 2015-04-09 STARTING DOT LIMITED
+ski
+
+// skin : 2015-01-15 L'Oréal
+skin
+
+// sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch
+sky
+
+// skype : 2014-12-18 Microsoft Corporation
+skype
+
+// sling : 2015-07-30 Hughes Satellite Systems Corporation
+sling
+
+// smart : 2015-07-09 Smart Communications, Inc. (SMART)
+smart
+
+// smile : 2014-12-18 Amazon EU S.à r.l.
+smile
+
+// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F
+sncf
+
+// soccer : 2015-03-26 Foggy Shadow, LLC
+soccer
+
+// social : 2013-11-07 United TLD Holdco Ltd.
+social
+
+// softbank : 2015-07-02 SoftBank Corp.
+softbank
+
+// software : 2014-03-20
+software
+
+// sohu : 2013-12-19 Sohu.com Limited
+sohu
+
+// solar : 2013-11-07 Ruby Town, LLC
+solar
+
+// solutions : 2013-11-07 Silver Cover, LLC
+solutions
+
+// song : 2015-02-26 Amazon EU S.à r.l.
+song
+
+// sony : 2015-01-08 Sony Corporation
+sony
+
+// soy : 2014-01-23 Charleston Road Registry Inc.
+soy
+
+// space : 2014-04-03 DotSpace Inc.
+space
+
+// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG
+spiegel
+
+// spot : 2015-02-26 Amazon EU S.à r.l.
+spot
+
+// spreadbetting : 2014-12-11 IG Group Holdings PLC
+spreadbetting
+
+// srl : 2015-05-07 mySRL GmbH
+srl
+
+// srt : 2015-07-30 FCA US LLC.
+srt
+
+// stada : 2014-11-13 STADA Arzneimittel AG
+stada
+
+// staples : 2015-07-30 Staples, Inc.
+staples
+
+// star : 2015-01-08 Star India Private Limited
+star
+
+// starhub : 2015-02-05 StarHub Ltd
+starhub
+
+// statebank : 2015-03-12 STATE BANK OF INDIA
+statebank
+
+// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company
+statefarm
+
+// statoil : 2014-12-04 Statoil ASA
+statoil
+
+// stc : 2014-10-09 Saudi Telecom Company
+stc
+
+// stcgroup : 2014-10-09 Saudi Telecom Company
+stcgroup
+
+// stockholm : 2014-12-18 Stockholms kommun
+stockholm
+
+// storage : 2014-12-22 Self Storage Company LLC
+storage
+
+// store : 2015-04-09 DotStore Inc.
+store
+
+// studio : 2015-02-11
+studio
+
+// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+study
+
+// style : 2014-12-04 Binky Moon, LLC
+style
+
+// sucks : 2014-12-22 Vox Populi Registry Inc.
+sucks
+
+// supersport : 2015-03-05 SuperSport International Holdings Proprietary Limited
+supersport
+
+// supplies : 2013-12-19 Atomic Fields, LLC
+supplies
+
+// supply : 2013-12-19 Half Falls, LLC
+supply
+
+// support : 2013-10-24 Grand Orchard, LLC
+support
+
+// surf : 2014-01-09 Top Level Domain Holdings Limited
+surf
+
+// surgery : 2014-03-20 Tin Avenue, LLC
+surgery
+
+// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION
+suzuki
+
+// swatch : 2015-01-08 The Swatch Group Ltd
+swatch
+
+// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited
+swiftcover
+
+// swiss : 2014-10-16 Swiss Confederation
+swiss
+
+// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet
+sydney
+
+// symantec : 2014-12-04 Symantec Corporation
+symantec
+
+// systems : 2013-11-07 Dash Cypress, LLC
+systems
+
+// tab : 2014-12-04 Tabcorp Holdings Limited
+tab
+
+// taipei : 2014-07-10 Taipei City Government
+taipei
+
+// talk : 2015-04-09 Amazon EU S.à r.l.
+talk
+
+// taobao : 2015-01-15 Alibaba Group Holding Limited
+taobao
+
+// target : 2015-07-31 Target Domain Holdings, LLC
+target
+
+// tatamotors : 2015-03-12 Tata Motors Ltd
+tatamotors
+
+// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic"
+tatar
+
+// tattoo : 2013-08-30 Uniregistry, Corp.
+tattoo
+
+// tax : 2014-03-20 Storm Orchard, LLC
+tax
+
+// taxi : 2015-03-19 Pine Falls, LLC
+taxi
+
+// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+tci
+
+// tdk : 2015-06-11 TDK Corporation
+tdk
+
+// team : 2015-03-05 Atomic Lake, LLC
+team
+
+// tech : 2015-01-30 Dot Tech LLC
+tech
+
+// technology : 2013-09-13 Auburn Falls
+technology
+
+// telecity : 2015-02-19 TelecityGroup International Limited
+telecity
+
+// telefonica : 2014-10-16 Telefónica S.A.
+telefonica
+
+// temasek : 2014-08-07 Temasek Holdings (Private) Limited
+temasek
+
+// tennis : 2014-12-04 Cotton Bloom, LLC
+tennis
+
+// teva : 2015-07-02 Teva Pharmaceutical Industries Limited
+teva
+
+// thd : 2015-04-02 Homer TLC, Inc.
+thd
+
+// theater : 2015-03-19 Blue Tigers, LLC
+theater
+
+// theatre : 2015-05-07
+theatre
+
+// theguardian : 2015-04-30 Guardian News and Media Limited
+theguardian
+
+// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America
+tiaa
+
+// tickets : 2015-02-05 Accent Media Limited
+tickets
+
+// tienda : 2013-11-14 Victor Manor, LLC
+tienda
+
+// tiffany : 2015-01-30 Tiffany and Company
+tiffany
+
+// tips : 2013-09-20 Corn Willow, LLC
+tips
+
+// tires : 2014-11-07 Dog Edge, LLC
+tires
+
+// tirol : 2014-04-24 punkt Tirol GmbH
+tirol
+
+// tjmaxx : 2015-07-16 The TJX Companies, Inc.
+tjmaxx
+
+// tjx : 2015-07-16 The TJX Companies, Inc.
+tjx
+
+// tkmaxx : 2015-07-16 The TJX Companies, Inc.
+tkmaxx
+
+// tmall : 2015-01-15 Alibaba Group Holding Limited
+tmall
+
+// today : 2013-09-20 Pearl Woods, LLC
+today
+
+// tokyo : 2013-11-13 GMO Registry, Inc.
+tokyo
+
+// tools : 2013-11-21 Pioneer North, LLC
+tools
+
+// top : 2014-03-20 Jiangsu Bangning Science & Technology Co.,Ltd.
+top
+
+// toray : 2014-12-18 Toray Industries, Inc.
+toray
+
+// toshiba : 2014-04-10 TOSHIBA Corporation
+toshiba
+
+// total : 2015-08-06 Total SA
+total
+
+// tours : 2015-01-22 Sugar Station, LLC
+tours
+
+// town : 2014-03-06 Koko Moon, LLC
+town
+
+// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION
+toyota
+
+// toys : 2014-03-06 Pioneer Orchard, LLC
+toys
+
+// trade : 2014-01-23 Elite Registry Limited
+trade
+
+// trading : 2014-12-11 IG Group Holdings PLC
+trading
+
+// training : 2013-11-07 Wild Willow, LLC
+training
+
+// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc.
+travelchannel
+
+// travelers : 2015-03-26 Travelers TLD, LLC
+travelers
+
+// travelersinsurance : 2015-03-26 Travelers TLD, LLC
+travelersinsurance
+
+// trust : 2014-10-16
+trust
+
+// trv : 2015-03-26 Travelers TLD, LLC
+trv
+
+// tube : 2015-06-11 Latin American Telecom LLC
+tube
+
+// tui : 2014-07-03 TUI AG
+tui
+
+// tunes : 2015-02-26 Amazon EU S.à r.l.
+tunes
+
+// tushu : 2014-12-18 Amazon EU S.à r.l.
+tushu
+
+// tvs : 2015-02-19 T V SUNDRAM IYENGAR  & SONS LIMITED
+tvs
+
+// ubank : 2015-08-20 National Australia Bank Limited
+ubank
+
+// ubs : 2014-12-11 UBS AG
+ubs
+
+// uconnect : 2015-07-30 FCA US LLC.
+uconnect
+
+// unicom : 2015-10-15 China United Network Communications Corporation Limited
+unicom
+
+// university : 2014-03-06 Little Station, LLC
+university
+
+// uno : 2013-09-11 Dot Latin LLC
+uno
+
+// uol : 2014-05-01 UBN INTERNET LTDA.
+uol
+
+// ups : 2015-06-25 UPS Market Driver, Inc.
+ups
+
+// vacations : 2013-12-05 Atomic Tigers, LLC
+vacations
+
+// vana : 2014-12-11 Lifestyle Domain Holdings, Inc.
+vana
+
+// vanguard : 2015-09-03 The Vanguard Group, Inc.
+vanguard
+
+// vegas : 2014-01-16 Dot Vegas, Inc.
+vegas
+
+// ventures : 2013-08-27 Binky Lake, LLC
+ventures
+
+// verisign : 2015-08-13 VeriSign, Inc.
+verisign
+
+// versicherung : 2014-03-20 dotversicherung-registry GmbH
+versicherung
+
+// vet : 2014-03-06
+vet
+
+// viajes : 2013-10-17 Black Madison, LLC
+viajes
+
+// video : 2014-10-16
+video
+
+// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe
+vig
+
+// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd.
+viking
+
+// villas : 2013-12-05 New Sky, LLC
+villas
+
+// vin : 2015-06-18 Holly Shadow, LLC
+vin
+
+// vip : 2015-01-22 Minds + Machines Group Limited
+vip
+
+// virgin : 2014-09-25 Virgin Enterprises Limited
+virgin
+
+// visa : 2015-07-30 Visa Worldwide Pte. Limited
+visa
+
+// vision : 2013-12-05 Koko Station, LLC
+vision
+
+// vista : 2014-09-18 Vistaprint Limited
+vista
+
+// vistaprint : 2014-09-18 Vistaprint Limited
+vistaprint
+
+// viva : 2014-11-07 Saudi Telecom Company
+viva
+
+// vivo : 2015-07-31 Telefonica Brasil S.A.
+vivo
+
+// vlaanderen : 2014-02-06 DNS.be vzw
+vlaanderen
+
+// vodka : 2013-12-19 Top Level Domain Holdings Limited
+vodka
+
+// volkswagen : 2015-05-14 Volkswagen Group of America Inc.
+volkswagen
+
+// vote : 2013-11-21 Monolith Registry LLC
+vote
+
+// voting : 2013-11-13 Valuetainment Corp.
+voting
+
+// voto : 2013-11-21 Monolith Registry LLC
+voto
+
+// voyage : 2013-08-27 Ruby House, LLC
+voyage
+
+// vuelos : 2015-03-05 Travel Reservations SRL
+vuelos
+
+// wales : 2014-05-08 Nominet UK
+wales
+
+// walmart : 2015-07-31 Wal-Mart Stores, Inc.
+walmart
+
+// walter : 2014-11-13 Sandvik AB
+walter
+
+// wang : 2013-10-24 Zodiac Leo Limited
+wang
+
+// wanggou : 2014-12-18 Amazon EU S.à r.l.
+wanggou
+
+// warman : 2015-06-18 Weir Group IP Limited
+warman
+
+// watch : 2013-11-14 Sand Shadow, LLC
+watch
+
+// watches : 2014-12-22 Richemont DNS Inc.
+watches
+
+// weather : 2015-01-08 The Weather Channel, LLC
+weather
+
+// weatherchannel : 2015-03-12 The Weather Channel, LLC
+weatherchannel
+
+// webcam : 2014-01-23 dot Webcam Limited
+webcam
+
+// weber : 2015-06-04 Saint-Gobain Weber SA
+weber
+
+// website : 2014-04-03 DotWebsite Inc.
+website
+
+// wed : 2013-10-01 Atgron, Inc.
+wed
+
+// wedding : 2014-04-24 Top Level Domain Holdings Limited
+wedding
+
+// weibo : 2015-03-05 Sina Corporation
+weibo
+
+// weir : 2015-01-29 Weir Group IP Limited
+weir
+
+// whoswho : 2014-02-20 Who's Who Registry
+whoswho
+
+// wien : 2013-10-28 punkt.wien GmbH
+wien
+
+// wiki : 2013-11-07 Top Level Design, LLC
+wiki
+
+// williamhill : 2014-03-13 William Hill Organization Limited
+williamhill
+
+// win : 2014-11-20 First Registry Limited
+win
+
+// windows : 2014-12-18 Microsoft Corporation
+windows
+
+// wine : 2015-06-18 June Station, LLC
+wine
+
+// winners : 2015-07-16 The TJX Companies, Inc.
+winners
+
+// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC
+wme
+
+// wolterskluwer : 2015-08-06 Wolters Kluwer N.V.
+wolterskluwer
+
+// woodside : 2015-07-09 Woodside Petroleum Limited
+woodside
+
+// work : 2013-12-19 Top Level Domain Holdings Limited
+work
+
+// works : 2013-11-14 Little Dynamite, LLC
+works
+
+// world : 2014-06-12 Bitter Fields, LLC
+world
+
+// wow : 2015-10-08 Amazon EU S.à r.l.
+wow
+
+// wtc : 2013-12-19 World Trade Centers Association, Inc.
+wtc
+
+// wtf : 2014-03-06 Hidden Way, LLC
+wtf
+
+// xbox : 2014-12-18 Microsoft Corporation
+xbox
+
+// xerox : 2014-10-24 Xerox DNHC LLC
+xerox
+
+// xfinity : 2015-07-09 Comcast IP Holdings I, LLC
+xfinity
+
+// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+xihuan
+
+// xin : 2014-12-11 Elegant Leader Limited
+xin
+
+// xn--11b4c3d : 2015-01-15 VeriSign Sarl
+कॉम
+
+// xn--1ck2e1b : 2015-02-26 Amazon EU S.à r.l.
+セール
+
+// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd.
+佛山
+
+// xn--30rr7y : 2014-06-12 Excellent First Limited
+慈善
+
+// xn--3bst00m : 2013-09-13 Eagle Horizon Limited
+集团
+
+// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED
+在线
+
+// xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd.
+大众汽车
+
+// xn--3pxu8k : 2015-01-15 VeriSign Sarl
+点看
+
+// xn--42c2d9a : 2015-01-15 VeriSign Sarl
+คอม
+
+// xn--45q11c : 2013-11-21 Zodiac Scorpio Limited
+八卦
+
+// xn--4gbrim : 2013-10-04 Suhub Electronic Establishment
+موقع
+
+// xn--4gq48lf9j : 2015-07-31 Wal-Mart Stores, Inc.
+一号店
+
+// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center
+公益
+
+// xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center)
+公司
+
+// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited
+香格里拉
+
+// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited
+网站
+
+// xn--6frz82g : 2013-09-23 Afilias Limited
+移动
+
+// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited
+我爱你
+
+// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+москва
+
+// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+католик
+
+// xn--80asehdb : 2013-07-14 CORE Association
+онлайн
+
+// xn--80aswg : 2013-07-14 CORE Association
+сайт
+
+// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited
+联通
+
+// xn--9dbq2a : 2015-01-15 VeriSign Sarl
+קום
+
+// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED
+时尚
+
+// xn--9krt00a : 2015-03-12 Sina Corporation
+微博
+
+// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited
+淡马锡
+
+// xn--bck1b9a5dre4c : 2015-02-26 Amazon EU S.à r.l.
+ファッション
+
+// xn--c1avg : 2013-11-14 Public Interest Registry
+орг
+
+// xn--c2br7g : 2015-01-15 VeriSign Sarl
+नेट
+
+// xn--cck2b3b : 2015-02-26 Amazon EU S.à r.l.
+ストア
+
+// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD
+삼성
+
+// xn--czr694b : 2014-01-16 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY. HONGKONG LIMITED
+商标
+
+// xn--czrs0t : 2013-12-19 Wild Island, LLC
+商店
+
+// xn--czru2d : 2013-11-21 Zodiac Capricorn Limited
+商城
+
+// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet”
+дети
+
+// xn--eckvdtc9d : 2014-12-18 Amazon EU S.à r.l.
+ポイント
+
+// xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社
+新闻
+
+// xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited
+工行
+
+// xn--fct429k : 2015-04-09 Amazon EU S.à r.l.
+家電
+
+// xn--fhbei : 2015-01-15 VeriSign Sarl
+كوم
+
+// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED
+中文网
+
+// xn--fiq64b : 2013-10-14 CITIC Group Corporation
+中信
+
+// xn--fjq720a : 2014-05-22 Will Bloom, LLC
+娱乐
+
+// xn--flw351e : 2014-07-31 Charleston Road Registry Inc.
+谷歌
+
+// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited
+電訊盈科
+
+// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited
+购物
+
+// xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l.
+クラウド
+
+// xn--gk3at1e : 2015-10-08 Amazon EU S.à r.l.
+通販
+
+// xn--hxt814e : 2014-05-15 Zodiac Libra Limited
+网店
+
+// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry
+संगठन
+
+// xn--imr513n : 2014-12-11 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY. HONGKONG LIMITED
+餐厅
+
+// xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center)
+网络
+
+// xn--j1aef : 2015-01-15 VeriSign Sarl
+ком
+
+// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation
+诺基亚
+
+// xn--jvr189m : 2015-02-26 Amazon EU S.à r.l.
+食品
+
+// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V.
+飞利浦
+
+// xn--kpu716f : 2014-12-22 Richemont DNS Inc.
+手表
+
+// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd
+手机
+
+// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company
+ارامكو
+
+// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH
+العليان
+
+// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat)
+اتصالات
+
+// xn--mgbab2bd : 2013-10-31 CORE Association
+بازار
+
+// xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L.
+موبايلي
+
+// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre
+ابوظبي
+
+// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+كاثوليك
+
+// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+همراه
+
+// xn--mk1bu44c : 2015-01-15 VeriSign Sarl
+닷컴
+
+// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd.
+政府
+
+// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd.
+شبكة
+
+// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House
+بيتك
+
+// xn--nqv7f : 2013-11-14 Public Interest Registry
+机构
+
+// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry
+组织机构
+
+// xn--nyqy26a : 2014-11-07 Stable Tone Limited
+健康
+
+// xn--p1acf : 2013-12-12 Rusnames Limited
+рус
+
+// xn--pbt977c : 2014-12-22 Richemont DNS Inc.
+珠宝
+
+// xn--pssy2u : 2015-01-15 VeriSign Sarl
+大拿
+
+// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc.
+みんな
+
+// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc.
+グーグル
+
+// xn--rhqv96g : 2013-09-11 Stable Tone Limited
+世界
+
+// xn--rovu88b : 2015-02-26 Amazon EU S.à r.l.
+書籍
+
+// xn--ses554g : 2014-01-16
+网址
+
+// xn--t60b56a : 2015-01-15 VeriSign Sarl
+닷넷
+
+// xn--tckwe : 2015-01-15 VeriSign Sarl
+コム
+
+// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+天主教
+
+// xn--unup4y : 2013-07-14 Spring Fields, LLC
+游戏
+
+// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+vermögensberater
+
+// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+vermögensberatung
+
+// xn--vhquv : 2013-08-27 Dash McCook, LLC
+企业
+
+// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd.
+信息
+
+// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited
+嘉里大酒店
+
+// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited
+嘉里
+
+// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd.
+广东
+
+// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center
+政务
+
+// xperia : 2015-05-14 Sony Mobile Communications AB
+xperia
+
+// xyz : 2013-12-05 XYZ.COM LLC
+xyz
+
+// yachts : 2014-01-09 DERYachts, LLC
+yachts
+
+// yahoo : 2015-04-02 Yahoo! Domain Services Inc.
+yahoo
+
+// yamaxun : 2014-12-18 Amazon EU S.à r.l.
+yamaxun
+
+// yandex : 2014-04-10 YANDEX, LLC
+yandex
+
+// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+yodobashi
+
+// yoga : 2014-05-29 Top Level Domain Holdings Limited
+yoga
+
+// yokohama : 2013-12-12 GMO Registry, Inc.
+yokohama
+
+// you : 2015-04-09 Amazon EU S.à r.l.
+you
+
+// youtube : 2014-05-01 Charleston Road Registry Inc.
+youtube
+
+// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+yun
+
+// zappos : 2015-06-25 Amazon EU S.à r.l.
+zappos
+
+// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.)
+zara
+
+// zero : 2014-12-18 Amazon EU S.à r.l.
+zero
+
+// zip : 2014-05-08 Charleston Road Registry Inc.
+zip
+
+// zippo : 2015-07-02 Zadco Company
+zippo
+
+// zone : 2013-11-14 Outer Falls, LLC
+zone
+
+// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich)
+zuerich
+
+
+// ===END ICANN DOMAINS===
+// ===BEGIN PRIVATE DOMAINS===
+// (Note: these are in alphabetical order by company name)
+
+// Amazon CloudFront : https://aws.amazon.com/cloudfront/
+// Submitted by Donavan Miller <donavanm@amazon.com> 2013-03-22
+cloudfront.net
+
+// Amazon Elastic Compute Cloud: https://aws.amazon.com/ec2/
+// Submitted by Osman Surkatty <osmans@amazon.com> 2014-12-16
+ap-northeast-1.compute.amazonaws.com
+ap-southeast-1.compute.amazonaws.com
+ap-southeast-2.compute.amazonaws.com
+cn-north-1.compute.amazonaws.cn
+compute.amazonaws.cn
+compute.amazonaws.com
+compute-1.amazonaws.com
+eu-west-1.compute.amazonaws.com
+eu-central-1.compute.amazonaws.com
+sa-east-1.compute.amazonaws.com
+us-east-1.amazonaws.com
+us-gov-west-1.compute.amazonaws.com
+us-west-1.compute.amazonaws.com
+us-west-2.compute.amazonaws.com
+z-1.compute-1.amazonaws.com
+z-2.compute-1.amazonaws.com
+
+// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/
+// Submitted by Adam Stein <astein@amazon.com> 2013-04-02
+elasticbeanstalk.com
+
+// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/
+// Submitted by Scott Vidmar <svidmar@amazon.com> 2013-03-27
+elb.amazonaws.com
+
+// Amazon S3 : https://aws.amazon.com/s3/
+// Submitted by Eric Kinolik <kilo@amazon.com> 2015-04-08
+s3.amazonaws.com
+s3-ap-northeast-1.amazonaws.com
+s3-ap-southeast-1.amazonaws.com
+s3-ap-southeast-2.amazonaws.com
+s3-external-1.amazonaws.com
+s3-external-2.amazonaws.com
+s3-fips-us-gov-west-1.amazonaws.com
+s3-eu-central-1.amazonaws.com
+s3-eu-west-1.amazonaws.com
+s3-sa-east-1.amazonaws.com
+s3-us-gov-west-1.amazonaws.com
+s3-us-west-1.amazonaws.com
+s3-us-west-2.amazonaws.com
+s3.cn-north-1.amazonaws.com.cn
+s3.eu-central-1.amazonaws.com
+
+// BetaInABox
+// Submitted by adrian@betainabox.com 2012-09-13
+betainabox.com
+
+// CentralNic : http://www.centralnic.com/names/domains
+// Submitted by registry <gavin.brown@centralnic.com> 2012-09-27
+ae.org
+ar.com
+br.com
+cn.com
+com.de
+com.se
+de.com
+eu.com
+gb.com
+gb.net
+hu.com
+hu.net
+jp.net
+jpn.com
+kr.com
+mex.com
+no.com
+qc.com
+ru.com
+sa.com
+se.com
+se.net
+uk.com
+uk.net
+us.com
+uy.com
+za.bz
+za.com
+
+// Africa.com Web Solutions Ltd : https://registry.africa.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com> 2014-02-04
+africa.com
+
+// iDOT Services Limited : http://www.domain.gr.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com> 2014-02-04
+gr.com
+
+// Radix FZC : http://domains.in.net
+// Submitted by Gavin Brown <gavin.brown@centralnic.com> 2014-02-04
+in.net
+
+// US REGISTRY LLC : http://us.org
+// Submitted by Gavin Brown <gavin.brown@centralnic.com> 2014-02-04
+us.org
+
+// co.com Registry, LLC : https://registry.co.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com> 2014-02-04
+co.com
+
+// c.la : http://www.c.la/
+c.la
+
+// cloudControl : https://www.cloudcontrol.com/
+// Submitted by Tobias Wilken <tw@cloudcontrol.com> 2013-07-23
+cloudcontrolled.com
+cloudcontrolapp.com
+
+// co.ca : http://registry.co.ca/
+co.ca
+
+// CDN77.com : http://www.cdn77.com
+// Submitted by Jan Krpes <jan.krpes@cdn77.com> 2015-07-13
+c.cdn77.org
+cdn77-ssl.net
+r.cdn77.net
+rsc.cdn77.org
+ssl.origin.cdn77-secure.org
+
+// CoDNS B.V.
+co.nl
+co.no
+
+// Commerce Guys, SAS
+// Submitted by Damien Tournoud <damien@commerceguys.com> 2015-01-22
+*.platform.sh
+
+// Cupcake : https://cupcake.io/
+// Submitted by Jonathan Rudenberg <jonathan@cupcake.io> 2013-10-08
+cupcake.is
+
+// DreamHost : http://www.dreamhost.com/
+// Submitted by Andrew Farmer <andrew.farmer@dreamhost.com> 2012-10-02
+dreamhosters.com
+
+// DuckDNS : http://www.duckdns.org/
+// Submitted by Richard Harper <richard@duckdns.org> 2015-05-17
+duckdns.org
+
+// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/
+dyndns-at-home.com
+dyndns-at-work.com
+dyndns-blog.com
+dyndns-free.com
+dyndns-home.com
+dyndns-ip.com
+dyndns-mail.com
+dyndns-office.com
+dyndns-pics.com
+dyndns-remote.com
+dyndns-server.com
+dyndns-web.com
+dyndns-wiki.com
+dyndns-work.com
+dyndns.biz
+dyndns.info
+dyndns.org
+dyndns.tv
+at-band-camp.net
+ath.cx
+barrel-of-knowledge.info
+barrell-of-knowledge.info
+better-than.tv
+blogdns.com
+blogdns.net
+blogdns.org
+blogsite.org
+boldlygoingnowhere.org
+broke-it.net
+buyshouses.net
+cechire.com
+dnsalias.com
+dnsalias.net
+dnsalias.org
+dnsdojo.com
+dnsdojo.net
+dnsdojo.org
+does-it.net
+doesntexist.com
+doesntexist.org
+dontexist.com
+dontexist.net
+dontexist.org
+doomdns.com
+doomdns.org
+dvrdns.org
+dyn-o-saur.com
+dynalias.com
+dynalias.net
+dynalias.org
+dynathome.net
+dyndns.ws
+endofinternet.net
+endofinternet.org
+endoftheinternet.org
+est-a-la-maison.com
+est-a-la-masion.com
+est-le-patron.com
+est-mon-blogueur.com
+for-better.biz
+for-more.biz
+for-our.info
+for-some.biz
+for-the.biz
+forgot.her.name
+forgot.his.name
+from-ak.com
+from-al.com
+from-ar.com
+from-az.net
+from-ca.com
+from-co.net
+from-ct.com
+from-dc.com
+from-de.com
+from-fl.com
+from-ga.com
+from-hi.com
+from-ia.com
+from-id.com
+from-il.com
+from-in.com
+from-ks.com
+from-ky.com
+from-la.net
+from-ma.com
+from-md.com
+from-me.org
+from-mi.com
+from-mn.com
+from-mo.com
+from-ms.com
+from-mt.com
+from-nc.com
+from-nd.com
+from-ne.com
+from-nh.com
+from-nj.com
+from-nm.com
+from-nv.com
+from-ny.net
+from-oh.com
+from-ok.com
+from-or.com
+from-pa.com
+from-pr.com
+from-ri.com
+from-sc.com
+from-sd.com
+from-tn.com
+from-tx.com
+from-ut.com
+from-va.com
+from-vt.com
+from-wa.com
+from-wi.com
+from-wv.com
+from-wy.com
+ftpaccess.cc
+fuettertdasnetz.de
+game-host.org
+game-server.cc
+getmyip.com
+gets-it.net
+go.dyndns.org
+gotdns.com
+gotdns.org
+groks-the.info
+groks-this.info
+ham-radio-op.net
+here-for-more.info
+hobby-site.com
+hobby-site.org
+home.dyndns.org
+homedns.org
+homeftp.net
+homeftp.org
+homeip.net
+homelinux.com
+homelinux.net
+homelinux.org
+homeunix.com
+homeunix.net
+homeunix.org
+iamallama.com
+in-the-band.net
+is-a-anarchist.com
+is-a-blogger.com
+is-a-bookkeeper.com
+is-a-bruinsfan.org
+is-a-bulls-fan.com
+is-a-candidate.org
+is-a-caterer.com
+is-a-celticsfan.org
+is-a-chef.com
+is-a-chef.net
+is-a-chef.org
+is-a-conservative.com
+is-a-cpa.com
+is-a-cubicle-slave.com
+is-a-democrat.com
+is-a-designer.com
+is-a-doctor.com
+is-a-financialadvisor.com
+is-a-geek.com
+is-a-geek.net
+is-a-geek.org
+is-a-green.com
+is-a-guru.com
+is-a-hard-worker.com
+is-a-hunter.com
+is-a-knight.org
+is-a-landscaper.com
+is-a-lawyer.com
+is-a-liberal.com
+is-a-libertarian.com
+is-a-linux-user.org
+is-a-llama.com
+is-a-musician.com
+is-a-nascarfan.com
+is-a-nurse.com
+is-a-painter.com
+is-a-patsfan.org
+is-a-personaltrainer.com
+is-a-photographer.com
+is-a-player.com
+is-a-republican.com
+is-a-rockstar.com
+is-a-socialist.com
+is-a-soxfan.org
+is-a-student.com
+is-a-teacher.com
+is-a-techie.com
+is-a-therapist.com
+is-an-accountant.com
+is-an-actor.com
+is-an-actress.com
+is-an-anarchist.com
+is-an-artist.com
+is-an-engineer.com
+is-an-entertainer.com
+is-by.us
+is-certified.com
+is-found.org
+is-gone.com
+is-into-anime.com
+is-into-cars.com
+is-into-cartoons.com
+is-into-games.com
+is-leet.com
+is-lost.org
+is-not-certified.com
+is-saved.org
+is-slick.com
+is-uberleet.com
+is-very-bad.org
+is-very-evil.org
+is-very-good.org
+is-very-nice.org
+is-very-sweet.org
+is-with-theband.com
+isa-geek.com
+isa-geek.net
+isa-geek.org
+isa-hockeynut.com
+issmarterthanyou.com
+isteingeek.de
+istmein.de
+kicks-ass.net
+kicks-ass.org
+knowsitall.info
+land-4-sale.us
+lebtimnetz.de
+leitungsen.de
+likes-pie.com
+likescandy.com
+merseine.nu
+mine.nu
+misconfused.org
+mypets.ws
+myphotos.cc
+neat-url.com
+office-on-the.net
+on-the-web.tv
+podzone.net
+podzone.org
+readmyblog.org
+saves-the-whales.com
+scrapper-site.net
+scrapping.cc
+selfip.biz
+selfip.com
+selfip.info
+selfip.net
+selfip.org
+sells-for-less.com
+sells-for-u.com
+sells-it.net
+sellsyourhome.org
+servebbs.com
+servebbs.net
+servebbs.org
+serveftp.net
+serveftp.org
+servegame.org
+shacknet.nu
+simple-url.com
+space-to-rent.com
+stuff-4-sale.org
+stuff-4-sale.us
+teaches-yoga.com
+thruhere.net
+traeumtgerade.de
+webhop.biz
+webhop.info
+webhop.net
+webhop.org
+worse-than.tv
+writesthisblog.com
+
+// EU.org https://eu.org/
+// Submitted by Pierre Beyssac <hostmaster@eu.org> 2015-04-17
+
+eu.org
+al.eu.org
+asso.eu.org
+at.eu.org
+au.eu.org
+be.eu.org
+bg.eu.org
+ca.eu.org
+cd.eu.org
+ch.eu.org
+cn.eu.org
+cy.eu.org
+cz.eu.org
+de.eu.org
+dk.eu.org
+edu.eu.org
+ee.eu.org
+es.eu.org
+fi.eu.org
+fr.eu.org
+gr.eu.org
+hr.eu.org
+hu.eu.org
+ie.eu.org
+il.eu.org
+in.eu.org
+int.eu.org
+is.eu.org
+it.eu.org
+jp.eu.org
+kr.eu.org
+lt.eu.org
+lu.eu.org
+lv.eu.org
+mc.eu.org
+me.eu.org
+mk.eu.org
+mt.eu.org
+my.eu.org
+net.eu.org
+ng.eu.org
+nl.eu.org
+no.eu.org
+nz.eu.org
+paris.eu.org
+pl.eu.org
+pt.eu.org
+q-a.eu.org
+ro.eu.org
+ru.eu.org
+se.eu.org
+si.eu.org
+sk.eu.org
+tr.eu.org
+uk.eu.org
+us.eu.org
+
+// Fastly Inc. http://www.fastly.com/
+// Submitted by Vladimir Vuksan <vladimir@fastly.com> 2013-05-31
+a.ssl.fastly.net
+b.ssl.fastly.net
+global.ssl.fastly.net
+a.prod.fastly.net
+global.prod.fastly.net
+
+// Firebase, Inc.
+// Submitted by Chris Raynor <chris@firebase.com> 2014-01-21
+firebaseapp.com
+
+// Flynn : https://flynn.io
+// Submitted by Jonathan Rudenberg <jonathan@flynn.io> 2014-07-12
+flynnhub.com
+
+// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains
+// Submitted by David Illsley <david.illsley@digital.cabinet-office.gov.uk> 2014-08-28
+service.gov.uk
+
+// GitHub, Inc.
+// Submitted by Ben Toews <btoews@github.com> 2014-02-06
+github.io
+githubusercontent.com
+
+// GlobeHosting, Inc.
+// Submitted by Zoltan Egresi <egresi@globehosting.com> 2013-07-12
+ro.com
+
+// Google, Inc.
+// Submitted by Eduardo Vela <evn@google.com> 2014-12-19
+appspot.com
+blogspot.ae
+blogspot.al
+blogspot.am
+blogspot.ba
+blogspot.be
+blogspot.bg
+blogspot.bj
+blogspot.ca
+blogspot.cf
+blogspot.ch
+blogspot.cl
+blogspot.co.at
+blogspot.co.id
+blogspot.co.il
+blogspot.co.ke
+blogspot.co.nz
+blogspot.co.uk
+blogspot.co.za
+blogspot.com
+blogspot.com.ar
+blogspot.com.au
+blogspot.com.br
+blogspot.com.by
+blogspot.com.co
+blogspot.com.cy
+blogspot.com.ee
+blogspot.com.eg
+blogspot.com.es
+blogspot.com.mt
+blogspot.com.ng
+blogspot.com.tr
+blogspot.com.uy
+blogspot.cv
+blogspot.cz
+blogspot.de
+blogspot.dk
+blogspot.fi
+blogspot.fr
+blogspot.gr
+blogspot.hk
+blogspot.hr
+blogspot.hu
+blogspot.ie
+blogspot.in
+blogspot.is
+blogspot.it
+blogspot.jp
+blogspot.kr
+blogspot.li
+blogspot.lt
+blogspot.lu
+blogspot.md
+blogspot.mk
+blogspot.mr
+blogspot.mx
+blogspot.my
+blogspot.nl
+blogspot.no
+blogspot.pe
+blogspot.pt
+blogspot.qa
+blogspot.re
+blogspot.ro
+blogspot.rs
+blogspot.ru
+blogspot.se
+blogspot.sg
+blogspot.si
+blogspot.sk
+blogspot.sn
+blogspot.td
+blogspot.tw
+blogspot.ug
+blogspot.vn
+codespot.com
+googleapis.com
+googlecode.com
+pagespeedmobilizer.com
+withgoogle.com
+withyoutube.com
+
+// Hashbang : https://hashbang.sh
+// Hashbang is a non-profit that provides shells and various other services.
+hashbang.sh
+
+// Heroku : https://www.heroku.com/
+// Submitted by Tom Maher <tmaher@heroku.com> 2013-05-02
+herokuapp.com
+herokussl.com
+
+// iki.fi
+// Submitted by Hannu Aronsson <haa@iki.fi> 2009-11-05
+iki.fi
+
+// info.at : http://www.info.at/
+biz.at
+info.at
+
+// Michau Enterprises Limited : http://www.co.pl/
+co.pl
+
+// Microsoft : http://microsoft.com
+// Submitted by Barry Dorrans <bdorrans@microsoft.com> 2014-01-24
+azurewebsites.net
+azure-mobile.net
+cloudapp.net
+
+// Mozilla Foundation : https://mozilla.org/
+// Submited by glob <glob@mozilla.com> 2015-07-06
+bmoattachments.org
+
+// Neustar Inc.
+// Submitted by Trung Tran <Trung.Tran@neustar.biz> 2015-04-23
+4u.com
+
+// ngrok : https://ngrok.com/
+// Submitted by Alan Shreve <alan@ngrok.com> 2015-11-10
+ngrok.io
+
+// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/
+// Submitted by Jeff Wheelhouse <support@nearlyfreespeech.net> 2014-02-02
+nfshost.com
+
+// NYC.mn : http://www.information.nyc.mn
+// Submitted by Matthew Brown <mattbrown@nyc.mn> 2013-03-11
+nyc.mn
+
+// One Fold Media : http://www.onefoldmedia.com/
+// Submitted by Eddie Jones <eddie@onefoldmedia.com> 2014-06-10
+nid.io
+
+// Opera Software, A.S.A.
+// Submitted by Yngve Pettersen <yngve@opera.com> 2009-11-26
+operaunite.com
+
+// OutSystems
+// Submitted by Duarte Santos <domain-admin@outsystemscloud.com> 2014-03-11
+outsystemscloud.com
+
+// Pagefront : https://www.pagefronthq.com/
+// Submitted by Jason Kriss <jason@pagefronthq.com> 2015-12-02
+pagefrontapp.com
+
+// .pl domains (grandfathered)
+art.pl
+gliwice.pl
+krakow.pl
+poznan.pl
+wroc.pl
+zakopane.pl
+
+// Pantheon Systems, Inc. : https://pantheon.io/
+// Submitted by Gary Dylina <gary@pantheon.io> 2015-09-14
+pantheon.io
+gotpantheon.com
+
+// priv.at : http://www.nic.priv.at/
+// Submitted by registry <lendl@nic.at> 2008-06-09
+priv.at
+
+// QA2
+// Submitted by Daniel Dent (https://www.danieldent.com/) 2015-07-16
+qa2.com
+
+// Rackmaze LLC : https://www.rackmaze.com
+// Submitted by Kirill Pertsev <kika@rackmaze.com> 2015-12-02
+rackmaze.com
+rackmaze.net
+
+// Red Hat, Inc. OpenShift : https://openshift.redhat.com/
+// Submitted by Tim Kramer <tkramer@rhcloud.com> 2012-10-24
+rhcloud.com
+
+// Sandstorm Development Group, Inc. : https://sandcats.io/
+// Submitted by Asheesh Laroia <asheesh@sandstorm.io> 2015-07-21
+sandcats.io
+
+// Service Online LLC : http://drs.ua/
+// Submitted by Serhii Bulakh <support@drs.ua> 2015-07-30
+biz.ua
+co.ua
+pp.ua
+
+// SinaAppEngine : http://sae.sina.com.cn/
+// Submitted by SinaAppEngine <saesupport@sinacloud.com> 2015-02-02
+sinaapp.com
+vipsinaapp.com
+1kapp.com
+
+// Synology, Inc. : https://www.synology.com/
+// Submitted by Rony Weng <ronyweng@synology.com> 2015-12-02
+synology.me
+diskstation.me
+i234.me
+myds.me
+dscloud.biz
+dscloud.me
+dscloud.mobi
+dsmynas.com
+dsmynas.net
+dsmynas.org
+familyds.com
+familyds.net
+familyds.org
+
+// TASK geographical domains (www.task.gda.pl/uslugi/dns)
+gda.pl
+gdansk.pl
+gdynia.pl
+med.pl
+sopot.pl
+
+// UDR Limited : http://www.udr.hk.com
+// Submitted by registry <hostmaster@udr.hk.com> 2014-11-07
+hk.com
+hk.org
+ltd.hk
+inc.hk
+
+// Yola : https://www.yola.com/
+// Submitted by Stefano Rivera <stefano@yola.com> 2014-07-09
+yolasite.com
+
+// ZaNiC : http://www.za.net/
+// Submitted by registry <hostmaster@nic.za.net> 2009-10-03
+za.net
+za.org
+
+// ===END PRIVATE DOMAINS===

+ 1 - 0
app/Models/.gitkeep

@@ -0,0 +1 @@
+

+ 27 - 0
app/Models/ProductConfiguration.php

@@ -0,0 +1,27 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Models;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 11:07
+ * Class ProductConfiguration
+ */
+class ProductConfiguration extends \ModulesGarden\Servers\KerioEmail\Core\Models\ExtendedEloquentModel
+{
+    protected $table = 'product_configuration';
+
+    protected $primaryKey = 'id';
+
+    protected $guarded = ['id'];
+
+    protected $fillable = ['product_id', 'setting','value'];
+
+    protected $softDelete = false;
+
+    public $timestamps = false;
+
+}

+ 39 - 0
app/Models/Whmcs/ProductConfigGroups.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Models\Whmcs;
+
+use \Illuminate\Database\Eloquent\model as EloquentModel;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\ProductConfigOption;
+
+/**
+ * Description of ProductConfigGroups
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@moduelsgarden.com>
+ *
+ * @property int $id
+ * @property string $name
+ * @property string $description
+ */
+class ProductConfigGroups extends EloquentModel
+{
+
+    /**
+     * Table name
+     *
+     * @var string
+     */
+    protected $table = 'tblproductconfiggroups';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = false;
+
+    public function options()
+    {
+        return $this->hasMany(ProductConfigOption::class, 'gid', 'id');
+    }
+
+}

+ 43 - 0
app/Models/Whmcs/ProductConfigLinks.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Models\Whmcs;
+
+use \Illuminate\Database\Eloquent\model as EloquentModel;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Product;
+
+/**
+ * Description of ProductConfigLinks
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@moduelsgarden.com>
+ *
+ * @property int $gid
+ * @property int $pid
+ */
+class ProductConfigLinks extends EloquentModel
+{
+
+    /**
+     * Table name
+     *
+     * @var string
+     */
+    protected $table = 'tblproductconfiglinks';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = false;
+
+    public function groups()
+    {
+        return $this->hasOne(ProductConfigGroups::class, 'id', 'gid');
+    }
+
+    public function product()
+    {
+        return $this->hasOne(Product::class, 'id', 'pid');
+    }
+
+}

+ 167 - 0
app/Services/ClientAreaSidebarService.php

@@ -0,0 +1,167 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Services;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Traits\HostingService;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ProductService;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\sl;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Sidebar\Sidebar;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Sidebar\SidebarItem;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Sidebar\SidebarService;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:23
+ * Class ClientAreaSidebarService
+ */
+class ClientAreaSidebarService
+{
+
+    const SUPPORTED_SERVER_TYPES = ['kerioEmail'];
+
+    use HostingService;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\WhmcsParams;
+    use ProductService;
+    //use ProductService;
+    //u/se BaseClientController;
+
+    /**
+     * @var \WHMCS\View\Menu\Item
+     */
+    private $primarySidebar;
+
+    /**
+     * ClientAreaSidebarService constructor.
+     * @param $hostingId
+     */
+    public function __construct($hostingId, \WHMCS\View\Menu\Item $primarySidebar)
+    {
+        $this->setHostingId($hostingId);
+        $this->primarySidebar = $primarySidebar;
+    }
+
+    /**
+     * @return $this|void
+     */
+    public function informationReplaceUri()
+    {
+        $overview = $this->primarySidebar->getChild('Service Details Overview');
+        if (!is_a($overview, '\WHMCS\View\Menu\Item'))
+        {
+            return;
+        }
+        $panel = $overview->getChild('Information');
+        if (!is_a($panel, '\WHMCS\View\Menu\Item'))
+        {
+            return;
+        }
+        $panel->setUri("clientarea.php?action=productdetails&id={$this->getHostingId()}");
+        $panel->setAttributes([]);
+        return $this;
+    }
+
+    /**
+     * @return $this|void
+     */
+    public function changePasswordReplaceUri()
+    {
+        $actions = $this->primarySidebar->getChild('Service Details Overview');
+        if (!is_a($actions, '\WHMCS\View\Menu\Item'))
+        {
+            return;
+        }
+        $panel = $actions->getChild('Change Password');
+        if (!is_a($panel, '\WHMCS\View\Menu\Item'))
+        {
+            return;
+        }
+        $panel->setUri("clientarea.php?action=productdetails&id={$this->getHostingId()}#tabChangepw");
+        $panel->setAttributes([]);
+        return $this;
+    }
+
+    /**
+     *
+     */
+    public function build()
+    {
+        if(!in_array($this->hosting()->product->servertype, self::SUPPORTED_SERVER_TYPES))
+        {
+            return;
+        }
+
+        /**
+         * @var SidebarService $sidebarService
+         */
+        $sidebarService = sl("sidebar");
+        $this->setProductId($this->hosting()->packageid);
+        /**
+         * product manager
+         */
+        $productManager = new ProductManager();
+        $productManager->loadById($this->hosting()->packageid);
+
+        /**
+         * @var $lang \ModulesGarden\Servers\ProxmoxVps\Core\Lang\Lang
+         */
+        $lang  = sl("lang");
+        $order = 671;
+        foreach ($sidebarService->get() as $sidebar)
+        {
+            /**
+             * @var Sidebar $sidebar
+             */
+            $newPanel = [
+                'label' => $lang->abtr($sidebar->getTitle()),
+                'order' => $order
+            ];
+            $order++;
+            $childPanel = $this->primarySidebar->addChild($sidebar->getName(), $newPanel);
+            foreach ($sidebar->getChildren() as $sidebarItem)
+            {
+                /**
+                 * @var SidebarItem $sidebarItem
+                 *
+                 * check if is enabled in configuration
+                 */
+                if(!$productManager->isSidebarEnabled($sidebarItem->getTitle()))
+                {
+                    continue;
+                }
+
+                /**
+                 *
+                 * add item to menu
+                 */
+                $newItem = [
+                    'label'   => $lang->abtr($sidebarItem->getTitle()),
+                    'uri'     => str_replace('{$hostingId}', $this->getHostingId(), $sidebarItem->getHref()),
+                    'order'   => $sidebarItem->getOrder(),
+                    "current" => $sidebarItem->isActive()
+                ];
+
+                $childPanel->addChild($sidebarItem->getName(), $newItem);
+            }
+        }
+    }
+
+    /**
+     * @return bool
+     */
+    public function isActive()
+    {
+        return true;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isSupportedModule()
+    {
+        return true;
+    }
+}

+ 287 - 0
app/Services/ConfigurableOptions/Abstracts/AbstractConfigurableOptions.php

@@ -0,0 +1,287 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Abstracts;
+
+use ModulesGarden\Servers\KerioEmail\App\Models\Whmcs\ProductConfigGroups;
+use ModulesGarden\Servers\KerioEmail\App\Models\Whmcs\ProductConfigLinks;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\Option;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\SubOption;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Currency;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Pricing;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Product;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\ProductConfigOption;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\ProductConfigOptionSub;
+
+/**
+ * Description of TypeConstans
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@modulesgarden.com>
+ */
+abstract class AbstractConfigurableOptions
+{
+    /*
+     * @var integer $productID;
+     */
+
+    protected $productID;
+    /*
+     * @var integer $optionsGroupID;
+     */
+    protected $optionsGroupID;
+    /*
+     * @var array $options;
+     */
+    protected $options = [];
+
+    /*
+     * Set Product ID
+     * 
+     * @params integer $productID
+     * @return void
+     */
+
+    public function __construct($porductID)
+    {
+        $this->productID = $porductID;
+    }
+
+    /*
+     * Create and assign configurable options group
+     * 
+     * @return object $this;
+     */
+
+
+    /*
+     * Get Product 
+     * 
+     * @return object \ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Product
+     * 
+     */
+
+    protected function getProduct()
+    {
+        return Product::where('id', $this->productID)->first();
+    }
+
+    protected function addGroup()
+    {
+        if (!$this->checkExistAssignedOptionsGroup())
+        {
+            $this->createOptionsGroup();
+            $this->assignGroupToProduct();
+            return true;
+        }
+    }
+
+    /*
+     * Check if configurable options exists
+     * 
+     * $params  integer $productId
+     * @throw \Exception
+     */
+
+    public function checkExistAssignedOptionsGroup()
+    {
+        $check = \ModulesGarden\Servers\KerioEmail\App\Models\Whmcs\ProductConfigLinks::where('pid', $this->productID)->first();
+        if (!is_null($check))
+        {
+            $this->optionsGroupID = $check->gid;
+            return true;
+        }
+    }
+
+    /*
+     * Prepare Options Array
+     * 
+     * 
+     * @return array $fields
+     */
+
+    protected function showOptions()
+    {
+        $fields = [];
+        foreach ($this->options as $option)
+        {
+            $fields[$option->getKey()] = $option->getName();
+        }
+        return $fields;
+    }
+
+    /*
+     * Add options group
+     *  
+     *
+     * @throw \Exception
+     */
+
+    protected function buildOptions()
+    {
+        if (is_array($this->options))
+        {
+            foreach ($this->options as $option)
+            {
+                $optionID = $this->createOptions($option);
+
+                if (!empty($option->getSubOptions()) && !empty($optionID))
+                {
+                    $this->buildSubOptions($optionID, $option->getSubOptions());
+                }
+            }
+        }
+    }
+
+    /*
+     * Add suboptions to options group
+     * 
+     * @params integer $optionsID
+     * @params object \ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\ProductConfigOptionSub $sobOptions
+     * @throw \Exception
+     */
+
+    protected function buildSubOptions($optionID, $subOptions)
+    {
+        if (is_array($subOptions))
+        {
+            foreach ($subOptions as $option)
+            {
+                $this->createSubOptions($optionID, $option);
+            }
+        }
+    }
+
+    /*
+     * Create configurable options exist
+     * 
+     * @params string $key
+     * @return mixed 
+     * @throw \Exception
+     */
+
+    public function checkExistOption($key)
+    {
+        return ProductConfigOption::where([
+                    ['gid', $this->optionsGroupID],
+                    ['optionname', 'LIKE', $key . '|%']
+                ])->first();
+    }
+
+    /*
+     * Create configurable options group
+     * 
+     * $params object \ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Product $product
+     * @throw \Exception
+     */
+
+    private function createOptionsGroup()
+    {
+        $product                   = $this->getProduct();
+        $optionsGroup              = new ProductConfigGroups();
+        $optionsGroup->name        = "Configurable options for " . $product->name . " product";
+        $optionsGroup->description = "Auto generated by module " . $product->servertype;
+        $optionsGroup->save();
+        $this->optionsGroupID      = $optionsGroup->id;
+    }
+
+    /*
+     * Assign Configurable Options Group to Product
+     * 
+     * $params object \ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\ProductConfigGroups $optionsGroup
+     * @throw \Exception
+     */
+
+    private function assignGroupToProduct()
+    {
+        $assignProduct      = new ProductConfigLinks();
+        $assignProduct->gid = $this->optionsGroupID;
+        $assignProduct->pid = $this->productID;
+        $assignProduct->save();
+    }
+
+    public function createOptions(Option $option)
+    {
+        if ($this->checkExistOption($option->getKey()))
+        {
+            return;
+        }
+        $model = new ProductConfigOption($option->setGid($this->optionsGroupID)->toArray());
+        $model->save();
+
+        return $model->id;
+    }
+
+    /*
+     * Create sub-options to configurable options
+     * Function automatically create pricing for configurable options
+     * 
+     * $params  integer $optionID
+     * @params object \ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\ProductConfigOptionSub $sobOption
+     * @throw \Exception
+     */
+
+    public function createSubOptions($optionID, SubOption $subOption)
+    {
+        $model = new ProductConfigOptionSub($subOption->setConfigid($optionID)->toArray());
+        $model->save();
+        $this->createPricingForOptions($model->id);
+    }
+
+    /*
+     * Get available currencies in WHMCS
+     */
+
+    private function getCurrencies()
+    {
+        $currencies = Currency::get();
+
+        $allCurrencies = [];
+        foreach ($currencies as $currency)
+        {
+            $allCurrencies[] = $currency->id;
+        }
+        return $allCurrencies;
+    }
+
+    /*
+     * Get all currencies and create pricing for each one
+     * 
+     * @params integer $subOptionID
+     */
+
+    private function createPricingForOptions($subOptionID)
+    {
+        foreach ($this->getCurrencies() as $currency)
+        {
+            $this->addPricing($subOptionID, $currency);
+        }
+    }
+
+    /*
+     * Add pricing for sub-options
+     * 
+     * @params integer $subOptionID, $currencyID string $type
+     * @throw \Exception
+     */
+
+    private function addPricing($subOptionID, $currencyID, $type = 'configoptions')
+    {
+        $pricing               = new Pricing();
+        $pricing->type         = $type;
+        $pricing->currency     = $currencyID;
+        $pricing->relid        = $subOptionID;
+        $pricing->msetupfee    = 0;
+        $pricing->qsetupfee    = 0;
+        $pricing->ssetupfee    = 0;
+        $pricing->asetupfee    = 0;
+        $pricing->bsetupfee    = 0;
+        $pricing->tsetupfee    = 0;
+        $pricing->monthly      = 0;
+        $pricing->quarterly    = 0;
+        $pricing->semiannually = 0;
+        $pricing->annually     = 0;
+        $pricing->biennially   = 0;
+        $pricing->triennially  = 0;
+        $pricing->save();
+    }
+
+}

+ 46 - 0
app/Services/ConfigurableOptions/Abstracts/AbstractSerialize.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Abstracts;
+
+/**
+ * Description of TypeConstans
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@modulesgarden.com>
+ */
+abstract class AbstractSerialize
+{
+
+    protected function prepareName($key, $name = null)
+    {
+        if (is_null($name))
+        {
+            return $key . "|" . $key;
+        }
+        return $key . "|" . $name;
+    }
+
+    public function toArray()
+    {
+        $out = [];
+
+        foreach (get_class_vars(get_called_class()) as $property => $value)
+        {
+
+
+            if (!isset($this->{$property}))
+            {
+                continue;
+            }
+            if (is_object($this->$property) || is_array($this->$property))
+            {
+                continue;
+            }
+            else
+            {
+                $out[$property] = $this->{$property};
+            }
+        }
+        return $out;
+    }
+
+}

+ 66 - 0
app/Services/ConfigurableOptions/ConfigurableOptions.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions;
+
+use Exception;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\Option;
+
+/**
+ * Description of ConfigurableOptions
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@modulesgarden.com>
+ */
+class ConfigurableOptions extends Abstracts\AbstractConfigurableOptions
+{
+    /*
+     * Create New Configurable Optoions group
+     * 
+     * @throw \Exception
+     */
+
+    public function create()
+    {
+        if ($this->checkExistAssignedOptionsGroup())
+        {
+            throw new Exception('Configurable options already exist.');
+        }
+        $this->addGroup();
+        $this->buildOptions();
+    }
+
+    /*
+     * Save additional fields 
+     * 
+     * 
+     * Return true, if mmethod create a new configurable group;
+     * 
+     * @return boolean $group;
+     * 
+     */
+
+    public function createOrUpdate()
+    {
+        $group = $this->addGroup();
+        $this->buildOptions();
+        return $group;
+    }
+
+    public function show()
+    {
+        return $this->showOptions();
+    }
+
+    /*
+     *  Add Option to group 
+     * 
+     * @param \ModulesGarden\Servers\KerioEmail\App\Service\ConfigurableOptions\Models\Option $option
+     */
+
+    public function addOption(Option $option)
+    {
+        $this->options[] = $option;
+
+        return $this;
+    }
+
+}

+ 18 - 0
app/Services/ConfigurableOptions/Helper/TypeConstans.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Helper;
+
+/**
+ * Description of TypeConstans
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@modulesgarden.com>
+ */
+class TypeConstans
+{
+
+    const DROPDOWN = 1;
+    const RADION   = 2;
+    const CHECKBOX = 3;
+    const QUANTITY = 4;
+
+}

+ 195 - 0
app/Services/ConfigurableOptions/Models/Option.php

@@ -0,0 +1,195 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models;
+
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Abstracts\AbstractSerialize;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Helper\TypeConstans;
+
+/**
+ * Description of Option
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@modulesgarden.com>
+ */
+class Option extends AbstractSerialize
+{
+    /*
+     * @var string $optionname
+     */
+
+    protected $gid;
+    /*
+     * @var string $optionname
+     */
+    protected $optionname;
+    /*
+     * @var string $optiontype
+     */
+    protected $optiontype = 1;
+    /*
+     * @var integer $min
+     */
+    protected $qtyminimum = 0;
+    /*
+     * @var integer $max
+     */
+    protected $qtymaximum = 0;
+    /*
+     * @var integer $order
+     */
+    protected $order      = 0;
+    /*
+     * @var integer $hidden
+     */
+    protected $hidden     = 0;
+
+    /*
+     * @var array $subOptions
+     */
+    protected $subOptions = [];
+
+    /*
+     * Alternative method to set required fields
+     * 
+     * @param string $name, \ModulesGarden\Servers\KerioEmail\App\Service\ConfigurableOptions\Helper\TypeConstans $type
+     */
+
+    public function __construct($key, $name = null, $type = null)
+    {
+        $this->optionname = $this->prepareName($key, $name);
+        $this->optiontype = $type;
+    }
+
+    /*
+     * Add additional suboptions
+     * 
+     * @params \ModulesGarden\Servers\KerioEmail\App\Service\ConfigurableOptions\Models\SubOption $option
+     * @return $this
+     */
+
+    public function addSubOption(SubOption $option)
+    {
+        $this->subOptions[] = $option;
+
+        return $this;
+    }
+
+    /*
+     * Set Option Name
+     * 
+     * @param string $name;
+     * 
+     * @return object $this
+     */
+
+    public function setName($name)
+    {
+        $this->optionname = $name;
+
+        return $this;
+    }
+
+    /*
+     * Set Option Name
+     * 
+     * @param object \ModulesGarden\Servers\KerioEmail\App\Service\ConfigurableOptions\Helper\TypeConstans
+     * 
+     * @return object $this
+     */
+
+    public function setType(TypeConstans $type)
+    {
+        $this->optiontype = $type;
+        return $this;
+    }
+
+    /*
+     * Set option min, require for quantity
+     * 
+     * @param string $min;
+     * 
+     * @return object $this
+     */
+
+    public function setMin($min)
+    {
+        $this->qtyminimum = $min;
+        return $this;
+    }
+
+    /*
+     * Set option max, require for quantity
+     * 
+     * @param string $max;
+     * 
+     * @return object $this
+     */
+
+    public function setMax($max)
+    {
+        $this->qtymaximum = $max;
+        return $this;
+    }
+
+    /*
+     * Set Order
+     * 
+     * @param integer $order;
+     * 
+     * @return object $this
+     */
+
+    public function setOrder($order)
+    {
+        $this->order = $order;
+        return $this;
+    }
+
+    /*
+     * Set Option Name
+     * 
+     * @param string $name;
+     * 
+     * @return object $this
+     */
+
+    public function setHidden($hidden)
+    {
+        $this->hidden = $hidden;
+        return $this;
+    }
+
+    /*
+     * Set Group Option ID
+     * 
+     * @param integer $gid;
+     * 
+     * @return object $this
+     */
+
+    public function setGid($gid)
+    {
+        $this->gid = $gid;
+        return $this;
+    }
+
+    public function getSubOptions()
+    {
+        return $this->subOptions;
+    }
+
+    public function getName()
+    {
+        $expoldeName = explode('|', $this->optionname);
+        if (!empty($expoldeName[1]))
+        {
+            return $expoldeName[1];
+        }
+        return $this->optionname;
+    }
+
+    public function getKey()
+    {
+        return explode('|', $this->optionname)[0];
+    }
+
+}

+ 101 - 0
app/Services/ConfigurableOptions/Models/SubOption.php

@@ -0,0 +1,101 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models;
+
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Abstracts\AbstractSerialize;
+
+/**
+ * Description of Option
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@modulesgarden.com>
+ */
+class SubOption extends AbstractSerialize
+{
+    /*
+     * @var integer $configid
+     */
+
+    protected $configid;
+    /*
+     * @var string $name
+     */
+    protected $optionname;
+
+    /*
+     * @var string $name
+     */
+    protected $sortorder = 0;
+
+    /*
+     * @var string $name
+     */
+    protected $hidden = 0;
+
+    /*
+     * Alternative method to set required fields
+     * 
+     * @param string $name
+     */
+
+    public function __construct($key, $name = null)
+    {
+        $this->optionname = $this->prepareName($key, $name);
+    }
+
+    /*
+     * Set Option Name
+     * 
+     * @param string $name
+     * 
+     * @return object $this
+     */
+
+    public function setName($name)
+    {
+        $this->optionname = $name;
+        return $this;
+    }
+
+    /*
+     * Set Option order
+     * 
+     * @param integer $sort
+     * 
+     * @return object $this
+     */
+
+    public function setSort($sort)
+    {
+        $this->sortorder = $sort;
+        return $this;
+    }
+
+    /*
+     * Set Option hidden status
+     * 
+     * @param integer $hidden
+     * 
+     * @return object $this
+     */
+
+    public function setHidden($hidden)
+    {
+        $this->hidden = $hidden;
+        return $this;
+    }
+
+    /*
+     * Set Config option ID
+     * 
+     * @param integer $configid
+     * 
+     * @return object $this
+     */
+
+    public function setConfigid($configid)
+    {
+        $this->configid = $configid;
+        return $this;
+    }
+
+}

+ 100 - 0
app/Services/ConfigurableOptions/Strategy/ConfigOptionsType.php

@@ -0,0 +1,100 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\AbstractOptions;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\BasedOptions;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\ClassOfServicesOptions;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\ServiceConfigurableOptions;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 30.09.19
+ * Time: 12:06
+ * Class ConfigOptions
+ */
+class ConfigOptionsType
+{
+
+    /**
+     * @var null
+     */
+    protected $productId = null;
+
+    /**
+     * @var null
+     */
+    protected $type = null;
+
+    /**
+     * @var AbstractOptions
+     */
+    protected $configurableOptions = null;
+
+    /**
+     * @return null
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * @param $type
+     * @return $this
+     */
+    public function setType($type)
+    {
+        $this->type = $type;
+        return $this;
+    }
+
+    /**
+     * @return null
+     */
+    public function getProductId()
+    {
+        return $this->productId;
+    }
+
+    /**
+     * @param null $productId
+     */
+    public function setProductId($productId)
+    {
+        $this->productId = $productId;
+    }
+
+    /**
+     * @return AbstractOptions
+     */
+    public function getConfigurableOptions()
+    {
+        return $this->configurableOptions;
+    }
+
+    /**
+     * @throws \Exception
+     */
+    public function load()
+    {
+        switch($this->type)
+        {
+            case ClassOfServices::ZIMBRA_CONFIG_OPTIONS:
+                $co = new ServiceConfigurableOptions($this->getProductId());
+                break;
+            case ClassOfServices::CLASS_OF_SERVICE_QUOTA:
+                $co = new ClassOfServicesOptions($this->getProductId());
+                break;
+            default:
+                $co = new BasedOptions($this->getProductId());
+                break;
+        }
+
+        $this->configurableOptions = $co;
+
+        return $this;
+    }
+
+}

+ 92 - 0
app/Services/ConfigurableOptions/Strategy/Types/AbstractOptions.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\Option;
+use ModulesGarden\Servers\KerioEmail\App\Traits\LangHandler;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 30.09.19
+ * Time: 12:21
+ * Class AbstractOptions
+ */
+abstract class AbstractOptions
+{
+    use LangHandler;
+
+    /**
+     * @var array
+     */
+    protected $options = [];
+
+    /**
+     * @var
+     */
+    protected $productId;
+
+    /**
+     * AbstractOptions constructor.
+     */
+    public function __construct($productId = null)
+    {
+        if($productId)
+        {
+            $this->setProductId($productId);
+        }
+
+        /**
+         * load configurable options
+         */
+        $this->initContent();
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getProductId()
+    {
+        return $this->productId;
+    }
+
+    /**
+     * @param $productId
+     * @return $this
+     */
+    public function setProductId($productId)
+    {
+        $this->productId = $productId;
+        return $this;
+    }
+
+
+
+    /**
+     * @param Option $option
+     * @return $this
+     */
+    public function addOption(Option $option)
+    {
+        $this->options[$option->getKey()] = $option;
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getOptions()
+    {
+        return $this->options;
+    }
+
+    /**
+     * load all options
+     *
+     * @return mixed
+     */
+    public abstract function initContent();
+
+}

+ 56 - 0
app/Services/ConfigurableOptions/Strategy/Types/BasedOptions.php

@@ -0,0 +1,56 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Helper\TypeConstans;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\Option;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\SubOption;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 30.09.19
+ * Time: 12:19
+ * Class BasedOptions
+ */
+class BasedOptions extends AbstractOptions
+{
+    /**
+     * @return $this|mixed
+     */
+    public function initContent()
+    {
+        $option  = new Option('acc_add', 'Email Accounts Additional', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'Email Account'));
+        $this->addOption($option);
+
+        $option  = new Option('acc_new', 'Email Accounts Increase', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'Email Account'));
+        $this->addOption($option);
+
+        $option  = new Option('acc_size', 'Email Account Size', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'MB'));
+        $this->addOption($option);
+
+        $option  = new Option('alias_limit', 'Email Aliases Limit', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'Email Alias'));
+        $this->addOption($option);
+
+        $option  = new Option('dist_list_limit', 'Distribution Lists Limit', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'Distribution List'));
+        $this->addOption($option);
+
+        $option  = new Option('domain_alias_limit', 'Domain Aliases Limit', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'Domain Alias'));
+        $this->addOption($option);
+
+        $option  = new Option('domainAddSize', 'Domain Space Additional', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'GB'));
+        $this->addOption($option);
+
+        $option  = new Option('domainNewSize', 'Domain Space Increase', TypeConstans::QUANTITY);
+        $option->addSubOption(new SubOption('1', 'GB'));
+        $this->addOption($option);
+
+        return $this;
+    }
+}

+ 50 - 0
app/Services/ConfigurableOptions/Strategy/Types/ClassOfServicesOptions.php

@@ -0,0 +1,50 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Helper\TypeConstans;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\Option;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\SubOption;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 30.09.19
+ * Time: 12:19
+ * Class ClassOfServicesOptions
+ */
+class ClassOfServicesOptions extends BasedOptions
+{
+    const COS_CONFIG_OPT_PREFIX = 'cosQuota_';
+
+    /**
+     * @return mixed|BasedOptions|void
+     */
+    public function initContent()
+    {
+        parent::initContent();
+
+
+        $api     = (new KerioManager())->getApiByProduct($this->getProductId());
+        $repository = new Repository($api->soap);
+        $classOfServices = $repository->cos->all();
+
+        /**
+         * add quantity config options Class of Services
+         */
+        foreach ($classOfServices as $cos)
+        {
+            /* @var $cos ClassOfService */
+            $key = self::COS_CONFIG_OPT_PREFIX.$cos->getId();
+            $name = sprintf($this->getLang()->absoluteT('COS %s with quota %s MB'), $cos->getName(), $cos->getMbMailQuote());
+
+            $option  = new Option($key, $name, TypeConstans::QUANTITY);
+            $subName = sprintf($this->getLang()->absoluteT('COS %s MB'),  $cos->getMbMailQuote());
+            $option->addSubOption(new SubOption('1', $subName));
+            $this->addOption($option);
+        }
+
+    }
+}

+ 46 - 0
app/Services/ConfigurableOptions/Strategy/Types/ServiceConfigurableOptions.php

@@ -0,0 +1,46 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Helper\TypeConstans;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\Option;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\SubOption;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 30.09.19
+ * Time: 12:20
+ * Class ServiceConfigurableOptions
+ */
+class ServiceConfigurableOptions extends BasedOptions
+{
+
+    /**
+     * @return mixed|BasedOptions|void
+     */
+    public function initContent()
+    {
+        parent::initContent();
+
+        $api     = (new KerioManager())->getApiByProduct($this->getProductId());
+        $repository = new Repository($api->soap);
+        $classOfServices = $repository->cos->all();
+
+
+        /**
+         *
+         */
+        $option  = new Option('cos', 'Class Of Service', TypeConstans::DROPDOWN);
+        foreach($classOfServices as $cos)
+        {
+            /* @var $cos ClassOfService */
+            $option->addSubOption(new SubOption($cos->getId(), $cos->getName()));
+        }
+
+        $this->addOption($option);
+    }
+
+}

+ 80 - 0
app/Traits/ConfigTrait.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 11.09.19
+ * Time: 14:24
+ * Class ConfigTrait
+ */
+trait ConfigTrait
+{
+    /**
+     * @var array
+     */
+    private $config = [];
+
+    /**
+     * @description set configuration value
+     * @param $name
+     * @param null $value
+     * @return mixed
+     */
+    public function set($name, $value = null)
+    {
+        $this->config[$name] = $value;
+        return $this;
+    }
+
+    /**
+     * @description get configuration value
+     * @param $name
+     * @param null $default
+     * @return mixed
+     */
+    public function get($name, $default = null)
+    {
+        return isset($this->config[$name]) ? $this->config[$name] : $default;
+    }
+
+    /**
+     * @description update value
+     * @param $name
+     * @param null $value
+     * @return mixed
+     */
+    public function update($name, $value = null)
+    {
+        $this->config[$name] = $value;
+
+        return $this;
+    }
+
+    /**
+     * @description remove parameter
+     * @param $name
+     * @return mixed
+     */
+    public function remove($name)
+    {
+        unset($this->config[$name]);
+        return $this;
+    }
+
+    /**
+     * @description check if configuration exists
+     * @param $name
+     * @return bool
+     */
+    public function exists($name)
+    {
+        return isset($this->config[$name]) ? true : false;
+    }
+
+
+
+}

+ 32 - 0
app/Traits/ExtensionsCheckerTrait.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Restriction;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Restrictions\Rules\ExtensionsValid;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 07.11.19
+ * Time: 09:54
+ * Class ExtensionsCheckerTrait
+ */
+trait ExtensionsCheckerTrait
+{
+
+    /**
+     *
+     * check about module extensions
+     * @throws \Exception
+     */
+    public function checkExtensionOrThrowError()
+    {
+        $restriction = new Restriction(new ExtensionsValid());
+        $restriction->enableThrowError();
+        $restriction->check();
+    }
+
+}

+ 59 - 0
app/Traits/FormExtendedTrait.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\RowSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 14:20
+ * Class FormExtendedTrait
+ */
+trait FormExtendedTrait
+{
+    protected $sectionCounter = 0;
+
+    /**
+     * auto generate double section helper
+     *
+     * @param array $fields
+     * @return $this
+     * @throws \Exception
+     */
+    protected function generateDoubleSection($fields = [])
+    {
+        if(!method_exists($this, 'addSection'))
+        {
+            throw new \Exception('This trait can not be used in class: '.self::class);
+        }
+
+        $sections = [];
+        $fieldCounter = 0;
+        foreach($fields as $field)
+        {
+            $halfPageSection = new HalfPageSection('generated_'.$this->sectionCounter.'_'.$fieldCounter);
+            $halfPageSection->addField($field);
+            $sections[] = $halfPageSection;
+
+            $fieldCounter++;
+        }
+
+        $rawSection = new RowSection('generated_row_section_'.$this->sectionCounter);
+
+        foreach($sections as $section)
+        {
+            $rawSection->addSection($section);
+        }
+
+        $this->addSection($rawSection);
+        $this->sectionCounter++;
+        return $this;
+    }
+
+}

+ 89 - 0
app/Traits/HostingService.php

@@ -0,0 +1,89 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\CustomField;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\CustomFieldValue;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:43
+ * Class HostingService
+ */
+trait HostingService
+{
+    /**
+     * @return mixed
+     */
+    public function getHostingId()
+    {
+        if (!$this->hostingId)
+        {
+            $this->hostingId = $this->getWhmcsParamByKey("serviceid");
+        }
+        return $this->hostingId;
+    }
+
+    /**
+     * @param mixed $hostingId
+     */
+    public function setHostingId($hostingId)
+    {
+        $this->hostingId = $hostingId;
+        return $this;
+    }
+
+    /**
+     * @return Hosting
+     */
+    public function hosting()
+    {
+        if ($this->hosting instanceof Hosting)
+        {
+            return $this->hosting;
+        }
+        return $this->hosting = Hosting::where("id", $this->getHostingId())->firstOrFail();
+    }
+
+    public function isActive()
+    {
+        return Hosting::ofId($this->getHostingId())->active()->count() == 1;
+    }
+
+    public function isSupportedModule()
+    {
+        return Hosting::ofServerType($this->getHostingId(), "proxmoxVPS")->count() == 1;
+    }
+
+    private function getCustomFieldId($fieldName)
+    {
+        return CustomField::select("id")
+            ->where("type", "product")
+            ->where("relid", $this->hosting()->packageid)
+            ->where("fieldname", "like", $fieldName . "%")
+            ->value("id");
+    }
+
+    public function customFieldUpdate($name, $value = '')
+    {
+        $fieldId = $this->getCustomFieldId($name);
+        //Update
+        if (CustomFieldValue::where('fieldid', $fieldId)->where("relid", $this->getHostingId())->count())
+        {
+            return CustomFieldValue::where('fieldid', $fieldId)->where("relid", $this->getHostingId())->update(['value' => $value]);
+        }
+        //Create
+        $customFiledValue = new CustomFieldValue();
+        $customFiledValue->fill([
+            'fieldid' => $fieldId,
+            'relid'   => $this->getHostingId(),
+            'value'   => $value
+        ]);
+        return $customFiledValue->save();
+    }
+}

+ 31 - 0
app/Traits/KerioApiHandler.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 14:08
+ * Class KerioApiHandler
+ */
+trait KerioApiHandler
+{
+
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api
+     */
+    public function getApi()
+    {
+        /* @var $api \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Api */
+        $api = di('kerio');
+        return $api;
+    }
+
+
+}

+ 37 - 0
app/Traits/LangHandler.php

@@ -0,0 +1,37 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Lang\Lang;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 10:43
+ * Trait LangHandler
+ */
+trait LangHandler
+{
+
+    /**
+     * @var Lang
+     */
+    protected $lang;
+
+    /**
+     * @return Lang
+     */
+    public function getLang()
+    {
+
+        if(!$this->lang)
+        {
+            $this->lang = di('lang');
+        }
+
+        return $this->lang;
+    }
+
+}

+ 61 - 0
app/Traits/ModuleConfigurationHandler.php

@@ -0,0 +1,61 @@
+<?php
+/**
+ * Class ModuleConfigurationHandler
+ * User: Nessandro
+ * Date: 2019-11-19
+ * Time: 08:21
+ * @package ModulesGarden\Servers\KerioEmail\App\Traits
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Data;
+
+trait ModuleConfigurationHandler
+{
+    /**
+     *
+     * @var Data
+     */
+    protected $moduleData;
+
+    /**
+     *
+     * @return Data
+     */
+    public function getModuleData()
+    {
+        return $this->moduleData;
+    }
+
+    /**
+     *
+     * @param bool $reload
+     * @return Data|null
+     */
+    public function loadModuleData($reload = false)
+    {
+        /**
+         * unset data if need reload
+         */
+        if($reload)
+        {
+            $this->moduleData = null;
+        }
+
+        /**
+         * load data
+         */
+        if(!$this->moduleData)
+        {
+            $this->moduleData = new Data();
+        }
+
+        /**
+         * return data
+         */
+        return $this->moduleData;
+    }
+
+}

+ 40 - 0
app/Traits/ParamsHandler.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 11:22
+ * Class ParamsHandler
+ */
+trait ParamsHandler
+{
+
+    /**
+     * @var array
+     */
+    protected $params = [];
+
+    /**
+     * @return array
+     */
+    public function getParams()
+    {
+        return $this->params;
+    }
+
+    /**
+     * @param $params
+     * @return $this
+     */
+    public function setParams($params = [])
+    {
+        $this->params = $params;
+        return $this;
+    }
+
+}

+ 38 - 0
app/Traits/ProductService.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:47
+ * Class ProductService
+ */
+trait ProductService
+{
+
+    /**
+     * @var
+     */
+    protected $productId;
+
+    /**
+     * @return mixed
+     */
+    public function getProductId()
+    {
+        return $this->productId;
+    }
+
+    /**
+     * @param int $productId
+     */
+    public function setProductId($productId)
+    {
+        $this->productId = $productId;
+    }
+
+}

+ 78 - 0
app/Traits/ServerParams.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Server;
+use WHMCS\Database\Capsule as DB;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 09.09.19
+ * Time: 13:53
+ * Class ServerParams
+ */
+trait ServerParams
+{
+
+    /**
+     * @param $id
+     * @return array
+     */
+    public function getServerParamsByProductId($id)
+    {
+        $serverId = DB::table('tblproducts')
+            ->join('tblservergroups', 'tblproducts.servergroup', '=', 'tblservergroups.id')
+            ->join('tblservergroupsrel', 'tblservergroups.id', '=', 'tblservergroupsrel.groupid')
+            ->join('tblservers', 'tblservergroupsrel.serverid', '=', 'tblservers.id')
+            ->where('tblproducts.id', '=', $id)
+            ->first(['tblservers.id'])
+            ->id;
+
+        if($serverId)
+        {
+            return $this->getServerParamsById($serverId);
+        }
+
+    }
+
+    /**
+     * @param $id
+     * @return array
+     */
+    public function getServerParamsByHostingId($id)
+    {
+        $hosting = Hosting::where('id', $id)->first();
+        if($hosting)
+        {
+            return $this->getServerParamsById($hosting->server);
+        }
+    }
+
+    /**
+     * @param $id
+     * @return array
+     */
+    public function getServerParamsById($id)
+    {
+        $server = Server::where('id', $id)->first();
+        if ($server)
+        {
+            return [
+                'serverid'         => $server->id,
+                'serverip'         => $server->ipaddress,
+                'serverhostname'   => $server->hostname,
+                'serversecure'     => $server->secure,
+                'serverusername'   => $server->username,
+                'serverpassword'   => decrypt($server->password) ? decrypt($server->password) : $server->password,
+                'serveraccesshash' => $server->accesshash,
+                'serverport'       => $server->port,
+            ];
+        }
+
+    }
+
+}

+ 34 - 0
app/Traits/StorageTrait.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Traits;
+
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 05.09.19
+ * Time: 14:13
+ * Class Storage
+ */
+trait StorageTrait
+{
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\App\Helpers\Storage
+     */
+    protected $storage;
+
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\App\Helpers\Storage
+     */
+    public function getStorage()
+    {
+        if(!$this->storage)
+        {
+            $this->storage = new \ModulesGarden\Servers\KerioEmail\App\Helpers\Storage();
+        }
+
+        return $this->storage;
+    }
+
+}

+ 111 - 0
app/UI/Admin/Custom/Fields/EnabledField.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\BaseField;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 10:49
+ * Class EnabledField
+ */
+class EnabledField extends BaseField
+{
+    protected $id    = 'enabledField';
+    protected $name  = 'enabledField';
+    protected $title = 'field_enabled_';
+
+    const TYPE_SUCCESS = 'success';
+    const TYPE_DEFAULT = 'default';
+
+    protected $enabled = false;
+    protected $rawType = false;
+
+    /**
+     * @return bool
+     */
+    public function isEnabled()
+    {
+
+        return $this->enabled;
+    }
+
+    /**
+     * @param bool $enabled
+     */
+    public function setEnabled($enabled)
+    {
+        $this->enabled = $enabled;
+    }
+
+    /**
+     * @return string
+     */
+    public function getType()
+    {
+        if($this->getRawType())
+        {
+            return $this->getRawType();
+        }
+
+        if($this->isEnabled())
+        {
+            $type = self::TYPE_SUCCESS;
+        }else{
+            $type = self::TYPE_DEFAULT;
+        }
+
+        return $type;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getTitle()
+    {
+        /**
+         * if raw return raw
+         */
+        if($this->titleRaw)
+        {
+            return $this->titleRaw;
+        }
+
+        /**
+         * return type depending on status
+         */
+        if($this->isEnabled())
+        {
+            $title = $this->title.self::TYPE_SUCCESS;
+        }else{
+            $title = $this->title.self::TYPE_DEFAULT;
+        }
+
+        /**
+         *
+         */
+        return $title;
+    }
+
+    /**
+     * @return bool
+     */
+    public function getRawType()
+    {
+        return $this->rawType;
+    }
+
+    /**
+     * @param bool $rawType
+     */
+    public function setRawType($rawType)
+    {
+        $this->rawType = $rawType;
+    }
+
+
+}

+ 78 - 0
app/UI/Admin/Custom/Fields/ExtendedInputField.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 10:32
+ * Class ExtendedInputField
+ */
+class ExtendedInputField extends Text implements AdminArea, ClientArea
+{
+    protected $id           = 'extendedInputField';
+    protected $name         = 'extendedInputField';
+    protected $fieldType    = self::TYPE_DEFAULT;
+
+    const TYPE_PASSWORD     = 'password';
+    const TYPE_EMAIL        = 'email';
+    const TYPE_TEXT         = 'text';
+    const TYPE_NUMBER       = 'number';
+    const TYPE_DEFAULT      = 'text';
+
+    protected $rawDescription = null;
+
+    /**
+     * @return string
+     */
+    public function getFieldType()
+    {
+        return $this->fieldType;
+    }
+
+    /**
+     * @param $fieldType
+     * @return $this
+     */
+    public function setFieldType($fieldType)
+    {
+        $this->fieldType = $fieldType;
+
+        return $this;
+    }
+
+    /**
+     * @return null
+     */
+    public function getRawDescription()
+    {
+        return $this->rawDescription;
+    }
+
+    /**
+     * @param $rawDescription
+     * @return $this
+     */
+    public function setRawDescription($rawDescription)
+    {
+        $this->rawDescription = $rawDescription;
+        return $this;
+    }
+
+    public function isRawDescription()
+    {
+        return $this->rawDescription !== null;
+    }
+
+
+
+
+
+}

+ 56 - 0
app/UI/Admin/Custom/Fields/ExtendedSelect.php

@@ -0,0 +1,56 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 10:08
+ * Class ExtendedSelect
+ */
+class ExtendedSelect extends Select implements AdminArea, ClientArea
+{
+    protected $id   = 'extendedSelect';
+    protected $name = 'extendedSelect';
+
+    protected $hidden = false;
+
+    /**
+     * @return bool
+     */
+    public function isHidden()
+    {
+        return $this->hidden;
+    }
+
+    /**
+     * @param $hidden
+     * @return $this
+     */
+    public function setHidden($hidden)
+    {
+        $this->hidden = $hidden;
+        return $this;
+    }
+
+    /**
+     * @return ExtendedSelect
+     */
+    public function enableHidden()
+    {
+        return $this->setHidden(true);
+    }
+
+    /**
+     * @return ExtendedSelect
+     */
+    public function disableHidden()
+    {
+        return $this->setHidden(false);
+    }
+
+}

+ 20 - 0
app/UI/Admin/Custom/Forms/BaseFormExtended.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 14:57
+ * Class BaseFormExtended
+ */
+class BaseFormExtended extends BaseForm
+{
+    protected $id         = 'baseFormExtended';
+    protected $name       = 'baseFormExtended';
+}

+ 112 - 0
app/UI/Admin/Custom/Forms/SortedFieldForm.php

@@ -0,0 +1,112 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\BaseField;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 11.09.19
+ * Time: 11:23
+ * Class SordetFieldForm
+ */
+class SortedFieldForm extends BaseForm
+{
+    /**
+     * @var string
+     */
+    protected $id    = 'sortedFieldForm';
+    /**
+     * @var string
+     */
+    protected $name  = 'sortedFieldForm';
+    /**
+     * @var string
+     */
+    protected $title = 'sortedFieldForm';
+
+    /**
+     * @var array
+     */
+    protected $indexContainer = [];
+
+
+    /**
+     * @param BaseField $field
+     * @param int $index
+     * @return BaseForm|void
+     */
+    public function addField(BaseField $field, $index = 0)
+    {
+        $this->addIndex($field->getId(), $index);
+        return parent::addField($field);
+    }
+
+    public function addSection($section, $index = 0)
+    {
+        $this->addIndex($section->getId(), $index);
+        return parent::addSection($section);
+    }
+
+    /**
+     * @param $id
+     * @param int $index
+     */
+    public function addIndex($id , $index = 0)
+    {
+        while($this->indexExists($index))
+        {
+            $index++;
+        }
+
+        $this->indexContainer[$index] = $id;
+    }
+
+    /**
+     * @param $id
+     * @return false|int|string
+     */
+    public function getIndexById($id)
+    {
+        return array_search($id, $this->indexContainer);
+    }
+
+    /**
+     * @param $index
+     * @return bool
+     */
+    public function indexExists($index)
+    {
+        return isset($this->indexContainer[$index]);
+    }
+
+    /**
+     * @return array
+     */
+    public function getSortedFields()
+    {
+        $tmp = [];
+        /**
+         * add fields to array with index
+         */
+        foreach($this->getFields() as $field)
+        {
+            $tmp[$this->getIndexById($field->getId())] = $field;
+        }
+
+        /**
+         * add sections to array with index
+         */
+        foreach($this->getSections() as $field)
+        {
+            $tmp[$this->getIndexById($field->getId())] = $field;
+        }
+        /**
+         * sort by key value
+         */
+        ksort($tmp);
+
+        return $tmp;
+    }
+}

+ 29 - 0
app/UI/Admin/Custom/Modals/ModalExtendedTabsEdit.php

@@ -0,0 +1,29 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Modals;
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\ModalTabsEdit;
+
+/**
+ * Class ModalExtendedTabsEdit
+ * User: Nessandro
+ * Date: 2019-09-20
+ * Time: 12:40
+ */
+
+class ModalExtendedTabsEdit extends ModalTabsEdit implements AdminArea
+{
+    protected $id    = 'modalExtendedTabsEdit';
+    protected $name  = 'modalExtendedTabsEdit';
+    protected $title = 'modalExtendedTabsEdit';
+
+    protected function afterInitContent()
+    {
+        parent::afterInitContent();
+
+        foreach ($this->forms as &$form)
+        {
+            $form->getHtml();
+        }
+    }
+}

+ 56 - 0
app/UI/Admin/Custom/Pages/Description.php

@@ -0,0 +1,56 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Pages;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Builder\BaseContainer;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\Alerts;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 15:13
+ * Class Description
+ */
+class Description extends BaseContainer implements ClientArea
+{
+    use Alerts;
+    protected $id    = 'description';
+    protected $name  = 'description';
+    protected $title = 'description';
+    protected $description;
+
+    public function __construct($baseId = null, $hasAlert = false,$type = null)
+    {
+        parent::__construct($baseId);
+        $this->setTitle($baseId . 'PageTitle');
+        $this->setDescription($baseId . 'PageDescription');
+        if($hasAlert)
+        {
+            $this->addInternalAlert($baseId . 'AlertDescription',$type);
+        }
+    }
+
+    public function getDescription()
+    {
+        return $this->description;
+    }
+
+    public function setDescription($description)
+    {
+        $this->description = $description;
+        return $this;
+    }
+
+    public function getAssetsUrl()
+    {
+        return BuildUrl::getAssetsURL();
+    }
+
+    public function getIcon()
+    {
+        $asset = BuildUrl::getAppAssetsURL();
+        return $asset.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.$this->id.'.png';
+    }
+}

+ 18 - 0
app/UI/Admin/Custom/Sections/BoxSectionExtended.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Class BoxSectionExtended
+ * User: Nessandro
+ * Date: 2019-10-07
+ * Time: 14:16
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+
+class BoxSectionExtended extends BoxSection
+{
+
+}

+ 18 - 0
app/UI/Admin/Custom/Sections/FreeFieldsSection.php

@@ -0,0 +1,18 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BaseSection;
+
+/**
+ * Class FreeFieldsSection
+ * User: Nessandro
+ * Date: 2019-09-20
+ * Time: 12:44
+ */
+
+class FreeFieldsSection extends BaseSection implements ClientArea, AdminArea
+{
+    protected $id   = 'freeFieldsSection';
+    protected $name = 'freeFieldsSection';
+}

+ 41 - 0
app/UI/Admin/Custom/Sections/HalfPageCustomCosSection.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * Class HalfPageCustomCosSection
+ * User: Nessandro
+ * Date: 2019-10-07
+ * Time: 15:22
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+class HalfPageCustomCosSection extends HalfPageSection
+{
+        public function loadDataToForm(&$dataProvider)
+        {
+            foreach($this->fields as &$field)
+            {
+                /**
+                 * update for cos fields
+                 */
+                $cos = $dataProvider->getValueById('cos');
+                $value = $cos[$field->getId()] ? $cos[$field->getId()] : $dataProvider->getValueById($field->getId());
+                $field->setValue($value);
+
+
+                $avValues = $dataProvider->getAvailableValuesById($field->getId());
+                if ($avValues && method_exists($field, 'setAvailableValues'))
+                {
+                    $field->setAvailableValues($avValues);
+                }
+            }
+
+            foreach ($this->sections as &$section)
+            {
+                $section->loadDataToForm($dataProvider);
+            }
+        }
+}

+ 20 - 0
app/UI/Admin/Custom/Sections/RowSection.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\SectionLuRow;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 14:04
+ * Class RowSection
+ */
+class RowSection extends SectionLuRow
+{
+    protected $id   = 'rowSection';
+    protected $name = 'rowSection';
+}

+ 14 - 0
app/UI/Admin/Home/Pages/HomePage.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\Home\Pages;
+
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Builder\BaseContainer;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+
+class HomePage extends BaseContainer implements AdminArea
+{
+    public function getText()
+    {
+        return 'Pobrany tekst';
+    }
+}

+ 27 - 0
app/UI/Admin/LoggerManager/Buttons/DeleteAllLoggersButton.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Buttons;
+
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonModal;
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Modals\DeleteAllLoggersModal;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+
+/**
+ * Description of AssignTldButton
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class DeleteAllLoggersButton extends ButtonModal implements AdminArea
+{
+    protected $id    = 'deleteAllLoggersButton';
+    protected $name  = 'deleteAllLoggersButton';
+    protected $title = 'deleteAllLoggersButton';
+
+    protected $class = ['lu-btn lu-btn--danger'];
+    protected $icon = 'lu-btn__icon lu-zmdi lu-zmdi-delete';
+    
+    public function initContent()
+    {
+        $this->initLoadModalAction(new DeleteAllLoggersModal());
+    }
+}

+ 26 - 0
app/UI/Admin/LoggerManager/Buttons/DeleteLoggerModalButton.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Buttons;
+
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Modals\DeleteLoggerModal;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+
+/**
+ * Description of DeleteLabelModalButton
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class DeleteLoggerModalButton extends ButtonDataTableModalAction implements AdminArea
+{
+    protected $id    = 'deleteLoggerModalButton';
+    protected $name  = 'deleteLoggerModalButton';
+    protected $title = 'deleteLoggerModalButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new DeleteLoggerModal());
+
+        $this->switchToRemoveBtn();
+    }
+}

+ 25 - 0
app/UI/Admin/LoggerManager/Buttons/MassDeleteLoggerButton.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Buttons;
+
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassActionContextLang;
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Modals\MassDeleteLoggerModal;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+
+/**
+ * Description of DeleteTldButton
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class MassDeleteLoggerButton extends ButtonMassActionContextLang implements AdminArea
+{
+    protected $id    = 'massDeleteLoggerButton';
+    protected $name  = 'massDeleteLoggerButton';
+    protected $title = 'massDeleteLoggerButton';
+    
+    public function initContent()
+    {
+        $this->initLoadModalAction(new MassDeleteLoggerModal());
+        $this->switchToRemoveBtn();
+    }
+}

+ 40 - 0
app/UI/Admin/LoggerManager/Forms/DeleteAllLoggerForm.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Forms;
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Providers\LoggerDataProvider;
+/**
+ * DOE DeleteLabelForm controler
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class DeleteAllLoggerForm extends BaseForm implements AdminArea
+{
+    protected $id    = 'deleteAllLoggerForm';
+    protected $name  = 'deleteAllLoggerForm';
+    protected $title = 'deleteAllLoggerForm';
+
+    public function initContent()
+    {
+        $this->setFormType('deleteall');
+        $this->dataProvider = new LoggerDataProvider();
+
+        $this->setConfirmMessage('confirmLabelRemoval');
+        
+        $field = new Hidden();
+        $field->setId('id');
+        $field->setName('id');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+    
+    protected function getDefaultActions()
+    {
+        return array_merge(parent::getDefaultActions(), ['deleteall']);
+    }
+}

+ 36 - 0
app/UI/Admin/LoggerManager/Forms/DeleteLoggerForm.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Forms;
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Providers\LoggerDataProvider;
+/**
+ * DOE DeleteLabelForm controler
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class DeleteLoggerForm extends BaseForm implements AdminArea
+{
+    protected $id    = 'deleteLoggerForm';
+    protected $name  = 'deleteLoggerForm';
+    protected $title = 'deleteLoggerForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::DELETE);
+        $this->dataProvider = new LoggerDataProvider();
+
+        $this->setConfirmMessage('confirmLabelRemoval');
+        
+        $field = new Hidden();
+        $field->setId('id');
+        $field->setName('id');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+}

+ 25 - 0
app/UI/Admin/LoggerManager/Modals/DeleteAllLoggersModal.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Modals;
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Forms\DeleteAllLoggerForm;
+
+/**
+ * DOE AddCategoryModal controler
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class DeleteAllLoggersModal extends BaseModal implements AdminArea
+{
+    protected $id    = 'deleteAllLoggersModal';
+    protected $name  = 'deleteAllLoggersModal';
+    protected $title = 'deleteAllLoggersModal';
+
+    public function initContent()
+    {
+        $this->addForm(new DeleteAllLoggerForm());
+    }
+}

+ 29 - 0
app/UI/Admin/LoggerManager/Modals/DeleteLoggerModal.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Modals;
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Forms\DeleteLoggerForm;
+
+/**
+ * DOE DeleteLabelModal controler
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class DeleteLoggerModal extends BaseModal implements AdminArea
+{
+    protected $id    = 'deleteLoggerModal';
+    protected $name  = 'deleteLoggerModal';
+    protected $title = 'deleteLoggerModal';
+
+    public function initContent()
+    {
+        $deleteLabelForm = new DeleteLoggerForm();
+
+        $this->replaceSubmitButtonClasses(['btn btn--danger submitForm']);
+        
+        $this->addForm($deleteLabelForm);
+    }
+}

+ 27 - 0
app/UI/Admin/LoggerManager/Modals/MassDeleteLoggerModal.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Modals;
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Forms\DeleteLoggerForm;
+
+/**
+ * DOE DeleteTldModal controler
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class MassDeleteLoggerModal extends BaseModal implements AdminArea
+{
+    protected $id    = 'massDeleteLoggerModal';
+    protected $name  = 'massDeleteLoggerModal';
+    protected $title = 'massDeleteLoggerModal';
+
+    public function initContent()
+    {
+        $this->replaceSubmitButtonClasses(['btn btn--danger submitForm']);
+        
+        $this->addForm(new DeleteLoggerForm());
+    }
+}

+ 103 - 0
app/UI/Admin/LoggerManager/Pages/LoggerPage.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Pages;
+
+use \ModulesGarden\Servers\KerioEmail\Core\Helper;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataTable;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\Column;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\DataProvider;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Others;
+use \ModulesGarden\Servers\KerioEmail\Core\Logger\Entity;
+
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Buttons\DeleteLoggerModalButton;
+use \ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Buttons\MassDeleteLoggerButton;
+
+/**
+ * Description of Filters
+ *
+ * @author inbs
+ */
+class LoggerPage extends DataTable implements AdminArea
+{ 
+    protected $id    = 'loggercont';
+    protected $name  = 'loggercont';
+    protected $title = null;
+    
+    protected $colorArray = [
+        Entity::TYPE_DEBUG => [
+            'color' => '7b007b',
+            'backgroundColor' => 'e9ebf0'
+        ],
+        Entity::TYPE_ERROR => [
+            'color' => 'fcffff',
+            'backgroundColor' => 'ed4040'
+        ],
+        Entity::TYPE_INFO => [
+            'color' => 'e9fff7',
+            'backgroundColor' => '737980'
+        ],
+        Entity::TYPE_SUCCESS => [
+            'color' => 'e5fff4',
+            'backgroundColor' => '5bc758'
+        ],
+        Entity::TYPE_CRITICAL => [
+            'color' => 'fcffff',
+            'backgroundColor' => 'ed4040'
+        ]
+    ];
+    
+    protected function loadHtml()
+    {
+        $this
+            ->addColumn((new Column('id'))
+                    ->setOrderable(DataProvider::SORT_DESC)
+                    ->setSearchable(true, Column::TYPE_INT))
+            ->addColumn((new Column('message'))
+                    ->setOrderable()
+                    ->setSearchable(true))
+            ->addColumn((new Column('type'))
+                    ->setOrderable()
+                    ->setSearchable(true))
+            ->addColumn((new Column('date'))
+                    ->setSearchable(true, Column::TYPE_DATE)
+                    ->setOrderable());
+    }
+    
+    public function replaceFieldMessage($key, $row)
+    {
+        return html_entity_decode($row[$key]);
+    }  
+    
+    public function replaceFieldType($key, $row)
+    {
+        return (new Others\Label())->initIds('label')
+                ->setMessage($row['typeLabel'])
+                ->setTitle($row['typeLabel'])
+                ->setColor($this->colorArray[$row[$key]]['color'])
+                ->setBackgroundColor($this->colorArray[$row[$key]]['backgroundColor'])
+                ->getHtml(); 
+    }
+
+    public function initContent()
+    {
+        $this->addActionButton((new DeleteLoggerModalButton()));
+        $this->addMassActionButton((new MassDeleteLoggerButton()));
+    }
+
+    protected function loadData()
+    {
+        $collection = Helper\sl('entityLogger')->all();
+        $data = [];
+        foreach ($collection as $model)
+        {
+            $data[] = $model->toArray();
+        }
+
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting('id', 'desc')->setData($data);
+
+        $this->setDataProvider($dataProv);
+    }
+}

+ 49 - 0
app/UI/Admin/LoggerManager/Providers/LoggerDataProvider.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\LoggerManager\Providers;
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseModelDataProvider;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates;
+
+/**
+ * CategoryDataProvider
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class LoggerDataProvider extends BaseModelDataProvider implements AdminArea
+{
+    
+    public function __construct()
+    {
+        parent::__construct('\ModulesGarden\Servers\KerioEmail\Core\Models\Logger\Model');
+    }
+
+    public function delete()
+    {
+        
+        if ($this->formData['id'])
+        {
+            parent::delete();
+            
+            return (new ResponseTemplates\HtmlDataJsonResponse())->setMessageAndTranslate('loggerDeletedSuccesfully');           
+        }
+        
+        if ($this->requestObj->get('massActions', []))
+        {
+            foreach ($this->requestObj->get('massActions', []) as $tldId)
+            {
+                $this->model->where('id', $tldId)->delete();      
+            }
+            
+            return (new ResponseTemplates\HtmlDataJsonResponse())->setMessageAndTranslate('loggersDeletedSuccesfully');  
+        }
+    }
+    
+    public function deleteall()
+    {
+        $this->model->truncate();
+        
+        return (new ResponseTemplates\HtmlDataJsonResponse())->setMessageAndTranslate('loggersDeletedSuccesfully');  
+    }
+}

+ 29 - 0
app/UI/Admin/ProductConfiguration/Buttons/CreateConfigurableOptionsBaseModalButton.php

@@ -0,0 +1,29 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Buttons;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Modals\CreateConfigurableOptionsConfirm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+
+/**
+ * Class CreateConfigurableOptionsBaseModalButton
+ * User: Nessandro
+ * Date: 2019-09-29
+ * Time: 15:29
+ */
+
+class CreateConfigurableOptionsBaseModalButton extends ButtonCreate implements AdminArea
+{
+    protected $id             = 'createCOBaseModalButton';
+    protected $name           = 'createCOBaseModalButton';
+    protected $title          = 'createCOBaseModalButton';
+    protected $class          = ['lu-btn lu-btn--success'];
+    protected $htmlAttributes = [
+        'href' => 'javascript:;',
+    ];
+
+    public function initContent() {
+
+        $this->initLoadModalAction(new CreateConfigurableOptionsConfirm());
+    }
+
+}

+ 44 - 0
app/UI/Admin/ProductConfiguration/Forms/CreateConfigurableAction.php

@@ -0,0 +1,44 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Forms;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\BaseFormExtended;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Providers\ConfigurableOptionManager;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ * Class CreateConfigurableAction
+ * User: Nessandro
+ * Date: 2019-09-29
+ * Time: 15:31
+ */
+
+class CreateConfigurableAction extends BaseFormExtended implements AdminArea
+{
+    protected $id    = 'createConfigurableAction';
+    protected $name  = 'createConfigurableAction';
+    protected $title = 'createConfigurableAction';
+
+    public function initContent()
+    {
+        $lang = di('lang');
+        $lang->addReplacementConstant('configurableOptionsNameUrl', '<a style="    color: #31708f; text-decoration: underline;" href="https://docs.whmcs.com/Addons_and_Configurable_Options" target="blank">here</a>');
+        $this->addInternalAlert($lang->absoluteT('configurableOptionsWhmcsInfo'), 'info', null, true);
+
+
+        $this->setFormType(FormConstants::CREATE);
+        $this->setProvider(new ConfigurableOptionManager());
+        $this->loadDataToForm();
+        $dataProvider = $this->getFormData();
+        if (is_array($dataProvider['fields']))
+        {
+            foreach ($dataProvider['fields'] as $key => $name)
+            {
+                $this->addField((new Switcher($key))->setDefaultValue('on')->setRawTitle($key.'|'.$name));
+            }
+        }
+        $this->loadDataToForm();
+    }
+}

+ 76 - 0
app/UI/Admin/ProductConfiguration/Helper/ConfigurableOptionsBuilder.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Helper;
+
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\ConfigurableOptions;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Helper\TypeConstans;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\Option;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Models\SubOption;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\AbstractOptions;
+
+/**
+ * Description of Config
+ *
+ * @author Mateusz Pawłowski <mateusz.pa@modulesgarden.com>
+ */
+class ConfigurableOptionsBuilder
+{
+
+    /**
+     * @param ConfigurableOptions $configurableOptions
+     * @param array $fieldsStatus
+     * @return ConfigurableOptions
+     */
+    public static function build(ConfigurableOptions $configurableOptions, $fieldsStatus = [],AbstractOptions $options)
+    {
+        $allOptions = $options->getOptions();
+
+        foreach ($fieldsStatus as $key => $field)
+        {
+            if ($field == "on")
+            {
+                $configurableOptions->addOption($allOptions[$key]);
+            }
+        }
+        return $configurableOptions;
+    }
+
+    /**
+     * @param ConfigurableOptions $configurableOptions
+     * @return ConfigurableOptions
+     */
+    public static function buildAll(ConfigurableOptions $configurableOptions,AbstractOptions  $options)
+    {
+        foreach($options->getOptions() as $option)
+        {
+            /* @var $option Option*/
+            $configurableOptions->addOption($option);
+        }
+
+        return $configurableOptions;
+    }
+
+    /**
+     * @param $string
+     * @param string $delimiter
+     * @param string $addPrefix
+     * @return string
+     */
+    private static function convertToCamelCase($string, $delimiter = "_", $addPrefix = ""){
+        $explodeString = explode($delimiter, $string);
+        $newString = "";
+
+        foreach($explodeString as $value){
+            if(empty($newString) && $addPrefix != ""){
+                $newString = lcfirst($addPrefix);
+            }elseif(empty($newString) && $addPrefix == ""){
+                $newString = lcfirst($value);
+                continue;
+            }
+            $newString .= ucfirst(($value));
+        }
+        return $newString;
+    }
+
+
+}

+ 27 - 0
app/UI/Admin/ProductConfiguration/Modals/CreateConfigurableOptionsConfirm.php

@@ -0,0 +1,27 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Modals;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Forms\CreateConfigurableAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ * Class CreateConfigurableOptionsConfirm
+ * User: Nessandro
+ * Date: 2019-09-29
+ * Time: 15:30
+ */
+
+class CreateConfigurableOptionsConfirm extends BaseEditModal implements AdminArea
+{
+    protected $id    = 'createCOConfirmModal';
+    protected $name  = 'createCOConfirmModal';
+    protected $title = 'createCOConfirmModal';
+
+    public function initContent()
+    {
+        $this->setModalSizeLarge();
+        $this->addForm(new CreateConfigurableAction());
+
+    }
+
+}

+ 74 - 0
app/UI/Admin/ProductConfiguration/Pages/ConfigForm.php

@@ -0,0 +1,74 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages;
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\CalendarFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\ClassOfServiceFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\ClientAreaFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\ConfigurableOptions;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\ContactFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\EssentialFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\GeneralFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\MailServiceFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\MimeFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\SearchFeatures;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections\KerioSettings;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Providers\ProductConfigurationDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormIntegration;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 09:12
+ * Class ConfigForm
+ */
+class ConfigForm extends FormIntegration implements AdminArea
+{
+    protected $id    = 'configForm';
+    protected $name  = 'configForm';
+    protected $title = 'configForm';
+
+    public function initContent()
+    {
+        /** add data provider **/
+        $this->setProvider(new ProductConfigurationDataProvider());
+
+        /** kerio setting section **/
+        $this->addSection(new KerioSettings());
+
+        /** essential features section **/
+        $this->addSection(new EssentialFeatures());
+
+        /** general features section **/
+        $this->addSection(new GeneralFeatures());
+
+        /** mail service features section **/
+        $this->addSection(new MailServiceFeatures());
+
+        /** contact features section **/
+        $this->addSection(new ContactFeatures());
+
+        /** calendar features section **/
+        $this->addSection(new CalendarFeatures());
+
+        /** search features section **/
+        $this->addSection(new SearchFeatures());
+
+        /** search features section **/
+        $this->addSection(new MimeFeatures());
+
+        /** class of service features section **/
+        $this->addSection(new ClassOfServiceFeatures());
+
+        /** available features in ca **/
+        $this->addSection(new ClientAreaFeatures());
+
+        /** configurable option section**/
+        $this->addSection(new ConfigurableOptions());
+
+        $this->loadDataToForm();
+    }
+
+}

+ 61 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/CalendarFeatures.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:34
+ * Class CalendarFeatures
+ */
+class CalendarFeatures extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'calendarFeatures';
+    protected $name     = 'calendarFeatures';
+    protected $title    = 'calendarFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+            ->addSection($this->getRightSection());
+
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getLeftSection()
+    {
+        $left = new HalfPageSection('left');
+
+        $field = new Switcher('kerioFeatureGroupCalendarEnabled');
+        $left->addField($field);
+
+        return $left;
+
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getRightSection()
+    {
+        $right = new HalfPageSection('right');
+
+        $field = new Switcher('kerioFeatureCalendarReminderDeviceEmailEnabled');
+        $right->addField($field);
+
+        return $right;
+    }
+
+}

+ 94 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/ClassOfServiceFeatures.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Traits\LangHandler;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ServerParams;
+use ModulesGarden\Servers\KerioEmail\App\Traits\KerioApiHandler;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields\ExtendedInputField;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\HalfPageCustomCosSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:35
+ * Class ClassOfServiceFeatures
+ */
+class ClassOfServiceFeatures extends BoxSectionExtended implements AdminArea
+{
+    use LangHandler;
+
+    protected $id       = 'classOfServiceFeatures';
+    protected $name     = 'classOfServiceFeatures';
+    protected $title    = 'classOfServiceFeatures';
+
+    public function initContent()
+    {
+        $this->loadCos();
+    }
+
+    /**
+     *
+     */
+    public function loadCos()
+    {
+        $lang = $this->getLang();
+
+        $left  = new HalfPageCustomCosSection('left');
+        $right = new HalfPageCustomCosSection('right');
+
+        /**
+         * api manager
+         */
+        $manager = new KerioManager();
+        /**
+         * repository
+         */
+        $repository = $manager->getApiByProduct($this->getRequestValue('id'))->soap->repository();
+        /**
+         * cos
+         */
+        $cos = $repository->cos->all();
+        $this->cos = $cos;
+
+        $pointer = 1;
+        foreach($cos as $key => $cosModel)
+        {
+            /* @var $cosModel ClassOfService */
+            $id = 'cos['.$cosModel->getId().']';
+            $quete = $cosModel->getMbMailQuote() ;
+
+            $field = new ExtendedInputField($cosModel->getId());
+            $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+            $field->addHtmlAttribute('min', Size::UNLIMITED);
+            $field->setName($id);
+            $field->setRawTitle("{$cosModel->getName()} ({$quete} MB)");
+            $field->setRawDescription(sprintf($lang->absoluteT('Enter to limit an accounts number of %s with quota %s MB or set -1 to unlimited'),ucfirst($cosModel->getName()), $quete) );
+            $field->setDefaultValue(Size::DEFAULT_NULL_VALUE);
+
+            if($pointer %2 == 0)
+            {
+                $right->addField($field);
+            }else{
+                $left->addField($field);
+            }
+            $pointer++;
+        }
+        $this
+            ->addSection($left)
+            ->addSection($right);
+    }
+
+}

+ 73 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/ClientAreaFeatures.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.10.19
+ * Time: 09:55
+ * Class ClientAreaFeatures
+ */
+class ClientAreaFeatures extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'clientAreaFeatures';
+    protected $name     = 'clientAreaFeatures';
+    protected $title    = 'clientAreaFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+            ->addSection($this->getRightSection());
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getLeftSection()
+    {
+        $leftSection = new HalfPageSection('clientAreaFeaturesLeft');
+
+        $field = new Switcher('ca_emailAccountPage');
+        $leftSection->addField($field);
+
+        $field = new Switcher('ca_distributionListPage');
+        $leftSection->addField($field);
+
+        $field = new Switcher('ca_goToWebmailPage');
+        $leftSection->addField($field);
+
+        $field = new Switcher('ca_ressourcePage');
+        $leftSection->addField($field);
+
+        return $leftSection;
+
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getRightSection()
+    {
+        $right = new HalfPageSection('clientAreaFeaturesRight');
+
+        $field = new Switcher('ca_emailAliasesPage');
+        $right->addField($field);
+
+        $field = new Switcher('ca_domainAliasesPage');
+        $right->addField($field);
+
+        $field = new Switcher('ca_logInToMailboxButton');
+        $right->addField($field);
+
+        return $right;
+    }
+}

+ 100 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/ConfigurableOptions.php

@@ -0,0 +1,100 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\ConfigOptionsType;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Buttons\CreateConfigurableOptionsBaseModalButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Helper\ConfigurableOptionsBuilder;
+use ModulesGarden\Servers\KerioEmail\App\Traits\KerioApiHandler;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Providers\ConfigurableOptionManager;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:32
+ * Class ConfigurableOptionsSection
+ */
+class ConfigurableOptions extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'configurableOptions';
+    protected $name     = 'configurableOptions';
+    protected $title    = 'configurableOptions';
+
+    use KerioApiHandler;
+
+    public function initContent()
+    {
+
+        $this->addButton(new CreateConfigurableOptionsBaseModalButton());
+    }
+
+    /**
+     * @return array
+     * @throws \Exception
+     */
+    public function getOptions()
+    {
+        /**
+         * product id
+         */
+        $productId = $this->getRequestValue('id');
+
+        /**
+         * product manager
+         */
+        $productManager = new ProductManager();
+        $productManager
+            ->loadById($productId);
+
+        /**
+         * config options strategy
+         */
+        $options = new ConfigOptionsType();
+        $options->setType($productManager->get(ProductParams::CLASS_OF_SERVICE_NAME));
+        $options->setProductId($productId);
+        $options->load();
+        ;
+
+        /**
+         * config option model
+         */
+        $configurableOptions = new \ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\ConfigurableOptions($productId);
+
+        /**
+         * build co to show
+         */
+        ConfigurableOptionsBuilder::buildAll($configurableOptions, $options->getConfigurableOptions());
+
+        /**
+         *
+         */
+        $fields = $configurableOptions->show();
+
+        /**
+         *
+         * add additional elements,
+         * resolve none full line issue (#156)
+         */
+        $limit = count($fields) % 3;
+
+        if($limit > 0)
+        {
+            while($limit < 3)
+            {
+                $fields['emptyFields'.$limit] = '-1';
+                $limit++;
+            }
+        }
+
+
+        return $fields;
+    }
+}

+ 44 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/ContactFeatures.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:34
+ * Class ContactFeatures
+ */
+class ContactFeatures extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'contactFeatures';
+    protected $name     = 'contactFeatures';
+    protected $title    = 'contactFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+        ;
+
+    }
+    public function getLeftSection()
+    {
+        $leftSection = new HalfPageSection('left');
+
+        $field = new Switcher('kerioFeatureDistributionListFolderEnabled');
+        $leftSection->addField($field);
+
+        return $leftSection;
+    }
+
+
+}

+ 71 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/EssentialFeatures.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:33
+ * Class EssentialFeatures
+ */
+class EssentialFeatures extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'essentialFeatures';
+    protected $name     = 'essentialFeatures';
+    protected $title    = 'essentialFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+            ->addSection($this->getRightSection());
+
+    }
+    public function getLeftSection()
+    {
+        $leftSection = new HalfPageSection('essentialFeaturesLeft');
+
+        $field = new Switcher('kerioFeatureMailEnabled');
+        //$field->setDescription('description');
+        $leftSection->addField($field);
+
+        $field = new Switcher('kerioFeatureCalendarEnabled');
+        //$field->setDescription('description');
+        $leftSection->addField($field);
+
+        $field = new Switcher('kerioFeatureBriefcasesEnabled');
+        //$field->setDescription('description');
+        $leftSection->addField($field);
+
+        return $leftSection;
+
+    }
+
+    public function getRightSection()
+    {
+        $right = new HalfPageSection('essentialFeaturesRight');
+
+        $field = new Switcher('kerioFeatureContactsEnabled');
+        //$field->setDescription('description');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureTasksEnabled');
+        //$field->setDescription('description');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureOptionsEnabled');
+        //$field->setDescription('description');
+        $right->addField($field);
+
+        return $right;
+    }
+}

+ 102 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/GeneralFeatures.php

@@ -0,0 +1,102 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:33
+ * Class GeneralFeatures
+ */
+class GeneralFeatures extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'generalFeatures';
+    protected $name     = 'generalFeatures';
+    protected $title    = 'generalFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+            ->addSection($this->getRightSection());
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getLeftSection()
+    {
+        $left = new HalfPageSection('generalFeaturesLeft');
+
+        $field = new Switcher('kerioFeatureTaggingEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureChangePasswordEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureManageZimlets');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureGalEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureEwsEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureWebClientOfflineAccessEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureImportFolderEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioDumpsterEnabled');
+        $left->addField($field);
+
+        return $left;
+
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getRightSection()
+    {
+        $right = new HalfPageSection('generalFeaturesRight');
+
+        $field = new Switcher('kerioFeatureSharingEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureSkinChangeEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureHtmlComposeEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureMAPIConnectorEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureTouchClientEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureGalAutoCompleteEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureExportFolderEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioDumpsterPurgeEnabled');
+        $right->addField($field);
+
+        return $right;
+    }
+
+}

+ 118 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/KerioSettings.php

@@ -0,0 +1,118 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields\ExtendedInputField;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 28.08.19
+ * Time: 09:15
+ * Class KerioSettingsSection
+ */
+class KerioSettings extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'kerioSettings';
+    protected $name     = 'kerioSettings';
+    protected $title    = 'kerioSettings';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+            ->addSection($this->getRightSection());
+
+    }
+
+    /**
+     * @description left section
+     * @return HalfPageSection
+     */
+    public function getLeftSection()
+    {
+        $leftSection = new HalfPageSection('leftSide');
+
+
+        $field = new ExtendedInputField('acc_limit');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $leftSection->addField($field);
+
+        $field = new ExtendedInputField('acc_base');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $leftSection->addField($field);
+
+        $field = new ExtendedInputField('alias_limit');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $leftSection->addField($field);
+
+        $field = new Select('cos_name');
+        $field->addHtmlAttribute('onChange','hiddeSections(event)');
+        $field->setDescription('description');
+        $leftSection->addField($field);
+
+        $loginLink = new Text('login_link');
+        $loginLink->setDescription('description');
+        $leftSection->addField($loginLink);
+
+        $field = new Switcher('filterAccountsByCOS');
+        $field->setDescription('description');
+        $leftSection->addField($field);
+
+        return $leftSection;
+    }
+
+    /**
+     * @description right section
+     * @return HalfPageSection
+     */
+    public function getRightSection()
+    {
+        $right = new HalfPageSection('rightSide');
+
+        $field = new ExtendedInputField('acc_size');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $right->addField($field);
+
+        $field = new ExtendedInputField('domain_alias_limit');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $right->addField($field);
+
+        $field = new ExtendedInputField('dist_list_limit');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $right->addField($field);
+
+        $field = new ExtendedInputField('domainMaxSize');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $right->addField($field);
+
+        $field = new ExtendedInputField('domainBaseSize');
+        $field->setFieldType(ExtendedInputField::TYPE_NUMBER);
+        $field->addHtmlAttribute('min', Size::UNLIMITED);
+        $field->setDescription('description');
+        $right->addField($field);
+
+        return $right;
+    }
+}

+ 87 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/MailServiceFeatures.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:34
+ * Class MailServiceFeatures
+ */
+class MailServiceFeatures extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'mailServiceFeatures';
+    protected $name     = 'mailServiceFeatures';
+    protected $title    = 'mailServiceFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+            ->addSection($this->getRightSection());
+
+    }
+    public function getLeftSection()
+    {
+        $left = new HalfPageSection('left');
+
+        $field = new Switcher('kerioFeatureMailPriorityEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioImapEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureImapDataSourceEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureMailSendLaterEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureFiltersEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureNewMailNotificationEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureReadReceiptsEnabled');
+        $left->addField($field);
+
+        return $left;
+    }
+
+    public function getRightSection()
+    {
+        $right = new HalfPageSection('right');
+
+        $field = new Switcher('kerioFeatureFlaggingEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioPop3Enabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeaturePop3DataSourceEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureConversationsEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureOutOfOfficeReplyEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeatureIdentitiesEnabled');
+        $right->addField($field);
+
+        return $right;
+
+    }
+
+}

+ 47 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/MimeFeatures.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:35
+ * Class MimeFeatures
+ */
+class MimeFeatures extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'mimeFeatures';
+    protected $name     = 'mimeFeatures';
+    protected $title    = 'mimeFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+        ;
+
+    }
+    /**
+     * @return HalfPageSection
+     */
+    public function getLeftSection()
+    {
+        $left = new HalfPageSection('left');
+
+        $field = new Switcher('kerioFeatureSMIMEEnabled');
+        $left->addField($field);
+
+        return $left;
+    }
+
+
+}

+ 65 - 0
app/UI/Admin/ProductConfiguration/Pages/Sections/SearchFeatures.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Pages\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\BoxSectionExtended;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\BoxSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 08:34
+ * Class SearchFeatures
+ */
+class SearchFeatures  extends BoxSectionExtended implements AdminArea
+{
+    protected $id       = 'searchFeatures';
+    protected $name     = 'searchFeatures';
+    protected $title    = 'searchFeatures';
+
+    public function initContent()
+    {
+        $this
+            ->addSection($this->getLeftSection())
+            ->addSection($this->getRightSection());
+
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getLeftSection()
+    {
+        $left = new HalfPageSection('left');
+
+        $field = new Switcher('kerioFeatureAdvancedSearchEnabled');
+        $left->addField($field);
+
+        $field = new Switcher('kerioFeatureInitialSearchPreferenceEnabled');
+        $left->addField($field);
+
+        return $left;
+    }
+
+    /**
+     * @return HalfPageSection
+     */
+    public function getRightSection()
+    {
+        $right = new HalfPageSection('right');
+
+        $field = new Switcher('kerioFeatureSavedSearchesEnabled');
+        $right->addField($field);
+
+        $field = new Switcher('kerioFeaturePeopleSearchEnabled');
+        $right->addField($field);
+
+        return $right;
+    }
+}

+ 91 - 0
app/UI/Admin/ProductConfiguration/Providers/ConfigurableOptionManager.php

@@ -0,0 +1,91 @@
+<?php
+/**
+ * Class ConfigurableOptionManager
+ * User: Nessandro
+ * Date: 2019-09-29
+ * Time: 15:33
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Providers
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\ConfigurableOptions;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\ConfigOptionsType;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Helper\ConfigurableOptionsBuilder;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+class ConfigurableOptionManager extends BaseDataProvider implements AdminArea
+{
+    public function read()
+    {
+        $productId = $this->getRequestValue('id');
+
+        $productManager = new ProductManager();
+        $productManager
+            ->loadById($productId);
+
+        $options = new ConfigOptionsType();
+        $options->setType($productManager->get(ProductParams::CLASS_OF_SERVICE_NAME));
+        $options->setProductId($productId);
+        $options->load();
+
+        $configurableOption = new ConfigurableOptions($productId);
+        ConfigurableOptionsBuilder::buildAll($configurableOption, $options->getConfigurableOptions());
+
+        $this->data         = [
+            'fields' => $configurableOption->show()
+        ];
+    }
+
+    /**
+     * @return HtmlDataJsonResponse|void
+     */
+    public function create()
+    {
+        $productId = $this->getRequestValue('id');
+
+        try
+        {
+            $productManager = new ProductManager();
+            $productManager
+                ->loadById($productId);
+
+            $options = new ConfigOptionsType();
+            $options->setType($productManager->get(ProductParams::CLASS_OF_SERVICE_NAME));
+            $options->setProductId($productId);
+            $options->load();
+
+            $configurableOption = new ConfigurableOptions($productId);
+
+            ConfigurableOptionsBuilder::build($configurableOption, $this->formData, $options->getConfigurableOptions());
+            $status             = $configurableOption->createOrUpdate();
+
+            $msg                = ($status) ? 'configurableOptionsCreate' : 'configurableOptionsUpdate';
+            return (new HtmlDataJsonResponse())
+                ->setStatusSuccess()
+                ->setCallBackFunction('redirectToConfigurableOptionsTab')
+                ->setMessageAndTranslate($msg);
+        }
+        catch (\Exception $ex)
+        {
+            return (new HtmlDataJsonResponse())
+                ->setStatusError()
+                ->setMessage($ex->getMessage());
+        }
+    }
+
+    public function delete()
+    {
+
+    }
+
+    public function update()
+    {
+
+    }
+}

+ 237 - 0
app/UI/Admin/ProductConfiguration/Providers/ProductConfigurationDataProvider.php

@@ -0,0 +1,237 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Admin\ProductConfiguration\Providers;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\LangHandler;
+use ModulesGarden\Servers\KerioEmail\App\Traits\ServerParams;
+use ModulesGarden\Servers\KerioEmail\App\Traits\KerioApiHandler;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+use \ModulesGarden\Servers\KerioEmail\App\Models\ProductConfiguration;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Migrations\Drivers\Version1To2;
+use \Illuminate\Database\Capsule\Manager as DB;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 29.08.19
+ * Time: 10:27
+ * Class ProductConfigurationDataProvider
+ */
+class ProductConfigurationDataProvider extends BaseDataProvider implements AdminArea
+{
+
+    const FORM_DATA = [
+            'acc_limit',
+            'acc_base',
+            'alias_limit',
+            'cos_name',
+            'login_link',
+            'filterAccountsByCOS',
+            'acc_size',
+            'domain_alias_limit',
+            'dist_list_limit',
+            'domainMaxSize',
+            'domainBaseSize',
+            'cos',
+            'ca_emailAccountPage',
+            'ca_ressourcePage',
+            'ca_distributionListPage',
+            'ca_goToWebmailPage',
+            'ca_emailAliasesPage',
+            'ca_domainAliasesPage',
+            'ca_logInToMailboxButton',
+        ];
+
+    const FILED_NOT_UPDATED = [
+        'login_link'
+    ];
+
+    use LangHandler;
+
+    /**
+     *
+     */
+    public function read()
+    {
+        /**
+         * load params from previous version
+         */
+        $this->checkConfigOrLoadFromPrevious($this->getRequestValue('id'));
+
+        $this->loadDefaultData();
+        $this->overrideDefaultDataByProductConfig();
+    }
+
+    /**
+     *
+     */
+    public function update()
+    {
+        $this->catchFormData();
+
+        $cos = $this->formData['cos'];
+        unset($this->formData['cos']);
+
+        $productId = $this->request->get('id');
+
+        foreach ($this->formData as $key => $value)
+        {
+            ProductConfiguration::updateOrCreate(['product_id' => $productId, 'setting' => $key], ['value' => $value]);
+        }
+
+        /**
+         * save  serialized cos
+         */
+        ProductConfiguration::updateOrCreate(['product_id' => $productId, 'setting' => 'cos'], ['value' => json_encode($cos)]);
+    }
+
+    /**
+     *
+     */
+    protected function loadDefaultData()
+    {
+        /* default data */
+        $this->data['acc_limit']          = Size::DEFAULT_ACC_LIMIT;
+        $this->data['acc_base']           = Size::DEFAULT_ACC_BASE;
+        $this->data['acc_size']           = Size::DEFAULT_ACC_SIZE;
+        $this->data['alias_limit']        = Size::DEFAULT_ALIAS_LIMIT;
+        $this->data['domain_alias_limit'] = Size::DEFAULT_DOMAIN_ALIAS_LIMIT;
+        $this->data['cos_name']           = ClassOfServices::CUSTOM_ZIMBRA;
+        $this->data['dist_list_limit']    = Size::DEFAULT_DIST_ALIAS_LIMIT;
+        $this->data['login_link']         = Kerio::DEFAULT_LOGIN_LINK;
+        $this->data['domainMaxSize']      = Size::UNLIMITED;
+        $this->data['domainBaseSize']     = Size::UNLIMITED;
+
+        /* available class of services*/
+        $this->availableValues['cos_name'] = [
+            ClassOfServices::CUSTOM_ZIMBRA          => $this->getLang()->absoluteT('addonAA', 'configuration', 'product', 'kerio', 'cos', 'Use Custom Settings'),
+            ClassOfServices::ZIMBRA_CONFIG_OPTIONS  => $this->getLang()->absoluteT('addonAA', 'configuration', 'product', 'kerio', 'cos', 'Allow clients to choose Class Of Service'),
+            ClassOfServices::CLASS_OF_SERVICE_QUOTA => $this->getLang()->absoluteT('addonAA', 'configuration', 'product', 'kerio', 'cos', 'Allow clients to choose Class Of Service Quota Per Account'),
+        ];
+
+
+        $manager    = new KerioManager();
+        $repository = $manager->getApiByProduct($this->getRequestValue('id'))->soap->repository();
+        $cosList        = $repository->cos->all();
+
+        /**
+         * class of services from API
+         */
+        foreach ($cosList as $cos)
+        {
+            /**
+             * @var $cos \ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService
+             */
+            $this->availableValues['cos_name'][$cos->getId()] = $this->getLang()->absoluteT($cos->getName());
+        }
+    }
+
+    /**
+     * @description load data from database
+     */
+    protected function overrideDefaultDataByProductConfig()
+    {
+        $settings = ProductConfiguration::where('product_id', $this->request->get('id'))->get();
+
+        foreach ($settings as $setting)
+        {
+            if('cos' === $setting->setting)
+            {
+                $this->data[$setting->setting] = json_decode($setting->value, true);
+                continue;
+            }
+            $this->data[$setting->setting] = $setting->value;
+        }
+    }
+
+    /**
+     * @description catch params from request
+     */
+    protected function catchFormData()
+    {
+        /**
+         * catch from request
+         */
+        $params = array_merge(Kerio::BASE_ACCOUNT_CONFIG,self::FORM_DATA);
+
+        foreach ($params as $name)
+        {
+            if ($value = $this->request->get($name))
+            {
+                $this->formData[$name] = $value;
+            }elseif(!in_array($name,self::FILED_NOT_UPDATED)){
+                $this->formData[$name] = ProductParams::SWITCHER_DISABLED;
+            }else{
+                $this->formData[$name] = '';
+            }
+        }
+    }
+
+
+    private function checkConfigOrLoadFromPrevious($id)
+    {
+
+        if(ProductConfiguration::where('product_id', $id)->first())
+        {
+            return;
+        }
+        $migration = new Version1To2\Settings();
+
+        $exists = DB::schema()->hasTable($migration->getFromTable());
+        if(!$exists)
+        {
+            return;
+        }
+
+        $previous = DB::table($migration->getFromTable())->where('product_id', $id)->get();
+
+        /**
+         *
+         */
+        $prodManager = new ProductConfiguration();
+
+        /**
+         *
+         * storage all params per product id
+         */
+        foreach($previous as $setting)
+        {
+            $settings[$setting->product_id][$setting->setting] = $setting->value;
+            $products[] = $setting->product_id;
+        }
+
+        /**
+         *
+         * update setting data & save
+         */
+        foreach($settings as $prodId => $settingsArray)
+        {
+            $attrs = $migration->updateValues($settingsArray, $prodId);
+
+            foreach($attrs as $key => $value)
+            {
+                $prodManager->updateOrCreate(['product_id' => $prodId, 'setting' => $key],['value' => $value]);
+            }
+        }
+
+        /**
+         *
+         * new options
+         */
+        foreach($migration->getNewFields() as $key => $value)
+        {
+
+            $prodManager->updateOrCreate(['product_id' => $id, 'setting' => $key],['value' => $value]);
+        }
+
+    }
+}

+ 50 - 0
app/UI/Admin/Templates/assets/css/integration.css

@@ -0,0 +1,50 @@
+#contentarea > div > h1 {
+    display: block!important;
+}
+
+#contentarea {
+    margin: 10px;
+    padding: 15px;
+    min-height: 600px;
+    background-color: #fff;
+    border: 4px solid #e2e7e9;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    -o-border-radius: 10px;
+    border-radius: 10px;
+    overflow: auto;
+}
+
+.mg-integration-container .lu-app {
+    height: 0px;
+    visibility: hidden;
+}
+
+#layers .lu-app {
+    background-color: #efefef;
+}
+
+#layers .lu-app-main__body {
+    padding: 0px;
+    margin-bottom: -15px;
+}
+
+#tblModuleSettings {
+    background-color: #efefef;
+}
+
+#layers .configOption {
+    border-bottom: 1px solid #edeff2;
+    padding: 10px;
+    height: auto;
+}
+
+
+#layers .configOptionButton {
+    padding: 16px 0px 15px 0px;
+}
+
+#layers .configOptionBox {
+    padding: 0px 15px 15px 15px !important;
+
+}

+ 0 - 0
app/UI/Admin/Templates/assets/css/module_styles.css


+ 0 - 0
app/UI/Admin/Templates/assets/js/.gitkeep


+ 164 - 0
app/UI/Admin/Templates/assets/js/productConfiguration/index.js

@@ -0,0 +1,164 @@
+//replace url wrapper
+var mgUrlParser = {
+    oldMgUrlParser: mgUrlParser,
+
+    getCurrentUrl: function(){
+        var url = this.oldMgUrlParser.getCurrentUrl();
+        return url.replace("action=edit", "action=module-settings").replace("&success=true", "");
+    }
+};
+
+
+function redirectToPage(tabNumber)
+{
+    var windowAddress = String(window.location);
+    var hashTab = windowAddress.indexOf('#tab=');
+    var andTab = windowAddress.indexOf('&tab=');
+    if (hashTab > 0 && andTab > 0) {
+        var count = Math.min(hashTab, andTab);
+    } else {
+        var count = Math.max(hashTab, andTab);
+    }
+
+    var redirectTo = (count > 0) ? windowAddress.substring(0, count) : windowAddress;
+    window.location = redirectTo + '&tab=' + tabNumber;
+}
+
+function redirectToConfigurableOptionsTab()
+{
+    redirectToPage(5);
+}
+
+function redirectToCustomFieldsTab()
+{
+    redirectToPage(4);
+
+}
+
+function productConfigurationSelect(event)
+{
+    productConfigurationSettings(event, event.target.value);
+}
+
+function productConfigurationSettings(event, packageName)
+{
+    // const formFields        = $(event.target).parents().find('.lu-form-group , .lu-form-check');
+    // const protectedFields = ['mgpci[package]','mgpci[dedicated_ip]','mgpci[reseller_ip]','mgpci[suspend_at_limit]'];
+    // formFields.each(function(key, item){
+    //     let name = $(item).find('input')[0].name;
+    //     if (!name)
+    //     {
+    //         name = $(item).find('select')[0].name;
+    //     }
+    //     if (protectedFields.indexOf(name) === -1)
+    //     {
+    //         if (packageName === 'custom'){
+    //             $(item).show();
+    //         }
+    //         else{
+    //             $(item).hide();
+    //         }
+    //     }
+    // });
+}
+
+function hiddeSections(event)
+{
+    /**
+     * all sections name
+     * @type {string[]}
+     */
+    var sections = [
+        'calendarFeatures',
+        'classOfServiceFeatures',
+        'contactFeatures',
+        'essentialFeatures',
+        'generalFeatures',
+        'mailServiceFeatures',
+        'mimeFeatures',
+        'searchFeatures',
+    ];
+
+    var availableSections = [];
+
+    /**
+     * set which section should be displayed
+     */
+    if(event.target.value == 'customMGkerio')
+    {
+        availableSections = [
+            'calendarFeatures',
+            'contactFeatures',
+            'essentialFeatures',
+            'generalFeatures',
+            'mailServiceFeatures',
+            'mimeFeatures',
+            'searchFeatures',
+        ];
+    }else if(event.target.value == 'kerioConfigurableOptions'){
+        availableSections = [];
+    }else if(event.target.value == 'cosQuota'){
+        availableSections = [
+            'classOfServiceFeatures'
+        ];
+    }
+    /**
+     * hide or show sections
+     */
+    hideSecction(sections, availableSections);
+}
+
+/**
+ * hide or display section
+ * @param sections
+ * @param availableSections
+ */
+function hideSecction(sections, availableSections)
+{
+
+    sections.forEach(function(entry, key, each){
+        if(availableSections.includes(entry) === true)
+        {
+            document.getElementById(entry).style.display="";
+        }else{
+            document.getElementById(entry).style.display="none";
+        }
+    })
+}
+
+$(document).ready(function(){
+
+
+})
+
+$('#ProductConfigurationPage').ready(function()
+{
+    /**
+     * trigg change select
+     */
+    $("[name=cos_name]").trigger("change");
+
+    // var packageName = $('select[name="mgpci[package]"]').val()
+    //
+    // if(packageName !== "custom")
+    // {
+    //
+    //     var protectedArrayFields = ['mgpci[package]','mgpci[dedicated_ip]','mgpci[reseller_ip]','mgpci[suspend_at_limit]'];
+    //     var fields = $('#layers').find('.lu-form-group , .lu-form-check')
+    //
+    //     fields.each(function(){
+    //         var fieldName = $(this).find('input').attr('name')
+    //
+    //         if(typeof fieldName === "undefined"){
+    //             fieldName = $(this).find('select').attr('name')
+    //         }
+    //         if (protectedArrayFields.indexOf(fieldName) === -1)
+    //         {
+    //             $(this).hide();
+    //         }
+    //     })
+    //
+    //
+    // }
+
+})

+ 3 - 0
app/UI/Admin/Templates/custom/fields/enabledField.tpl

@@ -0,0 +1,3 @@
+<span class="lu-label lu-label--{$rawObject->getType()} lu-label--status">
+    {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T($rawObject->getTitle())}{/if}
+</span>

+ 16 - 0
app/UI/Admin/Templates/custom/fields/extendedInputField.tpl

@@ -0,0 +1,16 @@
+<div class="lu-form-group">
+    <label class="lu-form-label">
+        {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T($rawObject->getTitle())}{/if}
+
+        {if $rawObject->isRawDescription()}
+            <i data-title="{$rawObject->getRawDescription()}" data-toggle="lu-tooltip" class="lu-i-c-2x lu-zmdi lu-zmdi-help-outline lu-form-tooltip-helper"></i>
+        {elseif $rawObject->getDescription()}
+            <i data-title="{$MGLANG->T($rawObject->getDescription())}" data-toggle="lu-tooltip" class="lu-i-c-2x lu-zmdi lu-zmdi-help-outline lu-form-tooltip-helper"></i>
+        {/if}
+    </label>
+    <input class="lu-form-control" type="{$rawObject->getFieldType()}" placeholder="{$rawObject->getPlaceholder()}" name="{$rawObject->getName()}"
+           value="{$rawObject->getValue()}" {if $rawObject->isDisabled()}disabled="disabled"{/if}
+    {foreach $htmlAttributes as $aValue} {$aValue@key}="{$aValue}" {/foreach}>
+    <div class="lu-form-feedback lu-form-feedback--icon" hidden="hidden">
+    </div>
+</div>

+ 50 - 0
app/UI/Admin/Templates/custom/fields/extendedSelect.tpl

@@ -0,0 +1,50 @@
+{**********************************************************************
+* KerioEmail product developed. (2017-10-30)
+* *
+*
+*  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+*  CONTACT                        ->       contact@modulesgarden.com
+*
+*
+* This software is furnished under a license and may be used and copied
+* only  in  accordance  with  the  terms  of such  license and with the
+* inclusion of the above copyright notice.  This software  or any other
+* copies thereof may not be provided or otherwise made available to any
+* other person.  No title to and  ownership of the  software is  hereby
+* transferred.
+*
+*
+**********************************************************************}
+
+{**
+* @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+*}
+
+<div class="lu-form-group" {if $rawObject->isHidden()} hidden='true'{/if}>
+    <label class="lu-form-label">
+        {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T($rawObject->getTitle())}{/if}
+        {if $rawObject->getDescription()}
+            <i data-title="{$MGLANG->T($rawObject->getDescription())}" data-toggle="lu-tooltip" class="lu-i-c-2x lu-zmdi lu-zmdi-help-outline lu-form-tooltip-helper"></i>
+        {/if}
+    </label>
+
+    <select
+            class="lu-form-control"
+            name="{$rawObject->getName()}"
+            {if $rawObject->isDisabled()}disabled="disabled"{/if}
+    {foreach $htmlAttributes as $aValue} {$aValue@key}="{$aValue}" {/foreach}
+    {if $rawObject->isMultiple()}data-options="removeButton:true; resotreOnBackspace:true; dragAndDrop:true; maxItems: null;" multiple="multiple"{/if}
+    >
+    {if $rawObject->getValue()|is_array}
+        {foreach from=$rawObject->getAvailableValues() key=opValue item=option}
+            <option value="{$opValue}" {if $opValue|in_array:$rawObject->getValue()}selected{/if}>{$option}</option>
+        {/foreach}
+    {else}
+        {foreach from=$rawObject->getAvailableValues() key=opValue item=option}
+            <option value="{$opValue}" {if $opValue == $rawObject->getValue()}selected{/if}>{$option}</option>
+        {/foreach}
+    {/if}
+    </select>
+    <div class="lu-form-feedback lu-form-feedback--icon" hidden="hidden">
+    </div>
+</div>

+ 32 - 0
app/UI/Admin/Templates/custom/forms/baseFormExtended.tpl

@@ -0,0 +1,32 @@
+{if $rawObject->haveInternalAlertMessage()}
+    <div class="lu-alert {if $rawObject->getInternalAlertSize() !== ''}lu-alert--{$rawObject->getInternalAlertSize()}{/if} lu-alert--{$rawObject->getInternalAlertMessageType()} lu-alert--faded modal-alert-top">
+        <div class="lu-alert__body">
+            {if $rawObject->isInternalAlertMessageRaw()|unescape:'html'}{$rawObject->getInternalAlertMessage()|unescape:'html'}{else}{$MGLANG->T($rawObject->getInternalAlertMessage())|unescape:'html'}{/if}
+        </div>
+    </div>
+{/if}
+{if $rawObject->getConfirmMessage()}
+    {if $rawObject->isTranslateConfirmMessage()}
+        {$MGLANG->T($rawObject->getConfirmMessage())|unescape:'html'}
+    {else}
+        {$rawObject->getConfirmMessage()|unescape:'html'}
+    {/if}
+{/if}
+
+<form id="{$rawObject->getId()}" namespace="{$namespace}" index="{$rawObject->getIndex()}" mgformtype="{$rawObject->getFormType()}"
+{foreach $htmlAttributes as $aValue} {$aValue@key}="{$aValue}" {/foreach}>
+{if $rawObject->getClasses()}
+<div class="{$rawObject->getClasses()}">
+    {/if}
+    {if $rawObject->getSections()}
+        {foreach from=$rawObject->getSections() item=section }
+            {$section->getHtml()}
+        {/foreach}
+    {else}
+        {foreach from=$rawObject->getFields() item=field }
+            {$field->getHtml()}
+        {/foreach}
+    {/if}
+    {if $rawObject->getClasses()}
+</div>
+{/if}

+ 32 - 0
app/UI/Admin/Templates/custom/forms/sortedFieldForm.tpl

@@ -0,0 +1,32 @@
+{**
+* @author Tomasz Bielecki <tomasz.bi@modulesgarden.com>
+*}
+
+{if $rawObject->haveInternalAlertMessage()}
+    <div class="lu-alert {if $rawObject->getInternalAlertSize() !== ''}lu-alert--{$rawObject->getInternalAlertSize()}{/if} lu-alert--{$rawObject->getInternalAlertMessageType()} lu-alert--faded modal-alert-top">
+        <div class="lu-alert__body">
+            {if $rawObject->isInternalAlertMessageRaw()|unescape:'html'}{$rawObject->getInternalAlertMessage()}{else}{$MGLANG->T($rawObject->getInternalAlertMessage())|unescape:'html'}{/if}
+        </div>
+    </div>
+{/if}
+{if $rawObject->getConfirmMessage()}
+    {if $rawObject->isTranslateConfirmMessage()}
+        {$MGLANG->T($rawObject->getConfirmMessage())|unescape:'html'}
+    {else}
+        {$rawObject->getConfirmMessage()|unescape:'html'}
+    {/if}
+{/if}
+
+<form id="{$rawObject->getId()}" namespace="{$namespace}" index="{$rawObject->getIndex()}"
+      mgformtype="{$rawObject->getFormType()}"
+{foreach $htmlAttributes as $aValue} {$aValue@key}="{$aValue}" {/foreach}>
+{if $rawObject->getClasses()}
+<div class="{$rawObject->getClasses()}">
+    {/if}
+    {foreach from=$rawObject->getSortedFields() item=field }
+        {$field->getHtml()}
+    {/foreach}
+    {if $rawObject->getClasses()}
+</div>
+{/if}
+</form>

+ 80 - 0
app/UI/Admin/Templates/custom/modals/modalExtendedTabsEdit.tpl

@@ -0,0 +1,80 @@
+
+<div class="lu-modal show lu-modal--{$rawObject->getModalSize()}" id="confirmationModal" namespace="{$rawObject->getNamespace()}" index="{$rawObject->getId()}">
+    <div class="lu-modal__dialog">
+        <div class="lu-modal__content" id="mgModalContainer">
+            <div class="lu-modal__top lu-top">
+                <div class="lu-top__title lu-type-6">
+                    <span class="lu-text-faded lu-font-weight-normal">
+                        {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T('modal', $rawObject->getTitle())}{/if}
+                    </span>
+                </div>
+                <div class="lu-top__toolbar">
+                    <button class="lu-btn lu-btn--xs lu-btn--default lu-btn--icon lu-btn--link lu-btn--plain closeModal" data-dismiss="lu-modal" aria-label="Close" @click='closeModal($event)'>
+                        <i class="lu-btn__icon lu-zmdi lu-zmdi-close"></i>
+                    </button>
+                </div>
+            </div>
+            {assign var="editForms" value=$rawObject->getForms()}
+            {assign var="editForm" value=$editForms|array_pop}
+            <div class="lu-modal__nav">
+                <ul class="lu-nav lu-nav--md lu-nav--h lu-nav--tabs">
+                    {assign var="sectArrKeys" value=$editForm->getSections()|array_keys}
+                    {foreach from=$editForm->getSections() key=sectionID  item=section }
+                        <li class="lu-nav__item {if $sectArrKeys[0] == $sectionID}is-active{/if}">
+                            <a class="lu-nav__link" data-toggle="lu-tab" href="#modalTab{$sectionID}">
+                                <span class="lu-nav__link-text">{$MGLANG->T($section->getName())}</span>
+                            </a>
+                        </li>
+                    {/foreach}
+                </ul>
+            </div>
+            <div class="lu-modal__body">
+                {if $editForm->haveInternalAlertMessage()}
+                    <div class="lu-alert {if $editForm->getInternalAlertSize() !== ''}lu-alert--{$editForm->getInternalAlertSize()}{/if} lu-alert--{$editForm->getInternalAlertMessageType()} lu-alert--faded modal-alert-top">
+                        <div class="lu-alert__body">
+                            {if $editForm->isInternalAlertMessageRaw()|unescape:'html'}{$editForm->getInternalAlertMessage()}{else}{$MGLANG->T($editForm->getInternalAlertMessage())|unescape:'html'}{/if}
+                        </div>
+                    </div>
+                {/if}
+                {if $editForm->getConfirmMessage()}
+                    {if $editForm->isTranslateConfirmMessage()}
+                        {$MGLANG->T($editForm->getConfirmMessage())|unescape:'html'}
+                    {else}
+                        {$editForm->getConfirmMessage()|unescape:'html'}
+                    {/if}
+                {/if}
+                <form id="{$editForm->getId()}" namespace="{$editForm->getNamespace()}" index="{$editForm->getId()}" mgformtype="{$editForm->getFormType()}">
+                    {foreach from=$editForm->getFields() item=field }
+                        {$field->getHtml()}
+                    {/foreach}
+                    <div class="lu-tab-content">
+                        {assign var="sectArrKeys" value=$editForm->getSections()|array_keys}
+                        {foreach from=$editForm->getSections() key=sectionID  item=section }
+                            <div class="lu-tab-pane {if $sectArrKeys[0] == $sectionID}is-active{/if}" id="modalTab{$sectionID}">
+                                <div class="lu-list-group lu-list-group--simple lu-list-group--p-h-0x list-group--collapse lu-m-b-0x">
+                                    <div class="lu-row">
+                                        {$section->getHtml()}
+                                    </div>
+                                </div>
+                            </div>
+                        {/foreach}
+                    </div>
+                </form>
+            </div>
+            <div class="lu-modal__actions">
+                {foreach from=$rawObject->getActionButtons() item=actionButton}
+                    {$actionButton->getHtml()}
+                {/foreach}
+            </div>
+            {if ($isDebug eq true AND (count($MGLANG->getMissingLangs()) != 0))}{literal}
+                <div class="lu-modal__actions">
+                <div class="lu-row">
+            {/literal}{foreach from=$MGLANG->getMissingLangs() key=varible item=value}{literal}
+                <div class="lu-col-md-12"><b>{/literal}{$varible}{literal}</b> = '{/literal}{$value}{literal}';</div>
+            {/literal}{/foreach}{literal}
+                </div>
+                </div>
+            {/literal}{/if}
+        </div>
+    </div>
+</div>

+ 21 - 0
app/UI/Admin/Templates/custom/pages/description.tpl

@@ -0,0 +1,21 @@
+{assign var="assetsUrl" value=$rawObject->getAssetsUrl()}
+<div class="lu-top lu-m-b-4x">
+    <div class="lu-top__addon">
+        <div class="lu-i-c lu-i-c-8x">
+            <img src="{$rawObject->getIcon()}">
+        </div>
+    </div>
+    <div class="lu-top__content">
+        <div class="lu-top__title">
+            <div class="lu-top__title-text lu-type-4 lu-m-b-2x">{$MGLANG->T($rawObject->getTitle())}</div>
+        </div>
+        <div class="lu-p-3">{$MGLANG->T($rawObject->getDescription())}</div>
+    </div>
+</div>
+{if $rawObject->haveInternalAlertMessage()}
+    <div class="lu-alert {if $rawObject->getInternalAllertSize() !== ''}alert--{$rawObject->getInternalAllertSize()}{/if} alert-{$rawObject->getInternalAllertMessageType()} alert--faded datatable-alert-top">
+        <div class="lu-alert__body">
+            {if $rawObject->isInternalAllertMessageRaw()|unescape:'html'}{$rawObject->getInternalAllertMessage()}{else}{$MGLANG->T($rawObject->getInternalAllertMessage())|unescape:'html'}{/if}
+        </div>
+    </div>
+{/if}

+ 33 - 0
app/UI/Admin/Templates/custom/sections/boxSectionExtended.tpl

@@ -0,0 +1,33 @@
+<div class="lu-widget" id="{$rawObject->getId()}">
+    {if ($rawObject->getRawTitle() || $rawObject->getTitle()) && $rawObject->isViewHeader()}
+        <div class="lu-widget__header">
+            <div class="lu-widget__top lu-top">
+                <div class="lu-top__title">
+                    {if $rawObject->getIcon()}<i class="{$rawObject->getIcon()}"></i>{/if}
+                    {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T($rawObject->getTitle())}{/if}
+                </div>
+            </div>
+        </div>
+    {/if}
+    <div class="lu-widget__body">
+        <div class="lu-widget__content">
+            {if $rawObject->getElementById('sectionDescription')}
+                {$rawObject->insertElementById('sectionDescription')}
+            {/if}
+            <div class="lu-row">
+                {if $rawObject->getFields()}
+                    <div class="lu-col-md-6 lu-p-r-4x">
+                        {foreach from=$rawObject->getFields() item=field }
+                            {$field->getHtml()}
+                        {/foreach}
+                    </div>
+                {/if}
+                {if $rawObject->getSections()}
+                    {foreach from=$rawObject->getSections() item=section }
+                        {$section->getHtml()}
+                    {/foreach}
+                {/if}
+            </div>
+        </div>
+    </div>
+</div>

+ 11 - 0
app/UI/Admin/Templates/custom/sections/freeFieldsSection.tpl

@@ -0,0 +1,11 @@
+<div class="lu-col-md-12">
+
+    {foreach from=$rawObject->getSections() item=section }
+        {$section->getHtml()}
+    {/foreach}
+
+    {foreach from=$rawObject->getFields() item=field }
+        {$field->getHtml()}
+    {/foreach}
+
+</div>

+ 8 - 0
app/UI/Admin/Templates/custom/sections/rowSection.tpl

@@ -0,0 +1,8 @@
+<div class='lu-row'>
+    {foreach from=$rawObject->getSections() item=section }
+        {$section->getHtml()}
+    {/foreach}
+    {foreach from=$rawObject->getFields() item=field }
+        {$field->getHtml()}
+    {/foreach}
+</div>

+ 17 - 0
app/UI/Admin/Templates/home/pages/homePage.tpl

@@ -0,0 +1,17 @@
+<div class="lu-widget">
+    <div class="lu-widget__header">  
+        <div class="lu-widget__top lu-top"> 
+            <div class="lu-top__title"> 
+                Base Info
+            </div>
+        </div>
+    </div>
+    <div class="lu-widget__body">
+        <div style="padding: 20px;">
+            <p>1. <a href="http://git.mglocal/modulesgardenlive/mgmoduleframework/wikis/home">Wiki Frameworka</a> <span data-toggle="lu-tooltip" class="label lu-tooltip drop-target drop-element-attached-bottom drop-element-attached-center drop-target-attached-top drop-target-attached-center" style="margin-left: 15px; background-color: rgb(224, 255, 205); color: rgb(255, 0, 73);" data-title="">In Progress</span></p>
+            <p>2. <a href="http://zavoloklom.github.io/material-design-iconic-font/icons.html">Lista Ikonek</a></p>
+            <p>3. <a href="http://dev.rsstudio.net/mg/statistics.html">Projekt Nowego Wyglądu</a></p>
+            <p>4. <a href="http://dev.rsstudio.net/mg/docs/getting-started/introduction.html">Docs Do CSS</a> <span data-toggle="lu-tooltip" class="label lu-tooltip drop-target drop-element-attached-bottom drop-element-attached-center drop-target-attached-top drop-target-attached-center" style="margin-left: 15px; background-color: rgb(224, 255, 205); color: rgb(255, 0, 73);" data-title="">In Progress</span></p>
+        </div>
+    </div>
+</div>

+ 32 - 0
app/UI/Admin/Templates/loggerManager/buttons/deleteAllLoggersButton.tpl

@@ -0,0 +1,32 @@
+{**********************************************************************
+* KerioEmail product developed. (2017-09-08)
+* *
+*
+*  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+*  CONTACT                        ->       contact@modulesgarden.com
+*
+*
+* This software is furnished under a license and may be used and copied
+* only  in  accordance  with  the  terms  of such  license and with the
+* inclusion of the above copyright notice.  This software  or any other
+* copies thereof may not be provided or otherwise made available to any
+* other person.  No title to and  ownership of the  software is  hereby
+* transferred.
+*
+*
+**********************************************************************}
+
+{**
+* @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+*}
+
+<a {foreach $htmlAttributes as $aValue} {$aValue@key}="{$aValue}" {/foreach} class="{$rawObject->getClasses()}">
+    {if $rawObject->getIcon()}
+        <span class="btn__icon btn__icon--left">
+            <i class="{$rawObject->getIcon()}"></i>
+        </span>
+    {/if}
+    <span class="btn__text">
+        {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->controlerContextT('button', $rawObject->getTitle())}{/if}
+    </span>
+</a>

+ 48 - 0
app/UI/Admin/Templates/productConfiguration/pages/sections/configurableOptions.tpl

@@ -0,0 +1,48 @@
+<div class="lu-widget widgetActionComponent{$class}" id="{$elementId}" {foreach from=$htmlAttributes key=name item=data} {$name}="{$data}"{/foreach}>
+<div class="lu-widget__header">
+    <div class="lu-widget__top lu-top">
+        <div class="lu-top__title">
+            {if $rawObject->getIcon()}<i class="{$rawObject->getIcon()}"></i>{/if}
+            {if $rawObject->isRawTitle()}{$rawObject->getRawTitle()}{elseif $rawObject->getTitle()}{$MGLANG->T($rawObject->getTitle())}{/if}
+        </div>
+    </div>
+    <div class="lu-top__toolbar">
+
+    </div>
+</div>
+
+<div class="lu-widget__body">
+    <div class="lu-widget__content configOptionBox">
+        {if $rawObject->getOptions()}
+            <div class="lu-row">
+                {foreach from=$rawObject->getOptions() key=oKey item=oName}
+                    {if !empty($oName) && $oName !== '-1'}
+                    <div class="lu-col-md-4 lu-p-r-4x configOption text-left">
+                            <b> {$oKey}|{$oName}</b>
+                    </div>
+                    {elseif $oName == '-1'}
+                        <div class="lu-col-md-4 lu-p-r-4x configOption text-left">
+
+                        </div>
+                    {/if}
+                {/foreach}
+            </div>
+        {/if}
+        {foreach from=$rawObject->getButtons() key=setting item=dataElement}
+            <div class="lu-col-md-12 lu-p-r-4x center text-center configOptionButton">
+                {$dataElement->getHtml()}
+            </div>
+        {/foreach}
+    </div>
+</div>
+</div>
+
+{if ($isDebug && (count($MGLANG->getMissingLangs()) > 0))}
+    <div class="lu-modal__actions">
+        <div class="lu-row">
+            {foreach from=$MGLANG->getMissingLangs() key=varible item=value}
+                <div class="lu-col-md-12"><b>{$varible}</b> = '{$value}';</div>
+            {/foreach}
+        </div>
+    </div>
+{/if}

+ 27 - 0
app/UI/Client/DistributionList/Buttons/AddListButton.php

@@ -0,0 +1,27 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals\AddListModal;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\AddAccountModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:32
+ * Class AddListButton
+ */
+class AddListButton extends ButtonCreate implements ClientArea
+{
+    protected $id    = 'addListButton';
+    protected $title = 'addListButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new AddListModal());
+    }
+
+
+}

+ 27 - 0
app/UI/Client/DistributionList/Buttons/DeleteListButton.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Class DeleteListButton
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 11:16
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals\DeleteListModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class DeleteListButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'deleteListButton';
+    protected $title = 'deleteListButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteListModal());
+    }
+}

+ 26 - 0
app/UI/Client/DistributionList/Buttons/EditListButton.php

@@ -0,0 +1,26 @@
+<?php
+/**
+ * Class EditListButton
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 11:16
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals\EditListModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+class EditListButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'editListButton';
+    protected $title = 'editListButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new EditListModal());
+    }
+}

+ 28 - 0
app/UI/Client/DistributionList/Buttons/MassDeleteListButton.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Class MassDeleteListButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:23
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals\MassDeleteListModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class MassDeleteListButton extends ButtonMassAction implements ClientArea
+{
+
+    protected $id    = 'massDeleteListButton';
+    protected $title = 'massDeleteListButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new MassDeleteListModal());
+    }
+}

+ 49 - 0
app/UI/Client/DistributionList/Forms/AddListForm.php

@@ -0,0 +1,49 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\AddListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddAliasesDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddMembersDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddOwnersDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddPreferencesDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddPropertiesDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\AccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:32
+ * Class AddListForm
+ */
+class AddListForm extends SortedFieldForm implements ClientArea
+{
+    protected $id    = 'addListForm';
+    protected $name  = 'addListForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::CREATE);
+        $this->setProvider(new AddListDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    protected function initFields()
+    {
+        $this->addSection(new AddMembersDistribution());
+        $this->addSection(new AddPropertiesDistribution());
+        $this->addSection(new AddAliasesDistribution());
+        $this->addSection(new AddOwnersDistribution());
+        $this->addSection(new AddPreferencesDistribution());
+
+    }
+
+    public function reloadFormStructure()
+    {
+        $this->loadDataToForm();
+    }
+}

+ 42 - 0
app/UI/Client/DistributionList/Forms/DeleteListForm.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class DeleteListForm
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 11:25
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\DeleteAccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class DeleteListForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'deleteAccountForm';
+    protected $name  = 'deleteAccountForm';
+    protected $title = 'deleteAccountForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::DELETE);
+        $this->dataProvider = new DeleteListDataProvider();
+
+        $this->setConfirmMessage('confirmRemoveList');
+
+        $field = new Hidden();
+        $field->setId('id');
+        $field->setName('id');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+
+}

+ 54 - 0
app/UI/Client/DistributionList/Forms/EditListForm.php

@@ -0,0 +1,54 @@
+<?php
+/**
+ * Class EditListForm
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 11:25
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\EditListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddAliasesDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddMembersDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddOwnersDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddPreferencesDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\AddPropertiesDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\EditMembersDistribution;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections\EditPropertiesDistribution;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class EditListForm extends SortedFieldForm implements ClientArea
+{
+    protected $id    = 'editListForm';
+    protected $name  = 'editListForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::UPDATE);
+        $this->setProvider(new EditListDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    protected function initFields()
+    {
+        $this->addSection(new EditMembersDistribution());
+        $this->addSection(new EditPropertiesDistribution());
+        $this->addSection(new AddAliasesDistribution());
+        $this->addSection(new AddOwnersDistribution());
+        $this->addSection(new AddPreferencesDistribution());
+
+    }
+
+    public function reloadFormStructure()
+    {
+
+        $this->loadDataToForm();
+    }
+
+}

+ 40 - 0
app/UI/Client/DistributionList/Forms/MassDeleteListForm.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * Class MassDeleteListForm
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:23
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class MassDeleteListForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'massDeleteListForm';
+    protected $name  = 'massDeleteListForm';
+    protected $title = 'massDeleteListForm';
+
+    protected function getDefaultActions()
+    {
+        return ['massDelete'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('massDelete');
+        $this->dataProvider = new DeleteListDataProvider();
+
+        $this->setConfirmMessage('MassDeleteListFormConfirm');
+
+        $this->loadDataToForm();
+    }
+
+}

+ 28 - 0
app/UI/Client/DistributionList/Modals/AddListModal.php

@@ -0,0 +1,28 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Modals\ModalExtendedTabsEdit;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms\AddListForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\AddAccountForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:32
+ * Class AddListModal
+ */
+class AddListModal extends ModalExtendedTabsEdit implements ClientArea
+{
+    protected $id    = 'addListModal';
+    protected $name  = 'addListModal';
+    protected $title = 'addListModal';
+
+    public function initContent()
+    {
+        $this->setModalSizeMedium();
+        $this->addForm(new AddListForm());
+    }
+}

+ 31 - 0
app/UI/Client/DistributionList/Modals/DeleteListModal.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class DeleteListModal
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 11:25
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms\DeleteListForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class DeleteListModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'deleteListModal';
+    protected $name  = 'deleteListModal';
+    protected $title = 'deleteListModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+        $this->addForm(new DeleteListForm());
+    }
+
+}

+ 28 - 0
app/UI/Client/DistributionList/Modals/EditListModal.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Class EditListModal
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 11:25
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Modals\ModalExtendedTabsEdit;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms\EditListForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+
+class EditListModal  extends ModalExtendedTabsEdit implements ClientArea
+{
+    protected $id    = 'editListModal';
+    protected $name  = 'editListModal';
+    protected $title = 'editListModal';
+
+    public function initContent()
+    {
+        $this->setModalSizeMedium();
+        $this->addForm(new EditListForm());
+    }
+}

+ 31 - 0
app/UI/Client/DistributionList/Modals/MassDeleteListModal.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class MassDeleteListModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:23
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Forms\MassDeleteListForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class MassDeleteListModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'massDeleteListModal';
+    protected $name  = 'massDeleteListModal';
+    protected $title = 'massDeleteListModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+        $this->addForm(new MassDeleteListForm());
+    }
+
+}

+ 116 - 0
app/UI/Client/DistributionList/Pages/Lists.php

@@ -0,0 +1,116 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Pages;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields\EnabledField;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons\AddListButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons\DeleteListButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons\EditListButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Buttons\MassDeleteListButton;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\DataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataTable;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:28
+ * Class Lists
+ */
+class Lists extends DataTable implements ClientArea
+{
+    protected $id    = 'lists';
+    protected $name  = 'lists';
+    protected $title = null;
+
+    protected function loadHtml()
+    {
+        $this
+            ->addColumn((new Column('email'))
+                ->setOrderable(DataProvider::SORT_ASC)
+                ->setSearchable(true, Column::TYPE_STRING))
+            ->addColumn((new Column('name'))
+                ->setOrderable()
+                ->setSearchable(true))
+            ->addColumn((new Column('status'))
+                ->setOrderable()
+                ->setSearchable(true));
+    }
+
+    /**
+     *
+     * return status as html element
+     * @param $key
+     * @param $row
+     * @return string
+     */
+    public function replaceFieldStatus($key, $row)
+    {
+        /**
+         * check status
+         */
+        $enabled =  $row[$key] === 'enabled' ? true : false;
+
+        /**
+         *
+         * create enabled element
+         */
+        $field = new EnabledField();
+        $field->setEnabled($enabled);
+        $field->setRawTitle(di('lang')->absoluteT('kerio','account','status',$row[$key]));
+
+        return $field->getHtml();
+    }
+
+    public function initContent()
+    {
+        $this->addMassActionButton(new MassDeleteListButton());
+        $this->addButton(new AddListButton());
+        $this->addActionButton(new EditListButton());
+        $this->addActionButton(new DeleteListButton());
+    }
+
+    public function loadData()
+    {
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+
+        /**
+         * load api
+         */
+        $api     = (new KerioManager())->getApiByServer($hosting->server);
+
+        $repository = new Repository($api->soap);
+        $lists = $repository->lists->getAllDistributionListsByDomain($hosting->domain);
+
+        $data = [];
+        foreach($lists as $list)
+        {
+            /* @var $list  DistributionList */
+
+            $tmp = [
+                'id' => $list->getId(),
+                'email' => $list->getName(),
+                'name' => $list->getDataResourceA(DistributionList::ATTR_DISPLAY_NAME),
+                'status' => $list->getDataResourceA(DistributionList::ATTR_MAIL_STATUS)
+            ];
+
+            $data[] = $tmp;
+        }
+
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting('id', 'ASC')->setData($data);
+
+        $this->setDataProvider($dataProv);
+    }
+
+}

+ 182 - 0
app/UI/Client/DistributionList/Providers/AddListDataProvider.php

@@ -0,0 +1,182 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\ServiceFactory;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDistributionList;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:32
+ * Class AddListDataProvider
+ */
+class AddListDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+        $this->data['domain'] = $hosting->domain;
+
+        /**
+         * load api
+         */
+        $accounts     = (new KerioManager())
+            ->getApiByServer($hosting->server)
+            ->soap
+            ->repository()
+            ->accounts
+            ->getByDomainName($hosting->domain);
+
+
+        /**
+         *
+         * load lang
+         */
+        $lang = di('lang');
+
+        /**
+         * subscription requests
+         */
+        $this->availableValues['subscriptionRequest'] = [
+            Kerio::STATUS_ACCEPT   => $lang->absoluteT('Automatically accept'),
+            Kerio::STATUS_APPROVAL => $lang->absoluteT('Require list owner approval'),
+            Kerio::STATUS_REJECT   => $lang->absoluteT('Automatically reject')
+        ];
+
+        /**
+         * unsubscription requests
+         */
+        $this->availableValues['unsubscriptionRequest'] = [
+            Kerio::STATUS_ACCEPT   => $lang->absoluteT('Automatically accept'),
+            Kerio::STATUS_APPROVAL => $lang->absoluteT('Require list owner approval'),
+            Kerio::STATUS_REJECT   => $lang->absoluteT('Automatically reject')
+        ];
+
+
+
+        /**
+         *
+         */
+        foreach($accounts as $account)
+        {
+            $this->availableValues['memberList'][$account->getName()] = $account->getName();
+        }
+
+        if($this->formData)
+        {
+            $this->loadReloadedData();
+        }
+
+    }
+
+    /**
+     *
+     */
+    public function loadReloadedData()
+    {
+        foreach($this->formData as $key => $value)
+        {
+            $this->data[$key] = $value;
+        }
+
+    }
+
+    public function create()
+    {
+        /**
+         *
+         * provided aliases
+         */
+        $customEmails = explode(',',$this->formData['emailAliases']);
+        $this->formData['emailAliases'] = [];
+        foreach($customEmails as $email)
+        {
+            if ($email !== '')
+            {
+                $this->formData['emailAliases'][] = $email;
+            }
+        }
+
+        /**
+         * provided owners
+         */
+        $owners = explode(',',$this->formData['owners']);
+        $this->formData['owners'] = [];
+        foreach($owners as $email)
+        {
+            if ($email !== '')
+            {
+                $this->formData['owners'][] = $email;
+            }
+        }
+
+        /**
+         * custom members
+         */
+        $customMembers = explode(',',$this->formData['customMember']);
+
+        foreach($customMembers as $customMember)
+        {
+            if($customMember !== '' && !in_array($customMember, $this->formData['memberList']))
+            {
+                $this->formData['memberList'][]  = $customMember;
+            }
+        }
+
+        /**
+         *  display name
+         */
+        $this->formData['displayName'] = htmlentities($this->formData['displayName']);
+
+        /**
+         *  reply display name
+         */
+        $this->formData['replyDisplayName'] = htmlentities($this->formData['replyDisplayName']);
+
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * load kerio manager by hosting id
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->createDistributionList()
+            ->setFormData($this->formData)
+        ;
+
+        /**
+         * load product configuration
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+        $service->setProductManager($productManager);
+        $result= $service->run();
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('distributionListHasBeenAdded')->setStatusSuccess();
+
+    }
+
+    public function update()
+    {
+        // TODO: Implement update() method.
+    }
+}

+ 103 - 0
app/UI/Client/DistributionList/Providers/DeleteListDataProvider.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteDistributionList;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 08:21
+ * Class DeleteListDataProvider
+ */
+class DeleteListDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        $this->data['id'] = $this->actionElementId;
+    }
+
+    public function update()
+    {
+        // TODO: Implement update() method.
+    }
+
+    public function delete()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * load kerio manager by hosting id
+         * get SOAP api
+         * get service
+         * set form data to service
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteDistributionList()
+            ->setFormData($this->formData)
+        ;
+
+        /**
+         *
+         * run service
+         */
+        $result= $service->run();
+
+        /**
+         * return error is has been detected
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('distributionListHasBeenDeleted')->setStatusSuccess();
+    }
+
+    public function massDelete()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * load kerio manager by hosting id
+         * get SOAP api
+         * get service
+         * set form data to service
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteDistributionList();
+
+        /**
+         *
+         */
+        foreach($this->request->get('massActions') as $id)
+        {
+            $service->setFormData(['id' => $id]);
+            $result = $service->run();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('massDistributionListHasBeenDeleted')->setStatusSuccess();
+    }
+
+}

+ 230 - 0
app/UI/Client/DistributionList/Providers/EditListDataProvider.php

@@ -0,0 +1,230 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\DistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateDistributionList;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 08:36
+ * Class EditListDataProvider
+ */
+class EditListDataProvider extends AddListDataProvider
+{
+
+    public function read()
+    {
+
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+
+        /**
+         * load api
+         */
+        $api = (new KerioManager())->getApiByServer($hosting->server);
+
+        $repository = new Repository($api->soap);
+
+        $list             = $repository->lists()->getDistributionListBydId($this->actionElementId);
+        $this->data['id'] = $list->getId();
+
+        $res                    = explode('@', $list->getName());
+        $this->data['listmail'] = $res[0];
+        $this->data['domain']   = $res[1];
+
+        $this->data['emailAliases']  = implode(',', $list->getResourceAliases());
+        $this->data['owners']        = implode(',', $list->getResourceOwners());
+
+        /**
+         * allow to check which should be removed
+         */
+        $this->availableValues['memberListActually']   = $this->data['memberListActually']      = $list->getResourceMembers();
+        $this->availableValues['emailAliasesActually'] = $this->data['emailAliasesActually']    = $list->getResourceAliases();
+        $this->availableValues['ownersActually']       = $this->data['ownersActually']          = $list->getResourceOwners();
+
+        $this->data['displayName']           = $list->getDataResourceA(DistributionList::ATTR_DISPLAY_NAME);
+        $this->data['description']           = $list->getDataResourceA(DistributionList::ATTR_DESCRIPTION);
+        $this->data['subscriptionRequest']   = $list->getDataResourceA(DistributionList::ATTR_SUBSCRIPTION_REQUEST);
+        $this->data['unsubscriptionRequest'] = $list->getDataResourceA(DistributionList::ATTR_UNSUBSCRIPTION_REQUEST);
+        $this->data['replyDisplayName']      = $list->getDataResourceA(DistributionList::REPLY_TO_DISPLAY);
+        $this->data['replyEmailAddress']     = $list->getDataResourceA(DistributionList::REPLY_TO_ADDRESS);
+        $this->data['sharesNotify']          = $list->getDataResourceA(DistributionList::ATTR_NOTIFY_SHARES) === Kerio::ATTR_ENABLED ? ProductParams::SWITCHER_ENABLED : ProductParams::SWITCHER_DISABLED;
+        $this->data['hideGal']               = $list->getDataResourceA(DistributionList::ATTR_HIDE_IN_GAL) === Kerio::ATTR_ENABLED ? ProductParams::SWITCHER_ENABLED : ProductParams::SWITCHER_DISABLED;
+        $this->data['receiveMail']           = $list->getDataResourceA(DistributionList::ATTR_MAIL_STATUS) === Kerio::ENABLED ? ProductParams::SWITCHER_ENABLED : ProductParams::SWITCHER_DISABLED;
+        $this->data['replyEmail']            = $list->getDataResourceA(DistributionList::REPLY_TO_ENABLED) === Kerio::ATTR_ENABLED ? ProductParams::SWITCHER_ENABLED : ProductParams::SWITCHER_DISABLED;
+        /**
+         * is dynamic group
+         */
+        $this->data['dynamicGroup']          = (int)$list->isDynamic() === Kerio::ENABLED_AS_INT ? ProductParams::SWITCHER_ENABLED : ProductParams::SWITCHER_DISABLED;
+
+
+        /**
+         * available members
+         */
+        $accounts = $repository->accounts->getByDomainName($hosting->domain);
+
+        /**
+         * load lang
+         */
+        $lang = di('lang');
+
+        /**
+         * subscription requests
+         */
+        $this->availableValues['subscriptionRequest'] = [
+            Kerio::STATUS_ACCEPT   => $lang->absoluteT('Automatically accept'),
+            Kerio::STATUS_APPROVAL => $lang->absoluteT('Require list owner approval'),
+            Kerio::STATUS_REJECT   => $lang->absoluteT('Automatically reject')
+        ];
+
+        /**
+         * unsubscription requests
+         */
+        $this->availableValues['unsubscriptionRequest'] = [
+            Kerio::STATUS_ACCEPT   => $lang->absoluteT('Automatically accept'),
+            Kerio::STATUS_APPROVAL => $lang->absoluteT('Require list owner approval'),
+            Kerio::STATUS_REJECT   => $lang->absoluteT('Automatically reject')
+        ];
+
+        $members = $list->getResourceMembers();
+
+        /**
+         *
+         */
+        foreach ($accounts as $account)
+        {
+            if(in_array($account->getName(),$members))
+            {
+                $this->data['memberList'][] = $account->getName();
+            }
+
+            $this->availableValues['memberList'][$account->getName()] = $account->getName();
+        }
+
+        /**
+         * add custom members to array
+         */
+        $ownMembers = $this->data['memberList'] ? $this->data['memberList'] : [];
+        $this->data['customMember'] = implode(',',array_diff($members, $ownMembers));
+
+        if($this->formData)
+        {
+            $this->loadReloadedData();
+        }
+
+    }
+
+    /**
+     *
+     */
+    public function update()
+    {
+
+        /**
+         *
+         * provided aliases
+         */
+        $customEmails = explode(',',$this->formData['emailAliases']);
+        $this->formData['emailAliases'] = [];
+        foreach($customEmails as $email)
+        {
+            if ($email !== '')
+            {
+                $this->formData['emailAliases'][] = $email;
+            }
+        }
+
+        /**
+         * provided owners
+         */
+        $owners = explode(',',$this->formData['owners']);
+        $this->formData['owners'] = [];
+        foreach($owners as $email)
+        {
+            if ($email !== '')
+            {
+                $this->formData['owners'][] = $email;
+            }
+        }
+
+        /**
+         *  display name
+         */
+        $this->formData['displayName'] = htmlentities($this->formData['displayName']);
+
+        /**
+         *  reply display name
+         */
+        $this->formData['replyDisplayName'] = htmlentities($this->formData['replyDisplayName']);
+
+        /**
+         * custom members
+         */
+        $customMembers = explode(',',$this->formData['customMember']);
+
+        foreach($customMembers as $customMember)
+        {
+            if($customMember !== '' && !in_array($customMember, $this->formData['memberList']))
+            {
+                $this->formData['memberList'][]  = $customMember;
+            }
+        }
+        $members = $this->formData['memberList'] ? $this->formData['memberList']  : [];
+
+        $this->formData['memberList'] = array_merge($customMembers, $members);
+
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * get product manager
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         * load kerio manager by hosting id
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateDistributionList()
+            ->setFormData($this->formData)
+            ->setProductManager($productManager)
+
+        ;
+
+        /**
+         *
+         */
+        $result = $service->run();
+
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('distributionListHasBeenUpdated')->setStatusSuccess();
+
+    }
+}

+ 30 - 0
app/UI/Client/DistributionList/Sections/AddAliasesDistribution.php

@@ -0,0 +1,30 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\EmailValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\TaggerEmailValidator;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Tagger;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+/**
+ * Class AddAliasesDistribution
+ * User: Nessandro
+ * Date: 2019-09-20
+ * Time: 12:43
+ */
+
+class AddAliasesDistribution extends FreeFieldsSection
+{
+    protected $id   = 'addAliasesDistribution';
+    protected $name = 'addAliasesDistribution';
+
+    public function initContent()
+    {
+        $this->addField(
+            (new Tagger('emailAliases'))
+            ->setPlaceholder(di('lang')->absoluteT('mail@example.com'))
+            ->addValidator(new TaggerEmailValidator())
+        );
+    }
+}

+ 49 - 0
app/UI/Client/DistributionList/Sections/AddMembersDistribution.php

@@ -0,0 +1,49 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\EmailValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\TaggerEmailValidator;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Tagger;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements\Text as InputText;
+
+/**
+ * Class Members
+ * User: Nessandro
+ * Date: 2019-09-20
+ * Time: 12:42
+ */
+
+class AddMembersDistribution extends FreeFieldsSection
+{
+    protected $id   = 'addMembersDistribution';
+    protected $name = 'addMembersDistribution';
+
+    public function initContent()
+    {
+
+        $email = new InputGroup('usernameGroup');
+        $email->addTextField('listmail', false, true);
+        $email->addInputAddon('emailSign', false, '@');
+        $email->addInputComponent((new InputText('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $this->addField((new Text('displayName')));
+
+        $this->addField(new Textarea('description'));
+
+        $this->addField((new Select('memberList'))->enableMultiple());
+
+        $this->addField((new Tagger('customMember'))
+            ->setPlaceholder(di('lang')->absoluteT('mail@example.com'))
+            ->addValidator(new TaggerEmailValidator())
+        );
+
+
+    }
+}

+ 32 - 0
app/UI/Client/DistributionList/Sections/AddOwnersDistribution.php

@@ -0,0 +1,32 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\EmailValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\TaggerEmailValidator;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Tagger;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+
+/**
+ * Class AddOwnersDistribuition
+ * User: Nessandro
+ * Date: 2019-09-20
+ * Time: 12:43
+ */
+
+class AddOwnersDistribution extends FreeFieldsSection
+{
+    protected $id   = 'addOwnersDistribution';
+    protected $name = 'addOwnersDistribution';
+
+    public function initContent()
+    {
+        $this->addField(
+            (new Tagger('owners'))
+                ->setPlaceholder(di('lang')->absoluteT('mail@example.com'))
+                ->addValidator(new TaggerEmailValidator())
+        );
+
+    }
+}

+ 39 - 0
app/UI/Client/DistributionList/Sections/AddPreferencesDistribution.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * Class AddPreferencesDistribution
+ * User: Nessandro
+ * Date: 2019-09-20
+ * Time: 12:44
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+
+class AddPreferencesDistribution extends FreeFieldsSection
+{
+    protected $id   = 'addPreferencesDistribution';
+    protected $name = 'addPreferencesDistribution';
+
+    public function initContent()
+    {
+        /**
+         *
+         */
+        $this->addField(new Switcher('replyEmail'));
+
+        $this->addField(new Text('replyDisplayName'));
+
+        $this->addField(
+            (new Text('replyEmailAddress'))
+                ->setPlaceholder(di('lang')->absoluteT('mail@example.com'))
+            );
+
+    }
+}

+ 36 - 0
app/UI/Client/DistributionList/Sections/AddPropertiesDistribution.php

@@ -0,0 +1,36 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+
+/**
+ * Class AddPropertiesDistribution
+ * User: Nessandro
+ * Date: 2019-09-20
+ * Time: 12:42
+ */
+
+class AddPropertiesDistribution extends FreeFieldsSection
+{
+    protected $id   = 'addPropertiesDistribution';
+    protected $name = 'addPropertiesDistribution';
+
+    public function initContent()
+    {
+
+        $this->addField((new Switcher('receiveMail'))->setDefaultValue('on'));
+
+        $this->addField(new Switcher('hideGal'));
+
+        $this->addField((new Switcher('dynamicGroup'))
+            ->addHtmlAttribute('@change', "initReloadModal()"));
+
+        $this->addField(new Select('subscriptionRequest'));
+
+        $this->addField(new Select('unsubscriptionRequest'));
+
+        $this->addField(new Switcher('sharesNotify'));
+    }
+
+}

+ 72 - 0
app/UI/Client/DistributionList/Sections/EditMembersDistribution.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields\ExtendedSelect;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\EmailValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\TaggerEmailValidator;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements\Text as InputText;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Tagger;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Textarea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 09:38
+ * Class EditMembersDistribution
+ */
+class EditMembersDistribution extends FreeFieldsSection
+{
+    protected $id   = 'editMembersDistribution';
+    protected $name = 'editMembersDistribution';
+
+    public function initContent()
+    {
+        $email = new InputGroup('usernameGroup');
+
+        //$email->addTextField('listmail', false, true);
+        $email->addInputComponent((new InputText('listmail'))->addHtmlAttribute('readonly','true'));
+        $email->addInputAddon('emailSign', false, '@');
+        $email->addInputComponent((new InputText('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $this->addField((new Text('displayName')));
+
+        $this->addField(new Textarea('description'));
+
+        $this->addField((new Select('memberList'))->enableMultiple());
+
+        $this->addField((new Tagger('customMember'))->setPlaceholder(di('lang')->absoluteT('mail@example.com'))->addValidator(new TaggerEmailValidator()));
+        ;
+
+        /**
+         * id for edit form
+         */
+        $this->addField((new Hidden('id')));
+
+        /**
+         * current email list for edit form
+         */
+        $this->addField((new ExtendedSelect('emailAliasesActually'))->enableMultiple()->enableHidden());
+
+        /**
+         * current member list for edit form
+         */
+        $this->addField((new ExtendedSelect('memberListActually'))->enableMultiple()->enableHidden());
+
+        /**
+         * current owners list for edit form
+         */
+        $this->addField((new ExtendedSelect('ownersActually'))->enableMultiple()->enableHidden());
+
+    }
+}

+ 39 - 0
app/UI/Client/DistributionList/Sections/EditPropertiesDistribution.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 13.11.19
+ * Time: 14:17
+ * Class EditPropertiesDistribution
+ */
+class EditPropertiesDistribution extends FreeFieldsSection
+{
+    protected $id   = 'addPropertiesDistribution';
+    protected $name = 'addPropertiesDistribution';
+
+    public function initContent()
+    {
+
+        $this->addField(new Switcher('receiveMail'));
+
+        $this->addField(new Switcher('hideGal'));
+
+//        $this->addField((new Switcher('dynamicGroup'))
+//            ->addHtmlAttribute('@change', "initReloadModal()"));
+
+        $this->addField(new Select('subscriptionRequest'));
+
+        $this->addField(new Select('unsubscriptionRequest'));
+
+        $this->addField(new Switcher('sharesNotify'));
+    }
+}

+ 26 - 0
app/UI/Client/DomainAlias/Buttons/AddDomainAliasButton.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Modals\AddDomainAliasModals;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:38
+ * Class AddDomainAliasButton
+ */
+class AddDomainAliasButton extends ButtonCreate implements ClientArea
+{
+    protected $id    = 'addDomainAliasButton';
+    protected $title = 'addDomainAliasButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new AddDomainAliasModals());
+    }
+
+
+}

+ 28 - 0
app/UI/Client/DomainAlias/Buttons/DeleteDomainAliasButton.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Modals\DeleteDomainAliasModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 14:24
+ * Class DeleteDomainAliasButton
+ */
+class DeleteDomainAliasButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'deleteDomainAliasButton';
+    protected $title = 'deleteDomainAliasButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteDomainAliasModal());
+    }
+}

+ 29 - 0
app/UI/Client/DomainAlias/Buttons/MassDeleteDomainAliasButton.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Class MassDeleteDomainAlias
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:24
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Modals\MassDeleteDomainAliasModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class MassDeleteDomainAliasButton extends ButtonMassAction implements ClientArea
+{
+
+    protected $id    = 'massDeleteDomainAliasButton';
+    protected $title = 'massDeleteDomainAliasButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new MassDeleteDomainAliasModal());
+    }
+
+}

+ 50 - 0
app/UI/Client/DomainAlias/Forms/AddDomainAliasForm.php

@@ -0,0 +1,50 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Forms;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Providers\AddDomainAliasDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Providers\AddListDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements\Text as InputText;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:38
+ * Class AddDomainAliasForm
+ */
+class AddDomainAliasForm extends SortedFieldForm implements ClientArea
+{
+    protected $id    = 'addDomainAliasForm';
+    protected $name  = 'addDomainAliasForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::CREATE);
+        $this->setProvider(new AddDomainAliasDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    protected function initFields()
+    {
+        $email = new InputGroup('aliasGroup');
+        $email->addInputComponent((new InputText('alias')));
+        $email->addInputAddon('emailSign', false, '→');
+        $email->addInputComponent((new InputText('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $this->addField((new Text('description'))->setDescription('descriptionDomainList'));
+
+        /**
+         * hidden fields
+         */
+        $this->addField((new Hidden('domainId')));
+
+    }
+}

+ 42 - 0
app/UI/Client/DomainAlias/Forms/DeleteDomainAliasForm.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Providers\AddDomainAliasDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Providers\DeleteDomainAliasProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 14:32
+ * Class DeleteDomainAliasForm
+ */
+class DeleteDomainAliasForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'deleteDomainAliasForm';
+    protected $name  = 'deleteDomainAliasForm';
+    protected $title = 'deleteDomainAliasForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::DELETE);
+        $this->setProvider(new DeleteDomainAliasProvider());
+        $this->setConfirmMessage('confirmRemoveDomainAlias');
+
+        $field = new Hidden();
+        $field->setId('id');
+        $field->setName('id');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+
+    }
+
+}

+ 41 - 0
app/UI/Client/DomainAlias/Forms/MassDeleteDomainAliasForm.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * Class MassDeleteDomainForm
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:24
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Providers\DeleteDomainAliasProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class MassDeleteDomainAliasForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'massDeleteDomainAliasForm';
+    protected $name  = 'massDeleteDomainAliasForm';
+    protected $title = 'massDeleteDomainAliasForm';
+
+    protected function getDefaultActions()
+    {
+        return ['massDelete'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('massDelete');
+        $this->dataProvider = new DeleteDomainAliasProvider();
+
+        $this->setConfirmMessage('confirmMassDeleteDomainAlias');
+
+        $this->loadDataToForm();
+    }
+
+}

+ 25 - 0
app/UI/Client/DomainAlias/Modals/AddDomainAliasModals.php

@@ -0,0 +1,25 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Modals;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Forms\AddDomainAliasForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:39
+ * Class AddDomainAliasModals
+ */
+class AddDomainAliasModals extends BaseEditModal implements ClientArea
+{
+    protected $id    = 'addDomainAliasModals';
+    protected $name  = 'addDomainAliasModals';
+    protected $title = 'addDomainAliasModals';
+
+    public function initContent()
+    {
+        $this->addForm(new AddDomainAliasForm());
+    }
+}

+ 33 - 0
app/UI/Client/DomainAlias/Modals/DeleteDomainAliasModal.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Forms\DeleteDomainAliasForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 14:32
+ * Class DeleteDomainAliasModal
+ */
+class DeleteDomainAliasModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'deleteDomainAliasModal';
+    protected $name  = 'deleteDomainAliasModal';
+    protected $title = 'deleteDomainAliasModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+        $this->addForm(new DeleteDomainAliasForm());
+
+    }
+
+}

+ 31 - 0
app/UI/Client/DomainAlias/Modals/MassDeleteDomainAliasModal.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class MassDeleteDomainAliasModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:26
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Forms\MassDeleteDomainAliasForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class MassDeleteDomainAliasModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'massDeleteDomainAliasModal';
+    protected $name  = 'massDeleteDomainAliasModal';
+    protected $title = 'massDeleteDomainAliasModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+        $this->addForm(new MassDeleteDomainAliasForm());
+    }
+
+}

+ 99 - 0
app/UI/Client/DomainAlias/Pages/DomainAliases.php

@@ -0,0 +1,99 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Pages;
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Domain;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons\AddDomainAliasButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons\AddListButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons\DeleteDomainAliasButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Buttons\MassDeleteDomainAliasButton;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\DataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataTable;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:37
+ * Class DomainAliases
+ */
+class DomainAliases extends DataTable implements ClientArea
+{
+    protected $id    = 'lists';
+    protected $name  = 'lists';
+    protected $title = null;
+
+    protected function loadHtml()
+    {
+        $this
+            ->addColumn((new Column('name'))
+                ->setOrderable(DataProvider::SORT_ASC)
+                ->setSearchable(true, Column::TYPE_STRING))
+            ->addColumn((new Column('description'))
+                ->setOrderable()
+                ->setSearchable(true));
+    }
+
+    public function initContent()
+    {
+        $this->addMassActionButton(new MassDeleteDomainAliasButton());
+
+        $this->addButton(new AddDomainAliasButton());
+
+        $this->addActionButton(new DeleteDomainAliasButton());
+    }
+
+    public function loadData()
+    {
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+
+        /**
+         * load api client by server id
+         * get repo
+         * get aliases per domain
+         */
+        $aliases = (new KerioManager())
+            ->getApiByServer($hosting->server)
+            ->soap
+            ->repository()
+            ->domains
+            ->getAliases($hosting->domain);
+
+
+        /**
+         *
+         * prepare new array
+         */
+        $data = [];
+
+        /**
+         * parse aliases
+         */
+        foreach ($aliases as $domain)
+        {
+            /* @var $domain Domain */
+            $tmp = [
+                'id'    => $domain->getId(),
+                'name'  => $domain->getName(),
+                'description' => $domain->getAttr(Domain::ATTR_DESCRIPTION)
+            ];
+
+            $data[] = $tmp;
+        }
+
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting('name', 'ASC')->setData($data);
+
+        $this->setDataProvider($dataProv);
+
+    }
+}

+ 95 - 0
app/UI/Client/DomainAlias/Providers/AddDomainAliasDataProvider.php

@@ -0,0 +1,95 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Providers;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDistributionList;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Create\CreateDomainAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteDomainAlias;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 13:39
+ * Class AddDomainAliasDataProvider
+ */
+class AddDomainAliasDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+
+        /**
+         * get API
+         */
+        $api =(new KerioManager())
+            ->getApiByServer($hosting->server)
+            ->soap;
+
+        /**
+         * load domain from repo
+         */
+        $domain = $api->repository()
+            ->domains
+            ->getByName($hosting->domain);
+
+        $this->data['domainId'] = $domain->getId();
+        $this->data['domain']   = $hosting->domain;
+
+    }
+
+    public function update()
+    {
+
+    }
+
+    public function create()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * load product configuration
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         * load kerio manager by hosting id
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->createDomainAlias()
+            ->setProductManager($productManager)
+            ->setFormData($this->formData)
+        ;
+
+        /**
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('domainAliasHasBeenCreated')->setStatusSuccess();
+    }
+
+
+}

+ 119 - 0
app/UI/Client/DomainAlias/Providers/DeleteDomainAliasProvider.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\DomainAlias\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteDomainAlias;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 02.10.19
+ * Time: 14:41
+ * Class DeleteDomainAliasProvider
+ */
+class DeleteDomainAliasProvider extends BaseDataProvider
+{
+
+    /**
+     *
+     */
+    public function read()
+    {
+        $this->data['id'] = $this->actionElementId;
+    }
+
+    /**
+     *
+     */
+    public function update()
+    {
+        // TODO: Implement update() method.
+    }
+
+    /**
+     * @return HtmlDataJsonResponse|void
+     */
+    public function delete()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * load product configuration
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         * load kerio manager by hosting id
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteDomainAlias()
+            ->setFormData($this->formData)
+        ;
+
+        /**
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('domainAliasHasBeenDeleted')->setStatusSuccess();
+    }
+
+    public function massDelete()
+    {
+
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * load product configuration
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         * load kerio manager by hosting id
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteDomainAlias();
+
+        /**
+         *
+         */
+        foreach($this->request->get('massActions') as $id)
+        {
+            $service->setFormData(['id' => $id]);
+            $result = $service->run();
+        }
+
+        return (new HtmlDataJsonResponse())
+            ->setMessageAndTranslate('massDomainAliasHasBeenDeleted')
+            ->setStatusSuccess();
+    }
+}

+ 26 - 0
app/UI/Client/EmailAccount/Buttons/AddAccountButton.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\AddAccountModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class AddAccountButton
+ */
+class AddAccountButton extends ButtonCreate implements ClientArea
+{
+    protected $id    = 'addAccountButton';
+    protected $title = 'addAccountButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new AddAccountModal());
+    }
+
+
+}

+ 30 - 0
app/UI/Client/EmailAccount/Buttons/ChangePasswordButton.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\ChangePasswordModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:07
+ * Class ChangePassword
+ */
+class ChangePasswordButton extends ButtonDropdownItem implements ClientArea
+{
+    protected $id    = 'changePassword';
+    protected $title = 'changePassword';
+    protected $icon  = 'lu-dropdown__link-icon lu-btn__icon lu-zmdi lu-zmdi-lock';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new ChangePasswordModal());
+    }
+
+}

+ 31 - 0
app/UI/Client/EmailAccount/Buttons/ChangeStatusButton.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class ChangeStatusButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\AddAccountModal;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\ChangeStatusModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+class ChangeStatusButton extends ButtonDropdownItem implements ClientArea
+{
+    protected $id    = 'changeStatusButton';
+    protected $title = 'changeStatusButton';
+    protected $icon  = 'lu-dropdown__link-icon lu-btn__icon lu-zmdi lu-zmdi-refresh-sync';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new ChangeStatusModal());
+    }
+
+}

+ 31 - 0
app/UI/Client/EmailAccount/Buttons/DeleteAccountButton.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\DeleteAccountModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:27
+ * Class DeleteAccountButton
+ */
+class DeleteAccountButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'deleteAccountButton';
+    protected $title = 'deleteAccountButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteAccountModal());
+    }
+
+}

+ 32 - 0
app/UI/Client/EmailAccount/Buttons/EditAccountButton.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\EditAccountModal;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\AddAccountModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCustomAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:29
+ * Class EditAccountButton
+ */
+class EditAccountButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'editAccountButton';
+    protected $title = 'editAccountButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new EditAccountModal());
+    }
+
+}

+ 103 - 0
app/UI/Client/EmailAccount/Buttons/LoginToPanelButton.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonRedirect;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 16:44
+ * Class LoginToPanel
+ */
+class LoginToPanelButton extends ButtonDropdownItem implements ClientArea
+{
+    protected $icon           = 'lu-dropdown__link-icon lu-btn__icon lu-zmdi lu-zmdi-email';
+
+    protected $rawUrl = null;
+    protected $redirectParams = [];
+
+    public function initContent()
+    {
+        $this->htmlAttributes['@click.middle'] = 'redirect($event, ' . $this->parseCustomParams() . ', true)';
+        $this->htmlAttributes['@click'] = 'redirect($event, ' . $this->parseCustomParams() . ', true)';
+
+    }
+
+    protected function parseCustomParams()
+    {
+        if (count($this->redirectParams) === 0 && $this->rawUrl === null)
+        {
+            return '{}';
+        }
+
+        return $this->parseListTOJsString($this->redirectParams);
+    }
+
+    protected function parseListTOJsString($params)
+    {
+        $jsString = '{';
+
+        if ($this->rawUrl !== null)
+        {
+            $params['rawUrl'] = $this->rawUrl;
+        }
+
+        foreach ($params as $key => $value)
+        {
+            $jsString .= ' ' . str_replace('-', '__', $key) . ': ' . (is_array($value) ? ($this->parseListTOJsString($value) . ',') : ("'" . (string) $value) . "',");
+        }
+
+        $jsString = trim($jsString, ',') . ' } ';
+
+        return $jsString;
+    }
+
+    public function setRawUrl($url)
+    {
+        $this->rawUrl = $url;
+
+        return $this;
+    }
+
+    public function addRedirectParam($key, $value)
+    {
+        $this->redirectParams[$key] = $value;
+
+        $this->updateHtmlAttributesByRedirectParams();
+
+        return $this;
+    }
+
+    public function setRedirectParams($paramsList)
+    {
+        $this->redirectParams = $paramsList;
+
+        $this->updateHtmlAttributesByRedirectParams();
+
+        return $this;
+    }
+
+    protected function updateHtmlAttributesByRedirectParams()
+    {
+        foreach ($this->redirectParams as $key => $value)
+        {
+            $this->updateHtmlAttribute($key, $value);
+        }
+    }
+
+    protected function updateHtmlAttribute($key, $value)
+    {
+        if (strpos($value, ':') === 0)
+        {
+            $this->addHtmlAttribute(':data-' . $key , 'dataRow.' . trim($value, ':'));
+        }
+    }
+}

+ 28 - 0
app/UI/Client/EmailAccount/Buttons/MassChangeStatusButton.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Class MassChangeStatusButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\MassChangeStatusModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class MassChangeStatusButton extends ButtonMassAction implements ClientArea
+{
+    protected $id    = 'massChangeStatusButton';
+    protected $title = 'massChangeStatusButton';
+    protected $icon  = 'lu-btn__icon lu-zmdi lu-zmdi-refresh-sync';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new MassChangeStatusModal());
+    }
+
+}

+ 28 - 0
app/UI/Client/EmailAccount/Buttons/MassDeleteAccountButton.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Class MassDeleteAccountButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals\MassDeleteAccountModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class MassDeleteAccountButton extends ButtonMassAction implements ClientArea
+{
+
+    protected $id    = 'massDeleteAccountButton';
+    protected $title = 'massDeleteAccountButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn(); 
+        $this->initLoadModalAction(new MassDeleteAccountModal());
+    }
+}

+ 19 - 0
app/UI/Client/EmailAccount/Buttons/SpanDropdownButton.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdown;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 13.11.19
+ * Time: 08:53
+ * Class SpanDropdownButton
+ */
+class SpanDropdownButton extends ButtonDropdown
+{
+    protected $id = 'spanDropdownButton';
+}

+ 58 - 0
app/UI/Client/EmailAccount/Forms/AddAccountForm.php

@@ -0,0 +1,58 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\RowSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\AccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections\AdditionalSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections\GeneralSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\PasswordsValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\RepeatPasswordValidator;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Password;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\RawSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class AddAccountForm
+ */
+class AddAccountForm extends SortedFieldForm implements ClientArea
+{
+    use FormExtendedTrait;
+
+    protected $id    = 'addAccountForm';
+    protected $name  = 'addAccountForm';
+    protected $title = 'addAccountForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::CREATE);
+        $this->setProvider(new AccountDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function initFields()
+    {
+        $this->addSection(new GeneralSection());
+        $this->addSection(new AdditionalSection());
+
+
+    }
+}

+ 58 - 0
app/UI/Client/EmailAccount/Forms/ChangePasswordForm.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\EditAccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\Validators\PasswordsValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\RepeatPasswordValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Password;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:07
+ * Class ChangePasswordForm
+ */
+class ChangePasswordForm extends BaseForm implements ClientArea
+{
+
+
+    protected $id    = 'changePasswordForm';
+    protected $name  = 'changePasswordForm';
+    protected $title = 'changePasswordForm';
+
+    protected function getDefaultActions()
+    {
+        return ['changePassword'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('changePassword');
+        $this->dataProvider = new EditAccountDataProvider();
+
+        $field = new Hidden('id');
+        $this->addField($field);
+
+        /**end**/
+        $field = new Password('password');
+        $field->setDescription('description');
+        $field->addValidator(new PasswordsValidator());
+        $field->notEmpty();
+        $this->addField($field);
+
+        $field = (new Password('repeat_password'))->addValidator(new RepeatPasswordValidator());
+        $field->notEmpty();
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+
+}

+ 47 - 0
app/UI/Client/EmailAccount/Forms/ChangeStatusForm.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\AccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\EditAccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 16.10.19
+ * Time: 13:20
+ * Class ChangeStatusForm
+ */
+class ChangeStatusForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'changeStatusForm';
+    protected $name  = 'changeStatusForm';
+    protected $title = 'changeStatusForm';
+
+    protected function getDefaultActions()
+    {
+        return ['updateStatus'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('updateStatus');
+        $this->dataProvider = new EditAccountDataProvider();
+
+        $field = new Hidden('id');
+        $this->addField($field);
+
+        $field = new Select('status');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+
+}

+ 40 - 0
app/UI/Client/EmailAccount/Forms/DeleteAccountForm.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\DeleteAccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:28
+ * Class DeleteAccountForm
+ */
+class DeleteAccountForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'deleteAccountForm';
+    protected $name  = 'deleteAccountForm';
+    protected $title = 'deleteAccountForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::DELETE);
+        $this->dataProvider = new DeleteAccountDataProvider();
+
+        $this->setConfirmMessage('confirmRemoveAccount');
+
+        $field = new Hidden();
+        $field->setId('id');
+        $field->setName('id');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+}

+ 55 - 0
app/UI/Client/EmailAccount/Forms/EditAccountForm.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\RowSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\AccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\EditAccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections\EditAdditionalSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections\EditGeneralSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:29
+ * Class EditAccountForm
+ */
+class EditAccountForm extends SortedFieldForm implements ClientArea
+{
+    use FormExtendedTrait;
+
+    protected $id    = 'editAccountForm';
+    protected $name  = 'editAccountForm';
+    protected $title = 'editAccountForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::UPDATE);
+        $this->setProvider(new EditAccountDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function initFields()
+    {
+        $this->addSection(new EditGeneralSection());
+
+        $this->addSection(new EditAdditionalSection());
+    }
+}

+ 38 - 0
app/UI/Client/EmailAccount/Forms/MassChangeStatusForm.php

@@ -0,0 +1,38 @@
+<?php
+/**
+ * Class MassChangeStatusForm
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 12:26
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\AccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class MassChangeStatusForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'massChangeStatusForm';
+    protected $name  = 'massChangeStatusForm';
+    protected $title = 'massChangeStatusForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::UPDATE);
+        $this->dataProvider = new AccountDataProvider();
+
+        $field = new Select('status');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+
+}

+ 42 - 0
app/UI/Client/EmailAccount/Forms/MassDeleteAccountForm.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class MassDeleteAccountForm
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\DeleteAccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class MassDeleteAccountForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'massDeleteAccountForm';
+    protected $name  = 'massDeleteAccountForm';
+    protected $title = 'massDeleteAccountForm';
+
+    protected function getDefaultActions()
+    {
+        return ['massDelete'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('massDelete');
+        $this->dataProvider = new DeleteAccountDataProvider();
+
+        $this->setConfirmMessage('massDeleteAccountFormConfirm');
+
+
+        $this->loadDataToForm();
+    }
+
+}

+ 26 - 0
app/UI/Client/EmailAccount/Modals/AddAccountModal.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Modals\ModalExtendedTabsEdit;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\AddAccountForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class AddAccountModal
+ */
+class AddAccountModal extends ModalExtendedTabsEdit implements ClientArea
+{
+    protected $id    = 'addAccountModal';
+    protected $name  = 'addAccountModal';
+    protected $title = 'addAccountModal';
+
+    public function initContent()
+    {
+        $this->addForm(new AddAccountForm());
+    }
+}

+ 29 - 0
app/UI/Client/EmailAccount/Modals/ChangePasswordModal.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\ChangePasswordForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\EditAccountForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:07
+ * Class ChangePasswordModal
+ */
+class ChangePasswordModal extends BaseEditModal implements ClientArea
+{
+    protected $id    = 'changePasswordModal';
+    protected $name  = 'changePasswordModal';
+    protected $title = 'changePasswordModal';
+
+    public function initContent()
+    {
+        $this->addForm(new ChangePasswordForm());
+    }
+}

+ 29 - 0
app/UI/Client/EmailAccount/Modals/ChangeStatusModal.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Class ChangeStatusModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\ChangeStatusForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\EditAccountForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+class ChangeStatusModal extends BaseEditModal implements ClientArea
+{
+    protected $id    = 'changeStatusModal';
+    protected $name  = 'changeStatusModal';
+    protected $title = 'changeStatusModal';
+
+    public function initContent()
+    {
+        $this->addForm(new ChangeStatusForm());
+    }
+}

+ 34 - 0
app/UI/Client/EmailAccount/Modals/DeleteAccountModal.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\DeleteAccountForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\EditAccountForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:28
+ * Class DeleteAccountModal
+ */
+class DeleteAccountModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'deleteAccountModal';
+    protected $name  = 'deleteAccountModal';
+    protected $title = 'deleteAccountModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+
+        $this->addForm(new DeleteAccountForm());
+    }
+
+}

+ 30 - 0
app/UI/Client/EmailAccount/Modals/EditAccountModal.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Modals\ModalExtendedTabsEdit;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\AddAccountForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\EditAccountForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:30
+ * Class EditAccountModal
+ */
+class EditAccountModal extends ModalExtendedTabsEdit implements ClientArea
+{
+    protected $id    = 'editAccountModal';
+    protected $name  = 'editAccountModal';
+    protected $title = 'editAccountModal';
+
+    public function initContent()
+    {
+        $this->addForm(new EditAccountForm());
+    }
+}

+ 30 - 0
app/UI/Client/EmailAccount/Modals/MassChangeStatusModal.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * Class MassChangeStatusModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:30
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\MassChangeStatusForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class MassChangeStatusModal extends BaseEditModal implements ClientArea
+{
+
+    protected $id    = 'massChangeStatusModal';
+    protected $name  = 'massChangeStatusModal';
+    protected $title = 'massChangeStatusModal';
+
+    public function initContent()
+    {
+        $this->addForm(new MassChangeStatusForm());
+    }
+
+}

+ 31 - 0
app/UI/Client/EmailAccount/Modals/MassDeleteAccountModal.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class MassDeleteAccountModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Forms\MassDeleteAccountForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class MassDeleteAccountModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'massDeleteAccountModal';
+    protected $name  = 'massDeleteAccountModal';
+    protected $title = 'massDeleteAccountModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+        $this->addForm(new MassDeleteAccountForm());
+    }
+
+}

+ 203 - 0
app/UI/Client/EmailAccount/Pages/Accounts.php

@@ -0,0 +1,203 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Pages;
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Connection;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\AccountHelper;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Filters\EmailAccounts\FilterByCosId;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields\EnabledField;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\AddAccountButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\ChangePasswordButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\ChangeStatusButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\DeleteAccountButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\EditAccountButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\LoginToPanelButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\MassChangeStatusButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\MassDeleteAccountButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Buttons\SpanDropdownButton;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdown;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\DataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataTable;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:51
+ * Class Accounts
+ */
+class Accounts extends DataTable implements ClientArea
+{
+
+    /**
+     * labels for statuses
+     */
+    const STATUS_LABEL = [
+        'active'        => 'success',
+        'locked'        => 'default',
+        'maintenance'   => 'warning',
+        'closed'        => 'default',
+        'lockout'       => 'info',
+        'pending'       => 'warning',
+        'default'       => 'default'
+    ];
+
+    protected $id    = 'accounts';
+    protected $name  = 'accounts';
+    protected $title = null;
+
+    /**
+     * load columns
+     */
+    protected function loadHtml()
+    {
+        $this
+            ->addColumn((new Column('mailbox'))
+                ->setOrderable(DataProvider::SORT_ASC)
+                ->setSearchable(true, Column::TYPE_STRING))
+            ->addColumn((new Column('date_created'))
+                ->setOrderable()
+                ->setSearchable(true))
+            ->addColumn((new Column('date_created'))
+                ->setOrderable()
+                ->setSearchable(true))
+            ->addColumn((new Column('last_login'))
+                ->setOrderable()
+                ->setSearchable(true))
+            ->addColumn((new Column('quota'))
+                ->setOrderable()
+                ->setSearchable(true, Column::TYPE_INT))
+            ->addColumn((new Column('status'))
+                ->setOrderable()
+                ->setSearchable(true));
+    }
+
+    /**
+     * @param $key
+     * @param $row
+     * @return mixed
+     */
+    public function replaceFieldStatus($key, $row)
+    {
+        $status = self::STATUS_LABEL[$row[$key]] ? self::STATUS_LABEL[$row[$key]] : self::STATUS_LABEL['default'];
+        $label = di('lang')->absoluteT('kerio','account','status',$row[$key]);
+
+        $field = new EnabledField();
+        $field->setRawType($status);
+        $field->setRawTitle($label);
+
+        return $field->getHtml();
+    }
+
+    /**
+     * @param $key
+     * @param $row
+     * @return mixed
+     */
+    public function replaceFieldLast_login($key, $row)
+    {
+        return $row[$key] ? $row[$key] : '-';
+    }
+
+    /**
+     * load buttons
+     */
+    public function initContent()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->getRequestValue('id'));
+
+        $this->addMassActionButton(new MassChangeStatusButton());
+        $this->addMassActionButton(new MassDeleteAccountButton());
+
+        $this->addButton(new AddAccountButton());
+
+
+        $this->addActionButton(new EditAccountButton());
+        $this->addActionButton(new DeleteAccountButton());
+
+        $mailBox = new LoginToPanelButton();
+        $mailBox
+            ->setRawUrl(BuildUrlExtended::getProvisioningUrl('webmail', true, true,'clientSso'))
+            ->setRedirectParams(['actionElementId' => 'true']);
+
+        $actions = new SpanDropdownButton('actions');
+        $actions->addButton(new ChangeStatusButton());
+        $actions->addButton(new ChangePasswordButton());
+
+        if ($productManager->get('ca_logInToMailboxButton') === 'on')
+        {
+            $actions->addButton($mailBox);
+        }
+
+        $this->addActionButton($actions);
+
+    }
+
+    /**
+     * load data
+     */
+    public function loadData()
+    {
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+
+
+        $accounts = (new KerioManager())
+            ->getApiByServer($hosting->server)
+            ->soap
+            ->repository()
+            ->accounts
+            ->getByDomainName($hosting->domain);
+
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hosting->id);
+
+        if($productManager->get('filterAccountsByCOS') === 'on' && $productManager->get('cos_name') !=  ClassOfServices::CUSTOM_ZIMBRA)
+        {
+            $availableCoses = is_array($productManager->getSettingCos()) ? array_keys($productManager->getSettingCos()) : [$productManager->getSettingCos()];
+            $filter = new FilterByCosId();
+            $filter->setAvailableCoses($availableCoses);
+            $accounts = $filter->filter($accounts);
+        }
+
+        /**
+         * format model to array
+         */
+        $data = [];
+        foreach ($accounts as $account)
+        {
+            /* @var $account Account */
+
+            $accountArray = [
+                'id'           => $account->getId(),
+                'mailbox'      => $account->getName(),
+                'date_created' => AccountHelper::getFormattedData($account->getDataResourceA('kerioCreateTimestamp')),
+                'last_login'   => AccountHelper::getFormattedData($account->getDataResourceA('kerioLastLogonTimestamp'), 'd/m/Y H:i'),
+                'quota'        => AccountHelper::getQuotaAsMb($account->getDataResourceA('kerioMailQuota')),
+                'status'       => $account->getDataResourceA('kerioAccountStatus'),
+
+            ];
+
+            $data[] = $accountArray;
+        }
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting('mailbox', 'ASC')->setData($data);
+
+        $this->setDataProvider($dataProv);
+    }
+
+}

+ 307 - 0
app/UI/Client/EmailAccount/Providers/AccountDataProvider.php

@@ -0,0 +1,307 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Http\Admin\ProductConfiguration;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\ServiceFactory;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\ClassOfServicesOptions;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class AccountDataProvider
+ */
+class AccountDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        $hosting = Hosting::where('id', $hid)->first();
+        //todo refactor
+        $this->data['domain'] = $hosting->domain;
+
+        $lang = di('lang');
+        $this->availableValues['status'] = [
+            Kerio::ACC_STATUS_ACTIVE        => $lang->absoluteT('kerio','account','status','active'),
+            Kerio::ACC_STATUS_LOCKED        => $lang->absoluteT('kerio','account','status','locked'),
+            Kerio::ACC_STATUS_MAINTENANCE   => $lang->absoluteT('kerio','account','status','maintenance'),
+            Kerio::ACC_STATUS_CLOSED        => $lang->absoluteT('kerio','account','status','closed'),
+            Kerio::ACC_STATUS_LOCKOUT       => $lang->absoluteT('kerio','account','status','lockout'),
+            Kerio::ACC_STATUS_PENDING       => $lang->absoluteT('kerio','account','status','pending')
+        ];
+
+        /**
+         * product manager allow to check product settings
+         */
+
+        $this->readCosParams();
+    }
+
+    public function create()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+
+        $fieldToProtection = ['firstname', 'lastname', 'display_name', 'company', 'title', 'country', 'state', 'city', 'street', 'post_code' ];
+
+        foreach ($this->formData as $field => &$value)
+        {
+            $value = in_array($field, $fieldToProtection) ? htmlentities($value) : $value;
+        }
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->createAccount($productManager->get('cos_name'));
+        /**
+         *
+         * set product manager & form data to service
+         */
+        $service
+            ->setProductManager($productManager)
+            ->setFormData($this->formData);
+
+        /**
+         *
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('emailAccountHasBeenAdded')->setStatusSuccess();
+
+    }
+
+    public function updateStatus()
+    {
+
+
+    }
+
+    public function update()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateAccountStatus()
+            ->setProductManager($productManager)
+        ;
+        /**
+         *
+         * set product manager & form data to service
+         */
+
+        /**
+         * run service for each id
+         */
+        foreach($this->request->get('massActions') as $id)
+        {
+            $service->setFormData(['status' => $this->formData['status'], 'id' => $id]);
+            $result = $service->run();
+        }
+
+        /**
+         * return success
+         */
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('massEmailAccountStatusHasBeenUpdated')->setStatusSuccess();
+    }
+
+    /**
+     *
+     * read data per cos_name
+     */
+    protected function readCosParams()
+    {
+        $hid = $this->request->get('id');
+
+
+        /**
+         *
+         * load product manager
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * check if class of services should be selectable
+         */
+        if($productManager->get('cos_name') === ClassOfServices::CLASS_OF_SERVICE_QUOTA)
+        {
+            /**
+             *
+             * get soap create domain  service
+             */
+            $api =(new KerioManager())
+                ->getApiByHosting($hid)
+                ->soap;
+
+            /**
+             *
+             * get cos from API
+             */
+            $classOfServices = $api->repository()->cos->all();
+
+            /**
+             *
+             * load configurable options coses
+             */
+            $supportedCos = $productManager->getSettingCos();
+
+            /**
+             *
+             * add COS to array
+             */
+            $configoptions = $this->getFilteredCosConfigurableOptions();
+
+            foreach($classOfServices as $cos)
+            {
+                /**
+                 *
+                 *
+                 * skip COS which is not used in configurable options
+                 */
+                if(!($supportedCos && array_key_exists($cos->getId(), $supportedCos)))
+                {
+                    continue;
+                }
+
+                /**
+                 * 1. check if config opts are available
+                 * 2. skip if class of services doesnt exists in config option list
+                 */
+                if($configoptions && !array_key_exists('cosQuota_'.$cos->getId(), $configoptions))
+                {
+                    continue;
+                }
+
+                /**
+                 * 1. check if config opts are available
+                 * 2. skip not purchased as CO
+                 */
+                if ($configoptions && $configoptions['cosQuota_'.$cos->getId()] == 0)
+                {
+                    continue;
+                }
+
+                /**
+                 * 1. check if config opts are not available
+                 * 2. skip if quantity === 0
+                 */
+                if(!$configoptions && $supportedCos[$cos->getId()] == 0)
+                {
+                    continue;
+                }
+
+                /* @var $cos ClassOfService*/
+                $this->availableValues['cosId'][$cos->getId()] = $cos->getMbMailQuote().' MB';
+            }
+
+
+            return $this;
+        }
+
+
+        /**
+         *
+         * check if class of service is choosen by config opt
+         */
+        if($productManager->get('cos_name') === ClassOfServices::ZIMBRA_CONFIG_OPTIONS)
+        {
+
+            $this->data['cosId'] = key($productManager->getSettingCos());
+            return $this;
+        }
+
+        /**
+         *
+         * if cos_name is dedicated (loaded from API)
+         */
+        if($productManager->get('cos_name') !== ClassOfServices::CUSTOM_ZIMBRA)
+        {
+            /**
+             * if dedicated class of service has been selected
+             */
+            $this->data['cosId'] = $productManager->get('cos_name');
+            return $this;
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return bool|mixed
+     */
+    protected function getFilteredCosConfigurableOptions()
+    {
+        $configoptions = $this->getWhmcsParamByKey('configoptions');
+
+        foreach($configoptions as $key => $value)
+        {
+            if(strpos($key, ClassOfServicesOptions::COS_CONFIG_OPT_PREFIX) === false)
+            {
+                unset($configoptions[$key]);
+            }
+
+        }
+
+        return $configoptions;
+    }
+}

+ 116 - 0
app/UI/Client/EmailAccount/Providers/DeleteAccountDataProvider.php

@@ -0,0 +1,116 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteAccount;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:28
+ * Class DeleteAccountDataProvider
+ */
+class DeleteAccountDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        $this->data['id'] = $this->actionElementId;
+    }
+
+    public function update()
+    {
+        // TODO: Implement update() method.
+    }
+
+    public function delete()
+    {
+
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteAccount();
+        /**
+         *
+         * set product manager & form data to service
+         */
+        $service
+            ->setFormData($this->formData);
+
+        /**
+         *
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('emailAccountHasBeenDeleted')->setStatusSuccess();
+
+    }
+
+    public function massDelete()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteAccount();
+
+        /**
+         *
+         */
+        foreach($this->request->get('massActions') as $id)
+        {
+            $service->setFormData(['id' => $id]);
+            $result = $service->run();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('massEmailAccountHasBeenDeleted')->setStatusSuccess();
+    }
+}

+ 354 - 0
app/UI/Client/EmailAccount/Providers/EditAccountDataProvider.php

@@ -0,0 +1,354 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateAccount;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\ClassOfServicesOptions;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:35
+ * Class EditAccountDataProvider
+ */
+class EditAccountDataProvider extends BaseDataProvider
+{
+
+    /**
+     *
+     */
+    public function read()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->getRequestValue('id');
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $hid)->first();
+
+        /**
+         * load api
+         */
+        $api = (new KerioManager())->getApiByServer($hosting->server);
+
+        $repository = new Repository($api->soap);
+
+        $result = $repository->accounts->getAccountOptionsById($this->actionElementId);
+
+        if($result instanceof Response && $result->getLastError())
+        {
+            throw new \Exception($result->getLastError());
+        }
+
+        $mailBoxParams              = explode('@', $result->getName());
+        $this->data['id']           = $result->getId();
+        $this->data['username']     = $mailBoxParams[0];
+        $this->data['domain']       = $mailBoxParams[1];
+        $this->data['firstname']    = $result->getDataResourceA(Account::ATTR_FIRSTNAME);
+        $this->data['lastname']     = $result->getDataResourceA(Account::ATTR_LASTNAME);
+        $this->data['display_name'] = $result->getDataResourceA(Account::ATTR_DISPLAY_NAME);
+        $this->data['status']       = $result->getDataResourceA(Account::ATTR_ACCOUNT_STATUS);
+        $this->data['company']      = $result->getDataResourceA(Account::ATTR_COMPANY);
+        $this->data['title']        = $result->getDataResourceA(Account::ATTR_PROF_TITLE);
+        $this->data['phone']        = $result->getDataResourceA(Account::ATTR_PHONE);
+        $this->data['home_phone']   = $result->getDataResourceA(Account::ATTR_HOME_PHONE);
+        $this->data['mobile_phone'] = $result->getDataResourceA(Account::ATTR_MOBILE_PHONE);
+        $this->data['fax']          = $result->getDataResourceA(Account::ATTR_FAX);
+        $this->data['pager']        = $result->getDataResourceA(Account::ATTR_PAGER);
+        $this->data['country']      = $result->getDataResourceA(Account::ATTR_COUNTRY);
+        $this->data['city']         = $result->getDataResourceA(Account::ATTR_CITY);
+        $this->data['street']       = $result->getDataResourceA(Account::ATTR_STREET);
+        $this->data['post_code']    = $result->getDataResourceA(Account::ATTR_POSTAL_CODE);
+        $this->data['currentCosId'] = $result->getDataResourceA(Account::ATTR_CLASS_OF_SERVICE_ID);
+        $this->data['cosId']        = $result->getDataResourceA(Account::ATTR_CLASS_OF_SERVICE_ID);
+        $this->data['state']        = $result->getDataResourceA(Account::ATTR_STATE);
+
+        $lang = di('lang');
+        $this->availableValues['status'] = [
+            Kerio::ACC_STATUS_ACTIVE        => $lang->absoluteT('kerio','account','status','active'),
+            Kerio::ACC_STATUS_LOCKED        => $lang->absoluteT('kerio','account','status','locked'),
+            Kerio::ACC_STATUS_MAINTENANCE   => $lang->absoluteT('kerio','account','status','maintenance'),
+            Kerio::ACC_STATUS_CLOSED        => $lang->absoluteT('kerio','account','status','closed'),
+            Kerio::ACC_STATUS_LOCKOUT       => $lang->absoluteT('kerio','account','status','lockout'),
+            Kerio::ACC_STATUS_PENDING       => $lang->absoluteT('kerio','account','status','pending')
+        ];
+
+        $this->readCosParams();
+
+    }
+
+    /**
+     * @return HtmlDataJsonResponse
+     */
+    public function update()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+
+        $fieldToProtection = ['firstname', 'lastname', 'display_name', 'company', 'title', 'country', 'state', 'city', 'street', 'post_code' ];
+
+        foreach ($this->formData as $field => &$value)
+        {
+            $value = in_array($field, $fieldToProtection) ? htmlentities($value) : $value;
+        }
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateAccount($productManager->get('cos_name'));
+        /**
+         *
+         * set product manager & form data to service
+         */
+        $service
+            ->setProductManager($productManager)
+            ->setFormData($this->formData);
+
+
+        /**
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('emailAccountHasBeenUpdated')->setStatusSuccess();
+    }
+
+    /**
+     * @return HtmlDataJsonResponse
+     */
+    public function updateStatus()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateAccountStatus()
+            ->setProductManager($productManager)
+        ;
+        /**
+         *
+         * set product manager & form data to service
+         */
+
+        /**
+         * run service for each id
+         */
+        $service->setFormData($this->formData);
+        $result = $service->run();
+
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        /**
+         * return success
+         */
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('emailAccountStatusHasBeenUpdated')->setStatusSuccess();
+
+    }
+
+    /**
+     * @return HtmlDataJsonResponse
+     */
+    public function changePassword()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateAccountPassword()
+            ->setProductManager($productManager)
+        ;
+        /**
+         *
+         * set product manager & form data to service
+         */
+
+        /**
+         * run service for each id
+         */
+        $service->setFormData($this->formData);
+        $result = $service->run();
+
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('passwordChangedSuccessfully')->setStatusSuccess();
+    }
+
+    /**
+     *
+     */
+    public function readCosParams()
+    {
+        $hid = $this->getRequestValue('id');
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+        if($productManager->get('cos_name') === ClassOfServices::CLASS_OF_SERVICE_QUOTA)
+        {
+            /**
+             *
+             * get soap create domain  service
+             */
+            $api =(new KerioManager())
+                ->getApiByHosting($hid)
+                ->soap;
+
+            /**
+             *
+             * get cos from API
+             */
+            $classOfServices = $api->repository()->cos->all();
+
+            /**
+             *
+             * load configurable options coses
+             */
+            $supportedCos = $productManager->getSettingCos();
+
+            /**
+             *
+             * add COS to array
+             */
+            $configoptions = $this->getFilteredCosConfigurableOptions();
+            foreach($classOfServices as $cos)
+            {
+                /**
+                 *
+                 *
+                 * skip COS which is not used in configurable options
+                 */
+                if(!($supportedCos && array_key_exists($cos->getId(), $supportedCos)))
+                {
+                    continue;
+                }
+
+                /**
+                 *
+                 * skip if class of services doesnt exists in config option list
+                 */
+                if($configoptions && !array_key_exists('cosQuota_'.$cos->getId(), $configoptions))
+                {
+                    continue;
+                }
+
+                /**
+                 * skip not purchased as CO
+                 */
+                if ($configoptions && $configoptions['cosQuota_'.$cos->getId()] == 0)
+                {
+                    continue;
+                }
+
+                /**
+                 * 1. check if config opts are not available
+                 * 2. skip if quantity === 0
+                 */
+                if(!$configoptions && $supportedCos[$cos->getId()] == 0)
+                {
+                    continue;
+                }
+
+
+                /* @var $cos ClassOfService*/
+                $this->availableValues['cosId'][$cos->getId()] = $cos->getMbMailQuote().' MB';
+            }
+        }
+
+    }
+
+    /**
+     * @return bool|mixed
+     */
+    protected function getFilteredCosConfigurableOptions()
+    {
+        $configoptions = $this->getWhmcsParamByKey('configoptions');
+
+        foreach($configoptions as $key => $value)
+        {
+            if(strpos($key, ClassOfServicesOptions::COS_CONFIG_OPT_PREFIX) === false)
+            {
+                unset($configoptions[$key]);
+            }
+
+        }
+
+        return $configoptions;
+    }
+
+}

+ 45 - 0
app/UI/Client/EmailAccount/Sections/AdditionalSection.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:42
+ * Class AdditionalSection
+ */
+class AdditionalSection extends FreeFieldsSection
+{
+    protected $id   = 'additionalSection';
+    protected $name = 'additionalSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        $this->generateDoubleSection([new Text('company'), new Text('title')]);
+
+        $field = new Text('phone');
+        $field->setPlaceholder(di('lang')->absoluteT('phoneNumberPlaceholder'));
+        $this->addField($field);
+
+        $this->generateDoubleSection([new Text('home_phone'), new Text('mobile_phone')]);
+
+        $this->generateDoubleSection([new Text('fax'), new Text('pager')]);
+
+        $this->generateDoubleSection([new Text('country'), new Text('state')]);
+
+        $this->generateDoubleSection([new Text('city'), new Text('street')]);
+
+        $field = new Text('post_code');
+        $this->addField($field);
+    }
+}

+ 44 - 0
app/UI/Client/EmailAccount/Sections/EditAdditionalSection.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:52
+ * Class EditAdditionalSection
+ */
+class EditAdditionalSection extends FreeFieldsSection
+{
+    protected $id   = 'editAdditionalSection';
+    protected $name = 'editAdditionalSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        $this->generateDoubleSection([new Text('company'), new Text('title')]);
+
+        $field = new Text('phone');
+        $this->addField($field);
+
+        $this->generateDoubleSection([new Text('home_phone'), new Text('mobile_phone')]);
+
+        $this->generateDoubleSection([new Text('fax'), new Text('pager')]);
+
+        $this->generateDoubleSection([new Text('country'), new Text('state')]);
+
+        $this->generateDoubleSection([new Text('city'), new Text('street')]);
+
+        $field = new Text('post_code');
+        $this->addField($field);
+    }
+
+}

+ 70 - 0
app/UI/Client/EmailAccount/Sections/EditGeneralSection.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:52
+ * Class EditGeneralSection
+ */
+class EditGeneralSection extends FreeFieldsSection
+{
+    protected $id   = 'editGeneralSection';
+    protected $name = 'editGeneralSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->getRequestValue('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         * add fields
+         */
+        $field = new Hidden('id');
+        $this->addField($field);
+
+        $this->generateDoubleSection([new Text('firstname'), new Text('lastname')]);
+
+        $email =new InputGroup('usernameGroup');
+
+        $email->addInputComponent((new InputGroupElements\Text('username'))->addHtmlAttribute('readonly','true'));
+        $email->addInputAddon('emailSign', false, '@');
+        $email->addInputComponent((new InputGroupElements\Text('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $this->generateDoubleSection([new Text('display_name'), new Select('status')]);
+
+        if($productManager->get('cos_name') === ClassOfServices::CLASS_OF_SERVICE_QUOTA)
+        {
+            $field = new Hidden('currentCosId');
+            $this->addField($field);
+
+            $field = new Select('cosId');
+            $this->addField($field);
+        }
+    }
+}

+ 83 - 0
app/UI/Client/EmailAccount/Sections/GeneralSection.php

@@ -0,0 +1,83 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Sections;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\PasswordsValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\RepeatPasswordValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Password;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:39
+ * Class GeneralSection
+ */
+class GeneralSection extends FreeFieldsSection
+{
+    protected $id   = 'generalSection';
+    protected $name = 'generalSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->getRequestValue('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        $this->generateDoubleSection([new Text('firstname'), new Text('lastname')]);
+
+        $email = new InputGroup('usernameGroup');
+
+        $email->addTextField('username', false, true);
+        $email->addInputAddon('emailSign', false, '@');
+        $email->addInputComponent((new InputGroupElements\Text('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $this->generateDoubleSection([new Text('display_name'), new Select('status')]);
+        /***
+         *
+         * set cosId dependent od cos_name
+         */
+        if($productManager->get('cos_name') === ClassOfServices::CLASS_OF_SERVICE_QUOTA)
+        {
+            $field = new Select('cosId');
+            $this->addField($field);
+        }elseif($productManager->get('cos_name') === ClassOfServices::ZIMBRA_CONFIG_OPTIONS)
+        {
+            $field = new Hidden('cosId');
+            $this->addField($field);
+        }elseif($productManager->get('cos_name') !== ClassOfServices::CUSTOM_ZIMBRA)
+        {
+            $field = new Hidden('cosId');
+            $this->addField($field);
+        }
+
+        $passwd = new Password('password');
+        $passwd->setDescription('description');
+        $passwd->addValidator(new PasswordsValidator());
+        $passwd->notEmpty();
+
+        $repPasswd = (new Password('repeat_password'))->addValidator(new RepeatPasswordValidator());
+        $repPasswd->notEmpty();
+
+        $this->generateDoubleSection([$passwd, $repPasswd]);
+
+    }
+}

+ 26 - 0
app/UI/Client/EmailAlias/Buttons/AddEmailAliasButton.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Buttons;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Modals\AddEmailAliasModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:50
+ * Class AddEmailAliasButton
+ */
+class AddEmailAliasButton extends ButtonCreate implements ClientArea
+{
+    protected $id    = 'addEmailAliasButton';
+    protected $title = 'addEmailAliasButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new AddEmailAliasModal());
+    }
+
+
+}

+ 29 - 0
app/UI/Client/EmailAlias/Buttons/DeleteEmailAliasButton.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Modals\DeleteEmailAliasModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 12:59
+ * Class DeleteEmailAliasButton
+ */
+class DeleteEmailAliasButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'deleteEmailAliasButton';
+    protected $title = 'deleteEmailAliasButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteEmailAliasModal());
+    }
+
+}

+ 28 - 0
app/UI/Client/EmailAlias/Buttons/MassDeleteEmailAliasButton.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Class MassDeleteEmailAliasButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:30
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Modals\MassDeleteEmailAliasModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class MassDeleteEmailAliasButton extends ButtonMassAction implements ClientArea
+{
+
+    protected $id    = 'massDeleteEmailAliasButton';
+    protected $title = 'massDeleteEmailAliasButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new MassDeleteEmailAliasModal());
+    }
+}

+ 47 - 0
app/UI/Client/EmailAlias/Forms/AddEmailAliasForm.php

@@ -0,0 +1,47 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Forms;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAccount\Providers\AccountDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Providers\AddEmailAliasDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:50
+ * Class AddEmailAliasForm
+ */
+class AddEmailAliasForm extends SortedFieldForm implements ClientArea
+{
+    protected $id    = 'addEmailAliasForm';
+    protected $name  = 'addEmailAliasForm';
+    protected $title = 'addEmailAliasForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::CREATE);
+        $this->setProvider(new AddEmailAliasDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function initFields()
+    {
+        $email =new InputGroup('usernameGroup');
+
+        $email->addTextField('aliasName', false, true);
+        $email->addInputAddon('emailSign', false, '@');
+        $email->addInputComponent((new InputGroupElements\Text('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $field = new Select('mailbox');
+        $field->notEmpty();
+        $this->addField($field);
+    }
+}

+ 41 - 0
app/UI/Client/EmailAlias/Forms/DeleteEmailAliasForm.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Providers\DeleteEmailAliasDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 12:59
+ * Class DeleteEmailAliasForm
+ */
+class DeleteEmailAliasForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'deleteAccountForm';
+    protected $name  = 'deleteAccountForm';
+    protected $title = 'deleteAccountForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::DELETE);
+        $this->dataProvider = new DeleteEmailAliasDataProvider();
+
+        $this->setConfirmMessage('confirmDeleteAccountAlias');
+
+        $field = new Hidden('id');
+        $this->addField($field);
+
+        $field = new Hidden('alias');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+}

+ 42 - 0
app/UI/Client/EmailAlias/Forms/MassDeleteEmailAliasForm.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class MassDeleteEmailAliasForm
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:30
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Providers\DeleteEmailAliasDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class MassDeleteEmailAliasForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'deleteAccountForm';
+    protected $name  = 'deleteAccountForm';
+    protected $title = 'deleteAccountForm';
+
+    protected function getDefaultActions()
+    {
+        return ['massDelete'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('massDelete');
+        $this->dataProvider = new DeleteEmailAliasDataProvider();
+
+        $this->setConfirmMessage('massDeleteEmailAliasModalConfirm');
+
+
+        $this->loadDataToForm();
+    }
+
+}

+ 25 - 0
app/UI/Client/EmailAlias/Modals/AddEmailAliasModal.php

@@ -0,0 +1,25 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Modals;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Forms\AddEmailAliasForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:50
+ * Class AddEmailAliasModal
+ */
+class AddEmailAliasModal extends BaseEditModal implements ClientArea
+{
+    protected $id    = 'addEmailAliasModal';
+    protected $name  = 'addEmailAliasModal';
+    protected $title = 'addEmailAliasModal';
+
+    public function initContent()
+    {
+        $this->addForm(new AddEmailAliasForm());
+    }
+}

+ 33 - 0
app/UI/Client/EmailAlias/Modals/DeleteEmailAliasModal.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Forms\DeleteEmailAliasForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 12:59
+ * Class DeleteEmailAliasModal
+ */
+class DeleteEmailAliasModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'deleteEmailAliasModal';
+    protected $name  = 'deleteEmailAliasModal';
+    protected $title = 'deleteEmailAliasModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+
+        $this->addForm(new DeleteEmailAliasForm());
+    }
+
+}

+ 31 - 0
app/UI/Client/EmailAlias/Modals/MassDeleteEmailAliasModal.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class MassDeleteEmailAliasModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:30
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Forms\MassDeleteEmailAliasForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class MassDeleteEmailAliasModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'massDeleteEmailAliasModal';
+    protected $name  = 'massDeleteEmailAliasModal';
+    protected $title = 'massDeleteEmailAliasModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+        $this->addForm(new MassDeleteEmailAliasForm());
+    }
+
+}

+ 123 - 0
app/UI/Client/EmailAlias/Pages/Aliases.php

@@ -0,0 +1,123 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Pages;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\AccountHelper;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Account;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Buttons\AddEmailAliasButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Buttons\DeleteEmailAliasButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Buttons\MassDeleteEmailAliasButton;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\DataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataTable;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Others\Label;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:46
+ * Class Aliases
+ */
+class Aliases extends DataTable implements ClientArea
+{
+    protected $id    = 'emailAliases';
+    protected $name  = 'emailAliases';
+    protected $title = null;
+
+
+    protected function loadHtml()
+    {
+        $this
+            ->addColumn((new Column('email_alias'))
+                ->setOrderable(DataProvider::SORT_ASC)
+                ->setSearchable(true, Column::TYPE_STRING))
+            ->addColumn((new Column('account'))
+                ->setOrderable()
+                ->setSearchable(true));
+    }
+
+    public function initContent()
+    {
+        $this->addMassActionButton(new MassDeleteEmailAliasButton());
+
+        $addEmailAliasesButton = new AddEmailAliasButton();
+
+        if($this->isCreateButtonDisabled())
+        {
+            $addEmailAliasesButton->addHtmlAttribute('disabled', true);
+        }
+
+        $this->addButton($addEmailAliasesButton);
+        $this->addActionButton(new DeleteEmailAliasButton());
+    }
+
+    public function loadData()
+    {
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+
+        /**
+         * load api
+         */
+        $aliases     = (new KerioManager())
+            ->getApiByServer($hosting->server)
+            ->soap->repository()
+            ->accounts
+            ->getAccountAliasesByDomainName($hosting->domain);
+
+        /**
+         * format model to array
+         */
+        $data = [];
+        foreach ($aliases as $alias)
+        {
+            /* @var $alias AccountAlias */
+            $tmp = [
+                'id'            => base64_encode(json_encode(['alias' => $alias->getAlias(), 'accId' => $alias->getAccountId()])),
+                'email_alias'   => $alias->getAlias(),
+                'account'       => $alias->getAccountName()
+            ];
+
+            $data[] = $tmp;
+        }
+
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting('account', 'ASC')->setData($data);
+
+        $this->setDataProvider($dataProv);
+    }
+
+    /**
+     *
+     * check if add button should be disabled
+     * @return bool
+     */
+    private function isCreateButtonDisabled()
+    {
+        $hid = $this->getRequestValue('id');
+
+        /**
+         * hosting model
+         */
+        $hosting = Hosting::where('id', $hid)->first();
+
+        $accounts =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->repository()
+            ->accounts
+            ->getByDomainName($hosting->domain);
+
+        return !(count($accounts) > 0);
+    }
+}

+ 109 - 0
app/UI/Client/EmailAlias/Providers/AddEmailAliasDataProvider.php

@@ -0,0 +1,109 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Providers;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:50
+ * Class AddEmailAliasDataProvider
+ */
+class AddEmailAliasDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->getRequestValue('id');
+
+        /**
+         * hosting model
+         */
+        $hosting = Hosting::where('id', $hid)->first();
+
+        /**
+         * hosting domain
+         */
+        $this->data['domain'] = $hosting->domain;
+
+        /**
+         * load api
+         * load repo
+         * load accounts from repo
+         */
+        $accounts =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->repository()
+            ->accounts
+            ->getByDomainName($hosting->domain);
+
+        /**
+         * available accounts
+         */
+        foreach($accounts as $account)
+        {
+            $this->availableValues['mailbox'][$account->getId()] = $account->getName();
+        }
+
+    }
+
+    public function create()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create alias service
+         * set service configuration
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->createAccountAlias()
+            ->setProductManager($productManager)
+            ->setFormData($this->formData);
+
+        /**
+         *
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('emailAliasHasBeenCreated')->setStatusSuccess();
+    }
+
+    public function update()
+    {
+        // TODO: Implement update() method.
+    }
+}

+ 115 - 0
app/UI/Client/EmailAlias/Providers/DeleteEmailAliasDataProvider.php

@@ -0,0 +1,115 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\EmailAlias\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\AccountAlias;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 12:59
+ * Class DeleteEmailAliasDataProvider
+ */
+class DeleteEmailAliasDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        $params = json_decode(base64_decode($this->actionElementId), true);
+
+        $this->data['id'] = $params['accId'];
+        $this->data['alias'] = $params['alias'];
+    }
+
+    public function update()
+    {
+        // TODO: Implement update() method.
+    }
+
+    public function delete()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create alias service
+         * set service configuration
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteAccountAlias()
+            ->setFormData($this->formData);
+
+        /**
+         *
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('emailAliasHasBeenDeleted')->setStatusSuccess();
+    }
+
+    public function massDelete()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create alias service
+         * set service configuration
+         */
+        $service = (new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteAccountAlias();
+
+        foreach ($this->request->get('massActions') as $endodedData)
+        {
+            $data = json_decode(base64_decode($endodedData), true);
+            $data['id'] = $data['accId'];
+            $service->setFormData($data);
+            $result = $service->run();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('massEmailAliasHasBeenDeleted')->setStatusSuccess();
+
+    }
+}

+ 69 - 0
app/UI/Client/Home/Fields/FeatureField.php

@@ -0,0 +1,69 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Home\Fields;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\BaseField;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 03.10.19
+ * Time: 14:37
+ * Class FeatureField
+ */
+class FeatureField extends BaseField implements ClientArea
+{
+    protected $id      = 'featureField';
+    protected $name    = 'featureField';
+    protected $url;
+
+    protected $targetBlank = false;
+
+    /**
+     * @return mixed
+     */
+    public function getUrl()
+    {
+        return $this->url;
+    }
+
+    /**
+     * @param $url
+     * @return $this
+     */
+    public function setUrl($url)
+    {
+        $this->url = $url;
+        return $this;
+    }
+
+    /**
+     * @return bool|string|null
+     */
+    public function getIcon()
+    {
+        $asset = BuildUrl::getAppAssetsURL();
+        return $asset.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.$this->id.'.png';
+    }
+
+    /**
+     * @return bool
+     */
+    public function isTargetBlank()
+    {
+        return $this->targetBlank;
+    }
+
+    /**
+     * @param $targetBlank
+     * @return $this
+     */
+    public function setTargetBlank($targetBlank)
+    {
+        $this->targetBlank = $targetBlank;
+        return $this;
+    }
+
+
+}

+ 128 - 0
app/UI/Client/Home/Pages/Dashboard.php

@@ -0,0 +1,128 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Home\Pages;
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\ControllerEnums;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Home\Fields\FeatureField;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Builder\BaseContainer;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:09
+ * Class Dashboard
+ */
+class Dashboard extends BaseContainer implements ClientArea
+{
+
+    /**
+     * @var array
+     */
+    protected $featureContainer = [];
+
+    public function initContent()
+    {
+        $this->initFeatures();
+    }
+
+    /**
+     *
+     */
+    protected function initFeatures()
+    {
+        /**
+         * product manager
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->getRequestValue('id'));
+
+        /**
+         *
+         * check if email account page is enabled
+         */
+        if($productManager->isControllerAccessible(ControllerEnums::EMAIL_ACCOUNT_PAGE))
+        {
+            $feature = new FeatureField('emailAccount');
+            $feature->setUrl(BuildUrlExtended::getProvisioningUrl('emailAccount'));
+            $this->addFeature($feature);
+        }
+
+        /**
+         *
+         * check if email alias page is enabled
+         */
+        if($productManager->isControllerAccessible(ControllerEnums::EMAIL_ALIAS_PAGE))
+        {
+            $feature = new FeatureField('emailAlias');
+            $feature->setUrl(BuildUrlExtended::getProvisioningUrl('emailAlias'));
+            $this->addFeature($feature);
+        }
+
+        /**
+         *
+         * check if ressource page is enabled
+         */
+        if($productManager->isControllerAccessible(ControllerEnums::RESSOURCE_PAGE))
+        {
+            $feature = new FeatureField('ressource');
+            $feature->setUrl(BuildUrlExtended::getProvisioningUrl('ressource'));
+            $this->addFeature($feature);
+        }
+
+        /**
+         *
+         * check if distribution list page is enabled
+         */
+        if($productManager->isControllerAccessible(ControllerEnums::DISTRIBUTION_MAIL_PAGE))
+        {
+            $feature = new FeatureField('distributionList');
+            $feature->setUrl(BuildUrlExtended::getProvisioningUrl('distributionList'));
+            $this->addFeature($feature);
+        }
+
+        /**
+         *
+         * check if domain alias page is enabled
+         */
+        if($productManager->isControllerAccessible(ControllerEnums::DOMAIN_ALIAS_PAGE)) {
+            $feature = new FeatureField('domainAlias');
+            $feature->setUrl(BuildUrlExtended::getProvisioningUrl('domainAlias'));
+            $this->addFeature($feature);
+        }
+
+        /**
+         *
+         * check if webmail is enabled
+         */
+        if($productManager->isControllerAccessible(ControllerEnums::WEBMAIL_PAGE)) {
+            $feature = new FeatureField('goWebmail');
+            $feature->setTargetBlank(true);
+            $feature->setUrl(BuildUrlExtended::getProvisioningUrl('webmail'));
+            $this->addFeature($feature);
+        }
+    }
+
+    /**
+     * @param FeatureField $feature
+     * @return $this
+     */
+    protected function addFeature(FeatureField $feature)
+    {
+        $this->featureContainer[$feature->getId()] = $feature;
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getFeatures()
+    {
+        return $this->featureContainer;
+    }
+
+}

+ 26 - 0
app/UI/Client/Ressource/Buttons/AddRessourceButton.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\AddRessourceModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class AddRessourceButton
+ */
+class AddRessourceButton extends ButtonCreate implements ClientArea
+{
+    protected $id    = 'addRessourceButton';
+    protected $title = 'addRessourceButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new AddRessourceModal());
+    }
+
+
+}

+ 30 - 0
app/UI/Client/Ressource/Buttons/ChangePasswordButton.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\ChangePasswordModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:07
+ * Class ChangePassword
+ */
+class ChangePasswordButton extends ButtonDropdownItem implements ClientArea
+{
+    protected $id    = 'changePassword';
+    protected $title = 'changePassword';
+    protected $icon  = 'lu-dropdown__link-icon lu-btn__icon lu-zmdi lu-zmdi-lock';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new ChangePasswordModal());
+    }
+
+}

+ 31 - 0
app/UI/Client/Ressource/Buttons/ChangeStatusButton.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class ChangeStatusButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\AddRessourceModal;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\ChangeStatusModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+class ChangeStatusButton extends ButtonDropdownItem implements ClientArea
+{
+    protected $id    = 'changeStatusButton';
+    protected $title = 'changeStatusButton';
+    protected $icon  = 'lu-dropdown__link-icon lu-btn__icon lu-zmdi lu-zmdi-refresh-sync';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new ChangeStatusModal());
+    }
+
+}

+ 31 - 0
app/UI/Client/Ressource/Buttons/DeleteRessourceButton.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\DeleteRessourceModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:27
+ * Class DeleteRessourceButton
+ */
+class DeleteRessourceButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'deleteRessourceButton';
+    protected $title = 'deleteRessourceButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn();
+        $this->initLoadModalAction(new DeleteRessourceModal());
+    }
+
+}

+ 32 - 0
app/UI/Client/Ressource/Buttons/EditRessourceButton.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\EditRessourceModal;
+use \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\AddRessourceModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCustomAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:29
+ * Class EditRessourceButton
+ */
+class EditRessourceButton extends ButtonDataTableModalAction implements ClientArea
+{
+    protected $id    = 'editRessourceButton';
+    protected $title = 'editRessourceButton';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new EditRessourceModal());
+    }
+
+}

+ 103 - 0
app/UI/Client/Ressource/Buttons/LoginToPanelButton.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\Helper\BuildUrl;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonRedirect;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 16:44
+ * Class LoginToPanel
+ */
+class LoginToPanelButton extends ButtonDropdownItem implements ClientArea
+{
+    protected $icon           = 'lu-dropdown__link-icon lu-btn__icon lu-zmdi lu-zmdi-email';
+
+    protected $rawUrl = null;
+    protected $redirectParams = [];
+
+    public function initContent()
+    {
+        $this->htmlAttributes['@click.middle'] = 'redirect($event, ' . $this->parseCustomParams() . ', true)';
+        $this->htmlAttributes['@click'] = 'redirect($event, ' . $this->parseCustomParams() . ', true)';
+
+    }
+
+    protected function parseCustomParams()
+    {
+        if (count($this->redirectParams) === 0 && $this->rawUrl === null)
+        {
+            return '{}';
+        }
+
+        return $this->parseListTOJsString($this->redirectParams);
+    }
+
+    protected function parseListTOJsString($params)
+    {
+        $jsString = '{';
+
+        if ($this->rawUrl !== null)
+        {
+            $params['rawUrl'] = $this->rawUrl;
+        }
+
+        foreach ($params as $key => $value)
+        {
+            $jsString .= ' ' . str_replace('-', '__', $key) . ': ' . (is_array($value) ? ($this->parseListTOJsString($value) . ',') : ("'" . (string) $value) . "',");
+        }
+
+        $jsString = trim($jsString, ',') . ' } ';
+
+        return $jsString;
+    }
+
+    public function setRawUrl($url)
+    {
+        $this->rawUrl = $url;
+
+        return $this;
+    }
+
+    public function addRedirectParam($key, $value)
+    {
+        $this->redirectParams[$key] = $value;
+
+        $this->updateHtmlAttributesByRedirectParams();
+
+        return $this;
+    }
+
+    public function setRedirectParams($paramsList)
+    {
+        $this->redirectParams = $paramsList;
+
+        $this->updateHtmlAttributesByRedirectParams();
+
+        return $this;
+    }
+
+    protected function updateHtmlAttributesByRedirectParams()
+    {
+        foreach ($this->redirectParams as $key => $value)
+        {
+            $this->updateHtmlAttribute($key, $value);
+        }
+    }
+
+    protected function updateHtmlAttribute($key, $value)
+    {
+        if (strpos($value, ':') === 0)
+        {
+            $this->addHtmlAttribute(':data-' . $key , 'dataRow.' . trim($value, ':'));
+        }
+    }
+}

+ 28 - 0
app/UI/Client/Ressource/Buttons/MassChangeStatusButton.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Class MassChangeStatusButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\MassChangeStatusModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class MassChangeStatusButton extends ButtonMassAction implements ClientArea
+{
+    protected $id    = 'massChangeStatusButton';
+    protected $title = 'massChangeStatusButton';
+    protected $icon  = 'lu-btn__icon lu-zmdi lu-zmdi-refresh-sync';
+
+    public function initContent()
+    {
+        $this->initLoadModalAction(new MassChangeStatusModal());
+    }
+
+}

+ 28 - 0
app/UI/Client/Ressource/Buttons/MassDeleteRessourceButton.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Class MassDeleteRessourceButton
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals\MassDeleteRessourceModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction;
+
+class MassDeleteRessourceButton extends ButtonMassAction implements ClientArea
+{
+
+    protected $id    = 'massDeleteRessourceButton';
+    protected $title = 'massDeleteRessourceButton';
+
+    public function initContent()
+    {
+        $this->switchToRemoveBtn(); 
+        $this->initLoadModalAction(new MassDeleteRessourceModal());
+    }
+}

+ 19 - 0
app/UI/Client/Ressource/Buttons/SpanDropdownButton.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdown;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 13.11.19
+ * Time: 08:53
+ * Class SpanDropdownButton
+ */
+class SpanDropdownButton extends ButtonDropdown
+{
+    protected $id = 'spanDropdownButton';
+}

+ 58 - 0
app/UI/Client/Ressource/Forms/AddRessourceForm.php

@@ -0,0 +1,58 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\RowSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\RessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections\AdditionalSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections\GeneralSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\PasswordsValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\RepeatPasswordValidator;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Password;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\RawSection;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class AddRessourceForm
+ */
+class AddRessourceForm extends SortedFieldForm implements ClientArea
+{
+    use FormExtendedTrait;
+
+    protected $id    = 'addRessourceForm';
+    protected $name  = 'addRessourceForm';
+    protected $title = 'addRessourceForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::CREATE);
+        $this->setProvider(new RessourceDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function initFields()
+    {
+        $this->addSection(new GeneralSection());
+        $this->addSection(new AdditionalSection());
+
+
+    }
+}

+ 58 - 0
app/UI/Client/Ressource/Forms/ChangePasswordForm.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\EditRessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\Validators\PasswordsValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\RepeatPasswordValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Password;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:07
+ * Class ChangePasswordForm
+ */
+class ChangePasswordForm extends BaseForm implements ClientArea
+{
+
+
+    protected $id    = 'changePasswordForm';
+    protected $name  = 'changePasswordForm';
+    protected $title = 'changePasswordForm';
+
+    protected function getDefaultActions()
+    {
+        return ['changePassword'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('changePassword');
+        $this->dataProvider = new EditRessourceDataProvider();
+
+        $field = new Hidden('id');
+        $this->addField($field);
+
+        /**end**/
+        $field = new Password('password');
+        $field->setDescription('description');
+        $field->addValidator(new PasswordsValidator());
+        $field->notEmpty();
+        $this->addField($field);
+
+        $field = (new Password('repeat_password'))->addValidator(new RepeatPasswordValidator());
+        $field->notEmpty();
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+
+}

+ 47 - 0
app/UI/Client/Ressource/Forms/ChangeStatusForm.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\RessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\EditRessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 16.10.19
+ * Time: 13:20
+ * Class ChangeStatusForm
+ */
+class ChangeStatusForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'changeStatusForm';
+    protected $name  = 'changeStatusForm';
+    protected $title = 'changeStatusForm';
+
+    protected function getDefaultActions()
+    {
+        return ['updateStatus'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('updateStatus');
+        $this->dataProvider = new EditRessourceDataProvider();
+
+        $field = new Hidden('id');
+        $this->addField($field);
+
+        $field = new Select('status');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+
+}

+ 40 - 0
app/UI/Client/Ressource/Forms/DeleteRessourceForm.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\DeleteRessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:28
+ * Class DeleteRessourceForm
+ */
+class DeleteRessourceForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'deleteRessourceForm';
+    protected $name  = 'deleteRessourceForm';
+    protected $title = 'deleteRessourceForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::DELETE);
+        $this->dataProvider = new DeleteRessourceDataProvider();
+
+        $this->setConfirmMessage('confirmRemoveRessource');
+
+        $field = new Hidden();
+        $field->setId('id');
+        $field->setName('id');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+}

+ 55 - 0
app/UI/Client/Ressource/Forms/EditRessourceForm.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Forms\SortedFieldForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\RowSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\RessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\EditRessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections\EditAdditionalSection;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections\EditGeneralSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\HalfPageSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:29
+ * Class EditRessourceForm
+ */
+class EditRessourceForm extends SortedFieldForm implements ClientArea
+{
+    use FormExtendedTrait;
+
+    protected $id    = 'editRessourceForm';
+    protected $name  = 'editRessourceForm';
+    protected $title = 'editRessourceForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::UPDATE);
+        $this->setProvider(new EditRessourceDataProvider());
+        $this->initFields();
+        $this->loadDataToForm();
+    }
+
+    public function initFields()
+    {
+        $this->addSection(new EditGeneralSection());
+
+        $this->addSection(new EditAdditionalSection());
+    }
+}

+ 38 - 0
app/UI/Client/Ressource/Forms/MassChangeStatusForm.php

@@ -0,0 +1,38 @@
+<?php
+/**
+ * Class MassChangeStatusForm
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 12:26
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\RessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class MassChangeStatusForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'massChangeStatusForm';
+    protected $name  = 'massChangeStatusForm';
+    protected $title = 'massChangeStatusForm';
+
+    public function initContent()
+    {
+        $this->setFormType(FormConstants::UPDATE);
+        $this->dataProvider = new RessourceDataProvider();
+
+        $field = new Select('status');
+        $this->addField($field);
+
+        $this->loadDataToForm();
+    }
+
+}

+ 42 - 0
app/UI/Client/Ressource/Forms/MassDeleteRessourceForm.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class MassDeleteRessourceForm
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\DistributionList\Providers\DeleteListDataProvider;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers\DeleteRessourceDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\BaseForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\FormConstants;
+
+class MassDeleteRessourceForm extends BaseForm implements ClientArea
+{
+    protected $id    = 'massDeleteRessourceForm';
+    protected $name  = 'massDeleteRessourceForm';
+    protected $title = 'massDeleteRessourceForm';
+
+    protected function getDefaultActions()
+    {
+        return ['massDelete'];
+    }
+
+    public function initContent()
+    {
+        $this->setFormType('massDelete');
+        $this->dataProvider = new DeleteRessourceDataProvider();
+
+        $this->setConfirmMessage('massDeleteRessourceFormConfirm');
+
+
+        $this->loadDataToForm();
+    }
+
+}

+ 26 - 0
app/UI/Client/Ressource/Modals/AddRessourceModal.php

@@ -0,0 +1,26 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Modals\ModalExtendedTabsEdit;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\AddRessourceForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class AddRessourceModal
+ */
+class AddRessourceModal extends ModalExtendedTabsEdit implements ClientArea
+{
+    protected $id    = 'addRessourceModal';
+    protected $name  = 'addRessourceModal';
+    protected $title = 'addRessourceModal';
+
+    public function initContent()
+    {
+        $this->addForm(new AddRessourceForm());
+    }
+}

+ 29 - 0
app/UI/Client/Ressource/Modals/ChangePasswordModal.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\ChangePasswordForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\EditRessourceForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 12:07
+ * Class ChangePasswordModal
+ */
+class ChangePasswordModal extends BaseEditModal implements ClientArea
+{
+    protected $id    = 'changePasswordModal';
+    protected $name  = 'changePasswordModal';
+    protected $title = 'changePasswordModal';
+
+    public function initContent()
+    {
+        $this->addForm(new ChangePasswordForm());
+    }
+}

+ 29 - 0
app/UI/Client/Ressource/Modals/ChangeStatusModal.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Class ChangeStatusModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\ChangeStatusForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\EditRessourceForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+class ChangeStatusModal extends BaseEditModal implements ClientArea
+{
+    protected $id    = 'changeStatusModal';
+    protected $name  = 'changeStatusModal';
+    protected $title = 'changeStatusModal';
+
+    public function initContent()
+    {
+        $this->addForm(new ChangeStatusForm());
+    }
+}

+ 34 - 0
app/UI/Client/Ressource/Modals/DeleteRessourceModal.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\DeleteRessourceForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\EditRessourceForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:28
+ * Class DeleteRessourceModal
+ */
+class DeleteRessourceModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'deleteRessourceModal';
+    protected $name  = 'deleteRessourceModal';
+    protected $title = 'deleteRessourceModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+
+        $this->addForm(new DeleteRessourceForm());
+    }
+
+}

+ 30 - 0
app/UI/Client/Ressource/Modals/EditRessourceModal.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Modals\ModalExtendedTabsEdit;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\AddRessourceForm;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\EditRessourceForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:30
+ * Class EditRessourceModal
+ */
+class EditRessourceModal extends ModalExtendedTabsEdit implements ClientArea
+{
+    protected $id    = 'editRessourceModal';
+    protected $name  = 'editRessourceModal';
+    protected $title = 'editRessourceModal';
+
+    public function initContent()
+    {
+        $this->addForm(new EditRessourceForm());
+    }
+}

+ 30 - 0
app/UI/Client/Ressource/Modals/MassChangeStatusModal.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * Class MassChangeStatusModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:30
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\MassChangeStatusForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseEditModal;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class MassChangeStatusModal extends BaseEditModal implements ClientArea
+{
+
+    protected $id    = 'massChangeStatusModal';
+    protected $name  = 'massChangeStatusModal';
+    protected $title = 'massChangeStatusModal';
+
+    public function initContent()
+    {
+        $this->addForm(new MassChangeStatusForm());
+    }
+
+}

+ 31 - 0
app/UI/Client/Ressource/Modals/MassDeleteRessourceModal.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Class MassDeleteRessourceModal
+ * User: Nessandro
+ * Date: 2019-10-11
+ * Time: 11:29
+ * @package ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals
+ */
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Modals;
+
+
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Forms\MassDeleteRessourceForm;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Modals\BaseModal;
+
+class MassDeleteRessourceModal extends BaseModal implements ClientArea
+{
+
+    protected $id    = 'massDeleteRessourceModal';
+    protected $name  = 'massDeleteRessourceModal';
+    protected $title = 'massDeleteRessourceModal';
+
+    public function initContent()
+    {
+        $this->setSubmitButtonClassesDanger();
+        $this->setModalTitleTypeDanger();
+        $this->addForm(new MassDeleteRessourceForm());
+    }
+
+}

+ 200 - 0
app/UI/Client/Ressource/Pages/Ressources.php

@@ -0,0 +1,200 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Pages;
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\BuildUrlExtended;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Connection;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\RessourceHelper;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Filters\Ressources\FilterByCosId;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Fields\EnabledField;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\AddRessourceButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\ChangePasswordButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\ChangeStatusButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\DeleteRessourceButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\EditRessourceButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\LoginToPanelButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\MassChangeStatusButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\MassDeleteRessourceButton;
+use ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Buttons\SpanDropdownButton;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdown;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\Column;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\DataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Interfaces\ClientArea;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataProviders\Providers\ArrayDataProvider;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\DataTable\DataTable;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 10:51
+ * Class Ressources
+ */
+class Ressources extends DataTable implements ClientArea
+{
+
+    /**
+     * labels for statuses
+     */
+    const STATUS_LABEL = [
+        'active'        => 'success',
+        'locked'        => 'default',
+        'maintenance'   => 'warning',
+        'closed'        => 'default',
+        'lockout'       => 'info',
+        'pending'       => 'warning',
+        'default'       => 'default'
+    ];
+
+    protected $id    = 'ressources';
+    protected $name  = 'ressources';
+    protected $title = null;
+
+    /**
+     * load columns
+     */
+    protected function loadHtml()
+    {
+        $this
+            ->addColumn((new Column('ressource'))
+                ->setOrderable(DataProvider::SORT_ASC)
+                ->setSearchable(true, Column::TYPE_STRING))
+            ->addColumn((new Column('date_created'))
+                ->setOrderable()
+                ->setSearchable(true))
+            ->addColumn((new Column('capacity'))
+                ->setOrderable()
+                ->setSearchable(true))
+            ->addColumn((new Column('type'))
+                ->setOrderable()
+                ->setSearchable(true, Column::TYPE_INT))
+            ->addColumn((new Column('status'))
+                ->setOrderable()
+                ->setSearchable(true));
+    }
+
+    /**
+     * @param $key
+     * @param $row
+     * @return mixed
+     */
+    public function replaceFieldStatus($key, $row)
+    {
+        $status = self::STATUS_LABEL[$row[$key]] ? self::STATUS_LABEL[$row[$key]] : self::STATUS_LABEL['default'];
+        $label = di('lang')->absoluteT('kerio','account','status',$row[$key]);
+
+        $field = new EnabledField();
+        $field->setRawType($status);
+        $field->setRawTitle($label);
+
+        return $field->getHtml();
+    }
+
+    /**
+     * @param $key
+     * @param $row
+     * @return mixed
+     */
+    public function replaceFieldLast_login($key, $row)
+    {
+        return $row[$key] ? $row[$key] : '-';
+    }
+
+    /**
+     * @param $key
+     * @param $row
+     * @return mixed
+     */
+    public function replaceFieldType($key, $row)
+    {
+        return $row[$key] == 'Location' ? di('lang')->absoluteT('kerio','ressource','type','location') : di('lang')->absoluteT('kerio','ressource','type','equipment');
+    }
+
+    /**
+     * load buttons
+     */
+    public function initContent()
+    {
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($this->getRequestValue('id'));
+
+        $this->addMassActionButton(new MassChangeStatusButton());
+        $this->addMassActionButton(new MassDeleteRessourceButton());
+
+        $this->addButton(new AddRessourceButton());
+
+
+        $this->addActionButton(new EditRessourceButton());
+        $this->addActionButton(new DeleteRessourceButton());
+
+        $mailBox = new LoginToPanelButton();
+        $mailBox
+            ->setRawUrl(BuildUrlExtended::getProvisioningUrl('webmail', true, true,'clientSso'))
+            ->setRedirectParams(['actionElementId' => 'true']);
+
+        $actions = new SpanDropdownButton('actions');
+        $actions->addButton(new ChangeStatusButton());
+        $actions->addButton(new ChangePasswordButton());
+
+        if ($productManager->get('ca_logInToMailboxButton') === 'on')
+        {
+            $actions->addButton($mailBox);
+        }
+
+        $this->addActionButton($actions);
+
+    }
+
+    /**
+     * load data
+     */
+    public function loadData()
+    {
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $this->getRequestValue('id'))->first();
+
+
+        $ressources = (new KerioManager())
+            ->getApiByServer($hosting->server)
+            ->soap
+            ->repository()
+            ->ressources
+            ->getByDomainName($hosting->domain);
+
+        /**
+         * format model to array
+         */
+        $data = [];
+        foreach ($ressources as $ressource)
+        {
+            /* @var $account Ressource */
+
+            $ressourceArray = [
+                'id'           => $ressource->getId(),
+                'ressource'    => $ressource->getDataResourceA('displayName'),
+                'date_created' => RessourceHelper::getFormattedData($ressource->getDataResourceA('kerioCreateTimestamp')),
+//                'last_login'   => RessourceHelper::getFormattedData($ressource->getDataResourceA('kerioLastLogonTimestamp'), 'd/m/Y H:i'),
+                'capacity'     => $ressource->getDataResourceA('kerioCalResCapacity'),
+                'type'         => $ressource->getDataResourceA('kerioCalResType'),
+                'status'       => $ressource->getDataResourceA('kerioAccountStatus')
+            ];
+
+            $data[] = $ressourceArray;
+        }
+
+        $dataProv = new ArrayDataProvider();
+        $dataProv->setDefaultSorting('ressource', 'ASC')->setData($data);
+
+        $this->setDataProvider($dataProv);
+    }
+
+}

+ 116 - 0
app/UI/Client/Ressource/Providers/DeleteRessourceDataProvider.php

@@ -0,0 +1,116 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Delete\DeleteRessource;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 11:28
+ * Class DeleteRessourceDataProvider
+ */
+class DeleteRessourceDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        $this->data['id'] = $this->actionElementId;
+    }
+
+    public function update()
+    {
+        // TODO: Implement update() method.
+    }
+
+    public function delete()
+    {
+
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteRessource();
+        /**
+         *
+         * set product manager & form data to service
+         */
+        $service
+            ->setFormData($this->formData);
+
+        /**
+         *
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('ressourceHasBeenDeleted')->setStatusSuccess();
+
+    }
+
+    public function massDelete()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->deleteRessource();
+
+        /**
+         *
+         */
+        foreach($this->request->get('massActions') as $id)
+        {
+            $service->setFormData(['id' => $id]);
+            $result = $service->run();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('massRessourceHasBeenDeleted')->setStatusSuccess();
+    }
+}

+ 274 - 0
app/UI/Client/Ressource/Providers/EditRessourceDataProvider.php

@@ -0,0 +1,274 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Response;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Services\Update\UpdateRessource;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\ClassOfServicesOptions;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 18.09.19
+ * Time: 09:35
+ * Class EditRessourceDataProvider
+ */
+class EditRessourceDataProvider extends BaseDataProvider
+{
+
+    /**
+     *
+     */
+    public function read()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->getRequestValue('id');
+        /**
+         * load hosting
+         */
+        $hosting = Hosting::where('id', $hid)->first();
+
+        /**
+         * load api
+         */
+        $api = (new KerioManager())->getApiByServer($hosting->server);
+
+        $repository = new Repository($api->soap);
+
+        $result = $repository->ressources->getRessourceOptionsById($this->actionElementId);
+
+        if($result instanceof Response && $result->getLastError())
+        {
+            throw new \Exception($result->getLastError());
+        }
+
+        $mailBoxParams               = explode('@', $result->getName());
+        $this->data['id']            = $result->getId();
+        $this->data['username']      = $mailBoxParams[0];
+        $this->data['domain']        = $mailBoxParams[1];
+        $this->data['status']        = $result->getDataResourceA(Ressource::ATTR_STATUS);
+        $this->data['type']          = $result->getDataResourceA(Ressource::ATTR_TYPE);
+        $this->data['display_name']  = $result->getDataResourceA(Ressource::ATTR_DISPLAY_NAME);
+        $this->data['description']   = $result->getDataResourceA(Ressource::ATTR_DESC);
+        $this->data['capacity']      = $result->getDataResourceA(Ressource::ATTR_CAPACITY);
+        $this->data['notes']         = $result->getDataResourceA(Ressource::ATTR_NOTE);
+        $this->data['contact']       = $result->getDataResourceA(Ressource::ATTR_CONT);
+        $this->data['site']          = $result->getDataResourceA(Ressource::ATTR_SITE);
+        $this->data['contact_mail']  = $result->getDataResourceA(Ressource::ATTR_CONT_EMAIL);
+        $this->data['contact_phone'] = $result->getDataResourceA(Ressource::ATTR_CONT_PHONE);
+        $this->data['street']        = $result->getDataResourceA(Ressource::ATTR_STREET);
+        $this->data['building']      = $result->getDataResourceA(Ressource::ATTR_BUILDING);
+        $this->data['floor']         = $result->getDataResourceA(Ressource::ATTR_FLOOR);
+        $this->data['room']          = $result->getDataResourceA(Ressource::ATTR_ROOM);
+        $this->data['post_code']     = $result->getDataResourceA(Ressource::ATTR_POSTAL_CODE);
+        $this->data['town']          = $result->getDataResourceA(Ressource::ATTR_TOWN);
+        $this->data['state']         = $result->getDataResourceA(Ressource::ATTR_STATE);
+        $this->data['county']        = $result->getDataResourceA(Ressource::ATTR_COUNTY);
+        $this->data['auto_accept']   = $result->getDataResourceA(Ressource::ATTR_AUTO) == 'TRUE' ? 'on' : 'off';
+        $this->data['auto_busy']     = $result->getDataResourceA(Ressource::ATTR_BUSY) == 'TRUE' ? 'on' : 'off';
+
+        $lang = di('lang');
+        $this->availableValues['status'] = [
+            Kerio::ACC_STATUS_ACTIVE        => $lang->absoluteT('kerio','account','status','active'),
+            Kerio::ACC_STATUS_LOCKED        => $lang->absoluteT('kerio','account','status','locked'),
+            Kerio::ACC_STATUS_MAINTENANCE   => $lang->absoluteT('kerio','account','status','maintenance'),
+            Kerio::ACC_STATUS_CLOSED        => $lang->absoluteT('kerio','account','status','closed'),
+            Kerio::ACC_STATUS_LOCKOUT       => $lang->absoluteT('kerio','account','status','lockout'),
+            Kerio::ACC_STATUS_PENDING       => $lang->absoluteT('kerio','account','status','pending')
+        ];
+
+        $this->availableValues['type'] = [
+            Kerio::RES_TYPE_LOCATION        => $lang->absoluteT('kerio','ressource','type','location'),
+            Kerio::RES_TYPE_EQUIPMENT       => $lang->absoluteT('kerio','ressource','type','equipment')
+        ];
+
+    }
+
+    /**
+     * @return HtmlDataJsonResponse
+     */
+    public function update()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        $fieldToProtection = [
+            'display_name',
+            'status',
+            'type',
+            'capacity',
+            'description',
+            'notes',
+            'contact',
+            'site',
+            'contact_mail',
+            'contact_phone',
+            'street',
+            'building',
+            'floor',
+            'room',
+            'post_code',
+            'town',
+            'state',
+            'county',
+            'auto_accept',
+            'auto_busy'
+        ];
+
+        foreach ($this->formData as $field => &$value)
+        {
+            $value = in_array($field, $fieldToProtection) ? htmlentities($value) : $value;
+        }
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateRessource();
+        /**
+         *
+         * set product manager & form data to service
+         */
+        $service
+            ->setProductManager($productManager)
+            ->setFormData($this->formData);
+
+        /**
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('ressourceHasBeenUpdated')->setStatusSuccess();
+    }
+
+    /**
+     * @return HtmlDataJsonResponse
+     */
+    public function updateStatus()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateRessourceStatus()
+            ->setProductManager($productManager)
+        ;
+        /**
+         *
+         * set product manager & form data to service
+         */
+
+        /**
+         * run service for each id
+         */
+        $service->setFormData($this->formData);
+        $result = $service->run();
+
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        /**
+         * return success
+         */
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('ressourceStatusHasBeenUpdated')->setStatusSuccess();
+
+    }
+
+    /**
+     * @return HtmlDataJsonResponse
+     */
+    public function changePassword()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateRessourcePassword()
+            ->setProductManager($productManager)
+        ;
+        /**
+         *
+         * set product manager & form data to service
+         */
+
+        /**
+         * run service for each id
+         */
+        $service->setFormData($this->formData);
+        $result = $service->run();
+
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('passwordChangedSuccessfully')->setStatusSuccess();
+    }
+}

+ 185 - 0
app/UI/Client/Ressource/Providers/RessourceDataProvider.php

@@ -0,0 +1,185 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Providers;
+use ModulesGarden\Servers\KerioEmail\App\Enums\ProductParams;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Size;
+use ModulesGarden\Servers\KerioEmail\App\Enums\Kerio;
+use ModulesGarden\Servers\KerioEmail\App\Helpers\KerioManager;
+use ModulesGarden\Servers\KerioEmail\App\Http\Admin\ProductConfiguration;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Helpers\ServiceFactory;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\Ressource;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Models\ClassOfService;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Services\ConfigurableOptions\Strategy\Types\ClassOfServicesOptions;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Hosting;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\HtmlDataJsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\DataProviders\BaseDataProvider;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.09.19
+ * Time: 13:06
+ * Class RessourceDataProvider
+ */
+class RessourceDataProvider extends BaseDataProvider
+{
+
+    public function read()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        $hosting = Hosting::where('id', $hid)->first();
+        //todo refactor
+        $this->data['domain'] = $hosting->domain;
+
+        $lang = di('lang');
+        $this->availableValues['status'] = [
+            Kerio::ACC_STATUS_ACTIVE        => $lang->absoluteT('kerio','account','status','active'),
+            Kerio::ACC_STATUS_LOCKED        => $lang->absoluteT('kerio','account','status','locked'),
+            Kerio::ACC_STATUS_MAINTENANCE   => $lang->absoluteT('kerio','account','status','maintenance'),
+            Kerio::ACC_STATUS_CLOSED        => $lang->absoluteT('kerio','account','status','closed'),
+            Kerio::ACC_STATUS_LOCKOUT       => $lang->absoluteT('kerio','account','status','lockout'),
+            Kerio::ACC_STATUS_PENDING       => $lang->absoluteT('kerio','account','status','pending')
+        ];
+
+        $this->availableValues['type'] = [
+            Kerio::RES_TYPE_LOCATION        => $lang->absoluteT('kerio','ressource','type','location'),
+            Kerio::RES_TYPE_EQUIPMENT       => $lang->absoluteT('kerio','ressource','type','equipment')
+        ];
+
+    }
+
+    public function create()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        $fieldToProtection = [
+            'display_name',
+            'status',
+            'type',
+            'capacity',
+            'description',
+            'notes',
+            'contact',
+            'site',
+            'contact_mail',
+            'contact_phone',
+            'street',
+            'building',
+            'floor',
+            'room',
+            'post_code',
+            'town',
+            'state',
+            'county',
+            'auto_accept',
+            'auto_busy'
+        ];
+
+        foreach ($this->formData as $field => &$value)
+        {
+            $value = in_array($field, $fieldToProtection) ? htmlentities($value) : $value;
+        }
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->createRessource();
+        /**
+         *
+         * set product manager & form data to service
+         */
+        $service
+            ->setProductManager($productManager)
+            ->setFormData($this->formData);
+
+        /**
+         *
+         * run service
+         */
+        $result = $service->run();
+
+        /**
+         *
+         * return success or error response
+         */
+        if(!$result)
+        {
+            return (new HtmlDataJsonResponse())->setMessageAndTranslate($service->getError())->setStatusError();
+        }
+
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('ressourceHasBeenAdded')->setStatusSuccess();
+
+    }
+
+    public function updateStatus()
+    {
+
+
+    }
+
+    public function update()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->request->get('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         *
+         * get soap create domain  service
+         */
+        $service =(new KerioManager())
+            ->getApiByHosting($hid)
+            ->soap
+            ->service()
+            ->updateRessourceStatus()
+            ->setProductManager($productManager)
+        ;
+        /**
+         *
+         * set product manager & form data to service
+         */
+
+        /**
+         * run service for each id
+         */
+        foreach($this->request->get('massActions') as $id)
+        {
+            $service->setFormData(['status' => $this->formData['status'], 'id' => $id]);
+            $result = $service->run();
+        }
+
+        /**
+         * return success
+         */
+        return (new HtmlDataJsonResponse())->setMessageAndTranslate('massRessourceStatusHasBeenUpdated')->setStatusSuccess();
+    }
+}

+ 43 - 0
app/UI/Client/Ressource/Sections/AdditionalSection.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use function ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:42
+ * Class AdditionalSection
+ */
+class AdditionalSection extends FreeFieldsSection
+{
+    protected $id   = 'additionalSection';
+    protected $name = 'additionalSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        $this->generateDoubleSection([new Text('contact'), new Text('site')]);
+
+        $this->generateDoubleSection([new Text('contact_mail'), new Text('contact_phone')]);
+
+        $this->generateDoubleSection([new Text('street'), new Text('building')]);
+
+        $this->generateDoubleSection([new Text('floor'), new Text('room')]);
+
+        $this->generateDoubleSection([new Text('post_code'), new Text('town')]);
+
+        $this->generateDoubleSection([new Text('state'), new Text('county')]);
+
+    }
+}

+ 41 - 0
app/UI/Client/Ressource/Sections/EditAdditionalSection.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:52
+ * Class EditAdditionalSection
+ */
+class EditAdditionalSection extends FreeFieldsSection
+{
+    protected $id   = 'editAdditionalSection';
+    protected $name = 'editAdditionalSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        $this->generateDoubleSection([new Text('contact'), new Text('site')]);
+
+        $this->generateDoubleSection([new Text('contact_mail'), new Text('contact_phone')]);
+
+        $this->generateDoubleSection([new Text('street'), new Text('building')]);
+
+        $this->generateDoubleSection([new Text('floor'), new Text('room')]);
+
+        $this->generateDoubleSection([new Text('post_code'), new Text('town')]);
+
+        $this->generateDoubleSection([new Text('state'), new Text('county')]);
+
+    }
+
+}

+ 76 - 0
app/UI/Client/Ressource/Sections/EditGeneralSection.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections;
+
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:52
+ * Class EditGeneralSection
+ */
+class EditGeneralSection extends FreeFieldsSection
+{
+    protected $id   = 'editGeneralSection';
+    protected $name = 'editGeneralSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->getRequestValue('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        /**
+         * add fields
+         */
+        $field = new Hidden('id');
+        $this->addField($field);
+
+        $email =new InputGroup('usernameGroup');
+
+        $email->addInputComponent((new InputGroupElements\Text('username'))->addHtmlAttribute('readonly','true'));
+        $email->addInputAddon('emailSign', false, '@');
+        $email->addInputComponent((new InputGroupElements\Text('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $this->generateDoubleSection([new Text('display_name'), new Select('status')]);
+
+        $type = new Select('type');
+        $capacity = new Text('capacity');
+
+        $this->generateDoubleSection([$type, $capacity]);
+
+        $field = new Text('description');
+        $this->addField($field);
+
+        $field = new Text('notes');
+        $this->addField($field);
+
+        $autoAcceptDecline = new Switcher('auto_accept');
+        $autoDeclineBusy = new Switcher('auto_busy');
+        $this->generateDoubleSection([$autoAcceptDecline, $autoDeclineBusy]);
+
+    }
+}

+ 81 - 0
app/UI/Client/Ressource/Sections/GeneralSection.php

@@ -0,0 +1,81 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\UI\Client\Ressource\Sections;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Product\ProductManager;
+use ModulesGarden\Servers\KerioEmail\App\Libs\Kerio\Components\Api\Soap\Repository\ClassOfServices;
+use ModulesGarden\Servers\KerioEmail\App\Traits\FormExtendedTrait;
+use ModulesGarden\Servers\KerioEmail\App\UI\Admin\Custom\Sections\FreeFieldsSection;
+use ModulesGarden\Servers\KerioEmail\App\Validators\PasswordsValidator;
+use ModulesGarden\Servers\KerioEmail\App\Validators\RepeatPasswordValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Hidden;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Password;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Select;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Text;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Switcher;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\Number;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Sections\InputGroup;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Fields\InputGroupElements;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 12.11.19
+ * Time: 13:39
+ * Class GeneralSection
+ */
+class GeneralSection extends FreeFieldsSection
+{
+    protected $id   = 'generalSection';
+    protected $name = 'generalSection';
+
+    use FormExtendedTrait;
+
+    public function initContent()
+    {
+        /**
+         * hosting id
+         */
+        $hid = $this->getRequestValue('id');
+
+        /**
+         * product manager allow to check product settings
+         */
+        $productManager = new ProductManager();
+        $productManager->loadByHostingId($hid);
+
+        $email = new InputGroup('usernameGroup');
+
+        $email->addTextField('username', false, true);
+        $email->addInputAddon('emailSign', false, '@');
+        $email->addInputComponent((new InputGroupElements\Text('domain'))->addHtmlAttribute('readonly','true'));
+        $this->addSection($email);
+
+        $this->generateDoubleSection([new Text('display_name'), new Select('status')]);
+
+        $passwd = new Password('password');
+        $passwd->setDescription('description');
+        $passwd->addValidator(new PasswordsValidator());
+        $passwd->notEmpty();
+
+        $repPasswd = (new Password('repeat_password'))->addValidator(new RepeatPasswordValidator());
+        $repPasswd->notEmpty();
+
+        $this->generateDoubleSection([$passwd, $repPasswd]);
+
+        $type = new Select('type');
+        $capacity = new Text('capacity');
+
+        $this->generateDoubleSection([$type, $capacity]);
+
+        $field = new Text('description');
+        $this->addField($field);
+
+        $field = new Text('notes');
+        $this->addField($field);
+
+        $autoAcceptDecline = (new Switcher('auto_accept'))->setDefaultValue('on');
+        $autoDeclineBusy = (new Switcher('auto_busy'))->setDefaultValue('on');
+        $this->generateDoubleSection([$autoAcceptDecline, $autoDeclineBusy]);
+
+    }
+}

+ 21 - 0
app/UI/Client/Templates/assets/css/integration.css

@@ -0,0 +1,21 @@
+#contentarea > div > h1 {
+    display: block!important;
+}
+
+#contentarea {
+    margin: 10px;
+    padding: 15px;
+    min-height: 600px;
+    background-color: #fff;
+    border: 4px solid #e2e7e9;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    -o-border-radius: 10px;
+    border-radius: 10px;
+    overflow: auto;
+}
+
+.mg-integration-container .lu-app {
+    height: 0px;
+    visibility: hidden;
+}

+ 5 - 0
app/UI/Client/Templates/assets/css/module_styles.css

@@ -0,0 +1,5 @@
+.lu-modal_fixed_position  {
+    position:absolute;
+    top:5px;
+    margin-bottom: 20px;
+}

BIN
app/UI/Client/Templates/assets/icons/distributionList.png


BIN
app/UI/Client/Templates/assets/icons/domainAlias.png


BIN
app/UI/Client/Templates/assets/icons/emailAccount.png


BIN
app/UI/Client/Templates/assets/icons/emailAlias.png


BIN
app/UI/Client/Templates/assets/icons/goWebmail.png


BIN
app/UI/Client/Templates/assets/icons/ressource.png


+ 0 - 0
app/UI/Client/Templates/assets/js/.gitkeep


+ 18 - 0
app/UI/Client/Templates/assets/js/distributionList/index.js

@@ -0,0 +1,18 @@
+/**
+ *
+ *
+ * Modal position fix.
+ * add custom class if modal height is bigger than window.
+ */
+mgEventHandler.on('ModalLoaded', null,function(){
+
+    $('.lu-modal__dialog').each(function(index){
+        var self = $(this);
+        var pixelDiff = $(window).height() - self.height();
+
+        if(pixelDiff < 30)
+        {
+            self.addClass('lu-modal_fixed_position');
+        }
+    });
+});

+ 18 - 0
app/UI/Client/Templates/assets/js/emailAccount/index.js

@@ -0,0 +1,18 @@
+/**
+ *
+ *
+ * Modal position fix.
+ * add custom class if modal height is bigger than window.
+ */
+mgEventHandler.on('ModalLoaded', null,function(){
+
+    $('.lu-modal__dialog').each(function(index){
+        var self = $(this);
+        var pixelDiff = $(window).height() - self.height();
+
+        if(pixelDiff < 30)
+        {
+            self.addClass('lu-modal_fixed_position');
+        }
+    });
+});

+ 18 - 0
app/UI/Client/Templates/assets/js/ressource/index.js

@@ -0,0 +1,18 @@
+/**
+ *
+ *
+ * Modal position fix.
+ * add custom class if modal height is bigger than window.
+ */
+mgEventHandler.on('ModalLoaded', null,function(){
+
+    $('.lu-modal__dialog').each(function(index){
+        var self = $(this);
+        var pixelDiff = $(window).height() - self.height();
+
+        if(pixelDiff < 30)
+        {
+            self.addClass('lu-modal_fixed_position');
+        }
+    });
+});

+ 5 - 0
app/UI/Client/Templates/emailAccount/buttons/spanDropdownButton.tpl

@@ -0,0 +1,5 @@
+<mg-component-body-{$elementId|strtolower}
+        component_id='{$elementId}'
+        component_namespace='{$namespace}'
+        component_index='{$rawObject->getIndex()}'
+></mg-component-body-{$elementId|strtolower}>

+ 30 - 0
app/UI/Client/Templates/emailAccount/buttons/spanDropdownButton_components.tpl

@@ -0,0 +1,30 @@
+
+<script type="text/x-template" id="t-mg-dropdawn-btn-wrapper-{$elementId|strtolower}"
+        :component_id="component_id"
+        :component_namespace="component_namespace"
+        :component_index="component_index"
+>
+    <span class="lu-has-dropdown">
+        <button @click="toogleDropdawn" class="mg-drop-target-btn lu-btn lu-btn--icon lu-btn--link lu-btn--default" data-tooltip="" data-title="{$MGLANG->T('More Actions')}">
+            <i class="lu-btn__icon lu-zmdi lu-zmdi-more-vert"></i>
+        </button>
+        <div class="mg-drop-bg-wrapper" v-show="dropOpen" @click="hideDrop"></div>
+        <div v-show="dropOpen"  @click="notHideDrop" class="drop lu-drop-element drop-enabled drop-element-attached-top drop-element-attached-left drop-target-attached-bottom drop-target-attached-left drop-open drop-open-transitionend drop-after-open">
+            <div class="drop-content">
+                <div class="lu-dropdown" data-dropdown-menu="">
+                    <div class="lu-dropdown__arrow" data-arrow="" style="left: auto; right: 10px;"></div>
+                    <ul class="lu-dropdown__menu">
+                        <li class="lu-dropdown__header">
+                            <span class="lu-dropdown__title">{$MGLANG->T('Additional Actions')}</span>
+                        </li>
+                        {foreach from=$rawObject->getButtons() key=buttonKey item=buttonValue}
+                            <li class="lu-dropdown__item">
+                                {$buttonValue->getHtml()}
+                            </li>
+                        {/foreach}
+                    </ul>
+                </div>
+            </div>
+        </div>
+    </span>
+</script>

+ 8 - 0
app/UI/Client/Templates/home/fields/featureField.tpl

@@ -0,0 +1,8 @@
+<div class="lu-col-sm-20p">
+    <a class="lu-tile lu-tile--btn" href="{$rawObject->getUrl()}">
+        <div class="lu-i-c-6x">
+            <img src="{$rawObject->getIcon()}" alt="">
+        </div>
+        <div class="lu-tile__title">{$MGLANG->absoluteT('addonCA' , 'homeIcons' ,$rawObject->getTitle())}</div>
+    </a>
+</div>

+ 15 - 0
app/UI/Client/Templates/home/pages/dashboard.tpl

@@ -0,0 +1,15 @@
+{if $rawObject->getFeatures()}
+    <div class="lu-h4 lu-m-b-3x lu-m-t-3x">{$MGLANG->absoluteT('addonCA','homePage','manageHeader')}</div>
+    <div class="lu-tiles lu-row row--eq-height">
+        {foreach from=$rawObject->getFeatures() key=setting item=controller}
+            <div class="lu-col-sm-20p">
+                <a class="lu-tile lu-tile--btn" href="{$controller->getUrl()}" {if $controller->isTargetBlank()} target="_blank" {/if}>
+                    <div class="lu-i-c-6x">
+                        <img src="{$controller->getIcon()}" alt="">
+                    </div>
+                    <div class="lu-tile__title">{$MGLANG->absoluteT('addonCA' , 'homeIcons' ,$controller->getTitle())}</div>
+                </a>
+            </div>
+        {/foreach}
+    </div>
+{/if}

+ 5 - 0
app/UI/Client/Templates/ressource/buttons/spanDropdownButton.tpl

@@ -0,0 +1,5 @@
+<mg-component-body-{$elementId|strtolower}
+        component_id='{$elementId}'
+        component_namespace='{$namespace}'
+        component_index='{$rawObject->getIndex()}'
+></mg-component-body-{$elementId|strtolower}>

+ 30 - 0
app/UI/Client/Templates/ressource/buttons/spanDropdownButton_components.tpl

@@ -0,0 +1,30 @@
+
+<script type="text/x-template" id="t-mg-dropdawn-btn-wrapper-{$elementId|strtolower}"
+        :component_id="component_id"
+        :component_namespace="component_namespace"
+        :component_index="component_index"
+>
+    <span class="lu-has-dropdown">
+        <button @click="toogleDropdawn" class="mg-drop-target-btn lu-btn lu-btn--icon lu-btn--link lu-btn--default" data-tooltip="" data-title="{$MGLANG->T('More Actions')}">
+            <i class="lu-btn__icon lu-zmdi lu-zmdi-more-vert"></i>
+        </button>
+        <div class="mg-drop-bg-wrapper" v-show="dropOpen" @click="hideDrop"></div>
+        <div v-show="dropOpen"  @click="hideDrop" class="drop lu-drop-element drop-enabled drop-element-attached-top drop-element-attached-left drop-target-attached-bottom drop-target-attached-left drop-open drop-open-transitionend drop-after-open">
+            <div class="drop-content">
+                <div class="lu-dropdown" data-dropdown-menu="">
+                    <div class="lu-dropdown__arrow" data-arrow="" style="left: auto; right: 10px;"></div>
+                    <ul class="lu-dropdown__menu">
+                        <li class="lu-dropdown__header">
+                            <span class="lu-dropdown__title">{$MGLANG->T('Additional Actions')}</span>
+                        </li>
+                        {foreach from=$rawObject->getButtons() key=buttonKey item=buttonValue}
+                            <li class="lu-dropdown__item">
+                                {$buttonValue->getHtml()}
+                            </li>
+                        {/foreach}
+                    </ul>
+                </div>
+            </div>
+        </div>
+    </span>
+</script>

+ 45 - 0
app/Validators/EmailValidator.php

@@ -0,0 +1,45 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\App\Validators;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\BaseValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\boolen;
+
+/**
+ * Class EmailValidator
+ * User: Nessandro
+ * Date: 2019-10-01
+ * Time: 08:29
+ */
+
+class EmailValidator extends BaseValidator
+{
+
+    /**
+     * return true if data is valid, false if not,
+     * add error messages to $errorsList
+     *
+     * @param $data mixed
+     * @param $additionalData mixed
+     * @return boolen
+     */
+    protected function validate($data, $additionalData = null)
+    {
+        /**
+         * if is empty
+         */
+        if(!strlen(trim($data)) > 0)
+        {
+            return true;
+        }
+
+        /**
+         * check if correct email
+         */
+        if (filter_var($data, FILTER_VALIDATE_EMAIL))
+        {
+            $this->addValidationError('incorrectEmailAddress');
+            return false;
+        }
+
+        return true;
+    }
+}

+ 68 - 0
app/Validators/IntegerValueValidator.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Validators;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\BaseValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\boolen;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 08.11.19
+ * Time: 10:18
+ * Class IntegerValueValidator
+ */
+class IntegerValueValidator extends BaseValidator
+{
+
+    /**
+     * @var bool
+     */
+    protected $disableNegative = false;
+
+    /**
+     * IntegerValueValidator constructor.
+     * @param bool $disableNegative
+     */
+    public function __construct($disableNegative = false)
+    {
+        $this->disableNegative = $disableNegative;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isDisableNegative()
+    {
+        return $this->disableNegative;
+    }
+
+    /**
+     * @param bool $disableNegative
+     */
+    public function setDisableNegative($disableNegative)
+    {
+        $this->disableNegative = $disableNegative;
+    }
+
+
+
+    /**
+     * return true if data is valid, false if not,
+     * add error messages to $errorsList
+     *
+     * @param $data mixed
+     * @param $additionalData mixed
+     * @return boolen
+     */
+    protected function validate($data, $additionalData = null)
+    {
+        if(is_numeric($data))
+        {
+
+        }
+
+    }
+}

+ 58 - 0
app/Validators/PasswordsValidator.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Validators;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\BaseValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\boolen;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.10.19
+ * Time: 11:20
+ * Class PasswordsValidator
+ */
+class PasswordsValidator extends BaseValidator
+{
+
+
+    /**
+     * return true if data is valid, false if not,
+     * add error messages to $errorsList
+     *
+     * @param $data mixed
+     * @param $additionalData mixed
+     * @return boolen
+     */
+    protected function validate($data, $additionalData = null)
+    {
+        if(strlen($data) < 8)
+        {
+            $this->addValidationError('passwordCharsLengthError');
+            return false;
+        }
+
+        if (!preg_match('#[0-9]+#', $data)) {
+            $this->addValidationError('passwordNumberError');
+            return false;
+        }
+    
+        if (!preg_match('#[A-Z]+#', $data)) {
+            $this->addValidationError('passwordUpperError');
+            return false;
+        }     
+    
+        if (!preg_match('#[a-z]+#', $data)) {
+            $this->addValidationError('passwordLowerError');
+            return false;
+        }     
+    
+        if (!preg_match('#[^\w]+#', $data)) {
+            $this->addValidationError('passwordSpecialError');
+            return false;
+        }
+        return true;
+    }
+}

+ 39 - 0
app/Validators/RepeatPasswordValidator.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Validators;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\BaseValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\boolen;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 10.10.19
+ * Time: 11:21
+ * Class RepeatPasswordValidator
+ */
+class RepeatPasswordValidator extends BaseValidator
+{
+
+    /**
+     * return true if data is valid, false if not,
+     * add error messages to $errorsList
+     *
+     * @param $data mixed
+     * @param $additionalData mixed
+     * @return boolen
+     */
+    protected function validate($data, $additionalData = null)
+    {
+        $formData =  $additionalData->get('formData');
+        if($data !== $formData['password'])
+        {
+            $this->addValidationError('passwordsIsNotTheSame');
+            return false;
+        }
+
+        return true;
+    }
+}

+ 67 - 0
app/Validators/TaggerEmailValidator.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\App\Validators;
+
+
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\BaseValidator;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Forms\Validators\boolen;
+
+/**
+ *
+ * Created by PhpStorm.
+ * User: Tomasz Bielecki ( tomasz.bi@modulesgarden.com )
+ * Date: 16.10.19
+ * Time: 12:21
+ * Class TaggerEmailValidator
+ */
+class TaggerEmailValidator extends BaseValidator
+{
+
+    private $invalidEmails = [];
+
+    /**
+     * return true if data is valid, false if not,
+     * add error messages to $errorsList
+     *
+     * @param $data mixed
+     * @param $additionalData mixed
+     * @return boolen
+     */
+    protected function validate($data, $additionalData = null)
+    {
+        /**
+         * return if empty
+         */
+        if (trim($data) === '')
+        {
+            return true;
+        }
+
+        /**
+         * explode emails
+         */
+        $emails = explode(',',$data);
+
+        /**
+         * check each email and add to invalid if true
+         */
+        foreach($emails as $email)
+        {
+            if (!filter_var($email, FILTER_VALIDATE_EMAIL))
+            {
+                $this->invalidEmails[] = html_entity_decode($email);
+            }
+        }
+
+        /**
+         * return invalid message
+         */
+        if($this->invalidEmails)
+        {
+            $this->addValidationError('incorrectEmailAddresses',false,['emails' => implode(',', $this->invalidEmails)]);
+            return false;
+        }
+
+        return true;
+    }
+}

+ 20 - 0
commands/commands.php

@@ -0,0 +1,20 @@
+<?php
+
+define('DS', DIRECTORY_SEPARATOR);
+$modulePath = dirname(__DIR__);
+$whmcsPath  = dirname(dirname(dirname($modulePath)));
+
+require_once $whmcsPath . DS . 'init.php';
+require_once $modulePath . DS . 'core' . DS . 'Bootstrap.php';
+
+//cause WHMCS
+ini_set('max_execution_time', 0);
+
+$argList = $argv ? $argv : $_SERVER['argv'];
+if (count($argList) === 0)
+{
+    $argList = [__FILE__];
+}
+
+(new \ModulesGarden\Servers\KerioEmail\Core\CommandLine\CronManager())
+    ->run();

+ 43 - 0
composer.json

@@ -0,0 +1,43 @@
+{
+    "name": "ModulesGarden/Servers/KerioEmail",
+    "description": "",
+    "version": "2.0.0",
+    "type": "project",
+    "license": "EULA",
+    "homepage": "https://www.modulesgarden.com",
+    "support":
+            {
+                "email": "contact@modulesgarden.com",
+                "issues": "https://www.modulesgarden.com/customers/support",
+                "forum": "https://www.forum.modulesgarden.com/"
+            },
+    "authors": [],
+    "require":
+            {
+                "php": ">=5.5.9",
+                "symfony/http-foundation": "3.4.20",
+                "symfony/yaml": "3.3.18",
+                "symfony/dependency-injection": "3.3.18",
+                "piwik/ini": "1.0.6",
+                "symfony/cache": "3.4.20",
+                "mso/idna-convert" : "1.1.0",
+                "adbario/php-dot-notation" : "2.1.0",
+                "psr/log" : "1.1.0",
+                "psr/cache" : "1.0.1",
+                "psr/simple-cache" : " 1.0.1",
+                "symfony/polyfill-apcu" : "1.10.0",
+                "psr/container" : "1.0.0",
+                "symfony/polyfill-mbstring" : "1.10.0",
+                "symfony/polyfill-php70" : "1.10.0",
+        "rappasoft/laravel-helpers": "^1.0"
+            },
+    "autoload": {
+        "psr-4": {
+            "ModulesGarden\\Servers\\KerioEmail\\Core\\": "./core",
+            "ModulesGarden\\Servers\\KerioEmail\\App\\": "./app"
+        },
+        "files": [
+            "./core/Helper/Functions.php"
+        ]
+    }
+}

+ 851 - 0
composer.lock

@@ -0,0 +1,851 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "c5c940bd1f61818cd38576bbd4a0249e",
+    "packages": [
+        {
+            "name": "adbario/php-dot-notation",
+            "version": "2.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/adbario/php-dot-notation.git",
+                "reference": "895fe4bb153ac875c61a6fba658ded45405e73a4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/895fe4bb153ac875c61a6fba658ded45405e73a4",
+                "reference": "895fe4bb153ac875c61a6fba658ded45405e73a4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0|^5.0|^6.0",
+                "squizlabs/php_codesniffer": "^3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/helpers.php"
+                ],
+                "psr-4": {
+                    "Adbar\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Riku Särkinen",
+                    "email": "riku@adbar.io"
+                }
+            ],
+            "description": "PHP dot notation access to arrays",
+            "homepage": "https://github.com/adbario/php-dot-notation",
+            "keywords": [
+                "ArrayAccess",
+                "dotnotation"
+            ],
+            "time": "2018-07-22T12:33:53+00:00"
+        },
+        {
+            "name": "mso/idna-convert",
+            "version": "v1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/algo26-matthias/idna-convert.git",
+                "reference": "a6dfb6f87611e3a89d2eec4924a0f51db755c573"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/algo26-matthias/idna-convert/zipball/a6dfb6f87611e3a89d2eec4924a0f51db755c573",
+                "reference": "a6dfb6f87611e3a89d2eec4924a0f51db755c573",
+                "shasum": ""
+            },
+            "require": {
+                "ext-pcre": "*",
+                "php": ">=5.6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Mso\\IdnaConvert\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1+"
+            ],
+            "authors": [
+                {
+                    "name": "Matthias Sommerfeld",
+                    "email": "mso@phlylabs.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A library for encoding and decoding internationalized domain names",
+            "homepage": "http://idnaconv.net/",
+            "keywords": [
+                "idn",
+                "idna",
+                "php"
+            ],
+            "abandoned": "algo26-matthias/idna-convert",
+            "time": "2016-06-19T18:08:43+00:00"
+        },
+        {
+            "name": "paragonie/random_compat",
+            "version": "v9.99.99",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/random_compat.git",
+                "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+                "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*|5.*",
+                "vimeo/psalm": "^1"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+            },
+            "type": "library",
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+            "keywords": [
+                "csprng",
+                "polyfill",
+                "pseudorandom",
+                "random"
+            ],
+            "time": "2018-07-02T15:55:56+00:00"
+        },
+        {
+            "name": "piwik/ini",
+            "version": "1.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/piwik/component-ini.git",
+                "reference": "bd2711ba4d5e20e4ca09b6829dc2831576b59dc3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/piwik/component-ini/zipball/bd2711ba4d5e20e4ca09b6829dc2831576b59dc3",
+                "reference": "bd2711ba4d5e20e4ca09b6829dc2831576b59dc3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "athletic/athletic": "0.1.*",
+                "phpunit/phpunit": "~4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Piwik\\Ini\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-3.0"
+            ],
+            "abandoned": "matomo/ini",
+            "time": "2016-01-14T21:13:33+00:00"
+        },
+        {
+            "name": "psr/cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/cache.git",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Cache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for caching libraries",
+            "keywords": [
+                "cache",
+                "psr",
+                "psr-6"
+            ],
+            "time": "2016-08-06T20:24:11+00:00"
+        },
+        {
+            "name": "psr/container",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/container.git",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Container\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common Container Interface (PHP FIG PSR-11)",
+            "homepage": "https://github.com/php-fig/container",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interface",
+                "container-interop",
+                "psr"
+            ],
+            "time": "2017-02-14T16:28:37+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
+                "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "Psr/Log/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2018-11-20T15:27:04+00:00"
+        },
+        {
+            "name": "psr/simple-cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/simple-cache.git",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\SimpleCache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for simple caching",
+            "keywords": [
+                "cache",
+                "caching",
+                "psr",
+                "psr-16",
+                "simple-cache"
+            ],
+            "time": "2017-10-23T01:57:42+00:00"
+        },
+        {
+            "name": "rappasoft/laravel-helpers",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/rappasoft/laravel-helpers.git",
+                "reference": "c8dfa1e979437528262725ebe99c2e6383b24c16"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/rappasoft/laravel-helpers/zipball/c8dfa1e979437528262725ebe99c2e6383b24c16",
+                "reference": "c8dfa1e979437528262725ebe99c2e6383b24c16",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/helpers.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Anthony Rappa",
+                    "email": "rappa819@gmail.com"
+                }
+            ],
+            "description": "Laravel Helpers for Non-Laravel Projects",
+            "keywords": [
+                "helpers",
+                "laravel"
+            ],
+            "time": "2019-04-03T13:15:59+00:00"
+        },
+        {
+            "name": "symfony/cache",
+            "version": "v3.4.20",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/cache.git",
+                "reference": "d31c2a1b80029d885307db47405daeffafcda759"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/cache/zipball/d31c2a1b80029d885307db47405daeffafcda759",
+                "reference": "d31c2a1b80029d885307db47405daeffafcda759",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "psr/cache": "~1.0",
+                "psr/log": "~1.0",
+                "psr/simple-cache": "^1.0",
+                "symfony/polyfill-apcu": "~1.1"
+            },
+            "conflict": {
+                "symfony/var-dumper": "<3.3"
+            },
+            "provide": {
+                "psr/cache-implementation": "1.0",
+                "psr/simple-cache-implementation": "1.0"
+            },
+            "require-dev": {
+                "cache/integration-tests": "dev-master",
+                "doctrine/cache": "~1.6",
+                "doctrine/dbal": "~2.4",
+                "predis/predis": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Cache\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Cache component with PSR-6, PSR-16, and tags",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "caching",
+                "psr6"
+            ],
+            "time": "2018-12-06T10:54:02+00:00"
+        },
+        {
+            "name": "symfony/dependency-injection",
+            "version": "v3.3.18",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/dependency-injection.git",
+                "reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54243abc4e1a1a15e274e391bd6f7090b44711f1",
+                "reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "psr/container": "^1.0"
+            },
+            "conflict": {
+                "symfony/config": "<3.3.7",
+                "symfony/finder": "<3.3",
+                "symfony/yaml": "<3.3"
+            },
+            "provide": {
+                "psr/container-implementation": "1.0"
+            },
+            "require-dev": {
+                "symfony/config": "~3.3",
+                "symfony/expression-language": "~2.8|~3.0",
+                "symfony/yaml": "~3.3"
+            },
+            "suggest": {
+                "symfony/config": "",
+                "symfony/expression-language": "For using expressions in service container configuration",
+                "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
+                "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
+                "symfony/yaml": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\DependencyInjection\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony DependencyInjection Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-01-29T09:02:23+00:00"
+        },
+        {
+            "name": "symfony/http-foundation",
+            "version": "v3.4.20",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/http-foundation.git",
+                "reference": "ea61dd57c4399b0b2a4162e1820cd9d0783acd38"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ea61dd57c4399b0b2a4162e1820cd9d0783acd38",
+                "reference": "ea61dd57c4399b0b2a4162e1820cd9d0783acd38",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "symfony/polyfill-mbstring": "~1.1",
+                "symfony/polyfill-php70": "~1.6"
+            },
+            "require-dev": {
+                "symfony/expression-language": "~2.8|~3.0|~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\HttpFoundation\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpFoundation Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-11-26T10:17:44+00:00"
+        },
+        {
+            "name": "symfony/polyfill-apcu",
+            "version": "v1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-apcu.git",
+                "reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/19e1b73bf255265ad0b568f81766ae2a3266d8d2",
+                "reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Apcu\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "apcu",
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-08-06T14:22:27+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
+                "reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-09-21T13:07:52+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php70",
+            "version": "v1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php70.git",
+                "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224",
+                "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224",
+                "shasum": ""
+            },
+            "require": {
+                "paragonie/random_compat": "~1.0|~2.0|~9.99",
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php70\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ],
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-09-21T06:26:08+00:00"
+        },
+        {
+            "name": "symfony/yaml",
+            "version": "v3.3.18",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "af615970e265543a26ee712c958404eb9b7ac93d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/af615970e265543a26ee712c958404eb9b7ac93d",
+                "reference": "af615970e265543a26ee712c958404eb9b7ac93d",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8"
+            },
+            "require-dev": {
+                "symfony/console": "~2.8|~3.0"
+            },
+            "suggest": {
+                "symfony/console": "For validating YAML files using the lint command"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-01-20T15:04:53+00:00"
+        }
+    ],
+    "packages-dev": [],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": ">=5.5.9"
+    },
+    "platform-dev": [],
+    "plugin-api-version": "1.1.0"
+}

+ 25 - 0
core/Api/AbstractApi.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Api;
+
+use \ModulesGarden\Servers\KerioEmail\Core\Api\AbstractApi\Curl\Request;
+use \ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+
+/**
+ * Description of AbstractApi
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class AbstractApi
+{
+    protected $token;
+    protected $code;
+
+    /**
+     * @return Request
+     */
+    protected function getNewRequest()
+    {
+        return DependencyInjection::create(Request::class);
+    }
+}

+ 158 - 0
core/Api/AbstractApi/Curl.php

@@ -0,0 +1,158 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Api\AbstractApi;
+
+use \ModulesGarden\Servers\KerioEmail\Core\Api\AbstractApi\Curl\Response;
+use \ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+use \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception;
+use \ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes\ErrorCodesLib;
+
+/**
+ * Description of Curl
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class Curl
+{
+    private $curl;
+    private $options = [
+        CURLOPT_TIMEOUT        => 30,
+        CURLOPT_HEADER         => false,
+        CURLOPT_RETURNTRANSFER => true,
+        CURLINFO_HEADER_OUT    => true
+    ];
+    protected $curlParser;
+
+    public function setCurlParser($curlParser)
+    {
+        $this->curlParser = $curlParser;
+
+        return $this;
+    }
+
+    public function setOptions($options, $value)
+    {
+        $this->options[$options] = $value;
+        return $this;
+    }
+
+    protected function open()
+    {
+        $this->curl = curl_init();
+
+        return $this;
+    }
+
+    protected function close()
+    {
+        curl_close($this->curl);
+
+        return $this;
+    }
+
+    protected function unsetOptions($options)
+    {
+        if (is_array($options))
+        {
+            foreach ($options as $option)
+            {
+                if (isset($this->options[$option]))
+                {
+                    unset($this->options[$option]);
+                }
+            }
+        }
+        else
+        {
+            unset($this->options[$options]);
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return Response
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception
+     */
+    protected function send()
+    {
+        $this->includeOptions();
+
+        if (($head = $this->execute()) === false)
+        {
+            throw new Exception(ErrorCodesLib::CORE_CURL_000001, ['lastCurlError' => $this->getLastErrorWithCurl()]);
+        }
+
+        if ($errno = $this->getLastErrorNumber())
+        {
+            throw new Exception(ErrorCodesLib::CORE_CURL_000002, ['curlError' => $this->getLastError($errno)]);
+        }
+
+        list($header, $body) = $this->curlParser->rebuild($head, $this->getHeaderSize());
+
+        return DependencyInjection::create(Response::class)
+                        ->setRequest($this->getHeaderOut())
+                        ->setHeader($header)
+                        ->setCode($this->getHttpCode())
+                        ->setBody($body);
+    }
+
+    private function execute()
+    {
+        return curl_exec($this->curl);
+    }
+
+    private function getLastErrorNumber()
+    {
+        return curl_errno($this->curl);
+    }
+
+    /**
+     * (PHP 5 &gt;= 5.5.0, PHP 7)<br/>
+     * Return string describing the given error code
+     * @link http://php.net/manual/en/function.curl-strerror.php
+     * @param int $errornum <p>
+     * One of the cURL error codes constants.
+     * </p>
+     * @return string error description or <b>NULL</b> for invalid error code.
+     */
+    private function getLastError($errmo)
+    {
+        return curl_strerror($errmo);
+    }
+
+    /**
+     * (PHP 4 &gt;= 4.0.3, PHP 5, PHP 7)<br/>
+     * Return a string containing the last error for the current session
+     * @link http://php.net/manual/en/function.curl-error.php
+     * @param resource $ch
+     * @return string the error message or '' (the empty string) if no
+     * error occurred.
+     */
+    private function getLastErrorWithCurl()
+    {
+        return curl_error($this->curl);
+    }
+
+    private function getHeaderSize()
+    {
+        return curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
+    }
+
+    private function getHeaderOut()
+    {
+        return curl_getinfo($this->curl, CURLINFO_HEADER_OUT);
+    }
+
+    private function getHttpCode()
+    {
+        return curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
+    }
+
+    private function includeOptions()
+    {
+        curl_setopt_array($this->curl, $this->options);
+
+        return $this;
+    }
+}

+ 193 - 0
core/Api/AbstractApi/Curl/Request.php

@@ -0,0 +1,193 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Api\AbstractApi\Curl;
+
+use ModulesGarden\Servers\KerioEmail\Core\Api\AbstractApi\Curl;
+
+/**
+ * Description of Request
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Request extends Curl
+{
+    protected $url = '';
+    
+    protected $lastResponse = [];
+    
+    protected $headers = [
+        "Content-Type: application/x-www-form-urlencoded"
+    ];
+
+    public function getLastResponse()
+    {
+        return $this->lastResponse;
+    }
+
+    public function setUrl($url = "")
+    {
+        $this->url = $url;
+
+        return $this;
+    }
+
+    public function resetHeaders()
+    {
+        $this->headers = [];
+
+        return $this;
+    }
+
+    public function setHeaders(array $headers = [])
+    {
+        $this->headers = $headers;
+
+        return $this;
+    }
+
+    public function addHeaders($headers)
+    {
+        if (is_array($headers))
+        {
+            $this->headers = $headers;
+        }
+        else
+        {
+            $this->headers[] = $headers;
+        }
+
+        return $this;
+    }
+
+    protected function send()
+    {
+        $return               = parent::send();
+        $this->close();
+        $this->lastResponse[] = $return;
+
+        return $return;
+    }
+
+    /**
+     * @param array $data
+     * @return string
+     */
+    protected function httpBuildQuery(array $data = [])
+    {
+        return empty($data) ? "" : http_build_query($data);
+    }
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function post($data = [])
+    {
+
+        $postvars = is_array($data) ? $this->httpBuildQuery($data) : $data;
+
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url)
+            ->setOptions(CURLOPT_POSTFIELDS, $postvars)
+            ->setOptions(CURLOPT_POST, true);
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+    }
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function put($data = [])
+    {
+
+        $postvars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url)
+            ->setOptions(CURLOPT_POSTFIELDS, $postvars)
+            ->setOptions(CURLOPT_CUSTOMREQUEST, "PUT");
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+    }
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function delete($data = [])
+    {
+
+        $deletevars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url . $deletevars)
+            ->setOptions(CURLOPT_CUSTOMREQUEST, "DELETE");
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+
+    }
+    
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function get($data = [])
+    {
+        $getvars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_URL, $this->url . $getvars);
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+        
+        return $this->send();
+    }  
+
+    /**
+     * @param array $data post field
+     * @return Response
+     */
+    public function options($data = [])
+    {
+        $deletevars = is_array($data)?$this->httpBuildQuery($data):$data;
+        
+        $this->open()
+            ->setOptions(CURLOPT_SSL_VERIFYPEER, false)
+            ->setOptions(CURLOPT_URL, $this->url)
+            ->setOptions(CURLOPT_CUSTOMREQUEST, "OPTIONS");
+        
+        if (!empty($this->headers))
+        {
+            $this->setOptions(CURLOPT_HTTPHEADER, $this->headers)
+                    ->setOptions(CURLOPT_HEADER, true);
+        }
+
+        return $this->send();
+    }
+}

+ 92 - 0
core/Api/AbstractApi/Curl/Response.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Api\AbstractApi\Curl;
+
+/**
+ * Description of Respons
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Response
+{
+    protected $body;
+    protected $request;
+    protected $header;
+    protected $code;
+
+    public function setRequest($request)
+    {
+        $this->request = $request;
+
+        return $this;
+    }
+
+    public function setHeader($header)
+    {
+        $this->header = $header;
+
+        return $this;
+    }
+
+    public function setBody($body)
+    {
+        $this->body = $body;
+
+        return $this;
+    }
+
+    public function setCode($code)
+    {
+        $this->code = $code;
+
+        return $this;
+    }
+
+    /**
+     * @param bool $isJson
+     * @return string|\stdClass
+     */
+    public function getBody($isJson = true)
+    {
+
+
+        if ($isJson)
+        {
+            return json_decode($this->body);
+        }
+
+        return $this->body;
+    }
+
+    /**
+     * @return string
+     */
+    public function getRequest()
+    {
+        return $this->request;
+    }
+
+    /**
+     * @return string
+     */
+    public function getHeader()
+    {
+        return $this->header;
+    }
+
+    /**
+     * @return int
+     */
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isSuccess()
+    {
+        return (bool) ($this->code >= 200 && $this->code < 300);
+    }
+}

+ 22 - 0
core/Api/AbstractApi/Parser.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Api\AbstractApi;
+
+use ModulesGarden\Servers\KerioEmail\Core\Interfaces\CurlParser;
+
+/**
+ * Description of Parser
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Parser implements CurlParser
+{
+
+    public function rebuild($head, $size)
+    {
+        return [
+            substr($head, 0, $size),
+            substr($head, $size)
+        ];
+    }
+}

+ 186 - 0
core/Api/Http.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Api;
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Exceptions\WhmcsApiException;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use ModulesGarden\Servers\KerioEmail\Core\Traits\IsDebugOn;
+
+use ModulesGarden\Servers\KerioEmail\App\Libs\Exceptions\ApiException;
+
+
+/**
+ * Description of Http
+ *
+ * @author Paweł Złamaniec <pawel.zl@modulesgarden.com>
+ */
+class Http
+{
+    use IsDebugOn;
+
+    /**
+     * @var \AltoRouter;
+     */
+    protected $router;
+
+    public function __construct($basepath)
+    {
+        $this->loadRouter($basepath);
+        $this->router->addMatchTypes(["d" => "[^/]+"]);
+    }
+
+    /**
+     * Parse API request
+     */
+    public function run()
+    {
+        try
+        {
+            $logger = $this->getLoggerObject();
+            $match = $this->router->match();
+            if($match)
+            {
+                $auth = $this->getAuthObject();
+                $auth->run($match["name"]);
+
+                $validator = $this->getValidatorObject();
+                $validator->run($match["name"]);
+
+                $request = explode("#", $match['target']);
+                $action = [$this->getController($request[0]), $request[1]];
+                $result = call_user_func_array($action, $match['params']);
+
+                $logger->logInfo($match["name"], array_merge($match["params"], $_REQUEST), $result);
+
+                echo json_encode($result);
+            }
+            else
+            {
+                header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
+                echo json_encode(["error" => "Action not found"]);
+            }
+
+            exit;
+        }
+        catch (ApiException $mgex)
+        {
+            $code   = $mgex->getMgHttpCode();
+            $exdata = $mgex->getAdditionalData();
+
+            $message = "{$mgex->getMgMessage(false)}" . ($this->isDebugOn() ? " | " . print_r($exdata, true) : "");
+        }
+        catch (WhmcsApiException $whmcsex)
+        {
+            $exdata = $whmcsex->getAdditionalData();
+            $message = "{$exdata["data"]["result"]["message"]}: {$exdata["data"]["result"]["error"]}";
+        }
+        catch (\Exception $ex)
+        {
+            $exdata  = $this->isDebugOn() ? print_r($ex, true) : null;
+            $message = "Please contact administration (server side issue)" . ($exdata ? " | ". $exdata : "");
+        }
+
+        $logger->logError($match["name"], array_merge($match["params"], $_REQUEST), $exdata);
+
+        $response = $this->getResponseBuilderObject();
+        $message = $response->build($match["name"], $message);
+
+        http_response_code($code ?: 500);
+        echo json_encode(["error" => $message]);
+    }
+
+    /**
+     * Load router object
+     *
+     * @param $basePath
+     * @throws \Exception
+     */
+    protected function loadRouter($basePath)
+    {
+        $this->router = new \AltoRouter();
+        $this->router->setBasePath($basePath);
+
+        $routes = require ModuleConstants::getDevConfigDir().DS."api".DS."routes.php";
+        $this->router->addRoutes($routes);
+    }
+
+    /**
+     * Get controller object
+     *
+     * @return Object
+     */
+    protected function getController($classname)
+    {
+        $classname = "\\ModulesGarden\\Servers\\KerioEmail\\App\\Http\\Api\\{$classname}";
+        return new $classname;
+    }
+
+    /**
+     * Get Authorization class object
+     *
+     * @return Auth class object
+     */
+    protected function getAuthObject()
+    {
+        $config = $this->getConfigElement("auth");
+        $auth = new $config["class"];
+
+        return $auth;
+    }
+
+    /**
+     * @return mixed
+     */
+    protected function getValidatorObject()
+    {
+        $config = $this->getConfigElement("validator");
+        $validator = new $config["class"];
+
+        return $validator;
+    }
+
+
+    /**
+     * Get Logger class object
+     *
+     * @return Logger class object
+     */
+    protected function getLoggerObject()
+    {
+        $config = $this->getConfigElement("logger");
+        $auth = new $config["class"];
+
+        return $auth;
+    }
+
+    /**
+     * Get Logger class object
+     *
+     * @return Logger class object
+     */
+    protected function getResponseBuilderObject()
+    {
+        $config = $this->getConfigElement("responseBuilder");
+        $auth = new $config["class"];
+
+        return $auth;
+    }
+
+    /**
+     * Get configuration element by type
+     *
+     * @param $type
+     * @return mixed
+     */
+    protected function getConfigElement($type)
+    {
+        $config = require ModuleConstants::getDevConfigDir().DS."api".DS."config.php";
+        foreach($config as $element)
+        {
+            if($element["type"] == $type)
+            {
+                return $element;
+            }
+        }
+    }
+}

+ 90 - 0
core/Api/Whmcs.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Api;
+
+use \ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Admins;
+use \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception;
+use \ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes\ErrorCodesLib;
+
+class Whmcs
+{
+    /**
+     * @var Admins
+     */
+    protected $admins;
+
+    /**
+     * @var string
+     */
+    protected $username;
+
+    /**
+     * @param Admins $admins
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception
+     */
+    public function __construct(Admins $admins)
+    {
+        $this->admins = $admins;
+        $this->getAdminUserName();
+
+        if (function_exists('localAPI') === false)
+        {
+            throw new Exception(ErrorCodesLib::CORE_WAPI_000001);
+        }
+    }
+
+    /**
+     * @return string
+     */
+    protected function getAdminUserName()
+    {
+        if (isset($this->username) === false)
+        {
+            $this->username = $this->admins->first()->toArray()['username'];
+        }
+
+        return $this->username;
+    }
+
+    public function call($command, $config = [])
+    {
+
+        $result = localAPI($command, $config, $this->getAdminUserName());
+
+        if ($result['result'] == 'error')
+        {
+            $exc = new Exception(ErrorCodesLib::CORE_WAPI_000002, ['command' => $command, 'data' => $config, 'result' => $result]);
+            $exc->setCustomMessage($result['message']);
+
+            throw $exc;
+        }
+        unset($result['result']);
+
+        return $result;
+    }
+
+    public function getAdminDetails($adminId)
+    {
+        $data = $this->admins->where("id", "LIKE", $adminId)->first();
+
+        if ($data === null)
+        {
+            throw new Exception(ErrorCodesLib::CORE_WAPI_000003, ['adminId' => $adminId], ['adminId' => $adminId]);
+        }
+
+        $result = localAPI("getadmindetails", [], $data->toArray()['username']);
+
+        if ($result['result'] == 'error')
+        {
+            $exc = new Exception(ErrorCodesLib::CORE_WAPI_000004, ['command' => "getadmindetails", 'data' => [], 'result' => $result]);
+            $exc->setCustomMessage($result['message']);
+
+            throw $exc;
+        }
+
+        $result['allowedpermissions'] = explode(",", $result['allowedpermissions']);
+        unset($result['result']);
+
+        return $result;
+    }
+}

+ 172 - 0
core/App/AppContext.php

@@ -0,0 +1,172 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App;
+
+use ModulesGarden\Servers\KerioEmail\Core\HandlerError\WhmcsErrorManagerWrapper;
+
+class AppContext
+{
+    protected $debugMode = true;
+
+    public function __construct()
+    {
+        require_once __DIR__ . DIRECTORY_SEPARATOR . 'ErrorHandler.php';
+
+        register_shutdown_function([$this, 'handleShutdown']);
+        set_error_handler([$this, 'handleError'], E_ALL);
+
+        $this->loadDebugState();
+
+        //require app bootstrap
+        require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Bootstrap.php';
+
+        if ($this->debugMode)
+        {
+            spl_autoload_register(array('\ModulesGarden\Servers\KerioEmail\Core\App\AppContext', 'loadClassLoader'), true, false);
+        }
+    }
+
+    public function runApp($callerName = null, $params = [])
+    {
+        try
+        {
+            $app = new Application();
+            $result = $app->run($callerName, $params);
+
+            restore_error_handler();
+        }
+        catch (\Exception $exc)
+        {
+            restore_error_handler();
+
+            return [
+                'status' => 'error',
+                'message' => $exc->getMessage()
+            ];
+        }
+
+        return $result;
+    }
+
+    public function handleError($errno, $errstr, $errfile, $errline, $errcontext = null)
+    {
+        if ($this->debugMode || (!in_array($errno, ErrorHandler::WARNINGS) && !in_array($errno, ErrorHandler::NOTICES)))
+        {
+            $handler = new ErrorHandler();
+            $errorToken = md5(time());
+            $handler->logError($errorToken, $errno, $errstr, $errfile, $errline, $errcontext);
+        }
+
+        return true;
+    }
+
+    public function handleShutdown()
+    {
+        $errorInstance = null;
+        $errManager = WhmcsErrorManagerWrapper::getErrorManager();
+        if (is_object($errManager) && method_exists($errManager, 'getRunner'))
+        {
+            $runner = $errManager->getRunner();
+            if (is_object($runner) && method_exists($runner, 'getHandlers'))
+            {
+                $handlers = $runner->getHandlers();
+                foreach ($handlers as $handler)
+                {
+                    $rfHandler = new \ReflectionClass($handler);
+                    $method = $rfHandler->getMethod('getException');
+                    $method->setAccessible(true);
+                    $error = $method->invoke($handler);
+                    if (is_object($error))
+                    {
+                        $errorInstance = $error;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if ($errorInstance === null)
+        {
+            $errorInstance = error_get_last();
+            if ($errorInstance === null)
+            {
+                return;
+            }
+
+            $this->handleError($errorInstance['type'], $errorInstance['message'], $errorInstance['file'], $errorInstance['line'], '');
+
+            return;
+        }
+
+        $handler = new ErrorHandler();
+        $errorToken = md5(time());
+        $handler->logError($errorToken, $errorInstance->getCode(), $errorInstance->getMessage(), $errorInstance->getFile(), $errorInstance->getLine(), $errorInstance->getTrace());
+        if ($errorToken)
+        {
+            echo '<input type="hidden" id="mg-sh-h-492318-64534" value="' . $errorToken . '" mg-sh-h-492318-64534-end >';
+        }
+    }
+
+    public function loadDebugState()
+    {
+        $path = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . '.debug';
+        if (file_exists($path))
+        {
+            $this->debugMode = true;
+
+            return;
+        }
+
+        $this->debugMode = false;
+    }
+
+    public static function loadClassLoader($class)
+    {
+        $rawClass = trim($class, '\\');
+        $pos = strpos($rawClass, 'ModulesGarden\Servers\KerioEmail');
+        if ($pos === 0)
+        {
+            if (!class_exists($class) && self::DEPRECATED[$rawClass])
+            {
+                echo 'This class no longer exists: ' . $class . '<br>';
+                echo 'Use: ' . self::DEPRECATED[$rawClass];
+                die();
+            }
+        }
+    }
+
+    const DEPRECATED = [
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\BaseMassActionButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassAction',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\AddIconModalButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCreate',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\BaseSubmitButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonSubmitForm',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\BaseButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonBase',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\BaseDatatableModalButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDatatableShowModal',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\BaseModalDataTableActionButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDataTableModalAction',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\RedirectButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonRedirect',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\BaseModalButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonModal',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\RedirectWithOutTooltipButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonRedirect',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\OnOffAjaxSwitch' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonSwitchAjax',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\CustomActionButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonCustomAction',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\CustomAjaxActionButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonAjaxCustomAction',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DatatableModalButtonContextLang' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDatatableModalContextLang',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdownButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDropdown',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\MassActionButtonContextLang' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonMassActionContextLang',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\Submit' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonSubmitForm',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\WhmcsRegisterLoggin' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\WhmcsLogsHandler',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\ButtonDropdown' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdown',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemCustonAjaxButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemCustonButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemDivider' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemModalButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\Dropdowntems\DropdownItemRedirectButton' => 'ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Buttons\DropdawnButtonWrappers\ButtonDropdownItem',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\ApiException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\ApiWhmcsException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\ControllerException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\DependencyInjectionException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\RegisterException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\ServiceLocatorException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+        'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\SmartyException' => 'ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception',
+    ];
+}

+ 34 - 0
core/App/AppParamsContainer.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App;
+
+class AppParamsContainer
+{
+    /**
+     * @var array
+     * params container
+     */
+    protected $params = [];
+    
+    public function getParams()
+    {
+        return $this->params;
+    }
+    
+    public function getParam($key, $default = null)
+    {
+        if (isset($this->params[$key]))
+        {
+            return $this->params[$key];
+        }
+        
+        return $default;
+    }
+    
+    public function setParam($key, $value = null)
+    {
+        $this->params[$key] = $value;
+        
+        return $this;
+    }
+}

+ 75 - 0
core/App/Application.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers\Http;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers\Addon;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers\Api;
+use \ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+use function \ModulesGarden\Servers\KerioEmail\Core\Helper\di;
+
+class Application
+{
+    public function run($callerName = null, $params = null)
+    {
+        try
+        {
+            $this->setWhmcsParams($params);
+            
+            $controller = $this->getControllerClass($callerName);
+
+            $controllerInstance = ServiceLocator::call($controller);
+
+            $result = $controllerInstance->runController($callerName, $params);
+
+            return $result;
+        }
+        catch (\Exception $exc)
+        {
+            $errorPage = ServiceLocator::call(Controllers\Instances\Http\ErrorPage::class);
+
+            $params['mgErrorDetails'] = $exc;
+
+            $result = $errorPage->execute($params);
+            
+            return $result;
+        }
+    }
+
+    /** 
+     * Saves provided WHMCS params to WhmcsParams service
+     * @param type array
+     */
+    protected function setWhmcsParams($params)
+    {
+        $whmcsParams = di('whmcsParams');
+        $whmcsParams->setParams($params);
+    }
+    
+    public function getControllerClass($callerName = null)
+    {
+        $functionName = str_replace($this->getModuleName() . '_', '', $callerName);
+        switch ($functionName)
+        {
+            //HTTP controllers
+            case 'output':
+                return Http::class;
+            case 'clientarea':
+                return Http::class;
+
+            //API controller
+            case 'api':
+                return Api::class;
+
+            //Addon controllers
+            default:
+                return Addon::class;
+        }
+    }
+
+    public function getModuleName ()
+    {
+        return 'KerioEmail';
+    }
+}

+ 19 - 0
core/App/Controllers/AppController.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+abstract class AppController
+{
+    public function runController($callerName, $params)
+    {
+        $controller = $this->getControllerInstanceClass($callerName, $params);
+
+        $controllerInstance = ServiceLocator::call($controller);
+
+        $result = $controllerInstance->runExecuteProcess($params);
+
+        return $result;
+    }
+}

+ 33 - 0
core/App/Controllers/AppControllers/Addon.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AppController;
+
+class Addon extends \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppController implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        $functionName = str_replace($this->getModuleName() . '_', '', $callerName);
+
+        $coreAddon = '\ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon\\' . ucfirst($functionName);
+        if (class_exists($coreAddon) && is_subclass_of($coreAddon, AddonController::class))
+        {
+            return $coreAddon;
+        }
+
+        $appAddon = '\ModulesGarden\Servers\KerioEmail\App\Http\Actions\\' . ucfirst($functionName);
+        if (class_exists($appAddon) && is_subclass_of($appAddon, AddonController::class))
+        {
+            return $appAddon;
+        }
+
+        return null;
+    }
+
+    public function getModuleName ()
+    {
+        return 'KerioEmail';
+    }
+}

+ 13 - 0
core/App/Controllers/AppControllers/Api.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AppController;
+
+class Api implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        // TODO: Implement getControllerInstanceClass() method.
+    }
+}

+ 13 - 0
core/App/Controllers/AppControllers/Cron.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AppController;
+
+class Cron implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        // TODO: Implement runCalledController() method.
+    }
+}

+ 13 - 0
core/App/Controllers/AppControllers/Hooks.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AppController;
+
+class Hooks implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        // TODO: Implement getControllerInstanceClass() method.
+    }
+}

+ 31 - 0
core/App/Controllers/AppControllers/Http.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppControllers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AppController;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\AdminPageController;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\ClientPageController;
+
+class Http extends \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\AppController implements AppController
+{
+    public function getControllerInstanceClass ($callerName, $params)
+    {
+        //todo
+        $functionName = str_replace($this->getModuleName() . '_', '', $callerName);
+        switch ($functionName)
+        {
+            //HTTP controllers
+            case 'output':
+                return AdminPageController::class;
+            case 'clientarea':
+                return ClientPageController::class;
+        }
+
+        return null;
+    }
+
+    public function getModuleName ()
+    {
+        return 'KerioEmail';
+    }
+}

+ 71 - 0
core/App/Controllers/Instances/Addon/Activate.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\DatabaseHelper;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Activate module actions
+ */
+class Activate extends \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+    /**
+     * @var null|DatabaseHelper
+     */
+    protected $databaseHelper = null;
+
+    public function execute($params = [])
+    {
+        try
+        {
+            //Before module activation
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Activate\Before::class)->execute($params);
+            if (!isset($return['status']))
+            {
+                $return['status'] = 'success';
+            }
+
+            //module activation process
+            $return = $this->activate($return);
+
+            //After module activation
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Activate\After::class)->execute($return);
+
+            return $return;
+        }
+        catch (\Exception $exc)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorManager::class)->addError(self::class, $exc->getMessage(), $return);
+            return [
+                'status' => 'error',
+                'description' => $exc->getMessage()
+            ];
+        }
+    }
+
+    protected function activate($params = [])
+    {
+        $this->databaseHelper = DependencyInjection::call(DatabaseHelper::class);
+
+        if ($params['status'] === 'error')
+        {
+            return $params;
+        }
+
+        $isErrorCore     = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('core', 'Database', 'schema.sql'));
+        $isErrorApp     = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('app', 'Database', 'schema.sql'));
+        $isErrorDataCore = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('core', 'Database', 'data.sql'));
+        $isErrorDataApp = $this->databaseHelper->performQueryFromFile(ModuleConstants::getFullPath('app', 'Database', 'data.sql'));
+
+        if ($isErrorCore || $isErrorDataCore || $isErrorApp || $isErrorDataApp)
+        {
+            return ['status' => 'error', 'description' => ServiceLocator::call('errorManager')->getFirstError()->getMessage()];
+        }
+
+        return ['status' => 'success'];
+    }
+}

+ 149 - 0
core/App/Controllers/Instances/Addon/Config.php

@@ -0,0 +1,149 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Data;
+use ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Module configuration wrapper
+ */
+class Config extends \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+    /**
+     * @var array
+     * list of params passed by WHMCS
+     */
+    private $params = [];
+
+    /**
+     * @var array
+     * module configuration list
+     */
+    protected $config = [];
+
+    /**
+     * @var null|\ModulesGarden\Servers\KerioEmail\Core\Configuration\Data
+     *
+     */
+    protected $data = null;
+
+    /**
+     * @var array
+     * list of values to be returned as a part of
+     */
+    protected $configFields = [
+        'name',
+        'description',
+        'version',
+        'author',
+        'fields',
+        'systemName',
+        'debug',
+        'moduleIcon',
+        'clientareaName'
+    ];
+
+    /**
+     * @param array $params - WHMCS params for function _config
+     * @return array
+     */
+    public function execute($params = [])
+    {
+        if (!$this->config)
+        {
+            $this->setParams($params);
+            $this->loadConfig();
+
+            return $this->getConfig();
+        }
+
+        return $this->config;
+    }
+
+    /**
+     * @param array $params
+     */
+    protected function setParams($params = [])
+    {
+        if (is_array($params))
+        {
+            $this->params = $params;
+        }
+    }
+
+    /**
+     * loads module configuration from files yaml configs and moduleVersion.php
+     */
+    protected function loadConfig()
+    {
+        if (!$this->data)
+        {
+            $this->data = DependencyInjection::call(Data::class);
+        }
+    }
+
+    /**
+     * parses config data
+     */
+    public function getConfig()
+    {
+        if ($this->config)
+        {
+            return $this->config;
+        }
+
+        try
+        {
+            //Before loading the config
+            $params = [];
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Config\Before::class)->execute($params);
+
+            foreach ($this->configFields as $field)
+            {
+                $value = $this->data->{$field};
+                if (isset($return[$field]) === false && $value !== null)
+                {
+                    if (is_numeric($value))
+                    {
+                        $return[$field] = (int)$value;
+                    }
+                    else
+                    {
+                        $return[$field] = $value;
+                    }
+                }
+            }
+
+            //After loading the config
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Config\After::class)->execute($return);
+
+            $this->config = $return;
+
+            return $return;
+        }
+        catch (\Exception $ex)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorManager::class)->addError(self::class, $ex->getMessage(), $return);
+
+            return $return ? : [];
+        }
+    }
+
+    public function getConfigValue($key, $defaultValue = null)
+    {
+        if (!$this->config)
+        {
+            $this->execute();
+        }
+
+        if (!isset($this->config[$key]))
+        {
+            return $defaultValue;
+        }
+
+        return $this->config[$key];
+    }
+}

+ 301 - 0
core/App/Controllers/Instances/Addon/ConfigOptions.php

@@ -0,0 +1,301 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\ResponseResolver;
+use ModulesGarden\Servers\KerioEmail\Core\App\Installer\ModuleInstaller;
+use ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Product;
+use ModulesGarden\Servers\KerioEmail\Core\Models\Whmcs\Server;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+use ModulesGarden\Servers\KerioEmail\Core\Traits\AppParams;
+use ModulesGarden\Servers\KerioEmail\Core\Traits\OutputBuffer;
+use ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+
+/**
+ * ConfigOptions module actions
+ */
+class ConfigOptions extends \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController
+{
+    use AppParams;
+    use RequestObjectHandler;
+    use OutputBuffer;
+
+    public function execute($params = null)
+    {
+        $productId = $this->getRequestValue('id');
+        if (($this->getRequestValue('action') === 'module-settings' || ($this->getRequestValue('loadData') && $this->getRequestValue('ajax') == '1')))
+        {
+            try
+            {
+                //check storage
+                $invalidStoragePermissions = $this->getInvalidStoragePermitions();
+                if ($invalidStoragePermissions)
+                {
+                    return $this->getInvalidStoragePermissionsError($invalidStoragePermissions);
+                }
+
+                //check server type
+                if (!$this->isCorrectServerType())
+                {
+                    return $this->getInvalidServerTypeError();
+                }
+
+                $requirementsHandler = new \ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Checker();
+
+                if ($requirementsHandler->getUnfulfilledRequirements())
+                {
+                    $data = $this->buildErrorMessage(implode('<br>', $requirementsHandler->getUnfulfilledRequirements()));
+
+                    return $this->returnAjaxResponse($data);
+                }
+
+                $this->updateProductType();
+
+                /**
+                 *
+                 * disabled because `packages` folder wasn't migrated
+                 */
+                //$this->addRequiredCustomFields();
+
+                //run installer
+                $installer = new ModuleInstaller();
+
+                $installer->makeInstall();
+
+                if (!$installer->isInstallCorrect())
+                {
+                    return $this->buildFailedQueriesMessage($installer->getFailedQueries());
+                }
+            }
+            catch (\Exception $exc)
+            {
+                $data = $this->buildErrorMessage($exc->getMessage());
+
+                return $this->returnAjaxResponse($data);
+            }
+
+            try
+            {
+                $this->setAppParam('IntegrationControlerName', \ModulesGarden\Servers\KerioEmail\App\Http\Actions\ConfigOptions::class);
+                $this->setAppParam('IntegrationControlerMethod', 'runExecuteProcess');
+
+                $configOptionsController = new \ModulesGarden\Servers\KerioEmail\App\Http\Actions\ConfigOptions();
+
+                $result = $configOptionsController->execute();
+
+                return $result;
+            }
+            catch (\Exception $exc)
+            {
+                $data = $this->buildErrorMessage($exc->getMessage());
+                $response = new JsonResponse();
+                $response->setData($data);
+
+                $resolver = new ResponseResolver($response);
+
+                $resolver->resolve();
+            }
+
+        }
+        else if ($this->getRequestValue('action') === 'save')
+        {
+            if (!$this->isCorrectServerType())
+            {
+                return [];
+            }
+
+            return [\ModulesGarden\Servers\KerioEmail\App\Http\Actions\ConfigOptions::class, 'runExecuteProcess'];
+        }
+
+        return [];
+    }
+
+    public function getInvalidStoragePermitions()
+    {
+        $requiredPaths = [
+            ModuleConstants::getFullPath('storage'),
+            ModuleConstants::getFullPath('storage', 'app'),
+            ModuleConstants::getFullPath('storage', 'crons'),
+            ModuleConstants::getFullPath('storage', 'logs')
+        ];
+
+        $invalidPermissions = [];
+        $lang = ServiceLocator::call('lang');
+        foreach ($requiredPaths as $path)
+        {
+            if (!is_writable($path))
+            {
+                $invalidPermissions[] = $lang->addReplacementConstant('storage_path', $path)->absoluteT('permissionsStorage');
+            }
+            if (!is_readable($path))
+            {
+                $invalidPermissions[] = $lang->addReplacementConstant('storage_path', $path)->absoluteT('permissionsStorageReadable');
+            }
+        }
+
+        return $invalidPermissions;
+    }
+
+    public function buildFailedQueriesMessage($failedQueries = [])
+    {
+        $content = '';
+        foreach ($failedQueries as $query)
+        {
+            $content .= '<div class="panel panel-danger"><div class="panel-heading">Installation Error</div><div class="panel-body" style="padding:0px;"><ul class="list-group" style="margin-bottom: -5px;margin-top: -5px;">';
+            //$content .= '<li class="list-group-item ">Status: ' . $query['status'] . '</li>';
+            $content .= '<li class="list-group-item ">File: ' . $query['file'] . '</li>';
+            $content .= '<li class="list-group-item ">Error Message: ' . $query['errorMessage'] . '</li>';
+            $content .= '<li class="list-group-item ">Raw Query: ' . $query['rawQuery'] . '</li>';
+            $content .= '</ul></div></div>';
+        }
+
+        $data = [
+            'content' =>
+                '<tr><td class="fieldlabel" style="width:0%; display:none;"></td><td style="width=100%;" class="fieldarea">' . $content . '</td></tr>',
+            'mode' => 'advanced'
+        ];
+
+        return $this->returnAjaxResponse($data);
+    }
+
+    public function getInvalidStoragePermissionsError($permissions = [])
+    {
+        $data = $this->buildErrorMessage(implode('<br>', $permissions));
+
+        return $this->returnAjaxResponse($data);
+    }
+
+    public function isCorrectServerType()
+    {
+        try
+        {
+            if (class_exists('\ModulesGarden\Servers\KerioEmail\App\Http\Actions\MetaData'))
+            {
+                $metaDataController = new \ModulesGarden\Servers\KerioEmail\App\Http\Actions\MetaData();
+                $details = $metaDataController->execute(null);
+                if ($details['RequiresServer'] !== true)
+                {
+                    return true;
+                }
+
+                $serverGroupId = $this->getServerGroupId();
+
+                $sModel = new Server();
+                $server = $sModel
+                    ->select(['tblservers.type'])
+                    ->join('tblservergroupsrel', 'tblservergroupsrel.serverid', '=', 'tblservers.id')
+                    ->where('tblservergroupsrel.groupid', $serverGroupId)->first();
+
+                if (!$server)
+                {
+                    return false;
+                }
+
+                if ($server->type !== $this->getModuleName())
+                {
+                    return false;
+                }
+            }
+        }
+        catch (\Exception $exception)
+        {
+            //todo log me
+            return false;
+        }
+
+        return true;
+    }
+
+    public function getServerGroupId()
+    {
+        $gid = $this->getRequestValue('servergroup', false);
+        if (!$gid && $gid !== '0' && $gid !== 0)
+        {
+            $pid = $this->getRequestValue('id', 0);
+            $productModel = new Product();
+            $product = $productModel->where('id', $pid)->first();
+            if (!$product)
+            {
+                //can add first product here if needed
+                return 0;
+            }
+
+            return $product->servergroup;
+        }
+
+        return (int)$gid;
+    }
+
+    public function getInvalidServerTypeError()
+    {
+        $lang = ServiceLocator::call('lang');
+
+        $messaage = $lang->addReplacementConstant('provisioning_name', $this->getModuleDisplayName())->absoluteT('invalidServerType');
+        $data = $this->buildErrorMessage($messaage);
+
+        return $this->returnAjaxResponse($data);
+    }
+
+    public function buildErrorMessage($message)
+    {
+        $data = [
+            'content' =>
+                '<tr><td class="fieldlabel" style="width:0%; display:none;"></td><td style="width=100%;" class="fieldarea"><div style="width=100%; margin-bottom: 0px;" class="alert alert-danger">' . $message . '</div></td></tr>',
+            'mode' => 'advanced'
+        ];
+
+        return $data;
+    }
+
+    public function returnAjaxResponse($data = [])
+    {
+        $response = new JsonResponse();
+        $response->setData($data);
+
+        return $response;
+    }
+
+    public function updateProductType()
+    {
+        if ($this->getRequestValue('action') !== 'module-settings'
+            || $this->getAppParam('moduleAppType') !== 'server')
+        {
+            return false;
+        }
+
+        $moduleName = $this->getAppParam('systemName');
+        $pid = $this->getRequestValue('id', false);
+        $servergroup = $this->getRequestValue('servergroup', 0);
+
+        if ($pid && $servergroup > 0)
+        {
+            $product = new Product();
+            $product->where('id', $pid)->update(['servertype' => $moduleName, 'servergroup' => $servergroup]);
+        }
+    }
+
+    public function getModuleName()
+    {
+        return $this->getAppParam('systemName');
+    }
+
+    public function getModuleDisplayName()
+    {
+        return $this->getAppParam('name');
+    }
+
+    public function addRequiredCustomFields()
+    {
+//        $pid = $this->getRequestValue('id', false);
+//        if ($pid === false)
+//        {
+//            return;
+//        }
+//
+//        $product = new \ModulesGarden\Servers\KerioEmail\Packages\WhmcsService\Product($pid);
+//
+//        $product->createCustomFieldsFromConfig();
+    }
+}

+ 44 - 0
core/App/Controllers/Instances/Addon/Deactivate.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Deactivate module action
+ */
+class Deactivate extends \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute($params = [])
+    {
+        try
+        {
+            // before
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Deactivate\Before::class)->execute($params);
+
+            if (!isset($return['status']))
+            {
+                $return['status'] = 'success';
+            }
+
+            // after
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Deactivate\After::class)->execute($return);
+
+            return $return;
+        }
+        catch (\Exception $exc)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorManager::class)->addError(self::class, $exc->getMessage(), $return);
+            return [
+                'status' => 'error',
+                'description' => $exc->getMessage()
+            ];
+        }
+    }
+}

+ 48 - 0
core/App/Controllers/Instances/Addon/Upgrade.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AddonController;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\DatabaseHelper;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * module update process
+ */
+class Upgrade extends \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\AddonController implements AddonController
+{
+    /**
+     * @var null|DatabaseHelper
+     */
+    protected $databaseHelper = null;
+
+    public function execute($params = [])
+    {
+        if ($version == '')
+        {
+            $version = isset($this->params['version']) ? $this->params['version'] : $params['version'];
+        }
+
+        try
+        {
+            // after
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update\After::class)->execute(['version' => $version]);
+
+            // update
+            if (!isset($return['version']))
+            {
+                $return['version'] = $version;
+            }
+            $patchManager = ServiceLocator::call("patchManager")->run(/*$this->getConfig("version")*/ '', $version);
+
+            // before
+            $return = ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update\Before::class)->execute($return);
+
+            return $return;
+        }
+        catch (\Exception $ex)
+        {
+            ServiceLocator::call(\ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorManager::class)->addError(self::class, $ex->getMessage(), $return);
+        }
+    }
+}

+ 169 - 0
core/App/Controllers/Instances/AddonController.php

@@ -0,0 +1,169 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\AddonIntegration;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\AdminServicesTabFieldsIntegration;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\ConfigOptionsIntegration;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\ResponseResolver;
+use ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ViewAjax;
+use ModulesGarden\Servers\KerioEmail\Core\UI\ViewIntegrationAddon;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\DefaultController;
+use ModulesGarden\Servers\KerioEmail\Core\Helper;
+
+/**
+ * Class AddonController
+ * @package ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances
+ */
+abstract class AddonController implements DefaultController
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\ErrorCodesLibrary;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\AppParams;
+
+    /**
+     * @param null $params
+     * @return mixed|Helper\type
+     */
+    public function runExecuteProcess($params = null)
+    {
+        /**
+         * load lang context
+         */
+        $this->loadLangContext();
+
+        /**
+         *
+         * result of execute
+         */
+        $resault = $this->execute($params);
+
+        /**
+         *
+         * return as json result
+         */
+        if ($resault instanceof JsonResponse)
+        {
+            $resolver = new ResponseResolver($resault);
+
+            $resolver->resolve();
+        }
+
+        /**
+         *
+         * check if is callable function & add params
+         */
+        if ($this->isValidIntegrationCallback($resault))
+        {
+            $this->setAppParam('IntegrationControlerName', $resault[0]);
+            $this->setAppParam('IntegrationControlerMethod', $resault[1]);
+
+            //to do catch exceptions
+            $resault = Helper\di($resault[0], $resault[1]);
+        }
+
+        /**
+         *
+         * return if view ajax
+         */
+        if ($resault instanceof ViewAjax)
+        {
+            $this->resolveAjax($resault);
+        }
+
+        /**
+         *  return as view integration addon
+         */
+        if (!$resault instanceof ViewIntegrationAddon)
+        {
+            return $resault;
+        }
+
+        /**
+         *
+         */
+        if ($resault instanceof JsonResponse)
+        {
+            $resolver = new ResponseResolver($resault);
+
+            $resolver->resolve();
+        }
+
+        $addonIntegration = $this->getIntegrationControler($params['action']);
+
+        return $addonIntegration->runExecuteProcess($resault);
+
+    }
+
+    /**
+     * @param null $callback
+     * @return bool
+     */
+    public function isValidIntegrationCallback($callback = null)
+    {
+        if (is_callable($callback))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param $resault
+     */
+    public function resolveAjax($resault)
+    {
+        $ajaxResponse = $resault->getResponse();
+
+        $resolver = new ResponseResolver($ajaxResponse);
+
+        $resolver->resolve();
+    }
+
+    /**
+     * @param null $action
+     * @return HttpController | ConfigOptionsIntegration | AdminServicesTabFieldsIntegration | AddonIntegration
+     */
+    protected function getIntegrationControler($action = null)
+    {
+        switch ($action)
+        {
+            case 'ConfigOptions':
+                return Helper\di(\ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\ConfigOptionsIntegration::class);
+                break;
+            case 'AdminServicesTabFields':
+                return Helper\di(\ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\AdminServicesTabFieldsIntegration::class);
+                break;
+            default:
+                return Helper\di(\ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http\AddonIntegration::class);
+        }
+    }
+
+    /**
+     *
+     */
+    public function loadLangContext()
+    {
+        $this->loadLang();
+
+        if ($this->getAppParam('IntegrationControlerName'))
+        {
+            $parts = explode('\\', $this->getAppParam('IntegrationControlerName'));
+
+            $controller = end($parts);
+        }
+        else
+        {
+            $parts = explode('\\', get_class($this));
+
+            $controller = end($parts);
+        }
+
+        $this->lang->setContext(($this->getAppParam('moduleAppType') . ($this->isAdmin() ? 'AA' : 'CA')), lcfirst($controller));
+    }
+}

+ 11 - 0
core/App/Controllers/Instances/Api/ApiController.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Api;
+
+class ApiController implements DefaultController
+{
+    public function execute ()
+    {
+        // TODO: Implement execute() method.
+    }
+}

+ 39 - 0
core/App/Controllers/Instances/Http/AddonIntegration.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class AddonIntegration extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'addonIntegration';
+    protected $templateDir = null;
+
+    public function execute($response = null)
+    {
+        $this->setControllerResult($response);
+        
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\KerioEmail\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 11 - 0
core/App/Controllers/Instances/Http/AdminPageController.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class AdminPageController extends HttpController implements AdminArea
+{
+
+}

+ 38 - 0
core/App/Controllers/Instances/Http/AdminServicesTabFieldsIntegration.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class AdminServicesTabFieldsIntegration extends HttpController implements AdminArea
+{
+    protected $templateName = 'adminServicesTabFieldsIntegration';
+    protected $templateDir = null;
+
+    public function execute($response = null)
+    {
+        $this->setControllerResult($response);
+
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        return ['' => $this->resolveResponse()];
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\KerioEmail\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 24 - 0
core/App/Controllers/Instances/Http/ClientPageController.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class ClientPageController extends HttpController implements ClientArea
+{
+    public function execute($params = null)
+    {
+        if (class_exists('\ModulesGarden\Servers\KerioEmail\App\Hooks\InternalHooks\PreClientAreaPageLoad'))
+        {
+            $preClietAreaHook = new \ModulesGarden\Servers\KerioEmail\App\Hooks\InternalHooks\PreClientAreaPageLoad($params);
+            $newParams = $preClietAreaHook->execute();
+            if ($newParams && is_array($newParams))
+            {
+                $params = $newParams;
+            }
+        }
+        
+        return parent::execute($params);
+    }
+}

+ 50 - 0
core/App/Controllers/Instances/Http/ConfigOptionsIntegration.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class ConfigOptionsIntegration extends HttpController implements AdminArea
+{
+
+    protected $templateName = 'configOptionsIntegration';
+    protected $templateDir = null;
+
+    public function execute($response = null)
+    {
+        $this->setControllerResult($response);
+
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        $result = $this->resolveResponse();
+
+        $data = [
+            'content' => $result,
+            'mode' => 'advanced'
+        ];
+
+        $enc = \json_encode($data);
+
+        $this->cleanOutputBuffer();
+        echo $enc;
+        exit;
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\KerioEmail\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 82 - 0
core/App/Controllers/Instances/Http/ErrorPage.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class ErrorPage extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'errorPage';
+
+    public function execute ($params = null)
+    {
+        $this->setParams($params);
+        
+        $this->parseError();
+        
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->getRequestValue('ajax') == '1')
+        {
+            return $this->resolveResponseAjax();
+        }
+
+        return $this->responseResolver->setResponse(\ModulesGarden\Servers\KerioEmail\Core\Helper\view())
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+    
+    public function parseError()
+    {
+        $err = $this->getParam('mgErrorDetails');
+        if (!$err)
+        {
+            return null;
+        }
+
+        if (!($err instanceof \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception))
+        {
+            $nErr = new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception(null, null, null, $err);
+
+            $this->setParam('mgErrorDetails', $nErr);
+        }
+
+        $this->logError();
+    }
+
+    public function logError()
+    {
+        $err = $this->getParam('mgErrorDetails');
+
+        /**
+         * \ModulesGarden\Servers\KerioEmail\Core\HandlerError\WhmcsLogsHandler
+         */
+        $logger = \ModulesGarden\Servers\KerioEmail\Core\ServiceLocator::call('whmcsLogger');
+
+        $logger->addModuleLogError($err);
+    }
+
+    public function resolveResponseAjax()
+    {
+        $err = $this->getParam('mgErrorDetails');
+        if (!$err)
+        {
+            return null;
+        }
+
+        $ajaxData = (new \ModulesGarden\Servers\KerioEmail\Core\UI\ResponseTemplates\DataJsonResponse($err->getDetailsToDisplay()))->setStatusError();
+
+        return $this->responseResolver->setResponse($ajaxData->getFormatedResponse())
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 38 - 0
core/App/Controllers/Instances/Http/Integration.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class Integration extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'integration';
+
+    public function execute($params = null)
+    {
+        $this->setParams($params);
+        
+        if (!$this->controllerResult)
+        {
+            return '';
+        }
+
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        if ($this->controllerResult instanceof \ModulesGarden\Servers\KerioEmail\Core\Http\Response)
+        {
+            $this->controllerResult->setForceHtml();
+        }
+
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 31 - 0
core/App/Controllers/Instances/Http/PageNotFound.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Http;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\HttpController;
+
+class PageNotFound extends HttpController implements AdminArea, ClientArea
+{
+    protected $templateName = 'pageNotFound';
+
+    public function execute ($params = null)
+    {
+        $this->setParams($params);
+        
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        $view = \ModulesGarden\Servers\KerioEmail\Core\Helper\view();
+        $view->replaceBreadcrumbTitle('1', 'pageNotFound');
+
+        return $this->responseResolver->setResponse($view)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+}

+ 179 - 0
core/App/Controllers/Instances/HttpController.php

@@ -0,0 +1,179 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances;
+
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\AdminArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\ClientArea;
+use \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces\DefaultController;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\ResponseResolver;
+use ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Router;
+use \ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+abstract class HttpController implements DefaultController
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Smarty;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\ErrorCodesLibrary;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Params;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\AppParams;
+
+    const ADMIN = 'admin';
+    const CLIENT = 'client';
+
+    protected $templateName = 'main';
+    protected $templateContext = 'default';
+    protected $templateDir = null;
+
+    protected $controllerResult = null;
+
+    /**
+     * @var Router|null
+     *
+     */
+    protected $router = null;
+    protected $responseResolver = null;
+
+    public function __construct()
+    {
+        $this->loadSmarty();
+        $this->isAdmin();
+
+        $this->router = new Router();
+        $this->responseResolver = new ResponseResolver();
+    }
+
+    public function execute($params = null)
+    {
+        $this->setParams($params);
+
+        if (!$this->router->isControllerCallable() || !$this->isAdminContextValid())
+        {
+            return $this->controllerResult = $this->getPageNotFound();
+        }
+        else
+        {
+            $this->setAppParam('HttpControlerName', $this->router->getControllerClass());
+            $this->setAppParam('HttpControlerMethod', $this->router->getControllerMethod());
+
+            $this->controllerResult = $this->getControllerResponse();
+        }
+
+        return $this->resolveResponse();
+    }
+
+    public function resolveResponse()
+    {
+        return $this->responseResolver->setResponse($this->controllerResult)
+            ->setTemplateName($this->getTemplateName())
+            ->setTemplateDir($this->getTemplateDir())
+            ->setPageController($this)
+            ->resolve();
+    }
+
+    public function isAdminContextValid()
+    {
+        if ($this->isAdmin() && !($this instanceof AdminArea))
+        {
+            return false;
+        }
+
+        if (!$this->isAdmin() && !($this instanceof ClientArea))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public function getPageNotFound()
+    {
+        $notFound = new Http\PageNotFound();
+
+        return $notFound->execute();
+    }
+
+    protected function getControllerResponse()
+    {
+        $this->loadLang();
+        $this->lang->setContext(($this->getType() . ($this->isAdmin() ? 'AA' : 'CA')), lcfirst($this->getControllerClass(true)));
+
+        $result = DependencyInjection::create(
+            $this->router->getControllerClass(),
+            $this->router->getControllerMethod()
+        );
+
+        return $result;
+    }
+
+    public function getTemplateName()
+    {
+        return $this->templateName;
+    }
+
+    public function getTemplateDir()
+    {
+        if ($this->templateDir === null)
+        {
+            $this->templateDir = ModuleConstants::getTemplateDir() . DIRECTORY_SEPARATOR .
+                ($this->isAdmin() ? self::ADMIN : (self::CLIENT . DIRECTORY_SEPARATOR . $this->getTemplateContext()))
+               . DIRECTORY_SEPARATOR . 'controlers';
+        }
+
+        return $this->templateDir;
+    }
+
+    public function getTemplateContext()
+    {
+        return $this->templateContext;
+    }
+
+    public function getControllerClass($raw = false)
+    {
+        if ($raw)
+        {
+            $namespaceParts = explode('\\', $this->getControllerClass());
+
+            return end($namespaceParts);
+        }
+
+        return $this->router->getControllerClass();
+    }
+
+    public function getControllerMethod()
+    {
+        return $this->router->getControllerMethod();
+    }
+
+    /**
+     * @param null $controllerResult
+     */
+    public function setControllerResult ($controllerResult)
+    {
+        $this->controllerResult = $controllerResult;
+    }
+
+    /**
+     * @return null
+     */
+    public function getControllerResult ()
+    {
+        return $this->controllerResult;
+    }
+
+    /**
+     * @return string
+     */
+    protected function getType()
+    {
+        return 'addon';
+    }
+
+    public function runExecuteProcess($params = null)
+    {
+        return $this->execute($params);
+    }
+}

+ 8 - 0
core/App/Controllers/Interfaces/AddonController.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces;
+
+interface AddonController
+{
+    public function execute($params = []);
+}

+ 8 - 0
core/App/Controllers/Interfaces/AdminArea.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces;
+
+interface AdminArea
+{
+
+}

+ 8 - 0
core/App/Controllers/Interfaces/AppController.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces;
+
+interface AppController
+{
+    public function getControllerInstanceClass($callerName, $params);
+}

+ 8 - 0
core/App/Controllers/Interfaces/ClientArea.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces;
+
+interface ClientArea
+{
+
+}

+ 10 - 0
core/App/Controllers/Interfaces/DefaultController.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Interfaces;
+
+interface DefaultController
+{
+    public function execute($params = null);
+
+    public function runExecuteProcess($params = null);
+}

+ 137 - 0
core/App/Controllers/ResponseResolver.php

@@ -0,0 +1,137 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers;
+
+use \ModulesGarden\Servers\KerioEmail\Core\UI\View;
+use \ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse;
+use \ModulesGarden\Servers\KerioEmail\Core\Http\RedirectResponse;
+use \ModulesGarden\Servers\KerioEmail\Core\Http\Response;
+
+class ResponseResolver
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Smarty;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Template;
+
+    protected $response = null;
+
+    /**
+     * @var null|HttpController
+     */
+    protected $pageController = null;
+
+    public function __construct($response = null)
+    {
+        $this->setResponse($response);
+
+        $this->loadSmarty();
+    }
+
+    /**
+     * @param null $response
+     * @return $this
+     */
+    public function setResponse($response = null)
+    {
+        if ($response)
+        {
+            $this->response = $response;
+        }
+
+        return $this;
+    }
+
+    /**
+     * resolves the response
+     */
+    public function resolve()
+    {
+        if ($this->response instanceof View)
+        {
+            $this->resolveView();
+        }
+
+        if ($this->response instanceof JsonResponse)
+        {
+            $this->resolveJson();
+        }
+        elseif ($this->response instanceof RedirectResponse)
+        {
+            $this->resolveRedirect();
+        }
+        elseif ($this->response instanceof Response)
+        {
+            $this->prepareResponse();
+
+            return $this->resolveResponse();
+        }
+    }
+
+    /**
+     * resolve View object to the processable response
+     */
+    public function resolveView()
+    {
+        /**
+         * @var $this->response \ModulesGarden\Servers\KerioEmail\Core\UI\View
+         */
+        $this->response->validateAcl($this->isAdmin());
+
+        $this->response = $this->response->getResponse();
+    }
+
+    public function prepareResponse()
+    {
+        $this->response->setLang($this->lang);
+        $this->response->setTemplateName($this->getTemplateName());
+        $this->response->setTemplateDir($this->getTemplateDir());
+        //$this->smarty->setTemplateDir();
+    }
+
+    /**
+     * resolve \ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse
+     */
+    public function resolveJson()
+    {
+        $this->cleanOutputBuffer();
+        /**
+         * @var \ModulesGarden\Servers\KerioEmail\Core\Http\JsonResponse
+         */
+        $this->response->send();
+        die();
+    }
+
+    public function resolveRedirect()
+    {
+        /**
+         * @var \ModulesGarden\Servers\KerioEmail\Core\Http\RedirectResponse
+         */
+        die($this->response->send());
+    }
+
+    public function resolveResponse()
+    {
+        return $this->response->getHtmlResponse($this);
+    }
+
+    /**
+     * @param null|HttpController $pageController
+     */
+    public function setPageController($pageController)
+    {
+        $this->pageController = $pageController;
+
+        return $this;
+    }
+
+    /**
+     * @return HttpController|null
+     */
+    public function getPageController()
+    {
+        return $this->pageController;
+    }
+}

+ 103 - 0
core/App/Controllers/Router.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Controllers;
+
+class Router
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Smarty;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\OutputBuffer;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\IsAdmin;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+
+    const ADMIN = 'admin';
+    const CLIENT = 'client';
+
+    protected $controllerClass = null;
+    protected $controllerMethod = null;
+
+    public function __construct()
+    {
+        $this->isAdmin();
+        $this->loadController();
+    }
+
+    /**
+     * load routing params
+     */
+    public function loadController()
+    {
+        $this->getControllerClass();
+        $this->getControllerMethod();
+    }
+
+    /**
+     * @return string
+     * class name of the controller
+     */
+    public function getControllerClass()
+    {
+        if ($this->controllerClass === null)
+        {
+            $this->controllerClass = '\ModulesGarden\Servers\KerioEmail\App\Http\\' . ucfirst($this->getControllerType()) . '\\' . ucfirst($this->getController());
+        }
+
+        return $this->controllerClass;
+    }
+
+    /**
+     * @return string
+     * admin/client context type
+     */
+    public function getControllerType()
+    {
+        return $this->isAdminStatus ? self::ADMIN : self::CLIENT;
+    }
+
+    /**
+     * @return string
+     * get controller name
+     */
+    public function getController()
+    {
+        return filter_var($this->getRequestValue('mg-page', 'Home'), FILTER_SANITIZE_SPECIAL_CHARS);
+    }
+
+    /**
+     * @return string
+     * controller method name
+     */
+    public function getControllerMethod()
+    {
+        if ($this->controllerMethod === null)
+        {
+            $this->controllerMethod = $this->request->get('mg-action', 'index');
+        }
+
+        return $this->controllerMethod;
+    }
+
+    /**
+     * @return bool
+     * determines if controller can be called
+     */
+    public function isControllerCallable()
+    {
+        if (!class_exists($this->controllerClass))
+        {
+            return false;
+        }
+
+        if (!method_exists($this->controllerClass, $this->controllerMethod))
+        {
+            return false;
+        }
+
+        if (!is_callable([$this->controllerClass, $this->controllerMethod]))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 46 - 0
core/App/ErrorHandler.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App;
+
+class ErrorHandler
+{
+    const ERRORS = [1, 4, 16, 64, 256, 4096];
+    const WARNINGS = [2, 32, 128, 512, 2048];
+    const NOTICES = [8, 1024, 8192, 16384];
+
+    public function __construct()
+    {
+        require_once __DIR__ . DIRECTORY_SEPARATOR . 'LowLevelLog.php';
+    }
+    
+    public function logError($errorToken, $errno, $errstr, $errfile, $errline, $errcontext = null)
+    {
+        $logType = $this->getLogType($errno);
+        $errorTime = date('d.m.Y H:i:s', time());
+        $errorDetails = [
+            'errno' => $errno,
+            'errstr' => $errstr,
+            'errfile' => $errfile,
+            'errline' => $errline,
+            'errcontext' => $logType === 'error' ? $errcontext : null
+        ];
+
+        $log = new LowLevelLog($logType, $errorToken, $errorTime);
+        $log->makeLogs($errorDetails);
+    }
+    
+    public function getLogType($errno = null)
+    {
+        if (in_array($errno, self::WARNINGS))
+        {
+            return 'warning';
+        }
+        
+        if (in_array($errno, self::NOTICES))
+        {
+            return 'notice';
+        }
+        
+        return 'error';
+    }
+}

+ 104 - 0
core/App/Installer/DatabaseInstaller.php

@@ -0,0 +1,104 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Installer;
+
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+use Illuminate\Database\Capsule\Manager;
+
+class DatabaseInstaller
+{
+    const STATUS = 'status';
+    const STATUS_SUCCESS = 'success';
+    const STATUS_ERROR = 'error';
+    const RAW_QUERY = 'rawQuery';
+    const ERROR_MESSAGE = 'errorMessage';
+    const FILE = 'file';
+
+    protected $queryResults = [];
+
+    public function performQueryFromFile($file = '')
+    {
+        $queries = $this->getQueries($file);
+
+        array_map(function($query) use ($file)
+        {
+            $this->execute($query, $file);
+        }, $queries);
+    }
+
+    protected function execute(&$query, $file)
+    {
+        try
+        {
+            $pdo = Manager::connection()->getPdo();
+            if (empty($query) === false)
+            {
+                $statement = $pdo->prepare($query);
+                $statement->execute();
+            }
+        }
+        catch (\PDOException $exc)
+        {
+            $this->queryResults[] = [
+                self::STATUS => self::STATUS_ERROR,
+                self::ERROR_MESSAGE => $exc->getMessage(),
+                self::FILE => $file,
+                self::RAW_QUERY => str_replace(PHP_EOL, '<br>', $query)
+            ];
+
+            return null;
+        }
+
+        $this->queryResults[] = [
+            self::STATUS => self::STATUS_SUCCESS,
+            self::FILE => $file,
+            self::RAW_QUERY => $query
+        ];
+    }
+
+    protected function getQueries($file)
+    {
+        return array_filter(explode(';', Reader::read($file)->get()), function ($element) {
+            $tElement = trim($element);
+            if ($element === '' || $tElement === '')
+            {
+                return false;
+            }
+
+            return true;
+        });
+    }
+
+    public function isInstallCorrect()
+    {
+        foreach ($this->queryResults as $result)
+        {
+            if ($result[self::STATUS] === self::STATUS_ERROR)
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public function getFailedQueries()
+    {
+        $failedList = [];
+
+        foreach ($this->queryResults as $result)
+        {
+            if ($result[self::STATUS] === self::STATUS_ERROR)
+            {
+                $failedList[] = $result;
+            }
+        }
+
+        return $failedList;
+    }
+
+    public function getQueriesResults()
+    {
+        return $this->queryResults;
+    }
+}

+ 76 - 0
core/App/Installer/ModuleInstaller.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Installer;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Packages\PackageManager;
+use ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+class ModuleInstaller
+{
+    protected $databaseInstaller = null;
+
+    public function __construct()
+    {
+        $this->databaseInstaller = DependencyInjection::get(DatabaseInstaller::class);
+    }
+
+    public function makeInstall()
+    {
+        $this->installModule();
+        $this->installPackages();
+    }
+
+    public function installModule()
+    {
+        array_map(function ($value){
+            $this->databaseInstaller->performQueryFromFile($value);
+        }, $this->getModuleQueriesPaths());
+    }
+
+    public function getModuleQueriesPaths()
+    {
+        return [
+            ModuleConstants::getFullPath('core', 'Database', 'schema.sql'),
+            ModuleConstants::getFullPath('app', 'Database', 'schema.sql'),
+            ModuleConstants::getFullPath('core', 'Database', 'data.sql'),
+            ModuleConstants::getFullPath('app', 'Database', 'data.sql')
+        ];
+    }
+
+    public function installPackages()
+    {
+        $packageManager = DependencyInjection::get(PackageManager::class);
+
+        array_map(function ($package){
+            $packageName = $package->getName();
+
+            $packageSchemaPath =  ModuleConstants::getFullPath('packages', $packageName, 'Database', 'schema.sql');
+            if (file_exists($packageSchemaPath) && is_readable($packageSchemaPath))
+            {
+                $this->databaseInstaller->performQueryFromFile($packageSchemaPath);
+            }
+
+            $packageDataPath =  ModuleConstants::getFullPath('packages', $packageName, 'Database', 'schema.sql');
+            if (file_exists($packageDataPath) && is_readable($packageDataPath))
+            {
+                $this->databaseInstaller->performQueryFromFile($packageDataPath);
+            }
+        }, $packageManager->getPackagesConfiguration());
+    }
+
+    public function isInstallCorrect()
+    {
+        return $this->databaseInstaller->isInstallCorrect();
+    }
+
+    public function getFailedQueries()
+    {
+        return $this->databaseInstaller->getFailedQueries();
+    }
+
+    public function getQueriesResults()
+    {
+        return $this->databaseInstaller->getQueriesResults();
+    }
+}

+ 90 - 0
core/App/LowLevelLog.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App;
+
+class LowLevelLog
+{
+    protected $logType = null;
+    protected $logToken = null;
+    protected $logTime = null;
+    protected $moduleName = null;
+
+    public function __construct($logType, $logToken, $logTime)
+    {
+        $this->logType = $logType;
+        $this->logToken = $logToken;
+        $this->logTime = $logTime;
+    }
+
+    public function makeLogs($logDetails)
+    {
+        if ($this->logType === 'error')
+        {
+            $this->logToDb($logDetails);
+        }
+        
+        $this->logToFile($logDetails);
+        
+        if ($this->logType === 'error')
+        {
+            $this->logToPHPLog($logDetails);
+        }
+    }
+    
+    public function logToDb($logDetails = [])
+    {
+        \logModuleCall(
+            $this->getModuleName() . ' Error',
+            'Token: ' . $this->logToken,
+            ['time' => $this->logTime],
+            var_export($logDetails, true)
+        );
+    }
+
+    public function logToFile($logDetails)
+    {
+        $logData = date('d.m.Y H:i:s', time()) . ' - Token: ' . $this->logToken . ' - ' . var_export($logDetails, true) . PHP_EOL;
+        $logFile = $this->getLogFile($this->logType);
+
+        file_put_contents($logFile, $logData, FILE_APPEND);
+    }
+
+    public function logToPHPLog($logDetails)
+    {
+        
+    }
+
+    public function getLogFile($logType = 'error')
+    {
+        $logDir = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'logs';
+        $logFile = $logDir . DIRECTORY_SEPARATOR . $logType . '.log';
+        if (!file_exists($logFile) && !is_writable($logDir))
+        {
+            //throw new \Exception('Insufficient permissions for directory: ' . $logDir);
+        }
+        if (file_exists($logFile) && !is_writable($logFile))
+        {
+            //throw new \Exception('Insufficient permissions for file: ' . $logFile);
+        }
+
+        return $logFile;
+    }
+
+    public function getModuleName()
+    {
+        if (!$this->moduleName)
+        {
+            $className = trim(self::class, '\\');
+            if (strpos($className, 'ModulesGarden') === 0)
+            {
+                $pt1 = str_replace('ModulesGarden\\', '', $className);
+                if (strpos($pt1, '\Core\App'))
+                {
+                    $this->moduleName = substr($pt1, 0, strpos($pt1, '\Core\App'));
+                }
+            }
+        }
+
+        return $this->moduleName;
+    }
+}

+ 21 - 0
core/App/Packages/AppPackageConfiguration.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Packages;
+
+abstract class AppPackageConfiguration
+{
+    const PACKAGE_STATUS = 'packageStatus';
+    const PACKAGE_STATUS_ACTIVE = 'active';
+    const PACKAGE_STATUS_INACTIVE = 'inactive';
+
+    public function getSuboptionsByCallback($optName = null)
+    {
+        $fullOptName = $optName . 'GetSubOptions';
+        if (method_exists($this, $fullOptName))
+        {
+            return $this->{$fullOptName}();
+        }
+
+        return false;
+    }
+}

+ 76 - 0
core/App/Packages/BasePackageConfiguration.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Packages;
+
+abstract class BasePackageConfiguration
+{
+    protected $configuration = null;
+    protected $appConfigFound = false;
+
+    static $protectedConfigOptions = [
+        PackageConfigurationConst::VERSION,
+        PackageConfigurationConst::PACKAGE_NAME
+    ];
+
+    public function __get($key)
+    {
+        $this->loadConfiguration();
+
+        if(isset($this->configuration[$key]))
+        {
+            return $this->configuration[$key];
+        }
+
+        return null;
+    }
+
+    public function getConfig()
+    {
+        $this->loadConfiguration();
+
+        return $this->configuration;
+    }
+
+    public function getName()
+    {
+        $this->loadConfiguration();
+
+        return $this->configuration[PackageConfigurationConst::PACKAGE_NAME];
+    }
+
+    public function loadConfiguration($forceReload = false)
+    {
+        if (!($this->configuration === null || $forceReload))
+        {
+            return;
+        }
+
+        $config = $this::CONFIGURATION;
+        $packageName = $config[PackageConfigurationConst::PACKAGE_NAME];
+
+        $appPackageConfig = $this->getAppPackageConfig($packageName);
+
+        $merged = array_merge($config, $appPackageConfig);
+        foreach (self::$protectedConfigOptions as $protectedOption)
+        {
+            $merged[$protectedOption] = $config[$protectedOption];
+        }
+
+        $this->configuration = $merged;
+    }
+
+    public function getAppPackageConfig($packageName = null)
+    {
+        $appConfigClassName = '\ModulesGarden\Servers\KerioEmail\App\Config\Packages\\' . $packageName;
+        if (!class_exists($appConfigClassName) || !is_subclass_of($appConfigClassName, AppPackageConfiguration::class)
+            || !defined($appConfigClassName . '::APP_CONFIGURATION'))
+        {
+
+            return [];
+        }
+
+        $this->appConfigFound = true;
+
+        return $appConfigClassName::APP_CONFIGURATION;
+    }
+}

+ 9 - 0
core/App/Packages/PackageConfigurationConst.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Packages;
+
+class PackageConfigurationConst
+{
+    const VERSION = 'version';
+    const PACKAGE_NAME = 'packageName';
+}

+ 103 - 0
core/App/Packages/PackageManager.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Packages;
+
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Directory;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+class PackageManager
+{
+    const STATUS_ACTIVE = 'active';
+    const STATUS_INACTIVE = 'inactive';
+
+    const STATUS_REASON_INACTIVE = 'Inactive in the configuration';
+    const STATUS_REASON_CONFIG_MISSING = 'Inactive because of lack of the configuration file';
+
+    protected $packageList = [];
+
+    public function __construct()
+    {
+        $this->loadPackages();
+    }
+
+    public function getPackageConfiguration($packageName)
+    {
+        if (isset($this->packageList[$packageName]))
+        {
+            return $this->packageList[$packageName];
+        }
+
+        return null;
+    }
+
+    public function getPackagesConfiguration()
+    {
+        return $this->packageList;
+    }
+
+    protected function loadPackages()
+    {
+        $packageList = $this->getPackageListByDirectory();
+        foreach ($packageList as $className)
+        {
+            $config = new $className();
+            $packageName = $config->getName();
+
+            if ($this->isNameValid($packageName) && $this->isVersionValid($config->{PackageConfigurationConst::VERSION}) && $this->isStatusValid($config->{AppPackageConfiguration::PACKAGE_STATUS}))
+            {
+                $this->packageList[$packageName] = $config;
+            }
+        }
+    }
+
+    public function getPackageListByDirectory()
+    {
+        $directoryHelper = new Directory();
+
+        $packagesDirectory = ModuleConstants::getModuleRootDir() . DIRECTORY_SEPARATOR . 'packages';
+
+        $packagesList = $directoryHelper->getFilesList($packagesDirectory);
+
+        $existing = [];
+        foreach ($packagesList as $packageName)
+        {
+            $className = '\ModulesGarden\Servers\KerioEmail\Packages\\' . $packageName . '\Config\PackageConfiguration';
+            if (class_exists($className) && is_subclass_of($className, BasePackageConfiguration::class))
+            {
+                $existing[] = $className;
+            }
+        }
+
+        return $existing;
+    }
+
+    public function isNameValid($name = null)
+    {
+        if(trim($name) === '' || !is_string($name))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public function isVersionValid($version = null)
+    {
+        if(trim($version) === '' || !is_string($version))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public function isStatusValid($status = null)
+    {
+        if(!in_array($status, [AppPackageConfiguration::PACKAGE_STATUS_ACTIVE, AppPackageConfiguration::PACKAGE_STATUS_INACTIVE]))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 93 - 0
core/App/Requirements/Checker.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements;
+
+/**
+ * Description of Handler
+ *
+ * @author INBSX-37H
+ */
+class Checker
+{
+    /** 
+     * \ModulesGarden\Servers\KerioEmail\Core\FileReader\PathValidator
+     * @var type null|\ModulesGarden\Servers\KerioEmail\Core\FileReader\|\ModulesGarden\Servers\KerioEmail\Core\FileReader\Directory
+     */
+    protected $directoryHandler = null;
+    
+    protected $requirementsList = [];
+    
+    protected $checkResaults = [];
+    
+    /** 
+     * Paths for Requirements class to be placed in
+     * @var type array
+     */
+    const PATHS = [
+        'app' . DIRECTORY_SEPARATOR . 'Configuration' . DIRECTORY_SEPARATOR . 'Requirements',
+        'core' . DIRECTORY_SEPARATOR . 'Configuration' . DIRECTORY_SEPARATOR . 'Requirements'
+    ];
+ 
+    public function __construct()
+    {
+        $this->directoryHandler = new \ModulesGarden\Servers\KerioEmail\Core\FileReader\Directory();
+
+        $this->loadRequirements();
+        
+        $this->checkRequirements();
+    }
+    
+    protected function loadRequirements()
+    {
+        foreach (self::PATHS as $path)
+        {
+            $this->loadClassesByPath($path);
+        }
+    }
+    
+    protected function loadClassesByPath($path)
+    {
+        $fullPath = \ModulesGarden\Servers\KerioEmail\Core\ModuleConstants::getModuleRootDir() . DIRECTORY_SEPARATOR . $path;
+        $files = $this->directoryHandler->getFilesList($fullPath, '.php', true);
+        $classNamespace = $this->getClassNamespaceByPath($path);
+        foreach ($files as $file)
+        {
+            $className = $classNamespace . $file;
+            if (!class_exists($className) || !is_subclass_of($className, RequirementInterface::class))
+            {
+                continue;
+            }
+            
+            $this->requirementsList[] = $className;
+        }
+    }
+    
+    protected function getClassNamespaceByPath($path)
+    {
+        $contextParts = explode('\\', self::class);
+        $coreParts = explode(DIRECTORY_SEPARATOR, $path);
+
+        $allParts = array_merge([$contextParts[0], $contextParts[1]], $coreParts);
+        array_walk($allParts, function(&$item){
+            $item = ucfirst($item);
+        });
+        
+        return '\\' . implode('\\', $allParts) . '\\';
+    }
+    
+    protected function checkRequirements()
+    {
+        foreach ($this->requirementsList as $requirement)
+        {
+            $instance = \ModulesGarden\Servers\KerioEmail\Core\DependencyInjection\DependencyInjection::call($requirement);
+            $handler = $instance->getHandlerInstance();
+            
+            $this->checkResaults = array_merge($this->checkResaults, $handler->getUnfulfilledRequirements());
+        }
+    }
+    
+    public function getUnfulfilledRequirements()
+    {
+        return $this->checkResaults;
+    }
+}

+ 35 - 0
core/App/Requirements/Handler.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements;
+
+/**
+ * Description of Handler
+ *
+ * @author INBSX-37H
+ */
+abstract class Handler
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+
+    protected $unfulfilledRequirements = [];
+
+    protected function addUnfulfilledRequirement($message = null, $params = [])
+    {
+        if ($message)
+        {
+            $this->loadLang();
+            $translated = $this->lang->absoluteTranslate('unfulfilledRequirement', $message);
+            foreach ($params as $searchKey => $searchValue)
+            {
+                $translated = str_replace(':' . (string)$searchKey . ':', (string)$searchValue, $translated);
+            }
+
+            $this->unfulfilledRequirements[] = $translated;
+        }
+    }
+
+    public function getUnfulfilledRequirements()
+    {
+        return $this->unfulfilledRequirements;
+    }
+}

+ 13 - 0
core/App/Requirements/HandlerInterface.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements;
+
+/**
+ * Description of RequirementInterface
+ *
+ * @author INBSX-37H
+ */
+interface HandlerInterface
+{
+    public function handleRequirements();
+}

+ 49 - 0
core/App/Requirements/Handlers/Classes.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handlers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handler;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Instances\Classes as ClassesInstance;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\HandlerInterface;
+
+/**
+ * Description of Files
+ *
+ * @author INBSX-37H
+ */
+class Classes extends Handler implements HandlerInterface
+{
+    protected $classList = [];
+
+    public function __construct(array $classList = [])
+    {
+        $this->classList = $classList;
+        
+        $this->handleRequirements();
+    }
+
+    public function handleRequirements()
+    {
+        foreach ($this->classList as $record)
+        {
+            $this->handleRequirement($record);
+        }
+    }
+
+    protected function handleRequirement($record)
+    {
+        $className = $record[ClassesInstance::CLASS_NAME];
+        if ($className[0] !== '\\')
+        {
+            $className = '\\' . $className;
+        }
+
+        if (class_exists($className))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, it requires the :class_name: class.',
+            ['class_name' => $className]);
+    }
+}

+ 114 - 0
core/App/Requirements/Handlers/Files.php

@@ -0,0 +1,114 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handlers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handler;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\HandlerInterface;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Instances\Files as FilesInstance;
+
+/**
+ * Description of Files
+ *
+ * @author INBSX-37H
+ */
+class Files extends Handler implements HandlerInterface
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    
+    protected $fileList = [];
+
+    public function __construct(array $fileList = [])
+    {
+        $this->fileList = $fileList;
+        
+        $this->handleRequirements();
+    }
+
+    public function handleRequirements()
+    {
+        foreach ($this->fileList as $record)
+        {
+            if (!$this->isValidPath($record[FilesInstance::PATH]))
+            {
+                continue;
+            }
+
+            $this->handleRequirement($record);
+        }
+    }
+    
+    public function isValidPath($path)
+    {
+        if (stripos($path, FilesInstance::WHMCS_PATH) === 0
+            || stripos($path, FilesInstance::MODULE_PATH) === 0)
+        {
+            return true;
+        }
+        
+        return false;
+    }
+    
+    protected function handleRequirement($record)
+    {
+        $filePath = $this->getFullPath($record[FilesInstance::PATH]);
+
+        switch ($record[FilesInstance::TYPE])
+        {
+            case FilesInstance::REMOVE:
+                $this->removeFile($filePath);
+                break;
+            case FilesInstance::IS_WRITABLE:
+                $this->checkIfWritable($filePath);
+                break;
+        }
+        
+    }
+    
+    public function getFullPath($recordPath = null)
+    {
+        if (stripos($recordPath, FilesInstance::WHMCS_PATH) === 0)
+        {
+            return str_replace(FilesInstance::WHMCS_PATH, \ModulesGarden\Servers\KerioEmail\Core\ModuleConstants::getFullPathWhmcs(),
+                    str_replace('/', DIRECTORY_SEPARATOR, $recordPath));
+        }
+
+        if (stripos($recordPath, FilesInstance::MODULE_PATH) === 0)
+        {
+            return str_replace(FilesInstance::MODULE_PATH, \ModulesGarden\Servers\KerioEmail\Core\ModuleConstants::getModuleRootDir(),
+                    str_replace('/', DIRECTORY_SEPARATOR, $recordPath));
+        }
+
+        return null;
+    }
+    
+    protected function removeFile($filePath = null)
+    {
+        $fileValidator = new \ModulesGarden\Servers\KerioEmail\Core\FileReader\PathValidator();
+        if (!$fileValidator->pathExists($filePath))
+        {
+            return null;
+        }
+        
+        unlink($filePath);
+        
+        if (!$fileValidator->pathExists($filePath))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, please remove the following file: :remove_file_requirement:',
+                ['remove_file_requirement' => $filePath]);
+    }
+
+    protected function checkIfWritable($filePath = null)
+    {
+        $fileValidator = new \ModulesGarden\Servers\KerioEmail\Core\FileReader\PathValidator();
+        if ($fileValidator->isPathWritable($filePath))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, please set up permissions to the :writable_file_requirement: directory as writable.',
+            ['writable_file_requirement' => $filePath]);
+    }
+}

+ 47 - 0
core/App/Requirements/Handlers/PhpExtensions.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handlers;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handler;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\HandlerInterface;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Instances\PhpExtensions as PhpExtensionsInstance;
+
+/**
+ * Description of PhpExtensions
+ *
+ * @author INBSX-37H
+ */
+class PhpExtensions extends Handler implements HandlerInterface
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    
+    protected $extensionsList = [];
+
+    public function __construct(array $classList = [])
+    {
+        $this->extensionsList = $classList;
+        
+        $this->handleRequirements();
+    }
+
+    public function handleRequirements()
+    {
+        foreach ($this->extensionsList as $record)
+        {
+            $this->handleRequirement($record);
+        }
+    }
+
+    protected function handleRequirement($record)
+    {
+        $extension = $record[PhpExtensionsInstance::EXTENSION_NAME];
+
+        if (extension_loaded($extension))
+        {
+            return null;
+        }
+
+        $this->addUnfulfilledRequirement('In order for the module to work correctly, it requires the :extension_name: PHP extension to be installed.',
+            ['extension_name' => $extension]);
+    }
+}

+ 20 - 0
core/App/Requirements/Instances/Classes.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Instances;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\RequirementsList;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\RequirementInterface;
+/**
+ * Description of Classes
+ *
+ * @author INBSX-37H
+ */
+abstract class Classes extends RequirementsList implements RequirementInterface
+{
+    const CLASS_NAME = 'className';
+
+    final public function getHandler()
+    {
+        return \ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handlers\Classes::class;
+    }
+}

+ 30 - 0
core/App/Requirements/Instances/Files.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Instances;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\RequirementsList;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\RequirementInterface;
+
+/**
+ * Description of Files
+ *
+ * @author INBSX-37H
+ */
+abstract class Files extends RequirementsList implements RequirementInterface
+{
+    const WHMCS_PATH = ':WHMCS_PATH:';
+    const MODULE_PATH = ':MODULE_PATH:';    
+    
+    const PATH = 'path';
+    const TYPE = 'type';
+    
+    const REMOVE = 'remove';
+    const EXISTS = 'exists';
+    const IS_WRITABLE = 'isWritable';
+    const IS_READABLE = 'isReadable';
+
+    final public function getHandler()
+    {
+        return \ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handlers\Files::class;
+    }
+}

+ 21 - 0
core/App/Requirements/Instances/PhpExtensions.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Instances;
+
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\RequirementsList;
+use ModulesGarden\Servers\KerioEmail\Core\App\Requirements\RequirementInterface;
+
+/**
+ * Description of PhpExtensions
+ *
+ * @author INBSX-37H
+ */
+abstract class PhpExtensions extends RequirementsList implements RequirementInterface
+{
+    const EXTENSION_NAME = 'extensionName';
+
+    final public function getHandler()
+    {
+        return \ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Handlers\PhpExtensions::class;
+    }
+}

+ 13 - 0
core/App/Requirements/RequirementInterface.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements;
+
+/**
+ * Description of RequirementInterface
+ *
+ * @author INBSX-37H
+ */
+interface RequirementInterface
+{
+
+}

+ 26 - 0
core/App/Requirements/RequirementsList.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App\Requirements;
+
+/**
+ * Description of Requirements
+ *
+ * @author INBSX-37H
+ */
+abstract class RequirementsList
+{
+    protected $requirementsList = [];
+
+    public function getHandlerInstance()
+    {
+        $handler = $this->getHandler();
+        if (!class_exists($handler))
+        {
+            return null;
+        }
+
+        return new $handler($this->requirementsList);
+    }
+
+    abstract function getHandler();
+}

+ 64 - 0
core/App/TemplateDisplayWrapper.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\App;
+
+use \ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Template Display Wrapper
+ *
+ * @author slawomir@modulesgarden.com
+ */
+class TemplateDisplayWrapper
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    
+    protected $templateName = null;
+    protected $templateDir = null;
+    protected $vars = [];
+
+
+    public function __construct($templateName = null, $templateDir = null, $vars = [], $lang = null)
+    {
+        $this->setTemplate($templateName, $templateDir);
+        $this->setVars($vars);
+        $this->setLang($lang);
+    }
+    
+    public function toHtml()
+    {
+            $pageContent = ServiceLocator::call('smarty')
+                ->setLang($this->lang)
+                ->setTemplateDir($path)
+                ->view($fileName, $vars);
+
+            return $pageContent;        
+    }
+    
+    public function setTemplate($templateName = null, $templateDir = null)
+    {
+        if (file_exists($templateDir . DIRECTORY_SEPARATOR . $templateName . '.tpl'))
+        {
+            $this->templateName = $templateName;
+            $this->templateDir = $templateDir;
+        }
+    }
+    
+    public function setVars($vars = [])
+    {
+        if (is_array($vars))
+        {
+            $this->vars = $vars;
+        }
+    }
+    
+    public function setLang($lang = null)
+    {
+        if ($lang instanceof \ModulesGarden\Servers\KerioEmail\Core\Lang)
+        {
+            $this->lang = $lang;
+        }
+        
+        $this->loadLang();
+    }
+}

+ 56 - 0
core/Bootstrap.php

@@ -0,0 +1,56 @@
+<?php
+
+use \ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use \ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+use \ModulesGarden\Servers\KerioEmail\Core\FileReader\PathValidator;
+use \ModulesGarden\Servers\KerioEmail\Core\FileReader\File;
+use \ModulesGarden\Servers\KerioEmail\Core\DependencyInjection\Builder;
+use \ModulesGarden\Servers\KerioEmail\Core\DependencyInjection\Services;
+
+if (!defined('DS')) define('DS', DIRECTORY_SEPARATOR);
+if (!defined('PS')) define('PS', PATH_SEPARATOR);
+if (!defined('CRLF')) define('CRLF', "\r\n");
+
+require_once dirname(__DIR__) . DS . "vendor" . DS . "autoload.php";
+
+/**
+ * Initialize base values
+ */
+ModuleConstants::initialize();
+
+/**
+ * Initailize DI builder
+ */
+new Builder();
+
+/**
+ * Initialize Services
+ */
+new Services();
+
+/**
+ * Check file permission
+ */
+if (is_dir(ModuleConstants::getFullPath('storage')) === false 
+        || is_writable(ModuleConstants::getFullPath('storage')) === false
+        || is_writable(ModuleConstants::getFullPath('storage', 'app')) === false
+        || is_writable(ModuleConstants::getFullPath('storage', 'crons')) === false
+        || is_writable(ModuleConstants::getFullPath('storage', 'logs')) === false)
+{
+    File::createPaths(
+            ['full' => ModuleConstants::getFullPath('storage'),              'permission' => 0777],
+            ['full' => ModuleConstants::getFullPath('storage', 'app'),       'permission' => 0777],
+            ['full' => ModuleConstants::getFullPath('storage', 'crons'),     'permission' => 0777],
+            ['full' => ModuleConstants::getFullPath('storage', 'logs'),      'permission' => 0777]
+    );
+}
+
+$pathValidator = new PathValidator();
+if (!$pathValidator->validatePath(ModuleConstants::getFullPath('storage', 'logs'), true, true, true))
+{
+    ServiceLocator::call('errorManager')->addError(
+        'Bootstrap',
+        PHP_EOL . ServiceLocator::call('lang')->absoluteT('permissionsStorage'),
+        ['path' => ModuleConstants::getFullPath('storage')]
+    );
+}

+ 209 - 0
core/Cache/CacheManager.php

@@ -0,0 +1,209 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Cache;
+
+use Symfony\Component\Cache\Simple\FilesystemCache;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use ModulesGarden\Servers\KerioEmail\Core\Interfaces\CacheManagerInterface;
+
+/**
+ * Description of CacheManager
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class CacheManager implements CacheManagerInterface
+{
+    protected static $instance = null;
+
+    /**
+     * @var CacheManagerInterface
+     */
+    protected $manager;
+    
+    /**
+     * @var string
+     */
+    protected $dir = '';
+    
+    /**
+     * @var string
+     */
+    protected $namespace = '';
+    
+    /**
+     * @var string
+     */
+    protected $key;
+    
+    /**
+     * @var string|array|object
+     */
+    protected $data;
+
+    public function __construct()
+    {
+        $this->namespace = ModuleConstants::getRootNamespace();
+        $this->dir = ModuleConstants::getModuleRootDir() . DS . 'storage' . DS . 'framework';
+        $this->manager = new FilesystemCache('', 0, $this->dir);
+    }
+    
+    private function __clone()
+    {
+        
+    }
+
+
+    /**
+     * @param string $key
+     * @return $this
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function setKey($key = 'default')
+    {
+        try
+        {
+            $this->key = $key;
+            $this->setData($this->manager->get($this->key));
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        
+        
+        return $this;
+    }
+    
+    /**
+     * @return string
+     */
+    public function getKey()
+    {
+        return $this->key;
+    }
+    
+    /**
+     * @param mixed $data
+     * @return $this
+     */
+    public function setData($data = null)
+    {
+        if ($data !== null)
+        {
+            $this->data = $data;
+        }
+        
+        return $this;
+    }
+    
+    /**
+     * @return mixed
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function getData()
+    {
+        try
+        {
+            if (isset($this->key))
+            {
+                $this->data = $this->manager->get($this->key);
+            }
+            return $this->data;
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        
+    }
+    
+    /**
+     * @return $this
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function save()
+    {
+        try
+        {
+            $this->manager->set($this->key, $this->data);
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        return $this;
+    }
+    
+    /**
+     * @return $this
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function remove()
+    {
+        try
+        {
+            $this->manager->delete($this->key);
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        return $this;
+    }
+    
+    /**
+     * @return $this
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function clearAll()
+    {
+        try
+        {
+            $this->manager->clear();
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+        return $this;
+    }
+    
+    /**
+     * @return type
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException
+     */
+    public function exist()
+    {
+        try
+        {
+            return $this->manager->has($this->key);
+        }
+        catch (\Exception $ex)
+        {
+            throw new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\MGModuleException(self::class, $ex->getMessage(), $ex->getCode(), $ex);
+        }
+    }
+
+    /**
+     * @return CacheManager
+     */
+    public static function instance()
+    {
+        if (CacheManager::$instance === null)
+        {
+            CacheManager::$instance = new CacheManager();
+        }
+        return CacheManager::$instance;
+    }
+    
+    public static function cache($key = null)
+    {
+        $istance = self::instance();
+        if ($key)
+        {
+            $istance->setKey($key);
+        }
+
+        return $istance;
+    }
+}

+ 107 - 0
core/CommandLine/AbstractCommand.php

@@ -0,0 +1,107 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+/**
+ * Class Command
+ * @package ModulesGarden\Servers\KerioEmail\Core\CommandLine
+ */
+class AbstractCommand extends \Symfony\Component\Console\Command\Command
+{
+    /**
+     * Command name
+     * @var string
+     */
+    protected $name         = null;
+
+    /**
+     * Command description
+     * @var string
+     */
+    protected $description  = '';
+
+    /**
+     * Command help text. Use --help to show
+     * @var string
+     */
+    protected $help         = '';
+
+    /**
+     * minimal command configuration
+     */
+    protected function configure()
+    {
+        $this
+            ->setName($this->name)
+            ->setDescription($this->description)
+            ->setHelp($this->help)
+            ->addOption('force', 'f', InputOption::VALUE_OPTIONAL, 'Force script to run, without checking if another instance is running', false);
+
+        $this->setup();
+    }
+
+    /**
+     * Execute command
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        try
+        {
+            $this->beforeProcess($input, $output);
+
+            $this->process($input, $output, new SymfonyStyle($input, $output));
+
+            $this->afterProcess($input, $output);
+        }
+        catch(\Exception $ex)
+        {
+            (new SymfonyStyle($input, $output))->error($ex->getMessage());
+        }
+
+        return 0;
+    }
+
+    /**
+     * Add some custom actions here based on documentation  https://symfony.com/doc/current/console.html
+     */
+    protected function setup()
+    {
+
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @param SymfonyStyle $io
+     */
+    protected function process(InputInterface $input, OutputInterface $output, SymfonyStyle $io)
+    {
+
+    }
+
+    /**
+     * Function will be called before executing "process" function
+     * @throws \Exception
+     */
+    protected function beforeProcess(InputInterface $input, OutputInterface $output)
+    {
+
+    }
+
+    /**
+     * Function will be called after executing "process" function
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    protected function afterProcess(InputInterface $input, OutputInterface $output)
+    {
+
+    }
+}

+ 43 - 0
core/CommandLine/AbstractCronController.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+/**
+ * Description of AbstractCronController
+ *
+ * @author Rafał
+ */
+if (class_exists(\Thread::class))
+{
+    class AbstractCronController extends \Thread
+    {
+        protected $className;
+        protected $cronManager;
+
+        public function setCronManager($cronManager)
+        {
+            $this->cronManager = $cronManager;
+
+            return $this;
+        }
+
+        public function setClassName($className)
+        {
+            $this->className = $className;
+
+            return $this;
+        }
+
+        protected function updatePid()
+        {
+            CronManager::updatePids($this->className);
+        }
+    }
+}
+else
+{
+    class AbstractCronController
+    {
+        
+    }
+}

+ 218 - 0
core/CommandLine/AbstractCronControllerWithoutThread.php

@@ -0,0 +1,218 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use \ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use \ModulesGarden\Servers\KerioEmail\Core\Models\CronTabs;
+
+/**
+ * Description of AbstractCronController
+ *
+ * @author Rafał
+ */
+abstract class AbstractCronControllerWithoutThread
+{
+    protected $exit = true;
+    protected $error = false;
+    protected $isChild = false;
+    protected $className;
+    protected $child = 0;
+    protected $childId;
+    protected $parentId;
+    protected $cronManager;   
+    protected $parentUserId;
+    protected $parentGroupId; 
+
+    public function setParentId($parentId)
+    {
+        $this->parentId = $parentId;
+
+        return $this;
+    }
+
+    public function setChildId($childId)
+    {
+        $this->childId = $childId;
+
+        return $this;
+    }
+
+    public function ischild($isChild)
+    {
+        $this->isChild = $isChild;
+
+        return $this;
+    }
+
+    public function setClassName($className)
+    {
+        $this->className = $className;
+
+        return $this;
+    }
+    
+    protected function canRunScript()
+    {
+        $run = true;
+        foreach (CronTabs::get() as $cronTab)
+        {
+            if ($cronTab->name == CronTabs::DEFAULT_CRON_MANAGER_NAME && $cronTab->status == 'stop')
+            {
+                $run = false;
+            }
+            elseif ($cronTab->name == $this->className && $cronTab->status == 'stop')
+            {
+                $run = false;
+            }
+        }
+        
+        return $run;
+    }
+
+    protected function updatePid()
+    {
+        if ($this->isChild)
+        {
+            CronManager::updatePids($this->className, $this->childId);
+            if ($this->parentGroupId === getmygid() && $this->parentUserId === getmyuid())
+            {
+                $this->removePid();
+            }
+        }
+
+        return $this;
+    }
+    
+    protected function isExistPid()
+    {
+        if ($this->isChild)
+        {
+            return CronManager::existPids($this->className, $this->childId);
+        }
+        
+        return $this->canRunScript();
+    }
+
+    protected function removePid()
+    {
+        if ($this->isChild)
+        {
+            CronManager::removePids($this->className, $this->childId);
+        }
+        
+        return $this;
+    }
+
+    abstract public function run();
+
+    public function isChildrenCreate()
+    {
+        return false;
+    }
+
+    public function getChildrenCount()
+    {
+        return $this->child;
+    }
+
+    public function setCronManager($cronManager)
+    {
+        $this->cronManager = $cronManager;
+
+        return $this;
+    }
+    
+    public function getIndexElements()
+    {
+        $childrenListIds = [];
+        
+        for ($key = 1; $key <= $this->getChildrenCount(); $key++)
+        {
+            $childrenListIds[] = $key;
+        }
+        
+        return $childrenListIds;
+    }
+
+    public function start()
+    {
+        try{
+            if ($this->isStart() === false)
+            {
+                if ($this->child > 0 && $this->isChild === false)
+                {
+                    while ($this->canRunScript())
+                    {
+                        if ($this->isChildrenCreate())
+                        {
+                            $parentId = getmypid();
+                            $parentUId = $this->parentUserId ? $this->parentUserId : getmyuid();
+                            $parentGId = $this->parentGroupId ? $this->parentGroupId : getmygid();
+                            foreach ($this->getIndexElements() as $key)
+                            {
+                                if ($this->cronManager->isChildRunning($this->className, $key))
+                                {
+                                    continue;
+                                }
+
+                                $phpInterpreter       = \PHP_BINARY ?: 'php';
+                                $internalCronDumpFile = ModuleConstants::getFullPath('storage', 'crons', 'cronLog');
+                                exec($phpInterpreter . " " . ModuleConstants::getModuleRootDir() . DS . 'cron' . DS . 'cron.php ' . $this->className
+                                        . " --parent {$parentId} --parentuid {$parentUId} --parentgid {$parentGId} --child {$key} >> {$internalCronDumpFile} &");
+                            }
+                        }
+                        $this->wait(4000000);
+                    }
+                }
+                elseif ($this->child === 0 && $this->isChild === false)
+                {
+                    $this->exit = false;
+                    $this->run();
+                }
+                elseif ($this->isChild === true)
+                {
+                    $this->exit = false;
+                    $this->run();
+                    $this->removePid();
+                    exit;
+                }
+            }
+        } 
+        catch (\Exception $ex) 
+        {
+            $this->error = $ex->getMessage();
+        }
+    }    
+    
+    public function setParentGroupId($parentGroupId)
+    {
+        $this->parentGroupId = $parentGroupId;
+        
+        return $this;
+    }
+    
+    public function setParentUserId($parentUserId)
+    {
+        $this->parentUserId = $parentUserId;
+        
+        return $this;
+    }
+
+    public function isStart()
+    {
+        return ($this->exit === false);
+    }
+
+    public function wait($seconds = 500000)
+    {
+        usleep($seconds);
+    }
+
+    function __destruct()
+    {
+        if ($this->error)
+        {
+            CronTabs::ifName($this->className)->addError($this->error);
+        }
+    }
+}

+ 54 - 0
core/CommandLine/Application.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+class Application extends \Symfony\Component\Console\Application
+{
+    protected $dir          = '';
+
+    /**
+     * @override
+     */
+    public function run()
+    {
+        $this->loadCommandsControllers($this->getCommands());
+
+        parent::run();
+    }
+
+    /**
+     * Get all available files
+     * @return array
+     */
+    protected function getCommands()
+    {
+        $files      = glob(ModuleConstants::getFullPath('app', $this->dir).'/*.php');
+        $commands   = [];
+
+        foreach($files as $file)
+        {
+            $file   = substr($file, strrpos($file, DIRECTORY_SEPARATOR)+1);
+            $file   = substr($file, 0, strrpos($file, '.'));
+
+            $commands[] = $file;
+        }
+
+        return $commands;
+    }
+
+    /**
+     * Create new objects and add it
+     * @param $commands
+     */
+    protected function loadCommandsControllers($commands)
+    {
+        foreach($commands as $command)
+        {
+            $class  = ModuleConstants::getRootNamespace().'\App\\'.$this->dir.'\\'.$command;
+
+            $this->add(new $class);
+        }
+    }
+}

+ 53 - 0
core/CommandLine/Command.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+/**
+ * Class Command
+ * @package ModulesGarden\Servers\KerioEmail\Core\CommandLine
+ */
+class Command extends AbstractCommand
+{
+    /**
+     *
+     */
+    final protected function configure()
+    {
+        parent::configure();
+    }
+
+    /**
+     * Execute command
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    final protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        return parent::execute($input, $output, new SymfonyStyle($input, $output));
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @throws \Exception
+     */
+    protected function beforeProcess(InputInterface $input, OutputInterface $output)
+    {
+        (new Hypervisor($this->getName(), $input->getOptions()))
+            ->lock();
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    protected function afterProcess(InputInterface $input, OutputInterface $output)
+    {
+        (new Hypervisor($this->getName(), $input->getOptions()))
+            ->unlock();
+    }
+}

+ 86 - 0
core/CommandLine/CommandLoop.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class CommandLoop extends AbstractCommand
+{
+    /**
+     * Loop interval in seconds
+     * @var int
+     */
+    protected $loopInterval = 5;
+
+    /**
+     * Loop counter
+     * @var int
+     * @TODO remove me
+     */
+    private $loopCounter  = 0;
+
+    /**
+     *
+     */
+    final protected function configure()
+    {
+        parent::configure();
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return int|null|void
+     * @throws \Exception
+     */
+    final protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $hypervisor = new Hypervisor($this->getName(), $input->getOptions());
+
+        /**
+         * Lock command in database. We want to run only one command in the same time
+         */
+        $hypervisor->lock();
+
+        do
+        {
+            /**
+             * Let's do something funny!
+             */
+            parent::execute($input, $output);
+
+            /**
+             * Ping... Pong... Ping...
+             */
+            $hypervisor->ping();
+
+            /**
+             * Time to sleep!
+             */
+            $hypervisor->sleep($this->loopInterval);
+
+            /**
+             * @TODO remove me
+             */
+            $this->loopCounter++;
+        }
+        while(!$hypervisor->shouldBeStopped());
+
+        /**
+         * Unlock command in database
+         */
+        $hypervisor->unlock();
+    }
+
+    /**
+     * @return int
+     */
+    final protected function getLoopCounter()
+    {
+        return $this->loopCounter;
+    }
+}
+
+
+//

+ 8 - 0
core/CommandLine/CommandManager.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+class CommandManager extends Application
+{
+
+}

+ 8 - 0
core/CommandLine/CronManager.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+class CronManager extends Application
+{
+    protected $dir          = 'Cron';
+}

+ 253 - 0
core/CommandLine/Hypervisor.php

@@ -0,0 +1,253 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use ModulesGarden\Servers\KerioEmail\Core\Models\Commands;
+
+/**
+ * We need that for calculating interval between operations and for killing process for PHP < 7.1
+ * Don't remove it!
+ */
+declare(ticks = 1);
+
+/**
+ * Class Hypervisor
+ * @package ModulesGarden\Servers\KerioEmail\Core\CommandLine
+ * @todo - clean up!
+ */
+class Hypervisor
+{
+    /**
+     * command name
+     * @var null
+     */
+    protected $name     = null;
+
+    /**
+     * command params
+     * @var null
+     */
+    protected $params   = null;
+
+    /**
+     * @var int
+     */
+    protected $counter  = 0;
+
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\Core\Models\Commands
+     */
+    protected $entity   = null;
+
+    protected $tickTime = 1;
+
+    /**
+     * @var int
+     */
+    protected $sleepInterval    =   5;
+
+    /**
+     * Hypervisor constructor.
+     * @param $name
+     * @param $params
+     */
+    public function __construct($name, $params)
+    {
+        $this->name     = $name;
+        $this->params   = $params;
+    }
+
+    /**
+     * Lock script
+     * @return $this
+     * @throws \Exception
+     */
+    public function lock()
+    {
+        if($this->isActive())
+        {
+            throw new \Exception('Cannot create lock. Command already running');
+        }
+
+        $this->registerTickHandler();
+        $this->registerSignalHandler();
+
+        $this->getEntity()->setRunning();
+
+        return $this;
+    }
+
+    /**
+     * Unlock script
+     * @return $this
+     */
+    public function unlock()
+    {
+        $this->getEntity()
+            ->setStopped()
+            ->clearAction();
+
+        return $this;
+    }
+
+    /**
+     * Update information about running command
+     * @return $this
+     */
+    public function ping()
+    {
+        $this->getEntity()
+            ->ping();
+
+        return $this;
+    }
+
+    /**
+     * @param $interval
+     * @return $this
+     */
+    public function sleep($interval)
+    {
+        $this->getEntity()
+            ->setSleeping();
+
+        /**
+         * We need run tick function during sleep, so we run many sleep function in loop
+         */
+        $counter    = 0;
+        while($counter < $interval)
+        {
+            if($interval <= $this->sleepInterval)
+            {
+                $time   = $interval;
+            }
+            else
+            {
+                $time   = $this->sleepInterval;
+            }
+
+
+            $counter    += $time;
+
+            sleep($time);
+        }
+
+
+        $this->getEntity()
+            ->setRunning();
+
+        return $this;
+    }
+
+    public function shouldBeStopped()
+    {
+        return $this->getEntity()
+                    ->shouldBeStopped();
+    }
+
+    /**
+     * @return bool
+     * @throws \Exception
+     */
+    public function checkIfRunning()
+    {
+        if(!$this->isRunning())
+        {
+            throw new \Exception('Script is not running');
+        }
+
+        return true;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isStopped()
+    {
+        $this->getEntity()
+            ->shouldBeStopped();
+    }
+
+    /**
+     * Returns true if command is running or sleeping
+     * @return bool
+     */
+    public function isActive()
+    {
+        $entity = $this->getEntity();
+        $diff   = time() - $entity->updated_at->timestamp;
+
+        if($entity->isSleeping() && $diff <= $this->sleepInterval)
+        {
+            return true;
+        }
+
+        if($entity->isRunning() && $entity->updated_at->timestamp + $this->tickTime > time())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param bool $force
+     * @return ModulesGarden\Servers\KerioEmail\Core\Models\Commands|Commands
+     */
+    protected function getEntity($force = false)
+    {
+        if($this->entity && $force === false)
+        {
+            return $this->entity;
+        }
+
+        $this->entity = Commands::where('name', $this->name)->first();
+
+        if(!$this->entity)
+        {
+            $this->entity        = new Commands();
+            $this->entity->name  = $this->name;
+            $this->entity->uuid  = uniqid();
+            $this->entity->save();
+        }
+
+        return $this->entity;
+    }
+
+    /**
+     *
+     */
+    protected function registerTickHandler()
+    {
+        $tick   = new Tick(function(){
+            $this->ping();
+        }, 10);
+        $tick->start();
+    }
+
+    /**
+     * Mark process as stopped and exit. This function will be called when you press ctrl c from console
+     */
+    protected function registerSignalHandler()
+    {
+        if(!function_exists('pcntl_signal'))
+        {
+            return;
+        }
+
+        //works from PHP 7.1
+        if(function_exists('pcntl_async_signals'))
+        {
+            pcntl_async_signals(true);
+        }
+
+        $exit = function(){
+            $this->getEntity()->setStopped();
+            exit;
+        };
+
+        pcntl_signal(SIGINT,  $exit);
+        pcntl_signal(SIGHUP, $exit);
+        pcntl_signal(SIGUSR1, $exit);
+    }
+}

+ 8 - 0
core/CommandLine/Job.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+class Job
+{
+
+}

+ 86 - 0
core/CommandLine/JobsLoop.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use Symfony\Component\Console\Input\InputOption;
+
+class JobsLoop extends AbstractCommand
+{
+    /**
+     * Loop interval in seconds
+     * @var int
+     */
+    protected $loopInterval = 5;
+
+    /**
+     * @var int
+     */
+    protected $maxChildren  = 5;
+
+    /**
+     * @var int
+     */
+    protected $tasksPerChildren = 10;
+    /**
+     *
+     */
+    final protected function configure()
+    {
+        parent::configure();
+    }
+
+    /**
+     *
+     */
+    final protected function setup()
+    {
+        $this->addOption('parent', InputOption::VALUE_OPTIONAL, 'Parent id', null);
+        $this->addOption('id', InputOption::VALUE_OPTIONAL, 'Child id', null);
+    }
+
+    /**
+     * Execute command in the loop
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     */
+    final protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $parent         =    $input->getOption('parent');
+        $id                 = $input->getOption('id');
+        $parentHypervior    = new Hypervisor($this->getName());
+
+        //Lock parent
+        if(!$parent)
+        {
+            $parentHypervior->lock();
+        }
+        else
+        {
+            $parentHypervior->checkIfRunning();
+        }
+
+        if($id)
+        {
+
+        }
+
+        do
+        {
+            parent::process($input, $output, new SymfonyStyle($input, $output));
+
+            sleep($this->loopInterval);
+        }
+        while(!$hypervisor->isStopped());
+    }
+
+    /**
+     * @param $jobs[]
+     */
+    protected function processJobs($jobs)
+    {
+        foreach($jobs as $job)
+        {
+
+        }
+    }
+}

+ 64 - 0
core/CommandLine/ReaderCronTask.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+/**
+ * Description of AbstractReaderYml
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class ReaderCronTask
+{
+    /**
+     * @var array
+     */
+    protected $data = [];
+
+    public function __construct()
+    {
+        if (count($this->data) == 0)
+        {
+            $this->load();
+        }
+    }
+
+    public function getData()
+    {
+        return $this->data;
+    }
+
+    protected function readYml($name)
+    {
+        return Reader::read($name)->get();
+    }
+
+    public static function get()
+    {
+
+        $instance = new static;
+        return $instance->getData();
+    }
+
+    protected function load()
+    {
+        $this->data = $this->rebuildData($this->readYml(ModuleConstants::getFullPath('app', 'Config', 'cron.yml')));
+    }
+    
+    protected function rebuildData($data)
+    {
+        $return = [];
+        foreach ($data['list'] as $name => $isRun)
+        {
+            if ((bool)$isRun)
+            {
+                $return[] = $name;
+            }
+        }
+        
+        return $return;
+    }
+    
+}

+ 68 - 0
core/CommandLine/Tick.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\CommandLine;
+
+/**
+ * Count time between callback time. It requires declare(ticks = 1);
+ * @package ModulesGarden\Servers\KerioEmail\Core\CommandLine
+ */
+class Tick
+{
+    /**
+     * @var callable
+     */
+    protected $callback          = null;
+    /**
+     * @var int
+     */
+    protected $callbackTime      = 0;
+    /**
+     * @var int
+     */
+    protected $callbackInterval  = 5;
+
+    /**
+     * Tick constructor.
+     * @param $callback
+     * @param $time
+     */
+    public function __construct($callback, $time)
+    {
+        $this->callback     = $callback;
+        $this->callbackTime = $time;
+    }
+
+    /**
+     *
+     */
+    public function start()
+    {
+        register_tick_function(function(){
+            $this->tick();
+        }, true);
+    }
+
+    /**
+     * @return int
+     */
+    public function getTimeFromLastCallback()
+    {
+        return time() - $this->callbackTime;
+    }
+
+    /**
+     * Call callback if time diffeence is
+     */
+    public function tick()
+    {
+        $difference = $this->getTimeFromLastCallback();
+
+        if($difference > $this->callbackInterval)
+        {
+            $this->callbackTime = time();
+            $callback   = $this->callback;
+
+            $callback();
+        }
+    }
+}

+ 8 - 0
core/Config/configuration.yml

@@ -0,0 +1,8 @@
+version: '1.0.0'
+systemName: 'KerioEmail'
+name: 'kerioEmail'
+description: 'Modules Garden Module Framework.<br>For more info visit our <a href="http://www.docs.modulesgarden.com/CHANGE_ME" style="color: #4169E1;" target="_blank">Wiki</a>.'
+clientareaName: 'MG Demo'
+author: '<a href="http://www.modulesgarden.com" targer="_blank">ModulesGarden</a>'
+fields: []
+moduleIcon: 'crm'

+ 1 - 0
core/Config/cron.yml

@@ -0,0 +1 @@
+class:

+ 5 - 0
core/Config/di/buildWithDefaultMethod.yml

@@ -0,0 +1,5 @@
+class:
+    - {name: "\\ModulesGarden\\Servers\\KerioEmail\\Core\\Http\\Request", method: "build",                        args: []}
+    - {name: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Http\\View\\Smarty',  method: "get",                    args: [NULL,NULL]}
+    - {name: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\HandlerError\\Logger',  method: "get",                  args: ["default","debug.log","warning.log","error.log"]}
+    - {name: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\RegisterManager\\Register',  method: "getInstace",      args: []}

+ 1 - 0
core/Config/di/interface.yml

@@ -0,0 +1 @@
+interface: []

+ 30 - 0
core/Config/di/register.yml

@@ -0,0 +1,30 @@
+class:
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Config\\After',            alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Activate\\After',          alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Deactivate\\After',        alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Update\\After',            alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Config\\Before',           alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Activate\\Before',         alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Deactivate\\Before',       alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Update\\Before',           alias: "", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\App\\Controllers\\Instances\\Addon\\Config', alias: "configurationAddon", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Data',           alias: "configurationData", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Lang\\Lang',                               alias: "lang", singleton: false ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Http\\View\\Smarty',                       alias: "smarty", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\HandlerError\\Logger',                     alias: "logger", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\HandlerError\\ErrorManager',         alias: "errorManager", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Http\\Request',                           alias: "request", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\UI\\View',                                   alias: "view", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\UI\\ViewAjax',                           alias: "viewAjax", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\UI\\ViewIntegrationAddon',   alias: "viewIntegrationAddon", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Http\\AbstractController',             alias: "controller", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Http\\AbstractClientController', alias: "clientController", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Http\\AbstractHooksClient',alias: "clientHookController", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Configuration\\Addon\\Update\\PatchManager',alias: "patchManager",singleton: true ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\HandlerError\\WhmcsLogsHandler',      alias: "whmcsLogger", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Logger\\Entity',                     alias: "entityLogger", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\CommandLine\\CronManager',            alias: "cronManager", singleton: true , auto: true }
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\RegisterManager\\Register',              alias: "register", singleton: true , auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\UI\\Widget\\Sidebar\\SidebarService',    alias: "sidebar", singleton: true ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\Helper\\WhmcsParams',                 alias: "whmcsParams", singleton: false ,auto: false}
+    - {namespace: '\\ModulesGarden\\Servers\\KerioEmail\\Core\\App\\AppParamsContainer',      alias: "appParamsContainer", singleton: false ,auto: false}

+ 8 - 0
core/Config/di/services.php

@@ -0,0 +1,8 @@
+<?php
+
+return [
+    \ModulesGarden\Servers\KerioEmail\Core\Lang\Lang::class,
+    \ModulesGarden\Servers\KerioEmail\Core\Events\Dispatcher::class,
+    \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon\Config::class,
+    \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Sidebar\SidebarService::class
+];

+ 5 - 0
core/Config/di/services.yml

@@ -0,0 +1,5 @@
+- \ModulesGarden\Servers\KerioEmail\Core\Lang\Lang
+- \ModulesGarden\Servers\KerioEmail\Core\App\Controllers\Instances\Addon\Config
+- \ModulesGarden\Servers\KerioEmail\Core\UI\Widget\Sidebar\SidebarService
+- \ModulesGarden\Servers\KerioEmail\Core\Helper\WhmcsParams
+- \ModulesGarden\Servers\KerioEmail\Core\App\AppParamsContainer

+ 18 - 0
core/Configuration/Addon/AbstractAfter.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon;
+
+/**
+ * Description of AbstractAfter
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class AbstractAfter
+{
+    public function __construct()
+    {
+        
+    }
+
+    abstract public function execute(array $params = []);
+}

+ 17 - 0
core/Configuration/Addon/AbstractBefore.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon;
+
+/**
+ * Description of AbstractBefore
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class AbstractBefore
+{
+
+    public function __construct()
+    {
+
+    }
+}

+ 22 - 0
core/Configuration/Addon/Activate/After.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Activate;
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * Runs after module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        return $params;
+    }
+}

+ 34 - 0
core/Configuration/Addon/Activate/Before.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Activate;
+
+use \ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractBefore;
+use \ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use \ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+/**
+ * Runs before module activation actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        $path = ModuleConstants::getModuleRootDir() . DS . 'storage';
+
+        if (is_writable($path) === false || is_readable($path) === false)
+        {
+            $params['status'] = 'error';
+            $params['description'] .= PHP_EOL . ServiceLocator::call('lang')
+                    ->addReplacementConstant('storage_path', ModuleConstants::getFullPath('storage'))
+                    ->absoluteT('permissionsStorage');
+        }
+
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Config/After.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Config;
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * Runs after loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 23 - 0
core/Configuration/Addon/Config/Before.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Config;
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractBefore;
+
+/**
+ * Runs before loading module configuration
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Deactivate/After.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Deactivate;
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * Runs after addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Deactivate/Before.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Deactivate;
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractBefore;
+
+/**
+ * Runs before addon deactivation
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 24 - 0
core/Configuration/Addon/Update/After.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update;
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractAfter;
+
+/**
+ * runs after module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class After extends AbstractAfter
+{
+
+    /**
+     * @param array $params
+     * @return array
+     */
+    public function execute(array $params = [])
+    {
+
+        return $params;
+    }
+}

+ 22 - 0
core/Configuration/Addon/Update/Before.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update;
+
+use ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\AbstractBefore;
+
+/**
+ * runs after module update actions
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Before extends AbstractBefore
+{
+
+    /**
+     * @return array
+     */
+    public function execute($version)
+    {
+        return [];
+    }
+}

+ 78 - 0
core/Configuration/Addon/Update/Patch/AbstractPatch.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update\Patch;
+
+use ModulesGarden\Servers\KerioEmail\Core\Helper\DatabaseHelper;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+/**
+ * Description of AbstractPatch
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class AbstractPatch
+{
+    /**
+     * @var DatabaseHelper 
+     */
+    protected $databaseHelper;
+
+    /**
+     * @var string
+     */
+    private $path;
+
+    /**
+     * @var string
+     */
+    private $versionName;
+
+    protected $version;
+
+    /**
+     * @param DatabaseHelper $databaseHelper
+     */
+    public function __construct(DatabaseHelper $databaseHelper)
+    {
+        $this->databaseHelper = $databaseHelper;
+        $this->path = ModuleConstants::getModuleRootDir() . DS . 'app' . DS . 'Database';
+        $this->versionName = end(explode("\\",get_called_class()));
+    }
+
+    /**
+     * @return bool
+     */
+    protected function runSchema()
+    {
+        return ($this->databaseHelper->performQueryFromFile($this->path . DS . $this->versionName . DS . 'schema.sql') === true)
+                ?false
+                :true;
+    }
+
+    /**
+     * @return bool
+     */
+    protected function runData()
+    {
+        return ($this->databaseHelper->performQueryFromFile($this->path . DS . $this->versionName . DS . 'data.sql') === true)
+                ?false
+                :true;
+    }
+
+    public function setVersion($version = null)
+    {
+        $this->version = $version;
+
+        return $this;
+    }
+
+    public function getVersion()
+    {
+        return $this->version;
+    }
+
+    public function execute()
+    {
+        
+    }
+}

+ 105 - 0
core/Configuration/Addon/Update/PatchManager.php

@@ -0,0 +1,105 @@
+<?php
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Addon\Update;
+
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of PatchManager
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class PatchManager
+{
+    
+    protected $updatePath;
+    
+    protected $updateFiles = [];
+        
+    public function __construct()
+    {
+        $this->updatePath = ModuleConstants::getModuleRootDir() . DS . "app" . DS . "Configuration" . DS . "Addon" . DS . "Update" . DS . "Patch";
+        $this->loadUpdatePath();
+    }
+    
+    public function run($newVersion, $oldVersion)
+    {
+        $fullPath = $this->getUpdatePath();
+        array_map(function ($version, $fileName) use($newVersion, $oldVersion, $fullPath)
+        {
+            if ($this->checkVersion($newVersion, $oldVersion, $version))
+            {
+                try
+                {
+                    $className = ModuleConstants::getRootNamespace() . "\App\Configuration\Addon\Update\Patch\\" . $fileName;
+                    DependencyInjection::create($className)->setVersion($version)->execute();
+                }
+                catch (\Exception $exc)
+                {
+                    ServiceLocator::call("errorManager")
+                        ->addError(
+                            self::class,
+                            $exc->getMessage(),
+                            [
+                                "newVersion"    => $newVersion,
+                                "oldVersion"    => $oldVersion,
+                                "updateVersion" => $version,
+                                "fullFileName"  => $fullPath . DS . $fileName . ".php"
+                            ]
+                    );
+                }
+                
+            }
+        },
+        array_keys($this->getUpdateFiles()),
+        $this->getUpdateFiles()
+        );
+        
+        return $this;
+    }
+    
+    
+    protected function checkVersion($newVersion, $oldVersion, $fileVersion)
+    {
+        if (version_compare($oldVersion, $fileVersion, "<"))
+        {
+            return true;
+        }
+        
+        return false;
+    }
+
+    protected function getUpdatePath()
+    {
+        return $this->updatePath;
+    }
+    
+    protected function getUpdateFiles()
+    {
+        return $this->updateFiles;
+    }
+
+    protected function loadUpdatePath()
+    {
+        $files = scandir($this->getUpdatePath(), 1);
+        
+        if (count($files) != 0)
+        {
+            foreach ($files as $file)
+            {
+               if ($file !== "." && $file !== "..")
+               {
+                   $version = $this->generateVersion($file);
+                   $this->updateFiles[$version] = explode(".", $file)[0];
+               }
+            }
+        }
+    }
+    
+    protected function generateVersion($fileName)
+    {
+        $name = explode('.', $fileName)[0];
+        return str_replace(["M","P"],".",substr($name,1));
+    }
+}

+ 122 - 0
core/Configuration/Data.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration;
+
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+/**
+ * Description of Data
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Data
+{
+    protected static $data = [];
+
+    public function __construct()
+    {
+        $this->load();
+    }
+
+    public function __get($name)
+    {
+        $this->load();
+        if (array_key_exists(lcfirst($name), self::$data))
+        {
+            return self::$data[lcfirst($name)];
+        }
+        return null;
+    }
+
+    public function getAll()
+    {
+        return self::$data;
+    }
+
+    private function load()
+    {
+        if (count(self::$data) == 0)
+        {
+            $this->loadConfig();
+        }
+    }
+
+    /**
+     * Loads YML configuration files
+     */
+    private function loadConfig()
+    {
+        $dataDev  = $this->read(ModuleConstants::getDevConfigDir() . DS . 'configuration.yml');
+        $dataCore = $this->read(ModuleConstants::getCoreConfigDir() . DS . 'configuration.yml');
+
+        $data = $this->parseConfigData($dataDev, $dataCore);
+
+        $this->loadPackageConfig($data);
+
+        self::$data = $data ? : [];
+    }
+
+    /**
+     * @param self::$data $data
+     *
+     * overwrites module version and wiki url basing on moduleVersion.php file,
+     * this file is added automatically during package creation
+     */
+    private function loadPackageConfig(&$data)
+    {
+        if (file_exists(ModuleConstants::getModuleRootDir() . DS . 'moduleVersion.php'))
+        {
+            include ModuleConstants::getModuleRootDir() . DS . 'moduleVersion.php';
+            if ($moduleVersion)
+            {
+                $data['version'] = $moduleVersion;
+            }
+        }
+
+        if ($data['description'] && strpos($data['description'], ':WIKI_URL:'))
+        {
+            $data['description'] = str_replace(':WIKI_URL:', ($moduleWikiUrl ? : 'https://www.docs.modulesgarden.com/'), $data['description']);
+        }
+
+        $data['debug'] = (file_exists(ModuleConstants::getModuleRootDir() . DIRECTORY_SEPARATOR . '.debug'))
+                ? true : false;
+    }
+
+    private function parseConfigData($dataDev, $dataCore)
+    {
+        if (!$dataDev && $dataCore)
+        {
+            return $dataCore;
+        }
+
+        if (!$dataDev && $dataCore)
+        {
+            return $dataCore;
+        }
+
+        foreach ($dataCore as $coreKey => $core)
+        {
+            $isFind = false;
+            foreach ($dataDev as $devKey => $dev)
+            {
+                if ($devKey === $coreKey)
+                {
+                    $isFind = true;
+                    break;
+                }
+            }
+            if (!$isFind)
+            {
+                $dataDev[$coreKey] = $core;
+            }
+        }
+
+        return $dataDev;
+    }
+
+    private function read($name)
+    {
+        return Reader::read($name)->get();
+    }
+}

+ 13 - 0
core/Configuration/Data/Version.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Data;
+
+/**
+ * Description of Version
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Version
+{
+    //put your code here
+}

+ 30 - 0
core/Configuration/Requirements/Files.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Configuration\Requirements;
+
+/**
+ * Description of RemoveFiles
+ *
+ * @author INBSX-37H
+ */
+class Files extends \ModulesGarden\Servers\KerioEmail\Core\App\Requirements\Instances\Files
+{
+    protected $requirementsList = [
+        [
+            self::PATH => self::MODULE_PATH . '/storage',
+            self::TYPE => self::IS_WRITABLE
+        ],
+        [
+            self::PATH => self::MODULE_PATH . '/storage/app',
+            self::TYPE => self::IS_WRITABLE
+        ],
+        [
+            self::PATH => self::MODULE_PATH . '/storage/crons',
+            self::TYPE => self::IS_WRITABLE
+        ],
+        [
+            self::PATH => self::MODULE_PATH . '/storage/logs',
+            self::TYPE => self::IS_WRITABLE
+        ]
+    ];
+}

+ 0 - 0
core/Database/data.sql


+ 67 - 0
core/Database/schema.sql

@@ -0,0 +1,67 @@
+--
+-- `#prefix#Logger`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#Logger` (
+    `id`            int(10) unsigned NOT NULL AUTO_INCREMENT,
+    `id_ref`        int(10) NOT NULL,
+    `id_type`       VARCHAR(255) NOT NULL,
+    `type`          VARCHAR(255) NOT NULL,
+    `level`         VARCHAR(255) NOT NULL,
+    `date`          DATETIME DEFAULT null,
+    `request`       TEXT NOT NULL,
+    `response`      TEXT NOT NULL,
+    `before_vars`   TEXT NOT NULL,
+    `vars`          TEXT NOT NULL,
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+--
+-- `#prefix#ModuleSettings`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#ModuleSettings` (
+    `setting`              VARCHAR(64) NOT NULL UNIQUE,
+    `value`            TEXT NOT NULL,
+    PRIMARY KEY (`setting`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+--
+-- `#prefix#Commands`
+--
+CREATE TABLE IF NOT EXISTS `#prefix#Commands` (
+    `name`             VARCHAR(64) NOT NULL UNIQUE,
+    `uuid`             VARCHAR(64) NOT NULL UNIQUE,
+    `parent_uuid`      VARCHAR(64) DEFAULT NULL,
+    `status`           enum('stopped', 'running', 'error') DEFAULT 'stopped',
+    `action`           enum('none', 'stop', 'reboot') DEFAULT 'none',
+    `params`           TEXT NOT NULL,
+    `created_at`       timestamp DEFAULT CURRENT_TIMESTAMP,
+    `updated_at`       timestamp,
+    PRIMARY KEY (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+
+CREATE TABLE IF NOT EXISTS `#prefix#Job` (
+    `id` int(10) unsigned  NOT NULL AUTO_INCREMENT,
+    `retry_after` datetime NOT NULL,
+    `retry_count` int(10) unsigned NOT NULL,
+    `job` varchar(255) NOT NULL,
+    `data` text,
+    `queue` varchar(32) DEFAULT 'default',
+    `status` varchar(32) NOT NULL,
+    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;
+
+CREATE TABLE IF NOT EXISTS `#prefix#JobLog` (
+    `id` int(10) unsigned  NOT NULL AUTO_INCREMENT,
+    `job_id` int(10) unsigned NOT NULL,
+    `type` varchar(32) NOT NULL,
+    `message` varchar(512) NOT NULL,
+    `additional` text,
+    `created_at` datetime NOT NULL,
+    `updated_at` datetime NOT NULL,
+    PRIMARY KEY (`id`),
+    KEY `job_id` (`job_id`),
+    KEY `type` (`type`)
+) ENGINE=InnoDB DEFAULT CHARSET=#charset# DEFAULT COLLATE #collation#;

+ 14 - 0
core/DependencyInjection.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core;
+
+
+/**
+ * Description of DependencyInjection
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class DependencyInjection extends \ModulesGarden\Servers\KerioEmail\Core\DependencyInjection\DependencyInjection
+{
+
+}

+ 76 - 0
core/DependencyInjection/Builder.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+
+use \ModulesGarden\Servers\KerioEmail\Core\SL\Data\DataSL;
+
+class Builder
+{
+    /**
+     * @var DataSL
+     */
+    protected $data = null;
+
+    /**
+     * @var array
+     */
+    protected $registers    = [];
+
+    public function __construct()
+    {
+        $this->init();
+        $this->loadAliases();
+        $this->loadRewrites();
+        $this->loadInstances();
+    }
+
+    protected function init()
+    {
+        Container::setInstance(new Container());
+
+        $this->data = new DataSL();
+
+        $this->registers    = $this->data->getRegisters();
+    }
+
+    protected function loadRewrites()
+    {
+        foreach($this->data->getRewrites() as $alias => $className)
+        {
+            Container::getInstance()->alias($className, $alias);
+        }
+    }
+
+    protected function loadAliases()
+    {
+        foreach($this->data->getAllAlias() as $className => $alias)
+        {
+            Container::getInstance()->alias($className, $alias);
+        }
+    }
+
+    protected function loadInstances()
+    {
+        foreach($this->data->getConfigurations() as $config)
+        {
+            $className  = $config['name'];
+            $method     = $config['method'];
+            $arguments  = $config['args'];
+
+
+            if(!$method)
+            {
+                $obj    = Container::getInstance()->make($className);
+            }
+            else
+            {
+                $obj    = call_user_func_array("$className::$method", $arguments);
+            }
+
+            if(array_key_exists($className, $this->registers) && $this->registers[$className]['singleton'])
+            {
+                Container::getInstance()->instance($className, $obj);
+            }
+        }
+    }
+}

+ 204 - 0
core/DependencyInjection/Container.php

@@ -0,0 +1,204 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+
+use Illuminate\Contracts\Container\Container as ContainerContract;
+use ModulesGarden\Servers\KerioEmail\Core\Helper\WhmcsVersionComparator;
+
+class Container extends \Illuminate\Container\Container
+{
+    protected static $instance = null;
+
+    public static function getInstance()
+    {
+        if (is_null(self::$instance))
+        {
+            self::$instance = new static;
+        }
+
+        return static::$instance;
+    }
+
+    public static function setInstance(ContainerContract $container)
+    {
+        self::$instance = $container;
+    }
+
+    /**
+     * @param $parameters
+     * @param array $primitives
+     * @return array
+     */
+    protected function getDependencies($parameters, array $primitives = array())
+    {
+        $dependencies = array();
+        foreach ($parameters as $parameter)
+        {
+            if($parameter->isOptional())
+            {
+                break;
+            }
+
+            $dependency = $parameter->getClass();
+            // If the class is null, it means the dependency is a string or some other
+            // primitive type which we can not resolve since it is not a class and
+            // we will just bomb out with an error since we have no-where to go.
+            if (array_key_exists($parameter->name, $primitives))
+            {
+                $dependencies[] = $primitives[$parameter->name];
+            }
+            elseif (is_null($dependency))
+            {
+                $dependencies[] = $this->resolveNonClass($parameter);
+            }
+            else
+            {
+                $dependencies[] = $this->resolveClass($parameter);
+            }
+        }
+        return (array) $dependencies;
+    }
+
+    /**
+     * Set null value as default parameter when cannot find default value
+     * @param ReflectionParameter $parameter
+     * @return null
+     */
+    protected function resolveNonClass(\ReflectionParameter $parameter)
+    {
+        if ($parameter->isDefaultValueAvailable())
+        {
+            return $parameter->getDefaultValue();
+        }
+
+        return null;
+    }
+
+    /* --------------------------------------- WHMCS 8 --------------------------------------- */
+    /**
+     * Resolve the given type from the container.
+     *
+     * @param  string  $abstract
+     * @param  array  $parameters
+     * @return mixed
+     *
+     * @throws \Illuminate\Contracts\Container\BindingResolutionException
+     */
+    public function make($abstract, array $parameters = [])
+    {
+        /* If $abstract contains namespace without slash at the begging, we need to add it */
+        $explodedAbstract = explode('\\', $abstract);
+        if($explodedAbstract[0] == 'ModulesGarden' && count($explodedAbstract) > 1)
+        {
+            $abstract = '\\'.$abstract;
+        }
+
+        /* This function executes a different code, depending on the version of the container - WHMCS 8 has a much newer version */
+        $version8OrHigher = (new WhmcsVersionComparator)->isWVersionHigherOrEqual('8.0.0');
+        if($version8OrHigher)
+        {
+            return $this->resolve($abstract, $parameters);
+        }
+
+        $abstract = $this->getAlias($this->normalize($abstract));
+        if (isset($this->instances[$abstract])) {
+            return $this->instances[$abstract];
+        }
+
+        $concrete = $this->getConcrete($abstract);
+        if ($this->isBuildable($concrete, $abstract)) {
+            $object = $this->build($concrete, $parameters);
+        } else {
+            $object = $this->make($concrete, $parameters);
+        }
+
+        foreach ($this->getExtenders($abstract) as $extender) {
+            $object = $extender($object, $this);
+        }
+
+        if ($this->isShared($abstract)) {
+            $this->instances[$abstract] = $object;
+        }
+
+        $this->fireResolvingCallbacks($abstract, $object);
+        $this->resolved[$abstract] = true;
+
+        return $object;
+    }
+
+    /**
+     * Resolve all of the dependencies from the ReflectionParameters.
+     *
+     * @param  array  $dependencies
+     * @return array
+     *
+     * @throws \Illuminate\Contracts\Container\BindingResolutionException
+     */
+    protected function resolveDependencies(array $dependencies)
+    {
+        $results = [];
+        foreach ($dependencies as $dependency) {
+            if($dependency->isOptional())
+            {
+                break;
+            }
+
+            if ($this->hasParameterOverride($dependency)) {
+                $results[] = $this->getParameterOverride($dependency);
+
+                continue;
+            }
+
+            $result = is_null($dependency->getClass())
+                ? $this->resolvePrimitive($dependency)
+                : $this->resolveClass($dependency);
+
+            if ($dependency->isVariadic()) {
+                $results = array_merge($results, $result);
+            } else {
+                $results[] = $result;
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Resolve a non-class hinted primitive dependency.
+     *
+     * @param  \ReflectionParameter  $parameter
+     * @return mixed
+     *
+     * @throws \Illuminate\Contracts\Container\BindingResolutionException
+     */
+    protected function resolvePrimitive(\ReflectionParameter $parameter)
+    {
+        if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) {
+            return $concrete instanceof \Closure ? $concrete($this) : $concrete;
+        }
+
+        if ($parameter->isDefaultValueAvailable()) {
+            return $parameter->getDefaultValue();
+        }
+
+        if($parameter->hasType())
+        {
+            $returnEmptyType = [];
+            switch(strtolower($parameter->getType()->getName()))
+            {
+                case 'string':
+                    $returnEmptyType  = '';
+                    break;
+                case 'array':
+                    $returnEmptyType  = [];
+                    break;
+                default:
+                    return null;
+            }
+
+            return $returnEmptyType;
+        }
+
+        return null;
+    }
+}

+ 57 - 0
core/DependencyInjection/DependencyInjection.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+
+/**
+ * Class DependencyInjection
+ * @package ModulesGarden\Servers\KerioEmail\Core\DependencyInjection
+ */
+class DependencyInjection
+{
+    /**
+     * @param null $className
+     * @param null $methodName
+     * @param bool $canClone
+     * @return mixed
+     */
+    public static function get($className = null, $methodName = null, $canClone = true)
+    {
+        if($methodName)
+        {
+            return Container::getInstance()->call("$className@$methodName");
+        }
+
+        return Container::getInstance()->make($className);
+    }
+
+    /**
+     * @param null $className
+     * @param null $methodName
+     * @param bool $canClone
+     * @return mixed
+     */
+    public static function create($className = null, $methodName = null, $canClone = true)
+    {
+        if($methodName)
+        {
+            return Container::getInstance()->call("$className@$methodName");
+        }
+
+        return Container::getInstance()->make($className);
+    }
+
+    /**
+     * @param null $className
+     * @param null $methodName
+     * @return mixed
+     */
+    public static function call($className = null, $methodName = null)
+    {
+        if($methodName)
+        {
+            return Container::getInstance()->call("$className@$methodName");
+        }
+
+        return Container::getInstance()->make($className);
+    }
+}

+ 63 - 0
core/DependencyInjection/Services.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+/**
+ * Load all services from yml file and mark them as shared in DI container
+ * @author Mariusz Miodowski <mariusz@modulesgarden.com>
+ * @package ModulesGarden\DomainOrdersExtended\Core\Services
+ */
+class Services
+{
+    /**
+     * Services constructor.
+     */
+    public function __construct()
+    {
+        $this->load();
+    }
+
+    /**
+     * Load all needed servies to DI container
+     */
+    protected function load()
+    {
+        foreach($this->getFilesList() as $file)
+        {
+            $servicesList   = Reader::read($file)->get();;
+            if(!is_array($servicesList) || empty($servicesList))
+            {
+                continue;
+            }
+
+            $this->registerServices($servicesList);
+        }
+    }
+
+    /**
+     * Register all services in DI container
+     * @param $servicesList
+     */
+    protected function registerServices($servicesList)
+    {
+        foreach($servicesList as $service)
+        {
+            Container::getInstance()->singleton($service);
+        }
+    }
+
+    /**
+     * Get file list with servies configuration
+     * @return array
+     */
+    protected function getFilesList()
+    {
+        return [
+            ModuleConstants::getFullPath('app', 'Config', 'di', 'services.yml'),
+            ModuleConstants::getFullPath('core', 'Config', 'di', 'services.yml')
+        ];
+    }
+}

+ 34 - 0
core/Enum/Enum.php

@@ -0,0 +1,34 @@
+<?php
+
+/* * ********************************************************************
+ * KerioEmail product developed. (Jan 8, 2019)
+ * *
+ *
+ *  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+ *  CONTACT                        ->       contact@modulesgarden.com
+ *
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  with  the  terms  of such  license and with the
+ * inclusion of the above copyright notice.  This software  or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ *
+ * ******************************************************************** */
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Enum;
+
+/**
+ * Description of Enum
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+abstract class Enum
+{
+    static function getKeys(){
+        $class = new ReflectionClass(get_called_class());
+        return array_keys($class->getConstants());
+    }
+}

+ 33 - 0
core/Enum/Level.php

@@ -0,0 +1,33 @@
+<?php
+
+/* * ********************************************************************
+ * KerioEmail product developed. (Jan 8, 2019)
+ * *
+ *
+ *  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+ *  CONTACT                        ->       contact@modulesgarden.com
+ *
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  with  the  terms  of such  license and with the
+ * inclusion of the above copyright notice.  This software  or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ *
+ * ******************************************************************** */
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Enum;
+
+/**
+ * Description of Level
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+final class Level extends Enum
+{
+    const LOW     = "low";
+    const MEDIUM  = "medium";
+    const HIGHT   = "hight";
+}

+ 37 - 0
core/Enum/Status.php

@@ -0,0 +1,37 @@
+<?php
+
+/* * ********************************************************************
+ * KerioEmail product developed. (Jan 8, 2019)
+ * *
+ *
+ *  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+ *  CONTACT                        ->       contact@modulesgarden.com
+ *
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  with  the  terms  of such  license and with the
+ * inclusion of the above copyright notice.  This software  or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ *
+ * ******************************************************************** */
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Enum;
+
+/**
+ * Description of Status
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+final class Status extends Enum
+{
+
+    const DEBUG    = "debug";
+    const ERROR    = "error";
+    const INFO     = "info";
+    const SUCCESS  = "success";
+    const CRITICAL = "critical";
+    
+}

+ 47 - 0
core/Enum/StatusColor.php

@@ -0,0 +1,47 @@
+<?php
+
+/* * ********************************************************************
+ * KerioEmail product developed. (Jan 23, 2019)
+ * *
+ *
+ *  CREATED BY MODULESGARDEN       ->       http://modulesgarden.com
+ *  CONTACT                        ->       contact@modulesgarden.com
+ *
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  with  the  terms  of such  license and with the
+ * inclusion of the above copyright notice.  This software  or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ *
+ * ******************************************************************** */
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Enum;
+
+/**
+ * Description of StatusColor
+ *
+ * @author Pawel Kopec <pawelk@modulesgardne.com>
+ */
+final class StatusColor extends Enum
+{
+    const PENDING   = "f89406";
+    const ACTIVE    = "46a546";
+    const COMPLETED = "008b8b";
+    const SUSPENDED = "0768b8";
+    const CANCELLED = "bfbfbf";
+    const FRAUD     = "000";
+    
+    public static function getColors(){
+        return [
+            "Pending"   => self::PENDING,
+            "Active"    => self::ACTIVE,
+            "Completed" => self::COMPLETED,
+            "Suspended" => self::SUSPENDED,
+            "Cancelled" => self::CANCELLED,
+            "Fraud"     => self::FRAUD
+        ];
+    }
+}

+ 80 - 0
core/Events/Dispatcher.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Events;
+
+use ModulesGarden\Servers\KerioEmail\Core\DependencyInjection;
+use ModulesGarden\Servers\KerioEmail\Core\DependencyInjection\Container;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+use ModulesGarden\Servers\KerioEmail\Core\Queue\DatabaseQueue;
+
+class Dispatcher extends \Illuminate\Events\Dispatcher
+{
+    public function __construct(Container $container)
+    {
+        $this->container    = $container;
+
+        $this->initialize();
+    }
+
+    /**
+     *
+     */
+    protected function initialize()
+    {
+        /**
+         * Load available events
+         */
+        $path   = ModuleConstants::getFullPath('app', 'Config', 'events.php');
+        $config = include($path);
+
+
+        foreach($config as $event => $listeners)
+        {
+            foreach($listeners as $listener)
+            {
+                $this->listen($event, $listener);
+            }
+        }
+
+        /**
+         * Set queue resolver
+         */
+        $this->setQueueResolver(function(){
+            return DependencyInjection::create(DatabaseQueue::class);
+        });
+    }
+
+    /**
+     * @param $class
+     * @param $arguments
+     */
+    public function queue($class, $arguments)
+    {
+        $class  = implode('@', $this->parseClassCallable($class));
+
+        $this->resolveQueue()->push("$class", serialize($arguments));
+    }
+
+    /**
+     * @param $class
+     * @param $method
+     * @override
+     * @return \Closure
+     */
+    protected function createQueuedHandlerCallable($class, $method)
+    {
+        return function () use ($class, $method)
+        {
+            $arguments = $this->cloneArgumentsForQueueing(func_get_args());
+
+            if (method_exists($class, 'queue'))
+            {
+                $this->callQueueMethodOnHandler($class, $method, $arguments);
+            }
+            else
+            {
+                $this->resolveQueue()->push("{$class}@{$method}", serialize($arguments));
+            }
+        };
+    }
+}

+ 8 - 0
core/Events/Event.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Events;
+
+class Event
+{
+
+}

+ 8 - 0
core/Events/Listener.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\Events;
+
+class Listener
+{
+
+}

+ 41 - 0
core/FileReader/Directory.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader;
+
+/**
+ * Description of Directory
+ *
+ * @author INBSX-37H
+ */
+class Directory extends PathValidator
+{
+    public function getFilesList($path, $extension = null, $trimExtensions = false)
+    {
+        if (!$this->pathExists($path) || !$this->isPathReadable($path))
+        {
+            return [];
+        }
+
+        $list = [];
+        $files = scandir($path, 1);
+        if (!$files)
+        {
+            return [];
+        }
+
+        foreach ($files as $key => $value)
+        {
+            //remove dots and a files with unwanted extensions
+            if ($value === "." || $value === ".." || 
+                    (is_string($extension) && $extension !=='' && !(stripos($value, $extension) > 0)))
+            {
+                unset($files[$key]);
+                continue;
+            }
+
+            $list[] = $trimExtensions ? str_replace($extension, '', $value) : $value;
+        }
+
+        return $list;
+    }
+}

+ 68 - 0
core/FileReader/File.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader;
+
+/**
+ * Description of File
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class File
+{
+    public static function createFile()
+    {
+        // next version
+    }
+
+    public static function createPaths()
+    {
+        foreach (func_get_args() as $path)
+        {
+            if (is_array($path) && isset($path['permission']) && self::createPath($path['full'], $path['permission']) === false)
+            {
+                $parentPath = explode(DS, $path['full']);
+                array_pop($pathFull);
+                $parentPath = implode(DS, $parentPath);
+                self::setPermission($parentPath);
+                self::setUser($path['full'], 'www-data');
+                self::createPath($path['full'], $path['permission']);
+            }
+            elseif (is_array($path) && self::createPath($path['full']) === false)
+            {
+                $parentPath = explode(DS, $path['full']);
+                array_pop($pathFull);
+                $parentPath = implode(DS, $parentPath);
+                self::setPermission($parentPath);
+                self::setUser($path['full'], 'www-data');
+                self::createPath($path['full']);
+            }
+            else
+            {
+                self::createPath($path);
+            }
+        }
+    }
+
+    public static function createPath($path, $permission = 0777)
+    {
+        return mkdir($path, $permission);
+    }
+
+    public static function setPermission($file, $permission = 0777)
+    {
+        return chmod($file, $permission);
+    }
+
+    public static function setUser($file, $user)
+    {
+        return chown($file, $user);
+    }
+
+    /**
+     * @return PathValidator
+     */
+    public static function getValidator()
+    {
+        return new PathValidator();
+    }
+}

+ 85 - 0
core/FileReader/PathValidator.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader;
+
+/**
+ * Wrapper for files and directories validation methods
+ *
+ * @author Sławomir Miśkowicz <slawomir@modulesgarden.com>
+ */
+class PathValidator
+{
+    /**
+     * @param string $path -a a path to be validated, can be a file path or a dir path
+     * @param bool $isReadable - states if path should be readable
+     * @param bool $isWritable - states if path should be writable
+     * @param bool $create - states if should try to create a directory if not exists
+     * @return bool
+     */
+    public function validatePath($path = "", $isReadable = true, $isWritable = false, $create = true)
+    {
+        //try to create a dir if does not exist
+        if ($create)
+        {
+            $this->createDirIfNotExists($path);
+        }
+
+        //if path does not exists
+        if (!$this->pathExists($path))
+        {
+            return false;
+        }
+
+        //if should be readable and it is not
+        if ($isReadable && !$this->isPathReadable($path))
+        {
+            return false;
+        }
+
+        //if should be writable and it is not
+        if ($isWritable && !$this->isPathWritable($path))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @param string $path - if provided path does not exist, a dir will be created
+     */
+    public function createDirIfNotExists($path)
+    {
+        if (!$this->pathExists($path))
+        {
+            mkdir($path);
+        }
+    }
+
+    /**
+     * @param string $path -a a path to be validated, can be a file path or a dir path
+     * @return bool
+     */
+    public function pathExists($path)
+    {
+        return file_exists($path);
+    }
+
+    /**
+     * @param $path -a a path to be validated, can be a file path or a dir path
+     * @return bool
+     */
+    public function isPathReadable($path)
+    {
+        return is_readable($path);
+    }
+
+    /**
+     * @param $path -a a path to be validated, can be a file path or a dir path
+     * @return bool
+     */
+    public function isPathWritable($path)
+    {
+        return is_writable($path);
+    }
+}

+ 84 - 0
core/FileReader/Reader.php

@@ -0,0 +1,84 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader;
+
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Ini;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Json;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Xml;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Yml;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Php;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Sql;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Js;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Css;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\Html;
+use ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader\AbstractType;
+
+/**
+ * Description of Reader
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Reader
+{
+
+    /**
+     * @param string $file
+     * @return AbstractType
+     */
+    public static function read($file, array $renderData = [])
+    {
+        $path = explode(DIRECTORY_SEPARATOR, $file);
+        $file = end($path);
+        array_pop($path);
+        $path = implode(DIRECTORY_SEPARATOR, $path);
+        $instance = null;
+        $type = self::getType($file);
+
+        switch ($type)
+        {
+            case "xml":
+                $instance = new Xml($file, $path, $renderData);
+                break;
+            case "ini":
+                $instance = new Ini($file, $path, $renderData);
+                break;
+            case "yml":
+                $instance = new Yml($file, $path, $renderData);
+                break;
+            case "json":
+                $instance = new Json($file, $path, $renderData);
+                break;
+            case "php":
+                $instance = new Php($file, $path, $renderData);
+                break;
+            case "sql":
+                $instance = new Sql($file, $path, $renderData);
+                break;
+            case "js":
+                $instance = new Js($file, $path, $renderData);
+                break;
+            case "css":
+                $instance = new Css($file, $path, $renderData);
+                break;
+            case "html":
+                $instance = new Html($file, $path, $renderData);
+                break;
+            default:
+                throw new \Exception('Can\'t read file: ' . $file);
+        }
+
+        return $instance;
+    }
+
+    private static function getType($file)
+    {
+        $type  = null;
+        $array = explode('.', $file);
+        if (is_array($array))
+        {
+            $type = end($array);
+        }
+
+        return strtolower($type);
+    }
+}

+ 49 - 0
core/FileReader/Reader/AbstractType.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+/**
+ * Description of AbstractType
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class AbstractType
+{
+    protected $data = [];
+    protected $renderData = [];
+    protected $file = '';
+    protected $path = '';
+
+    public function __construct($file, $path, $renderData = [])
+    {
+        $this->file       = $file;
+        $this->path       = $path;
+        $this->renderData = $renderData;
+        $this->loadFile();
+    }
+
+    abstract protected function loadFile();
+
+    public function get($key = null, $default = null)
+    {
+        if ($key == null)
+        {
+            return $this->data;
+        }
+
+        if ($this->isExist($key))
+        {
+            return $this->data[$key];
+        }
+
+        return $default;
+    }
+
+    protected function isExist($key)
+    {
+        if (isset($this->data[$key]) || array_key_exists($key, $this->data))
+        {
+            return true;
+        }
+    }
+}

+ 36 - 0
core/FileReader/Reader/Css.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Css extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 36 - 0
core/FileReader/Reader/Html.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Html extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 35 - 0
core/FileReader/Reader/Ini.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use Piwik\Ini\IniReader;
+use Piwik\Ini\IniReadingException;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Ini
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Ini extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = [];
+        $reader = new IniReader();
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = $reader->readFile($this->path . DS . $this->file);
+            }
+        }
+        catch (IniReadingException $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 36 - 0
core/FileReader/Reader/Js.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Js extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 33 - 0
core/FileReader/Reader/Json.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Json extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = [];
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $readFile = file_get_contents($this->path . DS . $this->file);
+                $return   = json_decode($readFile, true);
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 36 - 0
core/FileReader/Reader/Php.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Json
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Php extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = file_get_contents($this->path . DS . $this->file);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+}

+ 70 - 0
core/FileReader/Reader/Sql.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+use ModulesGarden\Servers\KerioEmail\Core\ModuleConstants;
+
+/**
+ * Description of Sql
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Sql extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = '';
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $collation = $this->getWHMCSTablesCollation();
+                $charset   = $this->getWHMCSTablesCharset();
+                $return = file_get_contents($this->path . DS . $this->file);
+                $return = str_replace("#collation#", $collation, $return);
+                $return = str_replace("#charset#", $charset, $return);
+                $return = str_replace("#prefix#", ModuleConstants::getPrefixDataBase(), $return);
+                foreach ($this->renderData as $key => $value)
+                {
+                    $return = str_replace("#$key#", $value, $return);
+                }
+            }
+        }
+        catch (\Exception $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+
+    protected function getWHMCSTablesCollation()
+    {
+        $pdo       = \Illuminate\Database\Capsule\Manager::connection()->getPdo();
+        $query = $pdo->prepare("SHOW TABLE STATUS WHERE name = 'tblclients'");
+        $query->execute();
+        $result = $query->fetchObject();
+
+        return $result->Collation;
+    }
+
+    protected function getWHMCSTablesCharset()
+    {
+        require ROOTDIR . DS . 'configuration.php';
+
+        $pdo = \Illuminate\Database\Capsule\Manager::connection()->getPdo();
+
+        $query = $pdo->prepare("SELECT CCSA.character_set_name as Charset FROM information_schema.`TABLES` T,
+            information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA
+            WHERE CCSA.collation_name = T.table_collation
+            AND T.table_schema = :db_name
+            AND T.table_name = 'tblclients';");
+
+        $query->execute(['db_name' => $db_name]);
+        $result = $query->fetchObject();
+
+        return $result->Charset;
+    }
+}

+ 23 - 0
core/FileReader/Reader/Xml.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Xml
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Xml extends AbstractType
+{
+
+    protected function loadFile()
+    {
+
+        // https://packagist.org/packages/sabre/xml
+
+        $this->data = [];
+        ServiceLocator::call('errorManager')->addError(self::class, "First install composer sabre/xml", ['url' => 'https://packagist.org/packages/sabre/xml']);
+    }
+}

+ 46 - 0
core/FileReader/Reader/Yml.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\FileReader\Reader;
+
+use Symfony\Component\Yaml\Yaml;
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of Yml
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class Yml extends AbstractType
+{
+
+    protected function loadFile()
+    {
+        $return = [];
+        try
+        {
+            if (file_exists($this->path . DS . $this->file))
+            {
+                $return = Yaml::parse(file_get_contents($this->path . DS . $this->file));
+                $return = array_map(self::class . '::replaceBackslash', $return ? : []);
+            }
+        }
+        catch (\Symfony\Component\Yaml\Exception\ParseException $e)
+        {
+            ServiceLocator::call('errorManager')->addError(self::class, $e->getMessage(), $e->getTrace());
+        }
+
+        $this->data = $return;
+    }
+
+    protected static function replaceBackslash($data)
+    {
+        if (is_array($data))
+        {
+            return array_map(self::class . '::replaceBackslash', $data);
+        }
+        else
+        {
+            return str_replace('\\\\', '\\', $data);
+        }
+    }
+}

+ 109 - 0
core/HandlerError/ErrorCodes/ErrorCode.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes;
+
+class ErrorCode
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+
+    protected $code = null;
+    protected $message = null;
+    protected $token = null;
+    protected $logable = false;
+
+    public function __construct($code = null, $codeDetails = null, $token = null)
+    {
+        $this->setToken($token);
+        $this->setCode($code);
+
+        $this->setDetails($codeDetails);
+    }
+
+    /**
+     * @param null $code
+     */
+    public function setCode($code = null)
+    {
+        if (is_string($code))
+        {
+            $this->code = $code;
+        }
+    }
+
+    /**
+     * @param null $message
+     */
+    public function setMessage($message = null)
+    {
+        if (is_string($message) && $message !== '')
+        {
+            $this->message = $message;
+        }
+    }
+
+    /**
+     * @param null $token
+     */
+    public function setToken($token = null)
+    {
+        if (is_string($token))
+        {
+            $this->token = $token;
+        }
+    }
+
+    /**
+     * @return string
+     */
+    public function getCode()
+    {
+        return $this->code === null ? '' : $this->code;
+    }
+
+    /**
+     * @return string
+     */
+    public function getToken()
+    {
+        return $this->token === null ? '' : $this->token;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessage()
+    {
+        return $this->message === null ? '' : $this->message;
+    }
+
+    public function getRawErrorMessage()
+    {
+        return 'Error Code: ' . ($this->getCode() ? : 'none') . ' Error Token: ' . ($this->getToken() ? : 'none') . 'Error Message: ' . $this->getMessage() ? : 'none.';
+    }
+
+    public function setLogable($logable)
+    {
+        if (is_bool($logable))
+        {
+            $this->logable = $logable;
+        }
+    }
+
+    public function isLogable()
+    {
+        return $this->logable;
+    }
+
+    public function setDetails($codeDetails)
+    {
+        if (is_string($codeDetails))
+        {
+            $this->setMessage($codeDetails);
+
+            return;
+        }
+
+        $this->setMessage($codeDetails[ErrorCodes::MESSAGE]);
+        $this->setLogable($codeDetails[ErrorCodes::LOG]);
+    }
+}

+ 73 - 0
core/HandlerError/ErrorCodes/ErrorCodes.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes;
+
+abstract class ErrorCodes
+{
+    const MESSAGE       = 'message';
+    const LOG           = 'log';
+    const CODE          = 'code';
+    const DEV_MESSAGE   = 'dev_message';
+    
+    /**
+     * @param null $code
+     * @param null $errorToken
+     * @return ErrorCode|null
+     */
+    public function getErrorMessageByCode($code = null, $errorToken = null)
+    {
+        $constantName = get_class($this) . '::' . $code;
+        if (!defined($constantName))
+        {
+            return $this->getUndefinedErrorMessage($code, $errorToken);
+        }
+
+        return $this->getErrorCode($code, constant($constantName), $errorToken);
+    }
+
+    /**
+     * @param null|string $code
+     * @param null|string $errorToken
+     * @return ErrorCode|null
+     */
+    public function getUndefinedErrorMessage($code = null, $errorToken = null)
+    {
+        return $this->getErrorCode($code, 'Invalid Error Code!', $errorToken);
+    }
+
+    /**
+     * @param null|string $code
+     * @param null|string $message
+     * @param null|string $token
+     * @return ErrorCode|null
+     */
+    protected function getErrorCode($code = null, $message = null, $token = null)
+    {
+        $token = new ErrorCode($code, $message, ($token ? : $this->genToken()));
+
+        return $token;
+    }
+
+    /**
+     * returns a string
+     */
+    protected function genToken()
+    {
+        return md5(time());
+    }
+
+    /**
+     * @param null|string $code
+     * @return bool
+     */
+    public function errorCodeExists($code = null)
+    {
+        $constantName = get_class($this) . '::' . $code;
+        if (!defined($constantName))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 109 - 0
core/HandlerError/ErrorCodes/ErrorCodesLib.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes;
+
+class ErrorCodesLib extends ErrorCodes
+{
+    const CORE_CT_000001 = 'Provided controller does not exists';
+    const CORE_CT_000002 = 'Provided controller does not exists';
+
+    const CORE_ACT_000001 = 'Database error';
+    const CORE_ACT_000002 = 'Database error';
+    const CORE_ACT_000003 = 'Database error';
+    const CORE_ACT_000004 = 'Database error';
+
+    /**
+     * Default error, used when no error code defined
+     */
+    const CORE_ERR_000001 = [
+        self::MESSAGE => 'Uncategorised error occured',
+        self::CODE => 'CORE_ERR_000001',
+        self::DEV_MESSAGE => "It's a default error code, used when no error code was specified"
+    ];
+
+    /**
+     * Logs class
+     */
+    const CORE_LOG_000001 = [
+        self::MESSAGE => 'Method does not exist in the Logger class',
+        self::CODE => 'CORE_LOG_000001',
+    ];
+
+    /**
+     * Register cache
+     */
+    const CORE_CREG_000001 = [
+        self::MESSAGE => 'Register key already exists',
+        self::CODE => 'CORE_CREG_000001',
+    ];
+
+    /**
+     * Database cache
+     */
+    const CORE_CDB_000001 = [
+        self::MESSAGE => 'The callback needs to ba a callable',
+        self::CODE => 'CORE_CDB_000001',
+    ];
+
+    /**
+     * GRAPHS
+     */
+    const CORE_GRA_000001 = [
+        self::MESSAGE => 'Tooltip mode does not exists',
+        self::CODE => 'CORE_GRA_000001',
+    ];
+
+    const CORE_GRA_000002 = [
+        self::MESSAGE => 'Width value is not numeric(:width:)',
+        self::CODE => 'CORE_GRA_000002',
+    ];
+
+    const CORE_GRA_000003 = [
+        self::MESSAGE => 'Height value is not numeric(:height:)',
+        self::CODE => 'CORE_GRA_000003',
+    ];
+
+    /**
+     * CURL
+     */
+    const CORE_CURL_000001 = [
+        self::MESSAGE => 'CURL error',
+        self::CODE => 'CORE_CURL_000001',
+    ];
+
+    const CORE_CURL_000002 = [
+        self::MESSAGE => 'CURL error',
+        self::CODE => 'CORE_CURL_000002',
+    ];
+
+    /**
+     * WHMCS API core lib
+     */
+    const CORE_WAPI_000001 = [
+        self::MESSAGE => 'No WHMCS files found',
+        self::CODE => 'CORE_WAPI_000001',
+    ];
+
+    const CORE_WAPI_000002 = [
+        self::MESSAGE => 'WHMCS API error',
+        self::CODE => 'CORE_WAPI_000002',
+    ];
+
+    const CORE_WAPI_000003 = [
+        self::MESSAGE => 'There is no admin with ID equal to ":adminId:"',
+        self::CODE => 'CORE_WAPI_000003',
+    ];
+
+    const CORE_WAPI_000004 = [
+        self::MESSAGE => 'WHMCS API error',
+        self::CODE => 'CORE_WAPI_000004',
+    ];
+
+    /**
+     * LIBS
+     */
+    const CORE_LIBS_DH_000001 = [
+        self::MESSAGE => 'The TLD is missing in tld.list file',
+        self::CODE => 'CORE_LIBS_DH_000001',
+    ];
+}

+ 263 - 0
core/HandlerError/ErrorManager.php

@@ -0,0 +1,263 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\HandlerError;
+
+use ModulesGarden\Servers\KerioEmail\Core\ServiceLocator;
+
+/**
+ * Description of ErrorManager
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+class ErrorManager
+{
+    const TYPE_ERROR   = "Error";
+    const TYPE_WARNING = "Warning";
+    
+    protected static $lastToken = null;
+    
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Error[]
+     */
+    protected static $errors = [];
+    
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Warning[]
+     */
+    protected static $warnings = [];
+
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\Core\HandlerError\WhmcsLogsHandler
+     */
+    protected static $whmcsLogger;
+
+
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\Core\Interfaces\LoggerInterface
+     */
+    protected $logger;
+    
+    /**
+     * @var bool
+     */
+    protected $withWarning = false;
+
+    /**
+     * @param Logger $logger
+     */
+    public function __construct(Logger $logger)
+    {
+        $this->logger = $logger;
+    }
+
+    /**
+     * @param string $classname
+     * @param string $message
+     * @param array $trace
+     */
+    public function addError($classname = null, $message = '', $trace = [])
+    {
+        $error = $this->createNewModel(self::TYPE_ERROR, $classname, $message, $trace);
+        $this->_addError($error)
+                ->logger->addError($error->getFullMessage(), $error->getTrace());
+        $this->getWhmcsLogger()->addModuleLog(
+            [
+                "type"    => "ERROR",
+                "class"   => $error->getClass(),
+                "message" => $error->getMessage(),
+                "data"    => $error->getTrace()
+            ]
+        );
+        
+        return $this;
+    }
+    
+    public  static function getLastErrorToken()
+    {
+        return self::$lastToken;
+    }
+
+    public  static function setLastErrorToken($token)
+    {
+        self::$lastToken = $token;
+        
+        return self;
+    }
+    
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Error
+     */
+    public static function getFirstError()
+    {
+        return (count(self::$errors)>0)?self::$errors[0]:null;
+    }
+
+    /**
+     * @param string $classname
+     * @param string $message
+     * @param array $trace
+     */
+    public function addWarning($classname = null, $message = '', $trace = [])
+    {
+        $warning = $this->createNewModel(self::TYPE_WARNING, $classname, $message, $trace);
+        $this->_addWarning($warning)
+                ->logger->addWarning($warning->getFullMessage(), $warning->getTrace());
+        $this->getWhmcsLogger()->addModuleLog(
+            [
+                "type"    => "WARNING",
+                "class"   => $warning->getClass(),
+                "message" => $warning->getMessage(),
+                "data"    => $warning->getTrace()
+            ]
+        );
+        
+        return $this;
+    }
+
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Error[]
+     */
+    public static function getErrors()
+    {
+        return self::$errors;
+    }
+    
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Warning[]
+     */
+    public static function getWarnings()
+    {
+        return self::$warnings;
+    }
+    
+    public static function reset()
+    {
+        self::$warnings = [];
+        self::$errors   = [];
+        
+        return self;
+    }
+    
+    /**
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\WhmcsLogsHandler
+     */
+    public function getWhmcsLogger()
+    {
+        if (isset(self::$whmcsLogger) === false)
+        {
+            self::$whmcsLogger = ServiceLocator::call("whmcsLogger");
+        }
+        
+        return self::$whmcsLogger;
+    }
+
+    /**
+     * @return bool
+     */
+    public function hesError()
+    {
+        return (bool) (count(self::$errors) != 0);
+    }
+    
+    /**
+     * @return bool
+     */
+    public function hesWarning()
+    {
+        return (bool) (count(self::$warnings) != 0);
+    }
+    
+    public function withWarnings()
+    {
+        $this->withWarning = true;
+        
+        return $this;
+    }
+    
+    public function withoutWarnings()
+    {
+        $this->withWarning = false;
+        
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        $string = '';
+        if (count(self::getErrors()) != 0 || (count(self::getWarnings()) != 0 ) && $this->withWarning)
+        {
+            $string .= '<div class="list-group">';
+            foreach (self::getErrors() as $error)
+            {
+                $string .= '<div class="alert alert-danger">';
+                $string .= '<h4>Class: <strong>';
+                $string .= $error->getClass();
+                $string .= '<span class="pull-right">' . $error->getDate() . " " . $error->getTime() . '</span>';
+                $string .= '</strong></h4>';
+                $string .= '<p>' . $error->getMessage() . '</p>';
+                $string .= '</div>';
+            }
+            if ($this->withWarning)
+            {
+                foreach (self::getWarnings() as $warning)
+                {
+                    $string .= '<div class="alert alert-warning">';
+                    $string .= '<h4>Class: <strong>';
+                    $string .= $warning->getClass();
+                    $string .= '<span class="pull-right">' . $warning->getDate() . " " . $warning->getTime() . '</span>';
+                    $string .= '</strong></h4>';
+                    $string .= '<p>' . $warning->getMessage() . '</p>';
+                    $string .= '</div>';
+                }
+            }
+            
+            $string      .= '</div>';
+            self::reset();
+        }
+        return $string;
+    }
+    
+    private function createNewModel($type = self::TYPE_ERROR, $class = "", $massage = "", $trace = [])
+    {
+        return $this->{"createNewModel".$type}($class, $massage, $trace);
+    }
+    
+    /**
+     * @param string $class
+     * @param string $massage
+     * @param array $trace
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Error
+     */
+    private function createNewModelError($class = "", $massage = "", $trace = [])
+    {
+        return new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Error($class, $massage, $trace);
+    }
+    
+    /**
+     * @param string $class
+     * @param string $massage
+     * @param array $trace
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Warning
+     */
+    private function createNewModelWarning($class = "", $massage = "", $trace = [])
+    {
+        return new \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Error($class, $massage, $trace);
+    }
+    
+    protected function _addError(\ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Error $error)
+    {
+        array_push(self::$errors, $error);
+        
+        return $this;
+    }
+    
+    protected function _addWarning(\ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model\Warning $warning)
+    {
+        array_push(self::$warnings, $warning);
+        
+        return $this;
+    }
+}

+ 314 - 0
core/HandlerError/Exceptions/Exception.php

@@ -0,0 +1,314 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions;
+
+/**
+ * Base module Exception type
+ *
+ * @author Sławomir Miśkowicz <rafal.os@modulesgarden.com>
+ */
+class Exception extends \Exception
+{
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\ErrorCodesLibrary;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\Lang;
+    use \ModulesGarden\Servers\KerioEmail\Core\Traits\IsDebugOn;
+    use \ModulesGarden\Servers\KerioEmail\Core\UI\Traits\RequestObjectHandler;
+    
+    /**
+     * A default error code number, selected when no code number provided
+     */
+    const DEFAULT_ERROR_CODE = 'CORE_ERR_000001';
+
+    /**
+     * An error code object
+     * 
+     * @var type \ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes\ErrorCode
+     */
+    protected $errorCode = null;
+
+    /** 
+     * Every Exception which can be caught as \Exception
+     * @var type \Exception
+     */
+    protected $originalException = null;
+
+    /** 
+     * An array of additionall data that will be logged with the Exception in order to help debug
+     * @var type array
+     */
+    protected $additionalData = [];
+
+    /** 
+     * An array of strings to be replaced in translate process, eg. for message:
+     * "An error :xyz: occured" in order to replace key ':xyz:' with a '123' set this
+     * param to: ['xyz' => '123']
+     * 
+     * @var type array
+     */
+    protected $toTranslate = [];
+
+    /** 
+     * This is a way to replace standard ErrorCode message, use it when no original exception
+     * is present and the ErrorCode message, needs to be replaced, eg. API string error responses
+     * 
+     * @var type string
+     */
+    protected $customMessage = null;
+
+    public function __construct($errorCode = null, $additionalData = null, $toTranslate = null, $originalException = null)
+    {
+        $this->errorCode = $this->genErrorCode(($errorCode ? : self::DEFAULT_ERROR_CODE));
+
+        $this->setAdditionalData($additionalData);
+        $this->setToTranslate($toTranslate);
+
+        $this->setOriginalException($originalException);
+    }
+
+    /**
+     * Returns an error code for the exception
+     * @return type string
+     */
+    public function getMgCode()
+    {
+        return $this->errorCode->getCode();
+    }
+
+    /**
+     * Returns an error token for the exception, an unique string based on exception occurence timestamp
+     * @return type string
+     */
+    public function getMgToken()
+    {
+        return $this->errorCode->getToken();
+    }
+
+    /**
+     * Returns a date for the exception occurence
+     * @return type string
+     */
+    public function getMgTime()
+    {
+        return date("Y-m-d H:i:s", time());
+    }
+
+    /**
+     * Returns a translated or raw error message
+     * @param type bool $translate
+     * @return type string
+     */
+    public function getMgMessage($translate = true)
+    {
+        if ($translate)
+        {
+            $this->loadLang();
+
+            $message = $this->lang->absoluteTranslate(
+                    $this->errorCode === self::DEFAULT_ERROR_CODE ? 'errorMessage' : 'errorCodeMessage', 
+                    $this->selectProperMessage());
+        }
+        else
+        {
+            $message = $this->selectProperMessage();
+        }
+
+        return $this->replaceMessageVars($message);
+    }
+
+    /**
+     * Replaces provided vars in the message string
+     * 
+     * @param type $message string
+     */
+    public function replaceMessageVars($message)
+    {
+        foreach ($this->toTranslate as $key => $value)
+        {
+            $message = str_replace(':' . $key . ':', $value, $message);
+        }
+
+        return $message;
+    }
+
+    /**
+     * Returns an originall exception object if such was provided
+     * 
+     * @return type \Exception
+     */
+    public function getOriginalException()
+    {
+        return $this->originalException;
+    }
+
+    /**
+     * Returns an array of data to be displayed when exception occured
+     * 
+     * @return type array
+     */
+    public function getDetailsToDisplay()
+    {
+        $errorDetails = [];
+
+        if ($this->isDebugOn() && $this->isAdminLogedIn())
+        {
+            $errorDetails['errorCode'] = $this->getMgCode();
+            $errorDetails['errorToken'] = $this->getMgToken();
+            $errorDetails['errorTime'] = $this->getMgTime();
+        }
+
+        $errorDetails['errorMessage'] = $this->getMgMessage(true);
+
+        return $errorDetails;
+    }
+
+    /**
+     * Returns an array of data to be logged when exception occured
+     * 
+     * @return type array
+     */
+    public function getDetailsToLog()
+    {
+        $errorDetails = [];
+
+        $errorDetails['errorCode'] = $this->getMgCode();
+        $errorDetails['errorToken'] = $this->getMgToken();
+        $errorDetails['errorTime'] = $this->getMgTime();
+        $errorDetails['errorMessage'] = $this->getMgMessage(false);
+        $errorDetails['additionalData'] = $this->getAdditionalData();
+        
+        return $errorDetails;        
+    }
+    
+    /** 
+     * Select a proper message for the exepction
+     * Priority:
+     * 1 custom message
+     * 2 original Exception message
+     * 3 error code message
+     * 
+     * @return type string
+     */
+    protected function selectProperMessage()
+    {
+        if (is_string($this->customMessage))
+        {
+            return $this->customMessage;
+        }
+        
+        if ($this->originalException !== null)
+        {
+            return $this->originalException->getMessage();
+        }
+        
+        return $this->errorCode->getMessage();
+    }
+    
+    /** 
+     * Sets a $originalException param, so you can wrap other exception in this one,
+     * in order to log and parse them automatically
+     * 
+     * @param \Exception $originalException
+     */
+    public function setOriginalException($originalException)
+    {
+        if ($originalException instanceof \Exception)
+        {
+            $this->originalException = $originalException;
+            
+            parent::__construct($originalException->getMessage(), $originalException->getCode(), $originalException->getPrevious());  
+        }
+    }    
+    
+    /** 
+     * 
+     * @param type $data array
+     * @return $this
+     */
+    public function setAdditionalData($data = [])
+    {
+        if (is_array($data))
+        {
+            $this->additionalData = $data;
+        }
+        
+        return $this;
+    }
+    
+    /** 
+     * 
+     * @return type array
+     */
+    public function getAdditionalData()
+    {
+        return $this->additionalData;
+    }
+    
+    /** 
+     * 
+     * @param type $data array
+     * @return $this
+     */
+    public function setToTranslate($data = [])
+    {
+        if (is_array($data))
+        {
+            $this->toTranslate = $data;
+        }
+        
+        return $this;
+    }
+    
+    /** 
+     * 
+     * @param type $message string
+     * @return $this
+     */
+    public function setCustomMessage($message = null)
+    {
+        if (is_string($message) && $message !== '')
+        {
+            $this->customMessage = $message;
+        }
+        
+        return $this;
+    }
+    
+    /** 
+     * Check if the exception should be logged or not
+     * 
+     * @return boolean
+     */
+    public function isLogable()
+    {
+        if ($this->errorCode->isLogable())
+        {
+            return true;
+        }
+
+        if ($this->isAdminLogedIn() && $this->isDebugOn())
+        {
+            return true;
+        }
+        
+        return false;
+    }
+    
+    /** 
+     * Check if the administrator user is logged in current session
+     *
+     * @return boolean
+     */
+    public function isAdminLogedIn()
+    {
+        $this->loadRequestObj();
+
+        $adminId = $this->request->getSession('adminid');
+
+        if (is_int($adminId) && $adminId > 0)
+        {
+            return true;
+        }
+        
+        return false;
+    }
+}

+ 243 - 0
core/HandlerError/Logger.php

@@ -0,0 +1,243 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\HandlerError;
+
+use \Monolog\Formatter\LineFormatter;
+use \Monolog\Handler\StreamHandler;
+use \ModulesGarden\Servers\KerioEmail\Core\Interfaces\LoggerInterface;
+use \ModulesGarden\Servers\KerioEmail\Core\HandlerError\ErrorCodes\ErrorCodesLib;
+use \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception;
+
+/**
+ * Description of Logger
+ * 
+ * @author Rafal Ossowski <rafal.os@modulesgarden.com>
+ */
+class Logger implements LoggerInterface
+{
+    /**
+     * @var \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Logger
+     */
+    protected static $instance;
+
+    protected $name;
+    /**
+     * @var \Monolog\Logger
+     */
+    protected $logger;
+    protected $mainPath = null;
+    protected $handlers = [];
+
+    /**
+     * @param string $name
+     * @param string $debugName
+     * @param string $warningName
+     * @param string $errorName
+     */
+    protected function __construct(
+    $name = '', $debugName = '', $warningName = '', $errorName = ''
+    )
+    {
+//        $this->name     = $name;
+//        $this->mainPath = ModuleConstants::getModuleRootDir() . DS . 'storage' . DS . 'logs' . DS;
+//        if (is_dir($this->mainPath) === false)
+//        {
+//            mkdir($this->mainPath);
+//        }
+//        $this->logger   = new \Monolog\Logger($this->name);
+//        
+//        foreach ([
+//            $this->mainPath . $debugName   => \Monolog\Logger::DEBUG,
+//            $this->mainPath . $warningName => \Monolog\Logger::WARNING,
+//            $this->mainPath . $errorName   => \Monolog\Logger::ERROR
+//        ] as $path => $status)
+//        {
+//            if (file_exists($path) === false)
+//            {
+//                $myfile = fopen($path, "w");
+//                fclose($myfile);
+//                File::setPermission($path);
+//            }
+//            $this->handlers[] = $this->buildHandlar($path, $status);
+//        }
+//
+//        $this->addHandlerToLogger();
+    }
+    
+    private function __clone()
+    {
+        
+    }
+
+    public function isLoggerExist()
+    {
+        return  isset($this->logger);
+    }
+    
+    public function createLogger()
+    {
+        $this->logger   = new \Monolog\Logger($this->name);
+        //$this->addHandlerToLogger();
+        return $this;
+    }
+
+    /**
+     * @param string $name
+     * @param array $arguments
+     * @return mixed
+     * @throws \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Exceptions\Exception
+     */
+    public function __call($name, $arguments)
+    {
+        if (method_exists($this->logger, $name))
+        {
+            return $this->logger->{$name}(
+                            (isset($arguments[0]) ? $arguments[0] : ''), (isset($arguments[1]) ? $arguments[1] : [])
+            );
+        }
+        
+        throw new Exception(ErrorCodesLib::CORE_LOG_000001, ['functionName' => $name]);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function debug($message, array $context = [])
+    {
+        //return $this->logger->debug($message, $context);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function error($message, array $context = [])
+    {
+        //return $this->logger->error($message, $context);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function warning($message, array $context = [])
+    {
+        //return $this->logger->warning($message, $context);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function err($message, array $context = [])
+    {
+        //return $this->logger->err($message, $context);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function warn($message, array $context = [])
+    {
+        //return $this->logger->warn($message, $context);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function addDebug($message, array $context = [])
+    {
+        //return $this->logger->addDebug($message, $context);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function addWarning($message, array $context = [])
+    {
+        //return $this->logger->addWarning($message, $context);
+    }
+    
+    /**
+     * @param string $message
+     * @param array $context
+     * @return bool
+     */
+    public function addError($message, array $context = [])
+    {
+        //return $this->logger->addError($message, $context);
+    }
+
+    private function addHandlerToLogger()
+    {
+        $formatter = $this->getFormatter();
+
+        foreach ($this->handlers as $handler)
+        {
+            $handler->setFormatter($formatter);
+            $this->logger->pushHandler($handler);
+        }
+    }
+
+    private function buildHandlar($path, $type)
+    {
+        return new StreamHandler($path, $type);
+    }
+
+    /**
+     * @return LineFormatter
+     */
+    private function getFormatter()
+    {
+        return new LineFormatter(null, null, false, true);
+    }
+
+    /**
+     * @param string $name
+     * @param string $debugName
+     * @param string $warningName
+     * @param string $errorName
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Logger
+     */
+    protected static function create(
+    $name = 'default', $debugName = 'debug.log', $warningName = 'warning.log', $errorName = 'error.log'
+    )
+    {
+        return new static($name, $debugName, $warningName, $errorName);
+    }
+
+    /**
+     * @param string $name
+     * @param string $debugName
+     * @param string $warningName
+     * @param string $errorName
+     * @return \ModulesGarden\Servers\KerioEmail\Core\HandlerError\Logger
+     */
+    public static function get(
+    $name = 'default', $debugName = 'debug.log', $warningName = 'warning.log', $errorName = 'error.log'
+    )
+    {
+        if (!isset(self::$instance))
+        {
+            self::$instance = self::create($name, $debugName, $warningName, $errorName);
+        }
+        
+        if (self::$instance->isLoggerExist())
+        {
+            self::$instance->createLogger();
+        }
+        
+        return self::$instance;
+    }
+}

+ 114 - 0
core/HandlerError/Model/AbstractModel.php

@@ -0,0 +1,114 @@
+<?php
+
+namespace ModulesGarden\Servers\KerioEmail\Core\HandlerError\Model;
+
+/**
+ * Description of AbstractModel
+ *
+ * @author Rafał Ossowski <rafal.os@modulesgarden.com>
+ */
+abstract class AbstractModel
+{
+    /**
+     * @var string
+     */
+    protected $class;
+    
+    /**
+     * @var string 
+     */
+    protected $message;
+    
+    /**
+     * @var array
+     */
+    protected $trace;
+    
+    /**
+     * @var string 
+     */
+    protected $date;
+    
+    /**
+     * @var string
+     */
+    protected $time;
+    
+    /**
+     * @param string $class
+     * @param string $massage
+     * @param array $trace
+     */
+    public function __construct($class = "", $massage = "", $trace = [])
+    {
+        $this->date = date('Y-m-d');
+        $this->time = date('H:i:s');
+        
+        $this->setClass($class)->setMessage($massage)->setTrace($trace);
+    }
+    
+    public function getClass()
+    {
+        return $this->class;
+    }
+    
+    public function setClass($class = "")
+    {
+        $this->class = $class;
+        
+        return $this;
+    }
+    
+    public function getMessage()
+    {
+        return $this->message;
+    }
+    
+    public function setMessage($message = "")
+    {
+        $this->message = $message;
+        
+        return $this;
+    }
+    
+    public function getTrace()
+    {
+        return $this->trace;
+    }
+    
+    public function setTrace($trace = [])
+    {
+        $this->trace = $trace;
+        
+        return $this;
+    }
+    
+    public function getDate()
+    {
+        return $this->date;
+    }
+    
+    public function setDate($date = '')
+    {
+        $this->date = $date;
+        
+        return $this;
+    }
+    
+    public function getTime()
+    {
+        return $this->time;
+    }
+    
+    public function setTime($time = "")
+    {
+        $this->time = $time;
+        
+        return $this;
+    }
+    
+    public function getFullMessage()
+    {
+        return "[ " . $this->getClass() . " ]( {$this->getDate()} {$this->getMessage()} ) :\n{$this->getMessage()}";
+    }
+}

Some files were not shown because too many files changed in this diff