diff --git a/WebsitePanel/Database/update_db.sql b/WebsitePanel/Database/update_db.sql index 3f2dd1b2..aad554db 100644 --- a/WebsitePanel/Database/update_db.sql +++ b/WebsitePanel/Database/update_db.sql @@ -4462,4 +4462,47 @@ GO BEGIN UPDATE [dbo].[ServiceItemTypes] SET [Suspendable] = 1 WHERE [ItemTypeID] = 38 AND [GroupID] = 23 END -GO \ No newline at end of file +GO + +/* ICE Warp */ +IF NOT EXISTS (SELECT * FROM [dbo].[Providers] WHERE [ProviderName] = 'IceWarp') +BEGIN +INSERT [dbo].[Providers] ([ProviderID], [GroupID], [ProviderName], [DisplayName], [ProviderType], [EditorControl], [DisableAutoDiscovery]) VALUES (160, 4, N'IceWarp', N'IceWarp Mail Server', N'WebsitePanel.Providers.Mail.IceWarp, WebsitePanel.Providers.Mail.IceWarp', N'IceWarp', NULL) +END +GO + +/* SQL 2014 Provider */ +IF NOT EXISTS (SELECT * FROM [dbo].[ResourceGroups] WHERE [GroupName] = 'MsSQL2014') +BEGIN +INSERT [dbo].[ResourceGroups] ([GroupID], [GroupName], [GroupOrder], [GroupController], [ShowGroup]) VALUES (46, N'MsSQL2014', 11, N'WebsitePanel.EnterpriseServer.DatabaseServerController', 1) +END +ELSE +BEGIN +UPDATE [dbo].[ResourceGroups] SET [ShowGroup] = 1 WHERE [GroupName] = 'MsSQL2014' +END +GO +IF NOT EXISTS (SELECT * FROM [dbo].[Providers] WHERE [DisplayName] = 'Microsoft SQL Server 2014') +BEGIN +INSERT [dbo].[Providers] ([ProviderID], [GroupID], [ProviderName], [DisplayName], [ProviderType], [EditorControl], [DisableAutoDiscovery]) VALUES (1203, 46, N'MsSQL', N'Microsoft SQL Server 2014', N'WebsitePanel.Providers.Database.MsSqlServer2014, WebsitePanel.Providers.Database.SqlServer', N'MSSQL', NULL) +INSERT [dbo].[ServiceItemTypes] ([ItemTypeID], [GroupID], [DisplayName], [TypeName], [TypeOrder], [CalculateDiskspace], [CalculateBandwidth], [Suspendable], [Disposable], [Searchable], [Importable], [Backupable]) VALUES (39, 46, N'MsSQL2014Database', N'WebsitePanel.Providers.Database.SqlDatabase, WebsitePanel.Providers.Base', 1, 1, 0, 0, 1, 1, 1, 1) +INSERT [dbo].[ServiceItemTypes] ([ItemTypeID], [GroupID], [DisplayName], [TypeName], [TypeOrder], [CalculateDiskspace], [CalculateBandwidth], [Suspendable], [Disposable], [Searchable], [Importable], [Backupable]) VALUES (40, 46, N'MsSQL2014User', N'WebsitePanel.Providers.Database.SqlUser, WebsitePanel.Providers.Base', 1, 0, 0, 0, 1, 1, 1, 1) +INSERT [dbo].[Quotas] ([QuotaID], [GroupID], [QuotaOrder], [QuotaName], [QuotaDescription], [QuotaTypeID], [ServiceQuota], [ItemTypeID], [HideQuota]) VALUES (470, 46, 1, N'MsSQL2014.Databases', N'Databases', 2, 0, 39, NULL) +INSERT [dbo].[Quotas] ([QuotaID], [GroupID], [QuotaOrder], [QuotaName], [QuotaDescription], [QuotaTypeID], [ServiceQuota], [ItemTypeID], [HideQuota]) VALUES (471, 46, 2, N'MsSQL2014.Users', N'Users', 2, 0, 40, NULL) +INSERT [dbo].[Quotas] ([QuotaID], [GroupID], [QuotaOrder], [QuotaName], [QuotaDescription], [QuotaTypeID], [ServiceQuota], [ItemTypeID], [HideQuota]) VALUES (472, 46, 3, N'MsSQL2014.MaxDatabaseSize', N'Max Database Size', 3, 0, NULL, NULL) +INSERT [dbo].[Quotas] ([QuotaID], [GroupID], [QuotaOrder], [QuotaName], [QuotaDescription], [QuotaTypeID], [ServiceQuota], [ItemTypeID], [HideQuota]) VALUES (473, 46, 5, N'MsSQL2014.Backup', N'Database Backups', 1, 0, NULL, NULL) +INSERT [dbo].[Quotas] ([QuotaID], [GroupID], [QuotaOrder], [QuotaName], [QuotaDescription], [QuotaTypeID], [ServiceQuota], [ItemTypeID], [HideQuota]) VALUES (474, 46, 6, N'MsSQL2014.Restore', N'Database Restores', 1, 0, NULL, NULL) +INSERT [dbo].[Quotas] ([QuotaID], [GroupID], [QuotaOrder], [QuotaName], [QuotaDescription], [QuotaTypeID], [ServiceQuota], [ItemTypeID], [HideQuota]) VALUES (475, 46, 7, N'MsSQL2014.Truncate', N'Database Truncate', 1, 0, NULL, NULL) +INSERT [dbo].[Quotas] ([QuotaID], [GroupID], [QuotaOrder], [QuotaName], [QuotaDescription], [QuotaTypeID], [ServiceQuota], [ItemTypeID], [HideQuota]) VALUES (476, 46, 4, N'MsSQL2014.MaxLogSize', N'Max Log Size', 3, 0, NULL, NULL) +END +ELSE +BEGIN +UPDATE [dbo].[Providers] SET [DisableAutoDiscovery] = NULL, GroupID = 46 WHERE [DisplayName] = 'Microsoft SQL Server 2014' +END +GO + + + +/*This should be [DefaultValue]= N'MsSQL2000=SQL Server 2000;MsSQL2005=SQL Server 2005;MsSQL2008=SQL Server 2008;MsSQL2012=SQL Server 2012;MsSQL2014=SQL Server 2014;MySQL4=MySQL 4.0;MySQL5=MySQL 5.0' but the field is not large enough!! */ +UPDATE [dbo].[ScheduleTaskParameters] SET [DefaultValue]= N'MsSQL2005=SQL Server 2005;MsSQL2008=SQL Server 2008;MsSQL2012=SQL Server 2012;MsSQL2014=SQL Server 2014;MySQL4=MySQL 4.0;MySQL5=MySQL 5.0' WHERE [TaskID]= 'SCHEDULE_TASK_BACKUP_DATABASE' AND [ParameterID]='DATABASE_GROUP' +GO + diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Base/Servers/ResourceGroups.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Base/Servers/ResourceGroups.cs index ca3e129a..78480041 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Base/Servers/ResourceGroups.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Base/Servers/ResourceGroups.cs @@ -39,6 +39,7 @@ namespace WebsitePanel.EnterpriseServer public const string MsSql2005 = "MsSQL2005"; public const string MsSql2008 = "MsSQL2008"; public const string MsSql2012 = "MsSQL2012"; + public const string MsSql2014 = "MsSQL2014"; public const string MySql5 = "MySQL5"; public const string Dns = "DNS"; public const string Statistics = "Statistics"; diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Packages/PackageController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Packages/PackageController.cs index 987e66e4..17bef13f 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Packages/PackageController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Packages/PackageController.cs @@ -482,6 +482,7 @@ namespace WebsitePanel.EnterpriseServer ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2005, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2008, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2012, domain, ""); + ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2014, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MySql4, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MySql5, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.Statistics, domain, ""); @@ -1999,6 +2000,7 @@ namespace WebsitePanel.EnterpriseServer SetSqlServerExternalAddress(packageId, items, ResourceGroups.MsSql2005); SetSqlServerExternalAddress(packageId, items, ResourceGroups.MsSql2008); SetSqlServerExternalAddress(packageId, items, ResourceGroups.MsSql2012); + SetSqlServerExternalAddress(packageId, items, ResourceGroups.MsSql2014); SetSqlServerExternalAddress(packageId, items, ResourceGroups.MySql4); SetSqlServerExternalAddress(packageId, items, ResourceGroups.MySql5); diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Servers/ServerController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Servers/ServerController.cs index eaca340c..02050909 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Servers/ServerController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Servers/ServerController.cs @@ -1780,6 +1780,7 @@ namespace WebsitePanel.EnterpriseServer ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2005, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2008, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2012, domain, ""); + ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MsSql2014, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MySql4, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.MySql5, domain, ""); ServerController.AddServiceDNSRecords(packageId, ResourceGroups.Statistics, domain, ""); @@ -2338,6 +2339,7 @@ namespace WebsitePanel.EnterpriseServer ServerController.AddServiceDNSRecords(domain.PackageId, ResourceGroups.MsSql2005, domain, ""); ServerController.AddServiceDNSRecords(domain.PackageId, ResourceGroups.MsSql2008, domain, ""); ServerController.AddServiceDNSRecords(domain.PackageId, ResourceGroups.MsSql2012, domain, ""); + ServerController.AddServiceDNSRecords(domain.PackageId, ResourceGroups.MsSql2014, domain, ""); ServerController.AddServiceDNSRecords(domain.PackageId, ResourceGroups.MySql4, domain, ""); ServerController.AddServiceDNSRecords(domain.PackageId, ResourceGroups.MySql5, domain, ""); ServerController.AddServiceDNSRecords(domain.PackageId, ResourceGroups.Statistics, domain, ""); diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/WebAppGallery/WebAppGalleryController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/WebAppGallery/WebAppGalleryController.cs index 3dc7c030..fdb190cb 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/WebAppGallery/WebAppGalleryController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/WebAppGallery/WebAppGalleryController.cs @@ -262,7 +262,8 @@ namespace WebsitePanel.EnterpriseServer //if (context.Groups.ContainsKey(ResourceGroups.MsSql2000) || // context.Groups.ContainsKey(ResourceGroups.MsSql2005) || // context.Groups.ContainsKey(ResourceGroups.MsSql2008) || - // context.Groups.ContainsKey(ResourceGroups.MsSql2012)) + // context.Groups.ContainsKey(ResourceGroups.MsSql2012) || + // context.Groups.ContainsKey(ResourceGroups.MsSql2014)) //{ // appsFilter.AddRange(SupportedAppDependencies.MSSQL_DATABASE); //} @@ -496,6 +497,7 @@ namespace WebsitePanel.EnterpriseServer || context.Groups.ContainsKey(ResourceGroups.MsSql2005) || context.Groups.ContainsKey(ResourceGroups.MsSql2008) || context.Groups.ContainsKey(ResourceGroups.MsSql2012) + || context.Groups.ContainsKey(ResourceGroups.MsSql2014) || context.Groups.ContainsKey(ResourceGroups.MySql4) || context.Groups.ContainsKey(ResourceGroups.MySql5))) result.ErrorCodes.Add(GalleryErrors.DatabaseRequired); @@ -505,7 +507,8 @@ namespace WebsitePanel.EnterpriseServer && !(context.Groups.ContainsKey(ResourceGroups.MsSql2000) || context.Groups.ContainsKey(ResourceGroups.MsSql2005) || context.Groups.ContainsKey(ResourceGroups.MsSql2008) - || context.Groups.ContainsKey(ResourceGroups.MsSql2012))) + || context.Groups.ContainsKey(ResourceGroups.MsSql2012) + || context.Groups.ContainsKey(ResourceGroups.MsSql2014))) result.ErrorCodes.Add(GalleryErrors.SQLRequired); // MySQL diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailAccount.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailAccount.cs index 6f1d0ada..0208da80 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailAccount.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailAccount.cs @@ -199,5 +199,31 @@ namespace WebsitePanel.Providers.Mail public string ResponderExpirationDate { get; set; } #endregion - } + + #region IceWarp + + public int IceWarpAccountType { get; set; } + public int IceWarpAccountState { get; set; } + public int IceWarpRespondType { get; set; } + + public bool RespondOnlyBetweenDates { get; set; } // Added this because Calendar Control used did not allow null values + public DateTime RespondFrom { get; set; } + public DateTime RespondTo { get; set; } + public string RespondWithReplyFrom { get; set; } + public int RespondPeriodInDays { get; set; } + + public bool DeleteOlder { get; set; } + public int DeleteOlderDays { get; set; } + public bool ForwardOlder { get; set; } + public int ForwardOlderDays { get; set; } + public string ForwardOlderTo { get; set; } + + public int MaxMessageSizeMegaByte { get; set; } + public int MegaByteSendLimit { get; set; } + public int NumberSendLimit { get; set; } + + public string FullName { get; set; } + + #endregion + } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailDomain.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailDomain.cs index 343e8cb6..a452d66d 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailDomain.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailDomain.cs @@ -365,5 +365,17 @@ namespace WebsitePanel.Providers.Mail #endregion - } + + #region IceWarp + + public int MegaByteSendLimit { get; set; } + public int NumberSendLimit { get; set; } + + public int DefaultUserQuotaInMB { get; set; } + public int DefaultUserMaxMessageSizeMegaByte { get; set; } + public int DefaultUserMegaByteSendLimit { get; set; } + public int DefaultUserNumberSendLimit { get; set; } + + #endregion + } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailEnums.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailEnums.cs index ac7f6c8b..f39b05f1 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailEnums.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailEnums.cs @@ -67,4 +67,42 @@ namespace WebsitePanel.Providers.Mail #endregion + #region IceWarp + + public enum IceWarpListMembersSource + { + MembersInFile = 0, + AllDomainUsers = 1, + AllDomainAdmins = 3 + } + + public enum IceWarpListFromAndReplyToHeader + { + NoChange = 0, + SetToSender = 1, + SetToValue = 2 + } + + public enum IceWarpListOriginator + { + Blank = 0, + Sender = 1, + Owner = 2 + } + + [Flags] + public enum IceWarpListDefaultRights + { + Receive = 1, + Post = 2, + Digest = 4 + } + + public enum IceWarpListConfirmSubscription + { + None = 0, + User = 1, + Owner = 2 + } + #endregion } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailList.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailList.cs index 99422f1f..be8f3dd2 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailList.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Mail/MailList.cs @@ -280,5 +280,26 @@ namespace WebsitePanel.Providers.Mail set { requireSmtpAuthentication = value; } } #endregion + + #region IceWarp + + public IceWarpListMembersSource MembersSource { get; set; } + public IceWarpListFromAndReplyToHeader FromHeader { get; set; } + public IceWarpListFromAndReplyToHeader ReplyToHeader { get; set; } + public bool SetReceipientsToToHeader { get; set; } + public IceWarpListOriginator Originator { get; set; } + public IceWarpListDefaultRights DefaultRights { get; set; } + public int MaxMembers { get; set; } + public bool SendToSender { get; set; } + public int MaxMessagesPerMinute { get; set; } + public IceWarpListConfirmSubscription ConfirmSubscription { get; set; } + public bool CommandsInSubject { get; set; } + public bool DisableWhichCommand { get; set; } + public bool DisableReviewCommand { get; set; } + public bool DisableVacationCommand { get; set; } + public string CommandPassword { get; set; } + public bool SuppressCommandResponses { get; set; } + + #endregion } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/MsSqlServer2014.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/MsSqlServer2014.cs new file mode 100644 index 00000000..a3e84919 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/MsSqlServer2014.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2014, Outercurve Foundation. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// - Neither the name of the Outercurve Foundation nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using System; + +namespace WebsitePanel.Providers.Database +{ + public class MsSqlServer2014 : MsSqlServer2005 + { + public override bool IsInstalled() + { + return CheckVersion("12."); + } + + public override void TruncateDatabase(string databaseName) + { + SqlDatabase database = GetDatabase(databaseName); + ExecuteNonQuery(String.Format(@"USE [{0}];DBCC SHRINKFILE ('{1}', 1);", + databaseName, database.LogName)); + } + } +} diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/WebsitePanel.Providers.Database.SqlServer.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/WebsitePanel.Providers.Database.SqlServer.csproj index 2e00638b..e1779c25 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/WebsitePanel.Providers.Database.SqlServer.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/WebsitePanel.Providers.Database.SqlServer.csproj @@ -66,6 +66,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/WebsitePanel.Providers.Database.SqlServer.sln b/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/WebsitePanel.Providers.Database.SqlServer.sln new file mode 100644 index 00000000..5f020c9c --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Database.SqlServer/WebsitePanel.Providers.Database.SqlServer.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.Database.SqlServer", "WebsitePanel.Providers.Database.SqlServer.csproj", "{3744791D-C7B5-4818-8521-78EB5261CB34}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3744791D-C7B5-4818-8521-78EB5261CB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3744791D-C7B5-4818-8521-78EB5261CB34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3744791D-C7B5-4818-8521-78EB5261CB34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3744791D-C7B5-4818-8521-78EB5261CB34}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/IceWarp.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/IceWarp.cs new file mode 100644 index 00000000..b622ae19 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/IceWarp.cs @@ -0,0 +1,1537 @@ +using System; +using System.IO; +using System.Net.Mail; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.Win32; +using WebsitePanel.Providers.Utils; +using WebsitePanel.Server.Utils; + +namespace WebsitePanel.Providers.Mail +{ + public class IceWarp : HostingServiceProviderBase, IMailServer + { + protected const string API_PROGID = "IceWarpServer.APIObject"; + protected const string DOMAIN_PROGID = "IceWarpServer.DomainObject"; + protected const string ACCOUNT_PROGID = "IceWarpServer.AccountObject"; + + private dynamic _currentApiObject = null; + + #region IceWarp Enums + + protected enum IceWarpErrorCode + { + S_OK = 0, + E_FAILURE = -1, // Function failure + E_LICENSE = -2, // Insufficient license + E_PARAMS = -3, // Size of parameters too short + E_PATH = -4, // Settings file does not exist + E_CONFIG = -5, // Configuration not found + E_PASSWORD = -6, // Password policy + E_CONFLICT = -7, // Item already exists + E_INVALID = -8, // Invalid mailbox / alias characters + E_PASSWORDCHARS = -9, // Invalid password characters + E_MIGRATION_IN_PROGRESS = -10 // User migration in progress + } + + protected enum IceWarpAccountType + { + User = 0, + MailingList = 1, + Executable = 2, + Notification = 3, + StaticRoute = 4, + Catalog = 5, + ListServer = 6, + UserGroup = 7 + } + + protected enum IceWarpUnknownUsersType + { + Reject = 0, + ForwardToAddress = 1, + Delete = 2 + } + + #endregion + + #region Protected Properties + + protected string MailPath + { + get + { + var apiObject = GetApiObject(); + return apiObject.GetProperty("C_System_Storage_Dir_MailPath"); + } + } + + protected string Version + { + get + { + var apiObject = GetApiObject(); + return apiObject.GetProperty("C_Version"); + } + } + + protected string BindIpAddress + { + get + { + var apiObject = GetApiObject(); + var adresses = ((object) apiObject.GetProperty("C_System_Services_BindIPAddress")); + return adresses == null ? "" : adresses.ToString().Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + } + } + + protected bool UseDomainDiskQuota + { + get + { + var apiObject = GetApiObject(); + return Convert.ToBoolean((object) apiObject.GetProperty("C_Accounts_Global_Domains_UseDiskQuota")); + } + } + + protected bool UseDomainLimits + { + get + { + var apiObject = GetApiObject(); + return Convert.ToBoolean((object) apiObject.GetProperty("C_Accounts_Global_Domains_UseDomainLimits")); + } + } + + protected bool UseUserLimits + { + get + { + var apiObject = GetApiObject(); + return Convert.ToBoolean((object) apiObject.GetProperty("C_Accounts_Global_Domains_UseUserLimits")); + } + } + + protected bool OverrideGlobal + { + get + { + var apiObject = GetApiObject(); + return Convert.ToBoolean((object) apiObject.GetProperty("C_Accounts_Global_Domains_OverrideGlobal")); + } + } + + protected int MaxMessageSizeInMB + { + get + { + var apiObject = GetApiObject(); + return Convert.ToInt32((object) apiObject.GetProperty("C_Mail_SMTP_Delivery_MaxMsgSize"))/1024/1024; + } + } + + protected int WarnMailboxUsage + { + get + { + var apiObject = GetApiObject(); + return Convert.ToInt32((object)apiObject.GetProperty("C_Accounts_Global_Domains_WarnMailboxUsage")); + } + } + + protected int WarnDomainSize + { + get + { + var apiObject = GetApiObject(); + return Convert.ToInt32((object)apiObject.GetProperty("C_Accounts_Global_Domains_WarnDomainSize")); + } + } + + + private void SaveApiSetting(dynamic apiObject) + { + if (!apiObject.Save()) + { + throw new Exception("Cannot save Api Object: " + GetErrorMessage(apiObject.LastErr)); + } + } + + #endregion + + #region Protected Methods + + protected static string GetErrorMessage(int errorCode) + { + switch ((IceWarpErrorCode) errorCode) + { + case IceWarpErrorCode.S_OK: + return "OK"; + case IceWarpErrorCode.E_FAILURE: + return "Function failure"; + case IceWarpErrorCode.E_LICENSE: + return "Insufficient license"; + case IceWarpErrorCode.E_PARAMS: + return "Size of parameters too short"; + case IceWarpErrorCode.E_PATH: + return "Settings file does not exist"; + case IceWarpErrorCode.E_CONFIG: + return "Configuration not found"; + case IceWarpErrorCode.E_PASSWORD: + return "IceWarp password policy denies use of this account"; + case IceWarpErrorCode.E_CONFLICT: + return "Item already exists"; + case IceWarpErrorCode.E_INVALID: + return "Invalid charcters in mailbox or alias"; + case IceWarpErrorCode.E_PASSWORDCHARS: + return "Invalid characters in password"; + case IceWarpErrorCode.E_MIGRATION_IN_PROGRESS: + return "User mgiration in progress"; + default: + return ""; + } + } + + protected object CreateObject(string progId) + { + var associatedType = Type.GetTypeFromProgID(progId); + + if (associatedType == null) + { + throw new Exception("Cannot get type of " + progId); + } + + try + { + var obj = Activator.CreateInstance(associatedType); + if (obj == null) + { + throw new Exception("Unable to create COM interface"); + } + + return obj; + } + catch (Exception ex) + { + throw new Exception("Unable to create COM interface", ex); + } + } + + protected dynamic GetApiObject() + { + if (_currentApiObject != null) return _currentApiObject; + + _currentApiObject = CreateObject(API_PROGID); + if (_currentApiObject == null) + { + throw new Exception("Returned COM is not of appropriate type"); + } + + return _currentApiObject; + } + + protected dynamic GetDomainObject() + { + var obj = CreateObject(DOMAIN_PROGID); + if (obj == null) + { + throw new Exception("Returned COM is not of appropriate type"); + } + + return obj; + } + + protected dynamic GetDomainObject(string domainName) + { + var obj = GetDomainObject(); + if (!obj.Open(domainName)) + { + throw new Exception("Cannot open domain " + domainName + ": " + GetErrorMessage(obj.LastErr)); + } + + return obj; + } + + protected dynamic GetAccountObject() + { + var obj = CreateObject(ACCOUNT_PROGID); + if (obj == null) + { + throw new Exception("Returned COM is not of appropriate type"); + } + + return obj; + } + + protected dynamic GetAccountObject(string accountName) + { + var obj = GetAccountObject(); + if (!obj.Open(accountName)) + { + throw new Exception("Cannot open account " + accountName + ": " + GetErrorMessage(obj.LastErr)); + } + + return obj; + } + + protected void SaveDomain(dynamic domain) + { + if (!domain.Save()) + { + throw new ArgumentException("Could not save domain:" + GetErrorMessage(domain.LastErr)); + } + } + + protected void SaveAccount(dynamic account, string accountTypeName = "account") + { + if (!account.Save()) + { + throw new ArgumentException("Could not save " + accountTypeName + ":" + GetErrorMessage(account.LastErr)); + } + } + + + protected string GetEmailUser(string email) + { + if (string.IsNullOrWhiteSpace(email)) + { + return string.Empty; + } + + try + { + return new MailAddress(email).User; + } + catch + { + return email.Contains('@') ? email.Substring(0, email.IndexOf('@')) : string.Empty; + } + } + + protected string GetEmailDomain(string email) + { + if (string.IsNullOrWhiteSpace(email)) + { + return string.Empty; + } + + try + { + return new MailAddress(email).Host; + } + catch + { + return email.Contains('@') ? email.Substring(email.IndexOf('@') + 1) : string.Empty; + } + } + + protected void CheckIfDomainExists(string domainName) + { + if (string.IsNullOrWhiteSpace(domainName) || !DomainExists(domainName)) + { + throw new ArgumentException("Specified domain does not exist!"); + } + } + + protected int GetDomainCount() + { + var apiObject = GetApiObject(); + return apiObject.GetDomainCount(); + } + + protected T[] GetItems(string domainName, IceWarpAccountType itemType, Func mailAccountCreator) + { + var mailAccounts = new List(); + + var accountObject = GetAccountObject(); + if (accountObject.FindInitQuery(domainName, "(U_Type = " + (int)itemType + ")")) + { + while (accountObject.FindNext()) + { + mailAccounts.Add(mailAccountCreator(accountObject)); + } + } + + return mailAccounts.ToArray(); + } + + protected void SaveProviderSettingsToService() + { + var apiObject = GetApiObject(); + apiObject.SetProperty("C_Accounts_Global_Domains_UseDiskQuota", ProviderSettings["UseDomainDiskQuota"]); + apiObject.SetProperty("C_Accounts_Global_Domains_UseDomainLimits", ProviderSettings["UseDomainLimits"]); + apiObject.SetProperty("C_Accounts_Global_Domains_UseUserLimits", ProviderSettings["UseUserLimits"]); + apiObject.SetProperty("C_Accounts_Global_Domains_OverrideGlobal", ProviderSettings["OverrideGlobal"]); + apiObject.SetProperty("C_Accounts_Global_Domains_WarnMailboxUsage", ProviderSettings["WarnMailboxUsage"]); + apiObject.SetProperty("C_Accounts_Global_Domains_WarnDomainSize", ProviderSettings["WarnDomainSize"]); + + apiObject.SetProperty("C_Mail_SMTP_Delivery_MaxMsgSize", Convert.ToInt32(ProviderSettings["MaxMessageSize"])*1024*1024); + apiObject.SetProperty("C_Mail_SMTP_Delivery_LimitMsgSize", Convert.ToInt32(ProviderSettings["MaxMessageSize"]) > 0); + + SaveApiSetting(apiObject); + } + + #endregion + + #region IHostingServiceProvier methods + + public override SettingPair[] GetProviderDefaultSettings() + { + var settings = new [] + { + new SettingPair("UseDomainDiskQuota", UseDomainDiskQuota.ToString()), + new SettingPair("UseDomainLimits", UseDomainLimits.ToString()), + new SettingPair("UseUserLimits", UseUserLimits.ToString()), + new SettingPair("OverrideGlobal", OverrideGlobal.ToString()), + new SettingPair("WarnMailboxUsage", WarnMailboxUsage.ToString()), + new SettingPair("WarnDomainSize", WarnDomainSize.ToString()), + new SettingPair("MaxMessageSize", MaxMessageSizeInMB.ToString()), + new SettingPair("ServerIpAddress", BindIpAddress) + }; + + return settings; + } + + public override string[] Install() + { + SaveProviderSettingsToService(); + return base.Install(); + } + + public override void ChangeServiceItemsState(ServiceProviderItem[] items, bool enabled) + { + foreach (var item in items.OfType()) + { + try + { + // enable/disable mail domain + if (DomainExists(item.Name)) + { + var mailDomain = GetDomain(item.Name); + mailDomain.Enabled = enabled; + UpdateDomain(mailDomain); + } + } + catch (Exception ex) + { + Log.WriteError(String.Format("Error switching '{0}' IceWarp domain", item.Name), ex); + } + } + } + + public override void DeleteServiceItems(ServiceProviderItem[] items) + { + foreach (var item in items.OfType()) + { + try + { + // delete mail domain + DeleteDomain(item.Name); + } + catch (Exception ex) + { + Log.WriteError(String.Format("Error deleting '{0}' IceWarp domain", item.Name), ex); + } + } + } + + public override ServiceProviderItemDiskSpace[] GetServiceItemsDiskSpace(ServiceProviderItem[] items) + { + var itemsDiskspace = new List(); + + // update items with diskspace + foreach (var item in items.OfType()) + { + try + { + Log.WriteStart(String.Format("Calculating mail account '{0}' size", item.Name)); + // calculate disk space + var accountObject = GetAccountObject(item.Name); + var size = Convert.ToInt64((object)accountObject.GetProperty("U_MailboxSize")); + + var diskspace = new ServiceProviderItemDiskSpace {ItemId = item.Id, DiskSpace = size}; + itemsDiskspace.Add(diskspace); + Log.WriteEnd(String.Format("Calculating mail account '{0}' size", item.Name)); + } + catch (Exception ex) + { + Log.WriteError(ex); + } + } + return itemsDiskspace.ToArray(); + } + + public override ServiceProviderItemBandwidth[] GetServiceItemsBandwidth(ServiceProviderItem[] items, DateTime since) + { + var itemsBandwidth = new ServiceProviderItemBandwidth[items.Length]; + + // update items with diskspace + for (int i = 0; i < items.Length; i++) + { + ServiceProviderItem item = items[i]; + + // create new bandwidth object + itemsBandwidth[i] = new ServiceProviderItemBandwidth + { + ItemId = item.Id, + Days = new DailyStatistics[0] + }; + + if (item is MailDomain) + { + try + { + // get daily statistics + itemsBandwidth[i].Days = GetDailyStatistics(since, item.Name); + } + catch (Exception ex) + { + Log.WriteError(ex); + System.Diagnostics.Debug.WriteLine(ex); + } + } + } + + return itemsBandwidth; + } + + public DailyStatistics[] GetDailyStatistics(DateTime since, string maildomainName) + { + var days = new List(); + var today = DateTime.Today; + + try + { + var api = GetApiObject(); + + for (var date = since; date < today; date = date.AddDays(1)) + { + var stats = api.GetUserStatistics(date.ToString("yyyy\"/\"MM\"/\"dd"), date.ToString("yyyy\"/\"MM\"/\"dd"), maildomainName); + + var statsBuffer = Encoding.ASCII.GetBytes(stats); + var mailSentField = 0; + var mailReceivedField = 0; + + var ms = new MemoryStream(statsBuffer); + var reader = new StreamReader(ms); + while (reader.Peek() != -1) + { + var line = reader.ReadLine(); + var fields = line.Split(','); + + switch (line[0]) + { + case '[': + for (var j = 1; j < fields.Length; j++) + { + if (fields[j] == "[Received Amount]") mailReceivedField = j; + if (fields[j] == "[Sent Amount]") mailSentField = j; + } + break; + case '*': + var dailyStats = new DailyStatistics + { + Year = date.Year, + Month = date.Month, + Day = date.Day, + BytesSent = line[mailSentField], + BytesReceived = line[mailReceivedField] + }; + days.Add(dailyStats); + continue; + } + } + reader.Close(); + ms.Close(); + } + } + catch (Exception ex) + { + Log.WriteError("Could not get IceWarp domain statistics", ex); + } + + return days.ToArray(); + } + + #endregion + + public override bool IsInstalled() + { + string version; + + var key32Bit = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\IceWarp\IceWarp Server"); + if (key32Bit != null) + { + version = key32Bit.GetValue("Version").ToString(); + } + else + { + var key64Bit = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\IceWarp\IceWarp Server"); + if (key64Bit != null) + { + version = key64Bit.GetValue("Version").ToString(); + } + else + { + return false; + } + } + + if (string.IsNullOrEmpty(version)) + { + return false; + } + + // Checking for version 10.4.0 (released 2012-03-21) or newer + // This version introduced L_ListFile_Contents, G_ListFile_Contents and M_ListFileContents that is the latest API variable used by this provider + var split = version.Split(new[] {'.'}); + var majorVersion = Convert.ToInt32(split[0]); + var minVersion = Convert.ToInt32(split[1]); + + return majorVersion >= 11 || majorVersion >= 10 && minVersion >= 4; + } + + #region Domains + + public bool DomainExists(string domainName) + { + var api = GetApiObject(); + return api.GetDomainIndex(domainName) >= 0; + } + + public string[] GetDomains() + { + var api = GetApiObject(); + return api.GetDomainList().Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries); + } + + public MailDomain GetDomain(string domainName) + { + var domain = GetDomainObject(domainName); + + var mailDomain = new MailDomain + { + Name = domain.Name, + PostmasterAccount = domain.GetProperty("D_AdminEmail"), + CatchAllAccount = domain.GetProperty("D_UnknownForwardTo"), + Enabled = Convert.ToBoolean((object) domain.GetProperty("D_DisableLogin")), + MaxDomainSizeInMB = Convert.ToInt32((object) domain.GetProperty("D_DiskQuota"))/1024, + MaxDomainUsers = Convert.ToInt32((object) domain.GetProperty("D_AccountNumber")), + MegaByteSendLimit = Convert.ToInt32((object) domain.GetProperty("D_VolumeLimit"))/1024, + NumberSendLimit = Convert.ToInt32((object) domain.GetProperty("D_NumberLimit")), + DefaultUserQuotaInMB = Convert.ToInt32((object) domain.GetProperty("D_UserMailbox"))/1024, + DefaultUserMaxMessageSizeMegaByte = Convert.ToInt32((object) domain.GetProperty("D_UserMsg"))/1024, + DefaultUserMegaByteSendLimit = Convert.ToInt32((object) domain.GetProperty("D_UserMB")), + DefaultUserNumberSendLimit = Convert.ToInt32((object) domain.GetProperty("D_UserNumber")) + }; + + return mailDomain; + } + + public void CreateDomain(MailDomain domain) + { + if (string.IsNullOrWhiteSpace(domain.Name)) + { + throw new ArgumentNullException("domain.Name"); + } + + var domainObject = GetDomainObject(); + + if (!domainObject.New(domain.Name)) + { + throw new ApplicationException("Failed to create domain: " + GetErrorMessage(domainObject.LastErr)); + } + + SaveDomain(domainObject); + + UpdateDomain(domain); + } + + public void UpdateDomain(MailDomain domain) + { + var domainObject = GetDomainObject(domain.Name); + + domainObject.SetProperty("D_AdminEmail", string.IsNullOrEmpty(domain.PostmasterAccount) ? "" : domain.PostmasterAccount); + + if (string.IsNullOrEmpty(domain.CatchAllAccount)) + { + domainObject.SetProperty("D_UnknownForwardTo", ""); + domainObject.SetProperty("D_UnknownUsersType", IceWarpUnknownUsersType.Reject); + } + else + { + domainObject.SetProperty("D_UnknownForwardTo", domain.CatchAllAccount); + domainObject.SetProperty("D_UnknownUsersType", IceWarpUnknownUsersType.ForwardToAddress); + } + + domainObject.SetProperty("D_DisableLogin", !domain.Enabled); + domainObject.SetProperty("D_DiskQuota", domain.MaxDomainSizeInMB*1024); + domainObject.SetProperty("D_AccountNumber", domain.MaxDomainUsers); + domainObject.SetProperty("D_VolumeLimit", domain.MegaByteSendLimit*1024); + domainObject.SetProperty("D_NumberLimit", domain.NumberSendLimit); + + domainObject.SetProperty("D_UserMailbox", domain.DefaultUserQuotaInMB*1024); + domainObject.SetProperty("D_UserMsg", domain.DefaultUserMaxMessageSizeMegaByte*1024); + domainObject.SetProperty("D_UserMB", domain.DefaultUserMegaByteSendLimit); + domainObject.SetProperty("D_UserNumber", domain.DefaultUserNumberSendLimit); + + SaveDomain(domainObject); + } + + public void DeleteDomain(string domainName) + { + var domainObject = GetDomainObject(domainName); + + if (domainObject.Delete()) + { + throw new Exception("Could not delete domain"); + } + } + + #endregion + + #region Domain alieses + + public bool DomainAliasExists(string domainName, string aliasName) + { + if (!DomainExists(aliasName)) + { + return false; + } + + var domainObject = GetDomainObject(aliasName); + + return Convert.ToInt32((object) domainObject.GetProperty("D_Type")) == 2 && string.Compare(domainObject.GetProperty("D_DomainValue").ToString(), domainName, true) == 0; + } + + public string[] GetDomainAliases(string domainName) + { + var aliasList = new List(); + + var apiObject = GetApiObject(); + + var domainCount = apiObject.GetDomainCount(); + + for (var i = 0; i < domainCount; i++) + { + var aliasName = apiObject.GetDomain(i); + if (DomainAliasExists(domainName, aliasName)) + { + aliasList.Add(aliasName); + } + } + + return aliasList.ToArray(); + } + + public void AddDomainAlias(string domainName, string aliasName) + { + var mailDomain = new MailDomain {Name = aliasName}; + CreateDomain(mailDomain); + var domainObject = GetDomainObject(aliasName); + + domainObject.SetProperty("D_Type", 2); + domainObject.SetProperty("D_DomainValue", domainName); + SaveDomain(domainObject); + } + + public void DeleteDomainAlias(string domainName, string aliasName) + { + DeleteDomain(aliasName); + } + + #endregion + + #region Accounts + + public bool AccountExists(string mailboxName) + { + var accountObject = GetAccountObject(); + + return accountObject.Open(mailboxName) && Convert.ToInt32((object) accountObject.GetProperty("U_Type")) == (int) IceWarpAccountType.User; + } + + protected class IceWarpResponderContent + { + public string From { get; set; } + public string To { get; set; } + public string Subject { get; set; } + public string Content { get; set; } + } + + private static IceWarpResponderContent ParseResponderContent(string responderContent) + { + var result = new IceWarpResponderContent(); + + if (string.IsNullOrWhiteSpace(responderContent)) + { + return result; + } + + var re = new Regex(@"\$\$(set\w*) (.*)\$\$\n"); + var matches = re.Matches(responderContent); + + foreach (Match match in matches) + { + if (match.Groups[1].Value == "setsubject") + { + result.Subject = match.Groups[2].Value; + } + + if (match.Groups[1].Value == "setactualto") + { + result.To = match.Groups[2].Value; + } + + if (match.Groups[1].Value == "setactualfrom") + { + result.From = match.Groups[2].Value; + } + } + + result.Content = re.Replace(responderContent, ""); + + return result; + } + + protected static MailAccount CreateMailAccountFromAccountObject(dynamic accountObject) + { + var mailAccount = new MailAccount + { + Name = accountObject.EmailAddress, + FullName = accountObject.GetProperty("U_Name"), + Enabled = Convert.ToInt32((object) accountObject.GetProperty("U_AccountDisabled")) == 0, + ForwardingEnabled = !string.IsNullOrWhiteSpace(accountObject.GetProperty("U_ForwardTo")) || string.IsNullOrWhiteSpace(accountObject.GetProperty("U_RemoteAddress")) && Convert.ToBoolean((object) accountObject.GetProperty("U_UseRemoteAddress")), + IsDomainAdmin = Convert.ToBoolean((object) accountObject.GetProperty("U_DomainAdmin")), + MaxMailboxSize = Convert.ToInt32((object) accountObject.GetProperty("U_MaxBoxSize"))/1024, + Password = accountObject.GetProperty("U_Password"), + ResponderEnabled = Convert.ToInt32((object) accountObject.GetProperty("U_Respond")) > 0, + QuotaUsed = Convert.ToInt64((object) accountObject.GetProperty("U_MailBoxSize")), + MaxMessageSizeMegaByte = Convert.ToInt32((object) accountObject.GetProperty("U_MaxMessageSize"))/1024, + MegaByteSendLimit = Convert.ToInt32((object) accountObject.GetProperty("U_MegabyteSendLimit")), + NumberSendLimit = Convert.ToInt32((object) accountObject.GetProperty("U_NumberSendLimit")), + DeleteOlder = Convert.ToBoolean((object) accountObject.GetProperty("U_DeleteOlder")), + DeleteOlderDays = Convert.ToInt32((object) accountObject.GetProperty("U_DeleteOlderDays")), + ForwardOlder = Convert.ToBoolean((object) accountObject.GetProperty("U_ForwardOlder")), + ForwardOlderDays = Convert.ToInt32((object) accountObject.GetProperty("U_ForwardOlderDays")), + ForwardOlderTo = accountObject.GetProperty("U_ForwardOlderTo"), + IceWarpAccountState = Convert.ToInt32((object) accountObject.GetProperty("U_AccountDisabled")), + IceWarpAccountType = Convert.ToInt32((object) accountObject.GetProperty("U_AccountType")), + IceWarpRespondType = Convert.ToInt32((object) accountObject.GetProperty("U_Respond")) + }; + + if (mailAccount.ForwardingEnabled) + { + mailAccount.ForwardingAddresses = new string[] {accountObject.GetProperty("U_ForwardTo") + accountObject.GetProperty("U_RemoteAddress")}; + mailAccount.DeleteOnForward = Convert.ToInt32(accountObject.GetProperty("U_UseRemoteAddress")) == 1; + mailAccount.RetainLocalCopy = !mailAccount.DeleteOnForward; + } + + if (mailAccount.ResponderEnabled) + { + var respondFromValue = accountObject.GetProperty("U_RespondBetweenFrom"); + var respondToValue = accountObject.GetProperty("U_RespondBetweenTo"); + DateTime respondFrom; + DateTime respondTo; + mailAccount.RespondOnlyBetweenDates = false; + var fromDateParsed = DateTime.TryParse(respondFromValue, out respondFrom); + + if (DateTime.TryParse(respondToValue, out respondTo) && fromDateParsed) + { + mailAccount.RespondOnlyBetweenDates = true; + mailAccount.RespondFrom = respondFrom; + mailAccount.RespondTo = respondTo; + } + + mailAccount.RespondPeriodInDays = Convert.ToInt32((object) accountObject.GetProperty("U_RespondPeriod")); + var responderContent = ParseResponderContent(accountObject.GetProperty("U_ResponderContent")); + mailAccount.ResponderMessage = responderContent.Content; + mailAccount.ResponderSubject = responderContent.Subject; + mailAccount.RespondWithReplyFrom = responderContent.From; + } + + return mailAccount; + } + + public MailAccount[] GetAccounts(string domainName) + { + return GetItems(domainName, IceWarpAccountType.User, CreateMailAccountFromAccountObject); + } + + public MailAccount GetAccount(string mailboxName) + { + var accountObject = GetAccountObject(mailboxName); + return CreateMailAccountFromAccountObject(accountObject); + } + + public void CreateAccount(MailAccount mailbox) + { + var accountObject = GetAccountObject(); + + var emailParts = new MailAddress(mailbox.Name); + if (!accountObject.CanCreateMailbox(emailParts.User, emailParts.User, mailbox.Password, emailParts.Host)) + { + throw new Exception("Cannot create account: " + GetErrorMessage(accountObject.LastErr)); + } + + if (accountObject.New(mailbox.Name)) + { + accountObject.Save(); + } + + UpdateAccount(mailbox); + } + + public void UpdateAccount(MailAccount mailbox) + { + var accountObject = GetAccountObject(mailbox.Name); + + accountObject.SetProperty("U_Name", mailbox.FullName); + accountObject.SetProperty("U_AccountDisabled", mailbox.IceWarpAccountState); + accountObject.SetProperty("U_DomainAdmin", mailbox.IsDomainAdmin); + accountObject.SetProperty("U_Password", mailbox.Password); + accountObject.SetProperty("U_MaxBoxSize", mailbox.MaxMailboxSize); + accountObject.SetProperty("U_MaxMessageSize", mailbox.MaxMessageSizeMegaByte*1024); + accountObject.SetProperty("U_MegabyteSendLimit", mailbox.MegaByteSendLimit); + accountObject.SetProperty("U_NumberSendLimit", mailbox.NumberSendLimit); + accountObject.SetProperty("U_AccountType", mailbox.IceWarpAccountType); + accountObject.SetProperty("U_Respond", mailbox.IceWarpRespondType); + + accountObject.SetProperty("U_DeleteOlder", mailbox.DeleteOlder); + accountObject.SetProperty("U_DeleteOlderDays", mailbox.DeleteOlderDays); + accountObject.SetProperty("U_ForwardOlder", mailbox.ForwardOlder); + accountObject.SetProperty("U_ForwardOlderDays", mailbox.ForwardOlderDays); + accountObject.SetProperty("U_ForwardOlderTo", mailbox.ForwardOlderTo); + + // Set initial defalt values for forwarding + accountObject.SetProperty("U_RemoteAddress", null); + accountObject.SetProperty("U_ForwardTo", null); + accountObject.SetProperty("U_UseRemoteAddress", false); + + if (mailbox.ForwardingEnabled) + { + if (mailbox.DeleteOnForward) + { + accountObject.SetProperty("U_RemoteAddress", string.Join(";", mailbox.ForwardingAddresses)); + accountObject.SetProperty("U_UseRemoteAddress", true); + } + else + { + accountObject.SetProperty("U_ForwardTo", string.Join(";", mailbox.ForwardingAddresses)); + } + } + + + if (mailbox.IceWarpRespondType > 0) + { + if (mailbox.RespondOnlyBetweenDates) + { + accountObject.SetProperty("U_RespondBetweenFrom", mailbox.RespondFrom.ToShortDateString()); + accountObject.SetProperty("U_RespondBetweenTo", mailbox.RespondTo.ToShortDateString()); + } + else + { + accountObject.SetProperty("U_RespondBetweenFrom", null); + accountObject.SetProperty("U_RespondBetweenTo", null); + } + + accountObject.SetProperty("U_RespondPeriod", mailbox.RespondPeriodInDays); + + var responderContent = ""; + if (!string.IsNullOrWhiteSpace(mailbox.RespondWithReplyFrom)) + { + responderContent += "$$setactualfrom " + mailbox.RespondWithReplyFrom + "$$\n"; + } + if (!string.IsNullOrWhiteSpace(mailbox.ResponderSubject)) + { + responderContent += "$$setsubject " + mailbox.ResponderSubject + "$$\n"; + } + + accountObject.SetProperty("U_ResponderContent", responderContent + mailbox.ResponderMessage); + } + + SaveAccount(accountObject); + } + + public void DeleteAccount(string mailboxName) + { + var accountObject = GetAccountObject(mailboxName); + if (!accountObject.Delete()) + { + throw new Exception("Cannot delete account: " + GetErrorMessage(accountObject.LastErr)); + } + } + + #endregion + + #region Mail aliases + + public bool MailAliasExists(string mailAliasName) + { + var accountObject = GetAccountObject(); + + return accountObject.Open(mailAliasName); + } + + protected IEnumerable GetAliasListFromAccountObject(dynamic accountObject) + { + return SplitStringProperty(accountObject, "U_EmailAlias", ';'); + } + + protected string GetForwardToAddressFromAccountObject(dynamic accountObject) + { + var forwardTo = accountObject.EmailAddress; + var remoteAddress = accountObject.GetProperty("U_RemoteAddress"); + if (!string.IsNullOrWhiteSpace(remoteAddress)) + { + forwardTo = remoteAddress; + } + + return forwardTo; + } + + public MailAlias[] GetMailAliases(string domainName) + { + var aliasList = new List(); + + var accountObject = GetAccountObject(); + + if (accountObject.FindInitQuery(domainName, "U_Type=" + (int)IceWarpAccountType.User)) + { + while (accountObject.FindNext()) + { + var forwardTo = GetForwardToAddressFromAccountObject(accountObject); + var aliases = GetAliasListFromAccountObject(accountObject) as IEnumerable; + aliasList.AddRange(aliases.Where(a => a != forwardTo).Select(alias => new MailAlias {Name = alias + "@" + domainName, ForwardTo = forwardTo + "@" + domainName})); + } + + accountObject.FindDone(); + } + + return aliasList.ToArray(); + } + + public MailAlias GetMailAlias(string mailAliasName) + { + var accountObject = GetAccountObject(mailAliasName); + + var forwardTo = GetForwardToAddressFromAccountObject(accountObject); + + return new MailAlias {ForwardTo = forwardTo, Name = mailAliasName}; + } + + public void CreateMailAlias(MailAlias mailAlias) + { + // If not forwardto-address exists or is in another domain, create a new account with remoteaddress + if (!GetEmailDomain(mailAlias.Name).Equals(GetEmailDomain(mailAlias.ForwardTo), StringComparison.InvariantCultureIgnoreCase) || !AccountExists(mailAlias.ForwardTo)) + { + mailAlias.ForwardingEnabled = true; + mailAlias.DeleteOnForward = true; + mailAlias.ForwardingAddresses = new[] {mailAlias.ForwardTo}; + mailAlias.Password = GetRandomPassword(); + CreateAccount(mailAlias); + } + // else open account and add alias to list + else + { + var accountOject = GetAccountObject(mailAlias.ForwardTo); + var aliases = GetAliasListFromAccountObject(accountOject).ToList(); + aliases.Add(GetEmailUser(mailAlias.Name)); + accountOject.SetProperty("U_EmailAlias", string.Join(";", aliases)); + + SaveAccount(accountOject, "account when creating mail alias"); + } + } + + private string GetRandowChars(string chars, int length) + { + var random = new Random(); + return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray()); + } + + protected string GetRandomPassword() + { + var apiObject = GetApiObject(); + var minLength = apiObject.GetProperty("C_Accounts_Policies_Pass_MinLength"); + var digits = apiObject.GetProperty("C_Accounts_Policies_Pass_Digits"); + var nonAlphaNum = apiObject.GetProperty("C_Accounts_Policies_Pass_NonAlphaNum"); + var alpha = apiObject.GetProperty("C_Accounts_Policies_Pass_Alpha"); + + return System.Web.Security.Membership.GeneratePassword(minLength, nonAlphaNum) + + GetRandowChars("0123456789", digits)+ + GetRandowChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", alpha); + } + + public void UpdateMailAlias(MailAlias mailAlias) + { + // Delete alias based on mailAlias.Name + DeleteMailAlias(mailAlias.Name); + + // Recreate alias + CreateMailAlias(mailAlias); + } + + public void DeleteMailAlias(string mailAliasName) + { + // Find account where alias exists + var accountObject = GetAccountObject(mailAliasName); + + // Check if it has any other aliases + var otherAliases = ((IEnumerable)GetAliasListFromAccountObject(accountObject)).Where(a => a != GetEmailUser(mailAliasName)).ToArray(); + if (otherAliases.Any()) + { + accountObject.SetProperty("U_EmailAlias", string.Join(";", otherAliases)); + SaveAccount(accountObject, "account during alias delete"); + } + // If no other aliases, this should be an account with a remote address and then we should delete the account + else + { + DeleteAccount(mailAliasName); + } + } + + #endregion + + #region Groups + + public bool GroupExists(string groupName) + { + var accountObject = GetAccountObject(); + + return accountObject.Open(groupName) && Convert.ToInt32(accountObject.GetProperty("U_Type")) == 7; + } + + public MailGroup[] GetGroups(string domainName) + { + return GetItems(domainName, IceWarpAccountType.UserGroup, CreateMailGroupFromAccountObject); + } + + protected MailGroup CreateMailGroupFromAccountObject(dynamic accountObject) + { + var mailGroup = new MailGroup + { + Name = accountObject.EmailAddress, + Enabled = Convert.ToInt32((object) accountObject.GetProperty("U_AccountDisabled")) == 0, + GroupName = accountObject.GetProperty("G_Name"), + Members = ((IEnumerable)SplitFileContents(accountObject, "G_ListFile_Contents")).ToArray() + }; + + return mailGroup; + } + + public MailGroup GetGroup(string groupName) + { + var accountObject = GetAccountObject(groupName); + return CreateMailGroupFromAccountObject(accountObject); + } + + public void CreateGroup(MailGroup @group) + { + var accountObject = GetAccountObject(); + + if (accountObject.New(group.Name)) + { + accountObject.SetProperty("U_Type", 7); + accountObject.SetProperty("G_GroupwareMailDelivery", false); + SaveAccount(accountObject, "group account"); + } + else + { + throw new ApplicationException("Failed to create group: " + GetErrorMessage(accountObject.LastErr)); + } + + UpdateGroup(group); + } + + public void UpdateGroup(MailGroup @group) + { + var accountObject = GetAccountObject(group.Name); + + accountObject.SetProperty("G_Name", group.GroupName); + accountObject.SetProperty("U_AccountDisabled", group.Enabled ? 0 : 2); + accountObject.SetProperty("G_ListFile_Contents", string.Join("\n", group.Members)); + + SaveAccount(accountObject, "group"); + } + + public void DeleteGroup(string groupName) + { + var accountObject = GetAccountObject(groupName); + if (!accountObject.Delete()) + { + throw new Exception("Cannot delete group: " + GetErrorMessage(accountObject.LastErr)); + } + } + + #endregion + + #region Lists + + public bool ListExists(string maillistName) + { + var accountObject = GetAccountObject(); + + return accountObject.Open(maillistName) && (IceWarpAccountType) Enum.Parse(typeof (IceWarpAccountType), ((object) accountObject.GetProperty("U_Type")).ToString()) == IceWarpAccountType.MailingList; + } + + public MailList[] GetLists(string domainName) + { + return GetItems(domainName, IceWarpAccountType.MailingList, CreateMailListFromAccountObject); + } + + protected IEnumerable SplitStringProperty(dynamic accountObject, string propertyName, char separator) + { + var value = (object) accountObject.GetProperty(propertyName); + return value == null ? new String[] {} : value.ToString().Split(new[] {separator}, StringSplitOptions.RemoveEmptyEntries); + } + + protected IEnumerable SplitFileContents(dynamic accountObject, string propertyName) + { + return SplitStringProperty(accountObject, propertyName, '\n'); + } + + protected MailList CreateMailListFromAccountObject(dynamic accountObject) + { + // IceWarp has separate settings for list server and mailing list. Together they have all the info we need for a WSP MailList + // From an accountObject of type list server, we can fetch the mailing lists associated with it + // So, first we search and find the list server account that is associated with this mailing list account. + var listServerAccountObject = FindMatchingListServerAccount(accountObject.EmailAddress, true); + + var mailList = new MailList + { + //From mailing list account + Name = accountObject.EmailAddress, + Description = accountObject.GetProperty("M_Name"), + ModeratorAddress = accountObject.GetProperty("M_OwnerAddress"), + MembersSource = (IceWarpListMembersSource) Enum.Parse(typeof (IceWarpListMembersSource), ((object) accountObject.GetProperty("M_SendAllLists")).ToString()), + Members = ((IEnumerable)SplitFileContents(accountObject, "M_ListFile_Contents")).Select(m => m.TrimEnd(new[] {';', '0', '1', '2'})).ToArray(), + SetReceipientsToToHeader = Convert.ToBoolean((object) accountObject.GetProperty("M_SeparateTo")), + SubjectPrefix = accountObject.GetProperty("M_AddToSubject"), + Originator = (IceWarpListOriginator) Enum.Parse(typeof (IceWarpListOriginator), ((object) accountObject.GetProperty("M_ListSender")).ToString()), + PostingMode = Convert.ToBoolean((object) accountObject.GetProperty("M_MembersOnly")) ? PostingMode.MembersCanPost : PostingMode.AnyoneCanPost, + PasswordProtection = (PasswordProtection) Enum.Parse(typeof (PasswordProtection), ((object) accountObject.GetProperty("M_Moderated")).ToString()), + Password = accountObject.GetProperty("M_ModeratedPassword"), + DefaultRights = (IceWarpListDefaultRights) Enum.Parse(typeof (IceWarpListDefaultRights), ((object) accountObject.GetProperty("M_DefaultRights")).ToString()), + MaxMessageSizeEnabled = Convert.ToBoolean((object) accountObject.GetProperty("M_MaxList")), + MaxMessageSize = Convert.ToInt32((object) accountObject.GetProperty("M_MaxListSize")), + MaxMembers = Convert.ToInt32((object) accountObject.GetProperty("M_MaxMembers")), + SendToSender = Convert.ToBoolean((object) accountObject.GetProperty("M_SendToSender")), + DigestMode = Convert.ToBoolean((object) accountObject.GetProperty("M_DigestConfirmed")), + MaxMessagesPerMinute = Convert.ToInt32((object) accountObject.GetProperty("M_ListBatch")), + SendSubscribe = Convert.ToBoolean((object) accountObject.GetProperty("M_NotifyJoin")), + SendUnsubscribe = Convert.ToBoolean((object) accountObject.GetProperty("M_NotifyLeave")), + + // From list server account + ConfirmSubscription = (IceWarpListConfirmSubscription) Enum.Parse(typeof (IceWarpListConfirmSubscription), ((object) listServerAccountObject.GetProperty("L_DigestConfirmed")).ToString()), + CommandsInSubject = Convert.ToBoolean((object) listServerAccountObject.GetProperty("L_ListSubject")), + DisableSubscribecommand = !Convert.ToBoolean((object) listServerAccountObject.GetProperty("M_JoinR")), + AllowUnsubscribe = Convert.ToBoolean((object) listServerAccountObject.GetProperty("M_LeaveR")), + DisableListcommand = !Convert.ToBoolean((object) listServerAccountObject.GetProperty("M_ListsR")), + DisableWhichCommand = !Convert.ToBoolean((object) listServerAccountObject.GetProperty("M_WhichR")), + DisableReviewCommand = !Convert.ToBoolean((object) listServerAccountObject.GetProperty("M_ReviewR")), + DisableVacationCommand = !Convert.ToBoolean((object) listServerAccountObject.GetProperty("M_VacationR")), + Moderated = Convert.ToBoolean((object) listServerAccountObject.GetProperty("L_Moderated")), + CommandPassword = listServerAccountObject.GetProperty("L_ModeratedPassword"), + SuppressCommandResponses = Convert.ToBoolean((object) listServerAccountObject.GetProperty("L_MaxList")) + }; + + + // This is how I get values for from and replyto header values. TODO: There must be a better way, but I don't see the pattern right now... + var ss = Convert.ToInt32((object) accountObject.GetProperty("M_SetSender")); + var sv = Convert.ToInt32((object) accountObject.GetProperty("M_SetValue")); + var vm = Convert.ToBoolean((object) accountObject.GetProperty("M_ValueMode")); + var value = accountObject.GetProperty("M_HeaderValue"); + + switch (ss) + { + case 0: + switch (sv) + { + case 0: + mailList.FromHeader = IceWarpListFromAndReplyToHeader.NoChange; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.NoChange; + break; + case 1: + if (vm) + { + mailList.FromHeader = IceWarpListFromAndReplyToHeader.NoChange; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.SetToValue; + mailList.ListReplyToAddress = value; + } + else + { + mailList.FromHeader = IceWarpListFromAndReplyToHeader.SetToValue; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.NoChange; + mailList.ListFromAddress = value; + } + break; + case 2: + mailList.FromHeader = IceWarpListFromAndReplyToHeader.SetToValue; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.SetToValue; + var values = value.Split('|'); + mailList.ListFromAddress = values[0]; + mailList.ListReplyToAddress = values[1]; + break; + } + break; + case 1: + switch (sv) + { + case 0: + mailList.FromHeader = IceWarpListFromAndReplyToHeader.SetToSender; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.NoChange; + break; + case 1: + if (vm) + { + mailList.FromHeader = IceWarpListFromAndReplyToHeader.SetToSender; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.SetToValue; + mailList.ListReplyToAddress = value; + } + else + { + mailList.FromHeader = IceWarpListFromAndReplyToHeader.SetToValue; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.SetToSender; + mailList.ListFromAddress = value; + } + + break; + } + break; + case 2: + mailList.FromHeader = IceWarpListFromAndReplyToHeader.SetToSender; + mailList.ReplyToHeader = IceWarpListFromAndReplyToHeader.SetToSender; + break; + } + + return mailList; + } + + public MailList GetList(string maillistName) + { + var accountObject = GetAccountObject(maillistName); + return CreateMailListFromAccountObject(accountObject); + } + + public void CreateList(MailList maillist) + { + if (string.IsNullOrWhiteSpace(maillist.Name)) + { + throw new ArgumentNullException("maillist.Name"); + } + + var accountObject = GetAccountObject(); + + if (!accountObject.New(maillist.Name)) + { + throw new ApplicationException("Failed to create mailing list: " + GetErrorMessage(accountObject.LastErr)); + } + + accountObject.SetProperty("U_Type", IceWarpAccountType.MailingList); + + SaveAccount(accountObject, "mailing list"); + + UpdateList(maillist); + } + + protected dynamic FindMatchingListServerAccount(string mailingListName, bool createListServerAccountIfNeeded) + { + var listServerAccountObject = GetAccountObject(); + var forceCreatelistServerAccountObject = false; + var listServerAccountFound = false; + + if (listServerAccountObject.FindInitQuery(GetEmailDomain(mailingListName), "U_Type=" + (int)IceWarpAccountType.ListServer)) + { + while (listServerAccountObject.FindNext()) + { + var lists = ((IEnumerable)SplitFileContents(listServerAccountObject, "L_ListFile_Contents")).ToList(); + if (lists.Contains(mailingListName)) + { + listServerAccountFound = true; + + // If this list server account is responsible for more than one mailing list, force creation of a new one. + if (lists.Count() > 1) + { + forceCreatelistServerAccountObject = true; + listServerAccountObject.SetProperty("L_ListFile_Contents", string.Join("\n", lists.Remove(mailingListName))); + SaveAccount(listServerAccountObject, "list server account "); + } + break; + } + } + } + + // If no list server was found that was responsible for this mailing list, create one + if (forceCreatelistServerAccountObject || !listServerAccountFound && createListServerAccountIfNeeded) + { + // Create list server account + if (!listServerAccountObject.New("srv" + mailingListName)) + { + throw new Exception("Cannot create listserver account to associate with mailing list." + GetErrorMessage(listServerAccountObject.LastErr)); + } + + listServerAccountObject.SetProperty("U_Type", IceWarpAccountType.ListServer); + listServerAccountObject.SetProperty("L_SendAllLists", 0); + listServerAccountObject.SetProperty("L_ListFile_Contents", mailingListName + "\n"); + + SaveAccount(listServerAccountObject, "listserver account to associate with mailing list"); + } + + return !listServerAccountFound ? null : listServerAccountObject; + } + + public void UpdateList(MailList maillist) + { + var accountObject = GetAccountObject(maillist.Name); + var listServerAccountObject = FindMatchingListServerAccount(maillist.Name, true); + + accountObject.SetProperty("M_Name", maillist.Description); + accountObject.SetProperty("M_OwnerAddress", maillist.ModeratorAddress); + accountObject.SetProperty("M_SendAllLists", maillist.MembersSource); + accountObject.SetProperty("L_ListFile_Contents", string.Join(";0;\n", maillist.Members) + ";0;\n"); // 0 means that the members will have the default rights + // TODO: Create some way to manage list member rights. As it is now, all members will loose rights that is set using some other tool + + var setSender = 0; + var setValue = 0; + var valueMode = false; + var value = ""; + + switch (maillist.FromHeader) + { + case IceWarpListFromAndReplyToHeader.NoChange: + switch (maillist.ReplyToHeader) + { + case IceWarpListFromAndReplyToHeader.NoChange: + break; + case IceWarpListFromAndReplyToHeader.SetToSender: + setSender = 1; + break; + case IceWarpListFromAndReplyToHeader.SetToValue: + setSender = 1; + valueMode = true; + value = maillist.ListReplyToAddress; + break; + } + break; + case IceWarpListFromAndReplyToHeader.SetToSender: + switch (maillist.ReplyToHeader) + { + case IceWarpListFromAndReplyToHeader.NoChange: + setSender = 1; + valueMode = true; + break; + case IceWarpListFromAndReplyToHeader.SetToSender: + setSender = 2; + valueMode = true; + break; + case IceWarpListFromAndReplyToHeader.SetToValue: + setSender = 1; + setValue = 1; + valueMode = true; + value = maillist.ListReplyToAddress; + break; + } + break; + case IceWarpListFromAndReplyToHeader.SetToValue: + switch (maillist.ReplyToHeader) + { + case IceWarpListFromAndReplyToHeader.NoChange: + setValue = 1; + value = maillist.ListFromAddress; + break; + case IceWarpListFromAndReplyToHeader.SetToSender: + setSender = 1; + setValue = 1; + value = maillist.ListFromAddress; + break; + case IceWarpListFromAndReplyToHeader.SetToValue: + setValue = 2; + value = maillist.ListFromAddress + "|" + maillist.ListReplyToAddress; + break; + } + break; + } + + accountObject.SetProperty("M_SetSender", setSender); + accountObject.SetProperty("M_SetValue", setValue); + accountObject.SetProperty("M_ValueMode", valueMode); + accountObject.SetProperty("M_HeaderValue", value); + accountObject.SetProperty("M_SeparateTo", maillist.SetReceipientsToToHeader); + accountObject.SetProperty("M_AddToSubject", maillist.SubjectPrefix); + accountObject.SetProperty("M_ListSender", maillist.Originator); + accountObject.SetProperty("M_MembersOnly", maillist.PostingMode == PostingMode.MembersCanPost); + accountObject.SetProperty("M_Moderated", maillist.PasswordProtection); + accountObject.SetProperty("M_ModeratedPassword", maillist.Password); + accountObject.SetProperty("M_DefaultRights", maillist.DefaultRights); + accountObject.SetProperty("M_MaxList", maillist.MaxMessageSizeEnabled); + accountObject.SetProperty("M_MaxListSize", maillist.MaxMessageSize); + accountObject.SetProperty("M_MaxMembers", maillist.MaxMembers); + accountObject.SetProperty("M_SendToSender", maillist.SendToSender); + accountObject.SetProperty("M_DigestConfirmed", maillist.DigestMode); + accountObject.SetProperty("M_ListBatch", maillist.MaxMessagesPerMinute); + accountObject.SetProperty("M_NotifyJoin", maillist.SendSubscribe); + accountObject.SetProperty("M_NotifyLeave", maillist.SendUnsubscribe); + + SaveAccount(accountObject, "mailing list account"); + + listServerAccountObject.SetProperty("L_Name", maillist.Description); + listServerAccountObject.SetProperty("L_OwnerAddress", maillist.ModeratorAddress); + listServerAccountObject.SetProperty("L_SendAllLists", 0); + listServerAccountObject.SetProperty("L_DigestConfirmed", maillist.ConfirmSubscription); + listServerAccountObject.SetProperty("L_ListSubject", maillist.CommandsInSubject); + listServerAccountObject.SetProperty("M_JoinR", !maillist.DisableSubscribecommand); + listServerAccountObject.SetProperty("M_LeaveR", maillist.AllowUnsubscribe); + listServerAccountObject.SetProperty("M_ListsR", !maillist.DisableListcommand); + listServerAccountObject.SetProperty("M_WhichR", !maillist.DisableWhichCommand); + listServerAccountObject.SetProperty("M_ReviewR", !maillist.DisableReviewCommand); + listServerAccountObject.SetProperty("M_VacationR", !maillist.DisableVacationCommand); + listServerAccountObject.SetProperty("L_Moderated", maillist.Moderated); + listServerAccountObject.SetProperty("L_ModeratedPassword", maillist.CommandPassword); + listServerAccountObject.SetProperty("L_ListSender", maillist.Originator); + listServerAccountObject.SetProperty("L_MaxList", maillist.SuppressCommandResponses); + + SaveAccount(accountObject, "listserver account associated with mailing list"); + } + + public void DeleteList(string maillistName) + { + var accountObject = GetAccountObject(maillistName); + var listServerAccountObject = FindMatchingListServerAccount(maillistName, false); + + if (accountObject.Delete()) + { + // If there is no matching list server account, we are done + if (listServerAccountObject == null) + { + return; + } + + var lists = ((IEnumerable)SplitFileContents(listServerAccountObject, "L_ListFile_Contents")).ToList(); + + if (lists.Count() == 1) + { + if (!listServerAccountObject.Delete()) + { + throw new Exception("Deleted mail list, but list server account remains: " + GetErrorMessage(listServerAccountObject.LastErr)); + } + } + else + { + listServerAccountObject.SetProperty("L_ListFile_Contents", string.Join("\n", lists.Remove(maillistName))); + if (!listServerAccountObject.Save()) + { + throw new Exception("Deleted mail list, but associated list server account could not be updated: " + GetErrorMessage(listServerAccountObject.LastErr)); + } + } + } + else + { + throw new Exception("Cannot delete mail list: " + GetErrorMessage(accountObject.LastErr)); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/Properties/AssemblyInfo.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..ddbeeac5 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WebsitePanel.Providers.Mail.IceWarp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WebsitePanel.Providers.Mail.IceWarp")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a1d6862c-a090-4043-9db3-591ca690da83")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/WebsitePanel.Providers.Mail.IceWarp.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/WebsitePanel.Providers.Mail.IceWarp.csproj new file mode 100644 index 00000000..ea74db0f --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Mail.IceWarp/WebsitePanel.Providers.Mail.IceWarp.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA} + Library + Properties + WebsitePanel.Providers.Mail.IceWarp + WebsitePanel.Providers.Mail.IceWarp + v4.0 + 512 + + + + true + full + false + ..\WebsitePanel.Server\bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + {684C932A-6C75-46AC-A327-F3689D89EB42} + WebsitePanel.Providers.Base + + + {E91E52F3-9555-4D00-B577-2B1DBDD87CA7} + WebsitePanel.Server.Utils + + + + + \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Server.sln b/WebsitePanel/Sources/WebsitePanel.Server.sln index 01b22496..8d0401c9 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server.sln +++ b/WebsitePanel/Sources/WebsitePanel.Server.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2010 +# Visual Studio 2012 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caching Application Block", "Caching Application Block", "{C8E6F2E4-A5B8-486A-A56E-92D864524682}" ProjectSection(SolutionItems) = preProject Bin\Microsoft.Practices.EnterpriseLibrary.Common.dll = Bin\Microsoft.Practices.EnterpriseLibrary.Common.dll @@ -150,6 +150,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.DNS. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.HostedSolution.Crm2013", "WebsitePanel.Providers.HostedSolution.Crm2013\WebsitePanel.Providers.HostedSolution.Crm2013.csproj", "{1EF935C9-6DB9-47A1-B261-CB56512DF980}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.Mail.IceWarp", "WebsitePanel.Providers.Mail.IceWarp\WebsitePanel.Providers.Mail.IceWarp.csproj", "{95EA2D6E-278C-4A74-97DB-946362C4DEEA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -760,6 +762,16 @@ Global {1EF935C9-6DB9-47A1-B261-CB56512DF980}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {1EF935C9-6DB9-47A1-B261-CB56512DF980}.Release|Mixed Platforms.Build.0 = Release|Any CPU {1EF935C9-6DB9-47A1-B261-CB56512DF980}.Release|x86.ActiveCfg = Release|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Debug|x86.ActiveCfg = Debug|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Release|Any CPU.Build.0 = Release|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {95EA2D6E-278C-4A74-97DB-946362C4DEEA}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj b/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj index 8b1d2bb6..b21aac2d 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Server/WebsitePanel.Server.csproj @@ -17,7 +17,7 @@ 4.0 - v3.5 + v4.0 false @@ -79,6 +79,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ESModule_ControlsHierarchy.config b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ESModule_ControlsHierarchy.config index 1d37b463..a4255204 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ESModule_ControlsHierarchy.config +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ESModule_ControlsHierarchy.config @@ -111,7 +111,7 @@ - + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ModulesData.config b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ModulesData.config index c418eca5..54627906 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ModulesData.config +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/ModulesData.config @@ -57,6 +57,7 @@ + @@ -115,6 +116,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config index 9dd556ee..7c08a0dc 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config @@ -417,6 +417,29 @@ + +