diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/ExchangeServer/ExchangeServerController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/ExchangeServer/ExchangeServerController.cs index 28acd980..f3641624 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/ExchangeServer/ExchangeServerController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/ExchangeServer/ExchangeServerController.cs @@ -408,7 +408,7 @@ namespace WebsitePanel.EnterpriseServer // rollback organization creation if (organizationExtended) mailboxRole.DeleteOrganization(org.OrganizationId, org.DistinguishedName, - org.GlobalAddressList, org.AddressList, org.OfflineAddressBook, org.SecurityGroup); + org.GlobalAddressList, org.AddressList, org.RoomsAddressList, org.OfflineAddressBook, org.SecurityGroup); // rollback domain if (authDomainCreated) @@ -504,6 +504,7 @@ namespace WebsitePanel.EnterpriseServer org.DistinguishedName, org.GlobalAddressList, org.AddressList, + org.RoomsAddressList, org.OfflineAddressBook, org.SecurityGroup); diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs index c61011ba..04ec8aa9 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IExchangeServer.cs @@ -45,7 +45,7 @@ namespace WebsitePanel.Providers.HostedSolution string GetOABVirtualDirectory(); Organization CreateOrganizationOfflineAddressBook(string organizationId, string securityGroup, string oabVirtualDir); void UpdateOrganizationOfflineAddressBook(string id); - bool DeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string offlineAddressBook, string securityGroup); + bool DeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup); void SetOrganizationStorageLimits(string organizationDistinguishedName, int issueWarningKB, int prohibitSendKB, int prohibitSendReceiveKB, int keepDeletedItemsDays); ExchangeItemStatistics[] GetMailboxesStatistics(string organizationDistinguishedName); diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/Organization.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/Organization.cs index 37c1d729..c320352b 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/Organization.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/Organization.cs @@ -39,6 +39,7 @@ namespace WebsitePanel.Providers.HostedSolution private string defaultDomain; private string offlineAddressBook; private string addressList; + private string roomsAddressList; private string globalAddressList; private string database; private string securityGroup; @@ -167,6 +168,13 @@ namespace WebsitePanel.Providers.HostedSolution set { addressList = value; } } + [Persistent] + public string RoomsAddressList + { + get { return roomsAddressList; } + set { roomsAddressList = value; } + } + [Persistent] public string GlobalAddressList { diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs index a056c350..c331b38e 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/Exchange2007.cs @@ -184,11 +184,11 @@ namespace WebsitePanel.Providers.HostedSolution } public bool DeleteOrganization(string organizationId, string distinguishedName, - string globalAddressList, string addressList, string offlineAddressBook, + string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup) { return DeleteOrganizationInternal(organizationId, distinguishedName, globalAddressList, - addressList, offlineAddressBook, securityGroup); + addressList, roomsAddressList, offlineAddressBook, securityGroup); } public void SetOrganizationStorageLimits(string organizationDistinguishedName, int issueWarningKB, int prohibitSendKB, @@ -618,7 +618,7 @@ namespace WebsitePanel.Providers.HostedSolution { Organization org = item as Organization; DeleteOrganization(org.OrganizationId, org.DistinguishedName, org.GlobalAddressList, - org.AddressList, org.OfflineAddressBook, org.SecurityGroup); + org.AddressList, org.RoomsAddressList, org.OfflineAddressBook, org.SecurityGroup); } else if (item is ExchangeDomain) { @@ -738,6 +738,12 @@ namespace WebsitePanel.Providers.HostedSolution ExchangeLog.LogInfo(" Address List: {0}", alId); UpdateAddressList(runSpace, alId, securityGroupPath); + //create RAL + string ralId = CreateRoomsAddressList(runSpace, organizationId); + transaction.RegisterNewRoomsAddressList(ralId); + ExchangeLog.LogInfo(" Rooms Address List: {0}", ralId); + UpdateRoomsAddressList(runSpace, ralId, securityGroupPath); + //create ActiveSync policy string asId = CreateActiveSyncPolicy(runSpace, organizationId); transaction.RegisterNewActiveSyncPolicy(asId); @@ -753,6 +759,7 @@ namespace WebsitePanel.Providers.HostedSolution info.AddressList = alId; info.GlobalAddressList = galId; + info.RoomsAddressList = ralId; info.OrganizationId = organizationId; info.Database = databaseId; @@ -904,7 +911,7 @@ namespace WebsitePanel.Providers.HostedSolution private bool DeleteOrganizationInternal(string organizationId, string distinguishedName, - string globalAddressList, string addressList, string offlineAddressBook, string securityGroup) + string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup) { ExchangeLog.LogStart("DeleteOrganizationInternal"); bool ret = true; @@ -986,6 +993,18 @@ namespace WebsitePanel.Providers.HostedSolution ExchangeLog.LogError("Could not delete Address List " + addressList, ex); } + //delete RAL (Rooms Address List) + try + { + if (!string.IsNullOrEmpty(roomsAddressList)) + DeleteRoomsAddressList(runSpace, roomsAddressList); + } + catch (Exception ex) + { + ret = false; + ExchangeLog.LogError("Could not delete Rooms Address List " + roomsAddressList, ex); + } + //delete GAL try { @@ -4730,7 +4749,7 @@ namespace WebsitePanel.Providers.HostedSolution #endregion - #region Address Lists (GAL, AL, OAB, ABP) + #region Address Lists (GAL, AL, RAL, OAB, ABP) private string GetAddressListDN(Runspace runSpace, string id) { @@ -4744,7 +4763,7 @@ namespace WebsitePanel.Providers.HostedSolution resultObjectDN = this.GetResultObjectDN(result); ExchangeLog.DebugInfo("AL DN: {0}", new object[] { resultObjectDN }); } - ExchangeLog.LogEnd("GetAddressListDN"); + ExchangeLog.LogEnd("GetAddressListDN"); return resultObjectDN; } @@ -4824,6 +4843,99 @@ namespace WebsitePanel.Providers.HostedSolution ExchangeLog.LogEnd("DeleteAddressList"); } + private string GetRoomsAddressListDN(Runspace runSpace, string id) + { + ExchangeLog.LogStart("GetRoomsAddressListDN"); + string resultObjectDN = null; + Command cmd = new Command("Get-AddressList"); + cmd.Parameters.Add("Identity", id); + Collection result = this.ExecuteShellCommand(runSpace, cmd); + if ((result != null) && (result.Count > 0)) + { + resultObjectDN = this.GetResultObjectDN(result); + ExchangeLog.DebugInfo("RAL DN: {0}", new object[] { resultObjectDN }); + } + ExchangeLog.DebugInfo("GetRommsAddressListDN, cmd = {0}", cmd.CommandText); + ExchangeLog.LogEnd("GetRoomsAddressListDN"); + return resultObjectDN; + } + + private string CreateRoomsAddressList(Runspace runSpace, string organizationId) + { + ExchangeLog.LogStart("CreateRoomsAddressList"); + string roomsAddressListName = this.GetRoomsAddressListName(organizationId); + string roomsAddressListDN = this.GetRoomsAddressListDN(runSpace, roomsAddressListName); + if (!string.IsNullOrEmpty(roomsAddressListDN)) + { + //rooms address list already exists - we will use it + ExchangeLog.LogWarning("Rooms Address List '{0}' already exists", new object[] { roomsAddressListName }); + } + else + { + //try to create a new rooms address list (10 attempts) + int attempts = 0; + Command cmd = null; + Collection result = null; + + while (true) + { + try + { + //try to create address list + cmd = new Command("New-AddressList"); + cmd.Parameters.Add("Name", roomsAddressListName); + cmd.Parameters.Add("IncludedRecipients", "Resources"); + cmd.Parameters.Add("ConditionalCustomAttribute1", organizationId); + + result = ExecuteShellCommand(runSpace, cmd); + roomsAddressListDN = CheckResultObjectDN(result); + } + catch (Exception ex) + { + ExchangeLog.LogError(ex); + } + if (roomsAddressListDN != null) + break; + + if (attempts > 9) + throw new Exception( + string.Format("Could not create Rooms Address List '{0}' cmd = '{1}'", roomsAddressListName, cmd)); + + attempts++; + ExchangeLog.LogWarning("Attempt #{0} to create rooms address list failed!", attempts); + // wait 1 sec + System.Threading.Thread.Sleep(1000); + } + } + + ExchangeLog.LogEnd("CreateRoomsAddressList"); + return roomsAddressListDN; + } + + private void UpdateRoomsAddressList(Runspace runSpace, string id, string securityGroup) + { + ExchangeLog.LogStart("UpdateRoomsAddressList"); + + string path = AddADPrefix(id); + Command cmd = new Command("Update-AddressList"); + cmd.Parameters.Add("Identity", id); + ExecuteShellCommand(runSpace, cmd); + + AdjustADSecurity(path, securityGroup, false); + + ExchangeLog.LogEnd("UpdateRoomsAddressList"); + } + + private void DeleteRoomsAddressList(Runspace runSpace, string id) + { + ExchangeLog.LogStart("DeleteRoomsAddressList"); + Command cmd = new Command("Remove-AddressList"); + cmd.Parameters.Add("Identity", id); + cmd.Parameters.Add("Confirm", false); + ExecuteShellCommand(runSpace, cmd); + ExchangeLog.LogEnd("DeleteRoomsAddressList"); + } + private string GetGlobalAddressListDN(Runspace runSpace, string id) { ExchangeLog.LogStart("GetGlobalAddressListDN"); @@ -4945,7 +5057,7 @@ namespace WebsitePanel.Providers.HostedSolution string AL = GetAddressListName(organizationId); string GAL = GetGlobalAddressListName(organizationId); string OAB = GetOfflineAddressBookName(organizationId); - string RL = "All Rooms"; + string RL = GetRoomsAddressListName(organizationId); Command cmd = new Command("New-AddressBookPolicy"); cmd.Parameters.Add("Name", ABP); @@ -4991,6 +5103,11 @@ namespace WebsitePanel.Providers.HostedSolution return orgName + " Address Policy"; } + private string GetRoomsAddressListName(string orgName) + { + return orgName + " Rooms"; + } + #endregion #region Active Directory @@ -6596,6 +6713,9 @@ namespace WebsitePanel.Providers.HostedSolution case TransactionAction.TransactionActionTypes.CreateAddressList: DeleteAddressList(runspace, action.Id); break; + case TransactionAction.TransactionActionTypes.CreateRoomsAddressList: + DeleteRoomsAddressList(runspace, action.Id); + break; case TransactionAction.TransactionActionTypes.CreateOfflineAddressBook: DeleteOfflineAddressBook(runspace, action.Id); break; diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/ExchangeTransaction.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/ExchangeTransaction.cs index 7708ca78..ce9fbaf3 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/ExchangeTransaction.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/ExchangeTransaction.cs @@ -84,6 +84,13 @@ namespace WebsitePanel.Providers.HostedSolution action.Id = id; Actions.Add(action); } + internal void RegisterNewRoomsAddressList(string id) + { + TransactionAction action = new TransactionAction(); + action.ActionType = TransactionAction.TransactionActionTypes.CreateRoomsAddressList; + action.Id = id; + Actions.Add(action); + } internal void RegisterNewAddressPolicy(string id) { TransactionAction action = new TransactionAction(); @@ -241,7 +248,8 @@ namespace WebsitePanel.Providers.HostedSolution AddMailboxFullAccessPermission, AddSendAsPermission, RemoveMailboxFullAccessPermission, - RemoveSendAsPermission + RemoveSendAsPermission, + CreateRoomsAddressList }; } diff --git a/WebsitePanel/Sources/WebsitePanel.Server.Client/ExchangeServerProxy.cs b/WebsitePanel/Sources/WebsitePanel.Server.Client/ExchangeServerProxy.cs index 4a068fd8..c4e51d8f 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server.Client/ExchangeServerProxy.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server.Client/ExchangeServerProxy.cs @@ -770,24 +770,26 @@ namespace WebsitePanel.Providers.Exchange { /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/DeleteOrganization", RequestNamespace="http://smbsaas/websitepanel/server/", ResponseNamespace="http://smbsaas/websitepanel/server/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public bool DeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string offlineAddressBook, string securityGroup) { + public bool DeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup) { object[] results = this.Invoke("DeleteOrganization", new object[] { organizationId, distinguishedName, globalAddressList, addressList, + roomsAddressList, offlineAddressBook, securityGroup}); return ((bool)(results[0])); } /// - public System.IAsyncResult BeginDeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string offlineAddressBook, string securityGroup, System.AsyncCallback callback, object asyncState) { + public System.IAsyncResult BeginDeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("DeleteOrganization", new object[] { organizationId, distinguishedName, globalAddressList, addressList, + roomsAddressList, offlineAddressBook, securityGroup}, callback, asyncState); } @@ -799,12 +801,12 @@ namespace WebsitePanel.Providers.Exchange { } /// - public void DeleteOrganizationAsync(string organizationId, string distinguishedName, string globalAddressList, string addressList, string offlineAddressBook, string securityGroup) { - this.DeleteOrganizationAsync(organizationId, distinguishedName, globalAddressList, addressList, offlineAddressBook, securityGroup, null); + public void DeleteOrganizationAsync(string organizationId, string distinguishedName, string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup) { + this.DeleteOrganizationAsync(organizationId, distinguishedName, globalAddressList, addressList, roomsAddressList, offlineAddressBook, securityGroup, null); } /// - public void DeleteOrganizationAsync(string organizationId, string distinguishedName, string globalAddressList, string addressList, string offlineAddressBook, string securityGroup, object userState) { + public void DeleteOrganizationAsync(string organizationId, string distinguishedName, string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup, object userState) { if ((this.DeleteOrganizationOperationCompleted == null)) { this.DeleteOrganizationOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDeleteOrganizationOperationCompleted); } @@ -813,6 +815,7 @@ namespace WebsitePanel.Providers.Exchange { distinguishedName, globalAddressList, addressList, + roomsAddressList, offlineAddressBook, securityGroup}, this.DeleteOrganizationOperationCompleted, userState); } diff --git a/WebsitePanel/Sources/WebsitePanel.Server/ExchangeServer.asmx.cs b/WebsitePanel/Sources/WebsitePanel.Server/ExchangeServer.asmx.cs index 35740f42..53875d70 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server/ExchangeServer.asmx.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server/ExchangeServer.asmx.cs @@ -176,12 +176,12 @@ namespace WebsitePanel.Server } [WebMethod, SoapHeader("settings")] - public bool DeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string offlineAddressBook, string securityGroup) + public bool DeleteOrganization(string organizationId, string distinguishedName, string globalAddressList, string addressList, string roomsAddressList, string offlineAddressBook, string securityGroup) { try { LogStart("DeleteOrganization"); - bool ret = ES.DeleteOrganization(organizationId, distinguishedName, globalAddressList, addressList, offlineAddressBook, securityGroup); + bool ret = ES.DeleteOrganization(organizationId, distinguishedName, globalAddressList, addressList, roomsAddressList, offlineAddressBook, securityGroup); LogEnd("DeleteOrganization"); return ret; }