From e4ba691ca77aece9e5f30254450684f92faf15d8 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 21 Aug 2017 15:32:36 +0100 Subject: [PATCH 001/142] ZCS-2344:ImapTestBase subscription cmd wrappers Added test command wrappers for Subscribe/Unsubscribe/Lsub --- .../com/zimbra/qa/unittest/ImapTestBase.java | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java index 1f828dd6494..71a9c9df60f 100644 --- a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java +++ b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java @@ -36,6 +36,7 @@ import com.zimbra.cs.mailclient.auth.AuthenticatorFactory; import com.zimbra.cs.mailclient.imap.AppendResult; import com.zimbra.cs.mailclient.imap.Body; +import com.zimbra.cs.mailclient.imap.CAtom; import com.zimbra.cs.mailclient.imap.Envelope; import com.zimbra.cs.mailclient.imap.Flags; import com.zimbra.cs.mailclient.imap.ImapConfig; @@ -312,6 +313,22 @@ protected void doRenameShouldSucceed(String origFolderName, String newFolderName } } + protected void doSubscribeShouldSucceed(ImapConnection imapConn, String folderName) { + try { + imapConn.subscribe(folderName); + } catch (Exception e) { + fail(String.format("%s %s failed - %s", CAtom.SUBSCRIBE, folderName, e.getMessage())); + } + } + + protected void doUnsubscribeShouldSucceed(ImapConnection imapConn, String folderName) { + try { + imapConn.unsubscribe(folderName); + } catch (Exception e) { + fail(String.format("%s %s failed - %s", CAtom.UNSUBSCRIBE, folderName, e.getMessage())); + } + } + protected void doListShouldFail(ImapConnection conn, String ref, String mailbox, String expected) throws IOException { try { @@ -326,16 +343,38 @@ protected void doListShouldFail(ImapConnection conn, String ref, String mailbox, protected List doListShouldSucceed(ImapConnection conn, String ref, String mailbox, int expected) throws IOException { + String cmdDesc = String.format("'%s \"%s\" \"%s\"'", CAtom.LIST, ref, mailbox); try { List listResult = conn.list(ref, mailbox); - assertNotNull(String.format("list result 'list \"%s\" \"%s\"' should not be null", - ref, mailbox), listResult); - assertEquals(String.format( "Number of entries in list returned for 'list \"%s\" \"%s\"'", - ref, mailbox), expected, listResult.size()); + assertNotNull(String.format("list result %s should not be null", cmdDesc), listResult); + assertEquals(String.format( "Number of entries in list returned for %s", cmdDesc), + expected, listResult.size()); + return listResult; + } catch (CommandFailedException cfe) { + String err = cfe.getError(); + fail(String.format("cmdDesc returned error '%s'", cmdDesc, err)); + return null; + } + } + + protected List doLSubShouldSucceed(ImapConnection conn, String ref, String mailbox, + List expectedMboxNames, String testDesc) + throws IOException { + String cmdDesc = String.format("'%s \"%s\" \"%s\"'", CAtom.LSUB, ref, mailbox); + try { + List listResult = conn.lsub(ref, mailbox); + assertNotNull(String.format("%s:list result from %s should not be null", testDesc, cmdDesc), listResult); + assertEquals(String.format( "%s:Number of entries in list returned for %s", testDesc, cmdDesc), + expectedMboxNames.size(), listResult.size()); + for (String mbox : expectedMboxNames) { + String tMbox = (mbox.startsWith("/")) ? mbox.substring(1) : mbox; + assertTrue(String.format("%s:Mailbox '%s' NOT in list returned by %s", testDesc, tMbox, cmdDesc), + listContains(listResult, tMbox)); + } return listResult; } catch (CommandFailedException cfe) { String err = cfe.getError(); - fail(String.format("'LIST \"%s\" \"%s\"' returned error '%s'", ref, mailbox, err)); + fail(String.format("%s:%s returned error '%s'", testDesc, cmdDesc, err)); return null; } } From 6c429ad92c519d1068a9a6408e3d34bbec256efc Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 21 Aug 2017 18:43:09 +0100 Subject: [PATCH 002/142] ZCS-2344:SaveIMAPSubscriptionsRequest fixes Was getting NPEs --- .../soap/mail/message/SaveIMAPSubscriptionsRequest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java b/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java index a4ec4506360..838d9e95a0c 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java @@ -7,6 +7,7 @@ import javax.xml.bind.annotation.XmlRootElement; import com.google.common.base.Objects; +import com.google.common.collect.Sets; import com.zimbra.common.soap.AccountConstants; import com.zimbra.common.soap.MailConstants; @@ -24,6 +25,9 @@ public class SaveIMAPSubscriptionsRequest { private final Set subscriptions; public Set getSubscriptions() { + if (subscriptions == null) { + return Collections.unmodifiableSet(Sets.newHashSet()); + } return Collections.unmodifiableSet(subscriptions); } @@ -32,7 +36,7 @@ public Set getSubscriptions() { */ @SuppressWarnings("unused") public SaveIMAPSubscriptionsRequest() { - this((Set)null); + this(Sets.newHashSet()); } public SaveIMAPSubscriptionsRequest(Set subs) { From c76392730f3f835f909edeb009ec94f137452fa1 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 21 Aug 2017 18:45:29 +0100 Subject: [PATCH 003/142] ZCS-2344:ImapCredentials subscriptions modifiable Make a modifiable list for the subscriptions when appropriate --- store/src/java/com/zimbra/cs/imap/ImapCredentials.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapCredentials.java b/store/src/java/com/zimbra/cs/imap/ImapCredentials.java index 3fc528b0a4b..c57d933c7c9 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapCredentials.java +++ b/store/src/java/com/zimbra/cs/imap/ImapCredentials.java @@ -25,6 +25,7 @@ import java.util.Set; import com.google.common.base.Objects; +import com.google.common.collect.Sets; import com.zimbra.client.ZMailbox; import com.zimbra.client.event.ZEventHandler; import com.zimbra.common.account.Key; @@ -158,8 +159,13 @@ private void saveSubscriptions(Set subscriptions) throws ServiceExceptio getImapMailboxStore().saveSubscriptions(getContext(), subscriptions); } + /** @return Modifiable set of subscriptions or null if there are no subscriptions */ protected Set listSubscriptions() throws ServiceException { - return getImapMailboxStore().listSubscriptions(getContext()); + Set subs = getImapMailboxStore().listSubscriptions(getContext()); + /* subs may be an unmodifiable set as that is what the JAXB provides in the remote case. + * Change it into a modifiable set, as the result is modified when subscribing/unsubscribing + */ + return (subs == null || subs.isEmpty()) ? null : Sets.newHashSet(subs); } protected void subscribe(ImapPath path) throws ServiceException { From f9bf9c4ed9083e8eab3d8295bc74be2ed6d46ce8 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 21 Aug 2017 18:47:04 +0100 Subject: [PATCH 004/142] ZCS-2344:ImapTestBase LSUB wrapper Be more flexible in names of expected mailboxes. I think we are currently being inconsistent in whether we prefix with "/" or not. --- .../com/zimbra/qa/unittest/ImapTestBase.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java index 71a9c9df60f..9a04da3d4df 100644 --- a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java +++ b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java @@ -364,12 +364,25 @@ protected List doLSubShouldSucceed(ImapConnection conn, String ref, St try { List listResult = conn.lsub(ref, mailbox); assertNotNull(String.format("%s:list result from %s should not be null", testDesc, cmdDesc), listResult); - assertEquals(String.format( "%s:Number of entries in list returned for %s", testDesc, cmdDesc), - expectedMboxNames.size(), listResult.size()); + assertEquals(String.format( "%s:Number of entries in list returned for %s\n%s", + testDesc, cmdDesc, listResult), expectedMboxNames.size(), listResult.size()); for (String mbox : expectedMboxNames) { - String tMbox = (mbox.startsWith("/")) ? mbox.substring(1) : mbox; - assertTrue(String.format("%s:Mailbox '%s' NOT in list returned by %s", testDesc, tMbox, cmdDesc), - listContains(listResult, tMbox)); + if (!listContains(listResult, mbox)) { + /* TODO we seem to include "/" at the start sometime and sometimes not. Investigate whether + * that is OK? + * e.g. Seen: + * C06 LSUB "" "*" + * * LSUB () "/" "INBOX" + * C07 OK LSUB completed + * and + * C07 LSUB "" "/home/user/*" + * * LSUB () "/" "/home/user/INBOX/shared" + * C07 OK LSUB completed + */ + String tMbox = (mbox.startsWith("/")) ? mbox.substring(1) : mbox; + assertTrue(String.format("%s:'%s' NOT in list returned by %s\n%s", + testDesc, mbox, cmdDesc, listResult), listContains(listResult, tMbox)); + } } return listResult; } catch (CommandFailedException cfe) { From fb83eb19b6426e9bbe915a8a90f699db9dc3b0d6 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 21 Aug 2017 18:48:33 +0100 Subject: [PATCH 005/142] ZCS-2344:SharedImapTests subscibe and shares Added tests `homeNameSpaceSubscribe()` and `mountpointSubscribe()` --- .../zimbra/qa/unittest/SharedImapTests.java | 117 ++++++++++++------ 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index 4722305f96f..6792016b862 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -1371,47 +1371,94 @@ public void testUidCopy() throws IOException, ServiceException { @Test(timeout=100000) public void testSubscribeNested() throws IOException, ServiceException { connection = connectAndSelectInbox(); - String folderName = "TestImap-testSubscribeNested"; - ZFolder folder = TestUtil.createFolder(TestUtil.getZMailbox(USER),Integer.toString(Mailbox.ID_FOLDER_INBOX), folderName); - List listResult = connection.lsub("", "*"); - assertNotNull(listResult); - assertEquals("Should have 0 subscriptions before subscribing", 0, listResult.size()); - try { - connection.subscribe(folder.getPath()); - } catch (Exception e) { - fail(e.getMessage()); - } - listResult = connection.lsub("", "*"); - assertNotNull(listResult); - assertEquals("Should have 1 subscription after subscribing", 1, listResult.size()); - assertTrue("Should be subscribed to " + folder.getPath().substring(1) + ". Instead got " + listResult.get(0).getMailbox(), folder.getPath().substring(1).equalsIgnoreCase(listResult.get(0).getMailbox())); + String folderName = testId; + ZFolder folder = TestUtil.createFolder( + TestUtil.getZMailbox(USER),Integer.toString(Mailbox.ID_FOLDER_INBOX), folderName); + assertNotNull("Folder object from createFolder", folder); + doLSubShouldSucceed(connection, "", "*", Lists.newArrayListWithExpectedSize(0), "before subscribe"); + doSubscribeShouldSucceed(connection, folder.getPath()); + doLSubShouldSucceed(connection, "", "*", Lists.newArrayList(folder.getPath()), "after subscribe"); } @Test(timeout=100000) public void testUnSubscribe() throws IOException, ServiceException { connection = connectAndSelectInbox(); - String folderName = "TestImap-testUnSubscribe"; + String folderName = testId; TestUtil.createFolder(TestUtil.getZMailbox(USER), folderName); - List listResult = connection.lsub("", "*"); - assertNotNull(listResult); - assertEquals("Should have 0 subscriptions before subscribing", 0, listResult.size()); - try { - connection.subscribe(folderName); - } catch (Exception e) { - fail(e.getMessage()); - } - listResult = connection.lsub("", "*"); - assertNotNull(listResult); - assertEquals("Should have 1 subscription after subscribing", 1, listResult.size()); - assertTrue("Should be subscribed to " + folderName + ". Instead got " + listResult.get(0).getMailbox(), folderName.equalsIgnoreCase(listResult.get(0).getMailbox())); - try { - connection.unsubscribe(folderName); - } catch (Exception e) { - fail(e.getMessage()); - } - listResult = connection.lsub("", "*"); - assertNotNull(listResult); - assertEquals("Should have 0 subscriptions after unsubscribing", 0, listResult.size()); + doLSubShouldSucceed(connection, "", "*", Lists.newArrayListWithExpectedSize(0), "before subscribe"); + doSubscribeShouldSucceed(connection, folderName); + doLSubShouldSucceed(connection, "", "*", Lists.newArrayList(folderName), "after subscribe"); + doUnsubscribeShouldSucceed(connection, folderName); + doLSubShouldSucceed(connection, "", "*", Lists.newArrayListWithExpectedSize(0), "after unsubscribe"); + } + + @Test(timeout=100000) + public void homeNameSpaceSubscribe() throws ServiceException, IOException, MessagingException { + String sharedFolderName = String.format("INBOX/%s-shared", testId); + String subFolder = sharedFolderName + "/subFolder"; + ZMailbox userZmbox = TestUtil.getZMailbox(USER); + TestUtil.createFolder(userZmbox, "/" + sharedFolderName); + TestUtil.createFolder(userZmbox, "/" + subFolder); + TestUtil.createAccount(SHAREE); + connection = connectAndLogin(USER); + connection.setacl(sharedFolderName, SHAREE, "lrswickxteda"); + connection.logout(); + connection = null; + String remFolder = String.format("/home/%s/%s", USER, sharedFolderName); + String underRemFolder = String.format("%s/subFolder", remFolder); + String homePatt = String.format("/home/%s/*", USER); + otherConnection = connectAndLogin(SHAREE); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayListWithExpectedSize(0), "before 1st subscribe"); + doSubscribeShouldSucceed(otherConnection, "INBOX"); + doSubscribeShouldSucceed(otherConnection, remFolder); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX"), + String.format("after subscribing to INBOX and '%s'", remFolder)); + doLSubShouldSucceed(otherConnection, "", homePatt, Lists.newArrayList(remFolder), + String.format("after subscribing to INBOX and '%s'", remFolder)); + doSubscribeShouldSucceed(otherConnection, underRemFolder); + doLSubShouldSucceed(otherConnection, "", homePatt, Lists.newArrayList(remFolder, underRemFolder), + String.format("after subscribing to INBOX and '%s' and '%s'", remFolder, underRemFolder)); + doUnsubscribeShouldSucceed(otherConnection, remFolder); + doLSubShouldSucceed(otherConnection, "", homePatt, Lists.newArrayList(underRemFolder), + String.format("after unsubscribing from '%s'", remFolder)); + doUnsubscribeShouldSucceed(otherConnection, underRemFolder); + doLSubShouldSucceed(otherConnection, "", homePatt, Lists.newArrayListWithExpectedSize(0), + String.format("after unsubscribing from '%s'", remFolder)); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX"), + String.format("after unsubscribing from '%s'", remFolder)); + otherConnection.logout(); + otherConnection = null; + } + + @Test(timeout=100000) + public void mountpointSubscribe() throws ServiceException, IOException { + TestUtil.createAccount(SHAREE); + ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); + ZMailbox mbox = TestUtil.getZMailbox(USER); + String remFolder = String.format("/INBOX/%s-shared", testId); + String underRemFolder = String.format("%s/subFolder", remFolder); + TestUtil.createFolder(mbox, remFolder); + TestUtil.createFolder(mbox, underRemFolder); + String mp = String.format("/%s's %s-shared", USER, testId); + String subMp = String.format("%s/subFolder", mp); + TestUtil.createMountpoint(mbox, remFolder, shareeZmbox, mp.substring(1)); + otherConnection = connectAndLogin(SHAREE); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayListWithExpectedSize(0), "before 1st subscribe"); + doSubscribeShouldSucceed(otherConnection, "INBOX"); + doSubscribeShouldSucceed(otherConnection, mp); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX", mp), + String.format("after subscribing to INBOX and '%s'", mp)); + doSubscribeShouldSucceed(otherConnection, subMp); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX", mp, subMp), + String.format("after subscribing to '%s'", subMp)); + doUnsubscribeShouldSucceed(otherConnection, mp); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX", subMp), + String.format("after unsubscribing from '%s'", mp)); + doUnsubscribeShouldSucceed(otherConnection, subMp); + doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX"), + String.format("after unsubscribing from '%s'", subMp)); + otherConnection.logout(); + otherConnection = null; } @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") // checking done in called methods From 077fb7353ba8fd083b40354fa28631d702f64a19 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 21 Aug 2017 21:05:15 +0100 Subject: [PATCH 006/142] ZCS-2344:ImapHandler ignore remote imapSubscribed The list of all folders on a remote mailbox includes sub-folders of mountpoints. The `imapSubscribed` flag on these should be ignored as they only have meaning in the context of that mailbox. --- store/src/java/com/zimbra/cs/imap/ImapHandler.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/store/src/java/com/zimbra/cs/imap/ImapHandler.java b/store/src/java/com/zimbra/cs/imap/ImapHandler.java index abc7bb66ebd..f11f6c80106 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapHandler.java +++ b/store/src/java/com/zimbra/cs/imap/ImapHandler.java @@ -2344,6 +2344,11 @@ boolean doLSUB(String tag, String referenceName, String mailboxName) throws Imap if ((isMailFolders) && (folder.isChatsFolder() || (folder.getName().equals ("Chats")))) { continue; } + String fAcctId = folder.getFolderItemIdentifier().accountId; + if ((fAcctId != null) && !fAcctId.equals(credentials.getAccountId())) { + // ignore imapSubscribed flag on remote folders - they apply to the remote acct + continue; + } if (folder.isIMAPSubscribed()) { checkSubscription(new SubscribedImapPath( new ImapPath(null, folder, credentials)), pattern, childPattern, hits); From 9f3ad93fefd3f21c8be63771642e6a6036d0a812 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 25 Aug 2017 11:16:01 +0100 Subject: [PATCH 007/142] ZCS-2344:ZMailbox split at mountpoint `getParentFolderStoreAndUnmatchedPart` attempts to split a path into the folder of the containing mountpoint and the sub-folder path remaining. This was not happening and just a folder representing a folder in another user's mailbox is returned. Note comment in previous code talked about using a more efficient algorithm but not convinced that was true (even though it was my comment) --- .../src/java/com/zimbra/client/ZMailbox.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index 05f357f6199..069780a7446 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -6109,6 +6109,12 @@ public Pair getFolderByPathLongestMatch(String baseFolderItemId break; } folder = subfolder; + if (folder instanceof ZMountpoint) { + if ((i + 1) < segments.length) { + unmatched = StringUtil.join("/", segments, i + 1, segments.length - (i + 1)); + } + break; + } } return new Pair(folder, unmatched); } @@ -6126,19 +6132,13 @@ public Pair getFolderByPathLongestMatch(String baseFolderItemId @Override public ExistingParentFolderStoreAndUnmatchedPart getParentFolderStoreAndUnmatchedPart(OpContext octxt, String path) throws ServiceException { - // Could have based this on getFolderByPathLongestMatch(ZFolder.ID_USER_ROOT, path); - // but that looks less efficient - for deep nesting, creating lots of ZFolders and throwing them away... - // This code borrowed (and moved) from ImapPath.getReferent() if (Strings.isNullOrEmpty(path)) { return new ExistingParentFolderStoreAndUnmatchedPart(getFolderById(ZFolder.ID_USER_ROOT), ""); } try { - for (int index = path.length(); index != -1; index = path.lastIndexOf('/', index - 1)) { - ZFolder zfolder = getFolderByPath(path.substring(0, index)); - if (zfolder != null) { - String subpathRemote = path.substring(Math.min(path.length(), index + 1)); - return new ExistingParentFolderStoreAndUnmatchedPart(zfolder, subpathRemote); - } + Pair pair = getFolderByPathLongestMatch(ZFolder.ID_USER_ROOT, path); + if (pair != null) { + return new ExistingParentFolderStoreAndUnmatchedPart(pair.getFirst(), pair.getSecond()); } } catch (ServiceException e) {} return new ExistingParentFolderStoreAndUnmatchedPart(getFolderById(ZFolder.ID_USER_ROOT), path); From 06064407b253c3201cf48fb0bbfb394e6305c5ea Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 25 Aug 2017 11:25:21 +0100 Subject: [PATCH 008/142] ZCS-2344:ImapPath ZMailbox useragent string --- store/src/java/com/zimbra/cs/imap/ImapPath.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/store/src/java/com/zimbra/cs/imap/ImapPath.java b/store/src/java/com/zimbra/cs/imap/ImapPath.java index e033f96804b..f14889aec5d 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapPath.java +++ b/store/src/java/com/zimbra/cs/imap/ImapPath.java @@ -31,6 +31,7 @@ import com.zimbra.common.mailbox.MountpointStore; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.Pair; +import com.zimbra.common.util.SystemUtil; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.AccountServiceException; @@ -307,6 +308,7 @@ private ZMailbox getZMailboxForAccount(Account target) throws ServiceException { ZMailbox.Options options = new ZMailbox.Options(AuthProvider.getAuthToken(acct).getEncoded(), AccountUtil.getSoapUri(target)); options.setTargetAccount(target.getName()); + options.setUserAgent("zclient-imap-onBehalfOf", SystemUtil.getProductVersion()); options.setNoSession(true); options.setAlwaysRefreshFolders(true); ZMailbox zmbx = ZMailbox.getMailbox(options); From e752098d41bb3c0fc025bc2cebfbc5487fdc0aa2 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 25 Aug 2017 18:39:12 +0100 Subject: [PATCH 009/142] ZCS-2344:ImapProxy.status Support proxying the STATUS command --- store/src/java/com/zimbra/cs/imap/ImapProxy.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/store/src/java/com/zimbra/cs/imap/ImapProxy.java b/store/src/java/com/zimbra/cs/imap/ImapProxy.java index 20ef01c02ea..ec765606132 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapProxy.java +++ b/store/src/java/com/zimbra/cs/imap/ImapProxy.java @@ -184,6 +184,21 @@ boolean select(final String tag, final byte params, final QResyncInfo qri) return proxyCommand(select.append("\r\n").toString().getBytes(), true, false); } + /** + * Proxy STATUS command. + * @param params - e.g. "(EXISTS RECENT)" + */ + boolean status(final String tag, final String params) + throws ImapProxyException, ServiceException { + String command = "STATUS"; + StringBuilder select = new StringBuilder(100); + select.append(tag).append(' ').append(command).append(' '); + select.append(path.getReferent().asUtf7String()); + select.append(' '); + select.append(params); + return proxyCommand(select.append("\r\n").toString().getBytes(), true, false); + } + /** * Proxy IDLE command. * From 38eba2bdfa634703ff9e58563b0e899c077fae57 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 25 Aug 2017 19:02:17 +0100 Subject: [PATCH 010/142] ZCS-2344:ImapHandler proxy STATUS if appropriate Added new `StatusDataItemNames` class which parses the next bit of an STATUS `ImapRequest` - expecting the "status data item names" into a bitmap field. The `toString()` method on this returns a suitable equivalent string to be used in a proxied STATUS command for the "status data item names" --- .../java/com/zimbra/cs/imap/ImapHandler.java | 120 +++++++++++------- 1 file changed, 76 insertions(+), 44 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapHandler.java b/store/src/java/com/zimbra/cs/imap/ImapHandler.java index f11f6c80106..5cb1ba521ca 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapHandler.java +++ b/store/src/java/com/zimbra/cs/imap/ImapHandler.java @@ -49,6 +49,7 @@ import org.dom4j.DocumentException; import com.google.common.base.Charsets; +import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; @@ -636,7 +637,8 @@ boolean executeRequest(ImapRequest req) throws IOException, ImapException { returnOptions |= RETURN_CHILDREN; } else if (option.equals("STATUS") && extensionEnabled("LIST-STATUS")) { req.skipSpace(); - status = parseStatusFields(req); + StatusDataItemNames cmdInfo = new StatusDataItemNames(req); + status = cmdInfo.cmdStatus; } else { throw new ImapParseException(tag, "unknown LIST return option \"" + option + '"'); } @@ -772,9 +774,9 @@ boolean executeRequest(ImapRequest req) throws IOException, ImapException { req.skipSpace(); ImapPath path = new ImapPath(req.readFolder(), credentials); req.skipSpace(); - byte status = parseStatusFields(req); + StatusDataItemNames dataItemNames = new StatusDataItemNames(req); checkEOF(tag, req); - return doSTATUS(tag, path, status); + return doSTATUS(tag, path, dataItemNames); } else if (command.equals("SORT") && extensionEnabled("SORT")) { Integer options = null; req.skipSpace(); @@ -914,32 +916,66 @@ boolean executeRequest(ImapRequest req) throws IOException, ImapException { throw new ImapParseException(tag, "command not implemented"); } - private byte parseStatusFields(ImapRequest req) throws ImapParseException { - byte status = 0; - req.skipChar('('); - do { - if (status != 0) { - req.skipSpace(); + private static class StatusDataItemNames { + static final int STATUS_MESSAGES = 0x01; + static final int STATUS_RECENT = 0x02; + static final int STATUS_UIDNEXT = 0x04; + static final int STATUS_UIDVALIDITY = 0x08; + static final int STATUS_UNSEEN = 0x10; + static final int STATUS_HIGHESTMODSEQ = 0x20; + public final byte cmdStatus; + + StatusDataItemNames(ImapRequest req) throws ImapParseException { + byte status = 0; + req.skipChar('('); + do { + if (status != 0) { + req.skipSpace(); + } + String flag = req.readATOM(); + if (flag.equals("MESSAGES")) { + status |= STATUS_MESSAGES; + } else if (flag.equals("RECENT")) { + status |= STATUS_RECENT; + } else if (flag.equals("UIDNEXT")) { + status |= STATUS_UIDNEXT; + } else if (flag.equals("UIDVALIDITY")) { + status |= STATUS_UIDVALIDITY; + } else if (flag.equals("UNSEEN")) { + status |= STATUS_UNSEEN; + } else if (flag.equals("HIGHESTMODSEQ")) { + status |= STATUS_HIGHESTMODSEQ; + } else { + throw new ImapParseException(req.getTag(), "unknown STATUS attribute \"" + flag + '"'); + } + } while (req.peekChar() != ')'); + req.skipChar(')'); + cmdStatus = status; + } + + @Override + public String toString() { + List requested = Lists.newArrayListWithExpectedSize(6); + if ((cmdStatus & STATUS_MESSAGES) != 0) { + requested.add("MESSAGES"); } - String flag = req.readATOM(); - if (flag.equals("MESSAGES")) { - status |= STATUS_MESSAGES; - } else if (flag.equals("RECENT")) { - status |= STATUS_RECENT; - } else if (flag.equals("UIDNEXT")) { - status |= STATUS_UIDNEXT; - } else if (flag.equals("UIDVALIDITY")) { - status |= STATUS_UIDVALIDITY; - } else if (flag.equals("UNSEEN")) { - status |= STATUS_UNSEEN; - } else if (flag.equals("HIGHESTMODSEQ")) { - status |= STATUS_HIGHESTMODSEQ; - } else { - throw new ImapParseException(req.getTag(), "unknown STATUS attribute \"" + flag + '"'); + if ((cmdStatus & STATUS_RECENT) != 0) { + requested.add("RECENT"); } - } while (req.peekChar() != ')'); - req.skipChar(')'); - return status; + if ((cmdStatus & STATUS_UIDNEXT) != 0) { + requested.add("UIDNEXT"); + } + if ((cmdStatus & STATUS_UIDVALIDITY) != 0) { + requested.add("UIDVALIDITY"); + } + if ((cmdStatus & STATUS_UNSEEN) != 0) { + requested.add("UNSEEN"); + } + if ((cmdStatus & STATUS_HIGHESTMODSEQ) != 0) { + requested.add("HIGHESTMODSEQ"); + } + return "(" + Joiner.on(' ').join(requested) + ")"; + } } private int parseSearchOptions(ImapRequest req) throws ImapParseException { @@ -1064,7 +1100,6 @@ FolderDetails setSelectedFolder(ImapPath path, byte params) throws ServiceExcept } FolderDetails selectdata = ImapSessionManager.getInstance().openFolder(path, params, this); selectedFolderListener = selectdata.listener; - ZimbraLog.imap.info("selected folder " + selectdata.listener.getPath()); return selectdata; } @@ -2475,19 +2510,16 @@ private void checkSubscription(SubscribedImapPath path, Pattern pattern, Pattern path.addUnsubsribedMatchingParents(pattern, hits); } - static final int STATUS_MESSAGES = 0x01; - static final int STATUS_RECENT = 0x02; - static final int STATUS_UIDNEXT = 0x04; - static final int STATUS_UIDVALIDITY = 0x08; - static final int STATUS_UNSEEN = 0x10; - static final int STATUS_HIGHESTMODSEQ = 0x20; - - boolean doSTATUS(String tag, ImapPath path, byte status) throws ImapException, IOException { + boolean doSTATUS(String tag, ImapPath path, StatusDataItemNames dataItemNames) + throws ImapException, IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } try { path.canonicalize(); + if (imapProxy != null && path.isEquivalent(imapProxy.getPath())) { + return imapProxy.status(tag, dataItemNames.toString()); + } if (!path.isVisible()) { ZimbraLog.imap.info("STATUS failed: folder not visible: %s", path); sendNO(tag, "STATUS failed"); @@ -2499,7 +2531,7 @@ boolean doSTATUS(String tag, ImapPath path, byte status) throws ImapException, I mbox.noOp(); } } - sendUntagged(status(path, status)); + sendUntagged(status(path, dataItemNames.cmdStatus)); } catch (ServiceException e) { if (e.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) { ZimbraLog.imap.info("STATUS failed: no such folder: %s", path); @@ -2528,7 +2560,7 @@ String status(ImapPath path, byte status) throws ImapException, ServiceException } ImapFolder i4folder = getSelectedFolder(); messages = folder.getImapMessageCount(); - if ((status & STATUS_RECENT) == 0) { + if ((status & StatusDataItemNames.STATUS_RECENT) == 0) { recent = -1; } else if (messages == 0) { recent = 0; @@ -2550,23 +2582,23 @@ String status(ImapPath path, byte status) throws ImapException, ServiceException throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner()); } - if (messages >= 0 && (status & STATUS_MESSAGES) != 0) { + if (messages >= 0 && (status & StatusDataItemNames.STATUS_MESSAGES) != 0) { data.append(data.length() != empty ? " " : "").append("MESSAGES ").append(messages); } - if (recent >= 0 && (status & STATUS_RECENT) != 0) { + if (recent >= 0 && (status & StatusDataItemNames.STATUS_RECENT) != 0) { data.append(data.length() != empty ? " " : "").append("RECENT ").append(recent); } // note: we're not supporting UIDNEXT for search folders; see the comments in selectFolder() - if (uidnext > 0 && (status & STATUS_UIDNEXT) != 0) { + if (uidnext > 0 && (status & StatusDataItemNames.STATUS_UIDNEXT) != 0) { data.append(data.length() != empty ? " " : "").append("UIDNEXT ").append(uidnext); } - if (uvv > 0 && (status & STATUS_UIDVALIDITY) != 0) { + if (uvv > 0 && (status & StatusDataItemNames.STATUS_UIDVALIDITY) != 0) { data.append(data.length() != empty ? " " : "").append("UIDVALIDITY ").append(uvv); } - if (unread >= 0 && (status & STATUS_UNSEEN) != 0) { + if (unread >= 0 && (status & StatusDataItemNames.STATUS_UNSEEN) != 0) { data.append(data.length() != empty ? " " : "").append("UNSEEN ").append(unread); } - if (modseq >= 0 && (status & STATUS_HIGHESTMODSEQ) != 0) { + if (modseq >= 0 && (status & StatusDataItemNames.STATUS_HIGHESTMODSEQ) != 0) { data.append(data.length() != empty ? " " : "").append("HIGHESTMODSEQ ").append(modseq); } From 1bf01f7e7f27c21f0d6b1c5e2a33268681f1b790 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 25 Aug 2017 21:01:49 +0100 Subject: [PATCH 011/142] PMD ImapHandler changes --- .../java/com/zimbra/cs/imap/ImapHandler.java | 426 +++++++++--------- 1 file changed, 220 insertions(+), 206 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapHandler.java b/store/src/java/com/zimbra/cs/imap/ImapHandler.java index 5cb1ba521ca..8ea752daff7 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapHandler.java +++ b/store/src/java/com/zimbra/cs/imap/ImapHandler.java @@ -122,9 +122,16 @@ import com.zimbra.soap.admin.type.CacheSelector; public abstract class ImapHandler { - enum State { NOT_AUTHENTICATED, AUTHENTICATED, SELECTED, LOGOUT } + protected enum State { NOT_AUTHENTICATED, AUTHENTICATED, SELECTED, LOGOUT } - enum ImapExtension { CONDSTORE, QRESYNC } + protected enum ImapExtension { CONDSTORE, QRESYNC } + + private static final Set SUPPORTED_EXTENSIONS = new LinkedHashSet(Arrays.asList( + "ACL", "BINARY", "CATENATE", "CHILDREN", "CONDSTORE", "ENABLE", "ESEARCH", "ESORT", + "I18NLEVEL=1", "ID", "IDLE", "LIST-EXTENDED", "LIST-STATUS", "LITERAL+", "LOGIN-REFERRALS", + "MULTIAPPEND", "NAMESPACE", "QRESYNC", "QUOTA", "RIGHTS=ektx", "SASL-IR", "SEARCHRES", + "SORT", "THREAD=ORDEREDSUBJECT", "UIDPLUS", "UNSELECT", "WITHIN", "XLIST" + )); private static final long MAXIMUM_IDLE_PROCESSING_MILLIS = 15 * Constants.MILLIS_PER_SECOND; @@ -132,23 +139,94 @@ enum ImapExtension { CONDSTORE, QRESYNC } private static final String ID_PARAMS = "\"NAME\" \"Zimbra\" \"VERSION\" \"" + BuildInfo.VERSION + "\" \"RELEASE\" \"" + BuildInfo.RELEASE + "\""; - static final char[] LINE_SEPARATOR = { '\r', '\n' }; - static final byte[] LINE_SEPARATOR_BYTES = { '\r', '\n' }; + private static final String IMAP_READ_RIGHTS = "lr"; + private static final String IMAP_WRITE_RIGHTS = "sw"; + private static final String IMAP_INSERT_RIGHTS = "ick"; + private static final String IMAP_DELETE_RIGHTS = "xted"; + private static final String IMAP_ADMIN_RIGHTS = "a"; + + /* All the supported IMAP rights, concatenated together into a single string. */ + private static final String IMAP_CONCATENATED_RIGHTS = IMAP_READ_RIGHTS + IMAP_WRITE_RIGHTS + + IMAP_INSERT_RIGHTS + IMAP_DELETE_RIGHTS + IMAP_ADMIN_RIGHTS; + /* All the supported IMAP rights, with linked sets of rights + * grouped together and the groups delimited by spaces. */ + private static final String IMAP_DELIMITED_RIGHTS = IMAP_READ_RIGHTS + ' ' + IMAP_WRITE_RIGHTS + ' ' + + IMAP_INSERT_RIGHTS + ' ' + IMAP_DELETE_RIGHTS + ' ' + IMAP_ADMIN_RIGHTS; + + /* The set of rights required to create a new subfolder in ZCS. */ + private final short SUBFOLDER_RIGHTS = ACL.RIGHT_INSERT | ACL.RIGHT_READ; + + protected static final char[] LINE_SEPARATOR = { '\r', '\n' }; + protected static final byte[] LINE_SEPARATOR_BYTES = { '\r', '\n' }; + + protected static final int FETCH_BODY = 0x0001; + protected static final int FETCH_BODYSTRUCTURE = 0x0002; + protected static final int FETCH_ENVELOPE = 0x0004; + protected static final int FETCH_FLAGS = 0x0008; + protected static final int FETCH_INTERNALDATE = 0x0010; + protected static final int FETCH_RFC822_SIZE = 0x0020; + protected static final int FETCH_BINARY_SIZE = 0x0040; + protected static final int FETCH_UID = 0x0080; + protected static final int FETCH_MODSEQ = 0x0100; + protected static final int FETCH_VANISHED = 0x0200; + protected static final int FETCH_MARK_READ = 0x1000; + + protected static final int FETCH_FROM_CACHE = FETCH_FLAGS | FETCH_UID; + protected static final int FETCH_FROM_MIME = FETCH_BODY | FETCH_BODYSTRUCTURE | FETCH_ENVELOPE; + + protected static final int FETCH_FAST = FETCH_FLAGS | FETCH_INTERNALDATE | FETCH_RFC822_SIZE; + protected static final int FETCH_ALL = FETCH_FAST | FETCH_ENVELOPE; + protected static final int FETCH_FULL = FETCH_ALL | FETCH_BODY; + + private static final byte SELECT_SUBSCRIBED = 0x01; + private static final byte SELECT_REMOTE = 0x02; + private static final byte SELECT_RECURSIVE = 0x04; + + private static final byte RETURN_SUBSCRIBED = 0x01; + private static final byte RETURN_CHILDREN = 0x02; + private static final byte RETURN_XLIST = 0x04; + + private final int SUGGESTED_BATCH_SIZE = 100; + private final int SUGGESTED_COPY_BATCH_SIZE = 50; + private final int SUGGESTED_DELETE_BATCH_SIZE = 30; + + protected enum StoreAction { REPLACE, ADD, REMOVE } + + private static final int RETURN_MIN = 0x01; + private static final int RETURN_MAX = 0x02; + private static final int RETURN_ALL = 0x04; + private static final int RETURN_COUNT = 0x08; + private static final int RETURN_SAVE = 0x10; + + private static final int LARGEST_FOLDER_BATCH = 600; + public static final Set ITEM_TYPES = ImapMessage.SUPPORTED_TYPES; + + protected static final boolean IDLE_START = true; + protected static final boolean IDLE_STOP = false; - ImapConfig config; + private static final boolean[] REGEXP_ESCAPED = new boolean[128]; + static { + REGEXP_ESCAPED['('] = REGEXP_ESCAPED[')'] = REGEXP_ESCAPED['.'] = true; + REGEXP_ESCAPED['['] = REGEXP_ESCAPED[']'] = REGEXP_ESCAPED['|'] = true; + REGEXP_ESCAPED['^'] = REGEXP_ESCAPED['$'] = REGEXP_ESCAPED['?'] = true; + REGEXP_ESCAPED['{'] = REGEXP_ESCAPED['}'] = REGEXP_ESCAPED['*'] = true; + REGEXP_ESCAPED['\\'] = true; + } + + protected ImapConfig config; protected OutputStream output; - Authenticator authenticator; - ImapCredentials credentials; - boolean startedTLS; - String lastCommand; - int consecutiveError; + protected Authenticator authenticator; + protected ImapCredentials credentials; + protected boolean startedTLS; + protected String lastCommand; + protected int consecutiveError; private ImapProxy imapProxy; - ImapListener selectedFolderListener; + protected ImapListener selectedFolderListener; private String idleTag; private String origRemoteIp; private String via; private String userAgent; - boolean goodbyeSent; + protected boolean goodbyeSent; private Set activeExtensions; private final ServerThrottle reqThrottle; private final ImapCommandThrottle commandThrottle; @@ -192,7 +270,7 @@ protected ImapHandler(ImapConfig config) { protected abstract boolean doSTARTTLS(String tag) throws IOException; protected abstract InetSocketAddress getLocalAddress(); - ImapCredentials getCredentials() { + protected ImapCredentials getCredentials() { return credentials; } @@ -211,19 +289,19 @@ public ImapConfig getConfig() { protected abstract String getRemoteIp(); - String getOrigRemoteIp() { + protected String getOrigRemoteIp() { return origRemoteIp; } - String getVia() { + protected String getVia() { return via; } - String getUserAgent() { + protected String getUserAgent() { return userAgent; } - void setLoggingContext() { + protected void setLoggingContext() { ZimbraLog.clearContext(); ImapListener i4selected = selectedFolderListener; MailboxStore mbox = i4selected == null ? null : i4selected.getMailbox(); @@ -261,13 +339,13 @@ protected void handleParseException(ImapParseException e) throws IOException { } } - void checkEOF(String tag, ImapRequest req) throws ImapParseException { + private void checkEOF(String tag, ImapRequest req) throws ImapParseException { if (!req.eof()) { throw new ImapParseException(tag, "excess characters at end of command"); } } - boolean continueAuthentication(ImapRequest req) throws IOException { + protected boolean continueAuthentication(ImapRequest req) throws IOException { String tag = getTag(authenticator); try { // use the tag from the original AUTHENTICATE command @@ -314,7 +392,7 @@ private boolean continueAuthentication(byte[] response) throws IOException { return true; } - boolean isIdle() { + protected boolean isIdle() { return idleTag != null; } @@ -326,7 +404,7 @@ private static boolean canContinue(Authenticator auth) { return ((ImapAuthenticatorUser) auth.getAuthenticatorUser()).canContinue(); } - boolean checkAccountStatus() { + protected boolean checkAccountStatus() { if (!config.isServiceEnabled()) { ZimbraLog.imap.warn("user services are disabled; dropping connection"); return false; @@ -369,7 +447,7 @@ boolean checkAccountStatus() { return true; } - boolean executeRequest(ImapRequest req) throws IOException, ImapException { + protected boolean executeRequest(ImapRequest req) throws IOException, ImapException { boolean isProxied = imapProxy != null; if (getCredentials() != null) { @@ -581,7 +659,9 @@ boolean executeRequest(ImapRequest req) throws IOException, ImapException { } else if (command.equals("LIST")) { Set patterns = new LinkedHashSet(2); boolean parenthesized = false; - byte selectOptions = 0, returnOptions = 0, status = 0; + byte selectOptions = 0; + byte returnOptions = 0; + byte status = 0; req.skipSpace(); if (req.peekChar() == '(' && extensionEnabled("LIST-EXTENDED")) { @@ -917,12 +997,12 @@ boolean executeRequest(ImapRequest req) throws IOException, ImapException { } private static class StatusDataItemNames { - static final int STATUS_MESSAGES = 0x01; - static final int STATUS_RECENT = 0x02; - static final int STATUS_UIDNEXT = 0x04; - static final int STATUS_UIDVALIDITY = 0x08; - static final int STATUS_UNSEEN = 0x10; - static final int STATUS_HIGHESTMODSEQ = 0x20; + private static final int STATUS_MESSAGES = 0x01; + private static final int STATUS_RECENT = 0x02; + private static final int STATUS_UIDNEXT = 0x04; + private static final int STATUS_UIDVALIDITY = 0x08; + private static final int STATUS_UNSEEN = 0x10; + private static final int STATUS_HIGHESTMODSEQ = 0x20; public final byte cmdStatus; StatusDataItemNames(ImapRequest req) throws ImapParseException { @@ -1032,7 +1112,7 @@ private QResyncInfo parseQResyncInfo(ImapRequest req) throws ImapParseException return qri; } - State getState() { + protected State getState() { if (goodbyeSent) { return State.LOGOUT; } else if (selectedFolderListener != null || imapProxy != null) { @@ -1048,7 +1128,7 @@ protected boolean isAuthenticated() { return credentials != null; } - boolean checkState(String tag, State required) throws IOException { + protected boolean checkState(String tag, State required) throws IOException { State state = getState(); if (required == State.NOT_AUTHENTICATED && state != State.NOT_AUTHENTICATED) { sendNO(tag, "must be in NOT AUTHENTICATED state"); @@ -1064,16 +1144,16 @@ boolean checkState(String tag, State required) throws IOException { } } - ImapListener getCurrentImapListener() { + protected ImapListener getCurrentImapListener() { return getState() == State.LOGOUT ? null : selectedFolderListener; } - ImapFolder getSelectedFolder() throws ImapSessionClosedException { + protected ImapFolder getSelectedFolder() throws ImapSessionClosedException { ImapListener i4selected = getCurrentImapListener(); return i4selected == null ? null : i4selected.getImapFolder(); } - void unsetSelectedFolder(boolean sendClosed) throws IOException { + protected void unsetSelectedFolder(boolean sendClosed) throws IOException { ImapListener i4selected = selectedFolderListener; selectedFolderListener = null; if (i4selected != null) { @@ -1093,7 +1173,8 @@ void unsetSelectedFolder(boolean sendClosed) throws IOException { } } - FolderDetails setSelectedFolder(ImapPath path, byte params) throws ServiceException, IOException { + protected FolderDetails setSelectedFolder(ImapPath path, byte params) + throws ServiceException, IOException { unsetSelectedFolder(true); if (path == null) { return new FolderDetails(null, null); @@ -1104,7 +1185,7 @@ FolderDetails setSelectedFolder(ImapPath path, byte params) throws ServiceExcept return selectdata; } - boolean canContinue(ServiceException e) { + protected boolean canContinue(ServiceException e) { String errCode = e.getCode(); if(errCode.equals(ServiceException.AUTH_EXPIRED)) { setCredentials(null); @@ -1113,7 +1194,7 @@ boolean canContinue(ServiceException e) { return e.getCode().equals(MailServiceException.MAINTENANCE) || e.getCode().equals(ServiceException.TEMPORARILY_UNAVAILABLE) ? false : true; } - OperationContext getContext() throws ServiceException { + protected OperationContext getContext() throws ServiceException { if (!isAuthenticated()) { throw ServiceException.AUTH_REQUIRED(); } @@ -1122,7 +1203,7 @@ OperationContext getContext() throws ServiceException { return oc; } - OperationContext getContextOrNull() { + protected OperationContext getContextOrNull() { try { return getContext(); } catch (ServiceException e) { @@ -1130,19 +1211,12 @@ OperationContext getContextOrNull() { } } - boolean doCAPABILITY(String tag) throws IOException { + private boolean doCAPABILITY(String tag) throws IOException { sendUntagged(getCapabilityString()); sendOK(tag, "CAPABILITY completed"); return true; } - private static final Set SUPPORTED_EXTENSIONS = new LinkedHashSet(Arrays.asList( - "ACL", "BINARY", "CATENATE", "CHILDREN", "CONDSTORE", "ENABLE", "ESEARCH", "ESORT", - "I18NLEVEL=1", "ID", "IDLE", "LIST-EXTENDED", "LIST-STATUS", "LITERAL+", "LOGIN-REFERRALS", - "MULTIAPPEND", "NAMESPACE", "QRESYNC", "QUOTA", "RIGHTS=ektx", "SASL-IR", "SEARCHRES", - "SORT", "THREAD=ORDEREDSUBJECT", "UIDPLUS", "UNSELECT", "WITHIN", "XLIST" - )); - protected String getCapabilityString() { // [IMAP4rev1] RFC 3501: Internet Message Access Protocol - Version 4rev1 // [LOGINDISABLED] RFC 3501: Internet Message Access Protocol - Version 4rev1 @@ -1204,7 +1278,7 @@ protected String getCapabilityString() { return capability.toString(); } - boolean extensionEnabled(String extension) { + protected boolean extensionEnabled(String extension) { if (config.isCapabilityDisabled(extension)) { // check whether the extension is explicitly disabled on the server return false; @@ -1232,7 +1306,7 @@ private boolean mechanismEnabled(String mechanism) { return extensionEnabled("AUTH=" + mechanism); } - boolean doNOOP(String tag) throws IOException { + private boolean doNOOP(String tag) throws IOException { ImapListener i4selected = getCurrentImapListener(); if(i4selected != null) { MailboxStore mbox = i4selected.getMailbox(); @@ -1254,7 +1328,7 @@ boolean doNOOP(String tag) throws IOException { // RFC 2971 3: "The sole purpose of the ID extension is to enable clients and servers // to exchange information on their implementations for the purposes of // statistical analysis and problem determination." - boolean doID(String tag, Map fields) throws IOException { + private boolean doID(String tag, Map fields) throws IOException { setIDFields(fields); sendNotifications(true, false); if (isAuthenticated()) { @@ -1331,7 +1405,7 @@ private void setIDFields(Map paramFields) { ZimbraLog.imap.debug("IMAP client identified as: %s", fields); } - String getNextVia() { + protected String getNextVia() { StringBuilder result = new StringBuilder(); if (via != null) { result.append(via).append(','); @@ -1343,7 +1417,7 @@ String getNextVia() { return result.toString(); } - boolean doENABLE(String tag, List extensions) throws IOException { + private boolean doENABLE(String tag, List extensions) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } @@ -1383,7 +1457,7 @@ boolean doENABLE(String tag, List extensions) throws IOException { return true; } - void activateExtension(ImapExtension ext) { + protected void activateExtension(ImapExtension ext) { if (ext == null) { return; } @@ -1393,11 +1467,11 @@ void activateExtension(ImapExtension ext) { activeExtensions.add(ext); } - boolean sessionActivated(ImapExtension ext) { + protected boolean sessionActivated(ImapExtension ext) { return activeExtensions != null && activeExtensions.contains(ext); } - boolean doLOGOUT(String tag) throws IOException { + private boolean doLOGOUT(String tag) throws IOException { sendBYE(); sendOK(tag, "LOGOUT completed"); return false; @@ -1410,7 +1484,8 @@ private boolean checkZimbraAdminAuth() { } - boolean doFLUSHCACHE(String tag, List types, List entries) throws IOException { + private boolean doFLUSHCACHE(String tag, List types, List entries) + throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } else if (!checkZimbraAdminAuth()) { @@ -1449,7 +1524,7 @@ boolean doFLUSHCACHE(String tag, List types, List mailboxNames, byte selectOptions, byte returnOptions, - byte status) throws ImapException, IOException { + private boolean doLIST(String tag, String referenceName, Set mailboxNames, + byte selectOptions, byte returnOptions, byte status) throws ImapException, IOException { checkCommandThrottle(new ListCommand(referenceName, mailboxNames, selectOptions, returnOptions, status)); if (!checkState(tag, State.AUTHENTICATED)) { return true; @@ -2161,15 +2232,6 @@ boolean doLIST(String tag, String referenceName, Set mailboxNames, byte return true; } - private static final boolean[] REGEXP_ESCAPED = new boolean[128]; - static { - REGEXP_ESCAPED['('] = REGEXP_ESCAPED[')'] = REGEXP_ESCAPED['.'] = true; - REGEXP_ESCAPED['['] = REGEXP_ESCAPED[']'] = REGEXP_ESCAPED['|'] = true; - REGEXP_ESCAPED['^'] = REGEXP_ESCAPED['$'] = REGEXP_ESCAPED['?'] = true; - REGEXP_ESCAPED['{'] = REGEXP_ESCAPED['}'] = REGEXP_ESCAPED['*'] = true; - REGEXP_ESCAPED['\\'] = true; - } - private static Pair resolvePath(String referenceName, String mailboxName) { int startWildcards = referenceName.length(); String resolved = mailboxName; @@ -2218,11 +2280,9 @@ private void accumulatePaths(ImapMailboxStore imapStore, String owner, ImapPath boolean isMailFolders = Provisioning.getInstance().getLocalServer().isImapDisplayMailFoldersOnly(); for (FolderStore folderStore : visibleFolders) { //bug 6418 ..filter out folders which are contacts and chat for LIST command. - if(isMailFolders) { - // chat has item type of message. hence ignoring the chat folder by name. - if (folderStore.isChatsFolder() || (folderStore.getName().equals ("Chats"))) { - continue; - } + // chat has item type of message. hence ignoring the chat folder by name. + if (isMailFolders && (folderStore.isChatsFolder() || (folderStore.getName().equals ("Chats")))) { + continue; } ImapPath path = relativeTo == null ? new ImapPath(owner, folderStore, credentials) : new ImapPath(owner, folderStore, relativeTo); @@ -2336,7 +2396,7 @@ private String getFolderAttrs(ImapPath path, byte returnOptions, Map subscriptions) throws ServiceException { if (path.belongsTo(credentials)) { - FolderStore folderStore = path.getFolder();; + FolderStore folderStore = path.getFolder(); if (folderStore != null) { return folderStore.isIMAPSubscribed(); } else { @@ -2352,7 +2412,8 @@ private boolean isPathSubscribed(ImapPath path, Set subscriptions) throw return false; } - boolean doLSUB(String tag, String referenceName, String mailboxName) throws ImapException, IOException { + private boolean doLSUB(String tag, String referenceName, String mailboxName) + throws ImapException, IOException { checkCommandThrottle(new LsubCommand(referenceName, mailboxName)); if (!checkState(tag, State.AUTHENTICATED)) { return true; @@ -2510,7 +2571,7 @@ private void checkSubscription(SubscribedImapPath path, Pattern pattern, Pattern path.addUnsubsribedMatchingParents(pattern, hits); } - boolean doSTATUS(String tag, ImapPath path, StatusDataItemNames dataItemNames) + private boolean doSTATUS(String tag, ImapPath path, StatusDataItemNames dataItemNames) throws ImapException, IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; @@ -2547,11 +2608,16 @@ boolean doSTATUS(String tag, ImapPath path, StatusDataItemNames dataItemNames) return true; } - String status(ImapPath path, byte status) throws ImapException, ServiceException { + private String status(ImapPath path, byte status) throws ImapException, ServiceException { StringBuilder data = new StringBuilder("STATUS ").append(path.asUtf7String()).append(" ("); int empty = data.length(); - int messages, recent, uidnext, uvv, unread, modseq; + int messages; + int recent; + int uidnext; + int uvv; + int unread; + int modseq; MailboxStore mboxStore = path.getOwnerMailbox(); if (mboxStore != null) { FolderStore folder = path.getFolder(); @@ -2605,7 +2671,8 @@ String status(ImapPath path, byte status) throws ImapException, ServiceException return data.append(')').toString(); } - boolean doAPPEND(String tag, ImapPath path, List appends) throws IOException, ImapException { + private boolean doAPPEND(String tag, ImapPath path, List appends) + throws IOException, ImapException { checkCommandThrottle(new AppendCommand(path, appends)); if (!checkState(tag, State.AUTHENTICATED)) { return true; @@ -2692,16 +2759,13 @@ private void deleteTags(List ltags) { } } - static final boolean IDLE_START = true; - static final boolean IDLE_STOP = false; - // RFC 2177 3: "The IDLE command is sent from the client to the server when the client is // ready to accept unsolicited mailbox update messages. The server requests // a response to the IDLE command using the continuation ("+") response. The // IDLE command remains active until the client responds to the continuation, // and as long as an IDLE command is active, the server is now free to send // untagged EXISTS, EXPUNGE, and other messages at any time." - boolean doIDLE(String tag, boolean begin, boolean success, ImapRequest req) throws IOException { + private boolean doIDLE(String tag, boolean begin, boolean success, ImapRequest req) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) return true; @@ -2729,7 +2793,7 @@ boolean doIDLE(String tag, boolean begin, boolean success, ImapRequest req) thro return true; } - boolean doSETQUOTA(String tag) throws IOException { + private boolean doSETQUOTA(String tag) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } @@ -2738,7 +2802,7 @@ boolean doSETQUOTA(String tag) throws IOException { return true; } - boolean doGETQUOTA(String tag, ImapPath qroot) throws IOException { + private boolean doGETQUOTA(String tag, ImapPath qroot) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) return true; @@ -2768,7 +2832,7 @@ boolean doGETQUOTA(String tag, ImapPath qroot) throws IOException { return true; } - boolean doGETQUOTAROOT(String tag, ImapPath qroot) throws IOException { + private boolean doGETQUOTAROOT(String tag, ImapPath qroot) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) return true; @@ -2807,7 +2871,7 @@ boolean doGETQUOTAROOT(String tag, ImapPath qroot) throws IOException { return true; } - boolean doNAMESPACE(String tag) throws IOException { + private boolean doNAMESPACE(String tag) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } @@ -2817,12 +2881,6 @@ boolean doNAMESPACE(String tag) throws IOException { return true; } - private static final String IMAP_READ_RIGHTS = "lr"; - private static final String IMAP_WRITE_RIGHTS = "sw"; - private static final String IMAP_INSERT_RIGHTS = "ick"; - private static final String IMAP_DELETE_RIGHTS = "xted"; - private static final String IMAP_ADMIN_RIGHTS = "a"; - // Returns whether all of a set of linked RFC 4314 rights is contained within a string. private boolean allRightsPresent(final String i4rights, final String linked) { for (int i = 0; i < linked.length(); i++) { @@ -2842,10 +2900,10 @@ public GranteeIdAndType(String granteeId, byte typ) { } } - GranteeIdAndType getPrincipalGranteeInfo(String principal) throws ServiceException { + private GranteeIdAndType getPrincipalGranteeInfo(String principal) throws ServiceException { String granteeId = null; byte granteeType = ACL.GRANTEE_AUTHUSER; - if (principal.equals("anyone")) { + if ("anyone".equals(principal)) { granteeId = GuestAccount.GUID_AUTHUSER; granteeType = ACL.GRANTEE_AUTHUSER; } else { @@ -2862,7 +2920,8 @@ GranteeIdAndType getPrincipalGranteeInfo(String principal) throws ServiceExcepti return new GranteeIdAndType(granteeId, granteeType); } - boolean doSETACL(String tag, ImapPath path, String principal, String i4rights, StoreAction action) throws IOException { + private boolean doSETACL(String tag, ImapPath path, String principal, String i4rights, + StoreAction action) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) return true; @@ -2965,7 +3024,7 @@ boolean doSETACL(String tag, ImapPath path, String principal, String i4rights, S return true; } - boolean doDELETEACL(String tag, ImapPath path, String principal) throws IOException { + private boolean doDELETEACL(String tag, ImapPath path, String principal) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } @@ -3016,7 +3075,7 @@ boolean doDELETEACL(String tag, ImapPath path, String principal) throws IOExcept return true; } - boolean doGETACL(String tag, ImapPath path) throws IOException { + private boolean doGETACL(String tag, ImapPath path) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } @@ -3074,9 +3133,6 @@ boolean doGETACL(String tag, ImapPath path) throws IOException { return true; } - /* The set of rights required to create a new subfolder in ZCS. */ - private final short SUBFOLDER_RIGHTS = ACL.RIGHT_INSERT | ACL.RIGHT_READ; - /* Converts a Zimbra rights bitmask to an RFC 4314-compatible rights string */ private String exportRights(short rights) { StringBuilder imapRights = new StringBuilder(12); @@ -3101,21 +3157,13 @@ private String exportRights(short rights) { return imapRights.length() == 0 ? "\"\"" : imapRights.toString(); } - /* All the supported IMAP rights, concatenated together into a single string. */ - private static final String IMAP_CONCATENATED_RIGHTS = IMAP_READ_RIGHTS + IMAP_WRITE_RIGHTS + IMAP_INSERT_RIGHTS + - IMAP_DELETE_RIGHTS + IMAP_ADMIN_RIGHTS; - /* All the supported IMAP rights, with linked sets of rights - * grouped together and the groups delimited by spaces. */ - private static final String IMAP_DELIMITED_RIGHTS = IMAP_READ_RIGHTS + ' ' + IMAP_WRITE_RIGHTS + ' ' + - IMAP_INSERT_RIGHTS + ' ' + IMAP_DELETE_RIGHTS + ' ' + IMAP_ADMIN_RIGHTS; - - boolean doLISTRIGHTS(String tag, ImapPath path, String principal) throws IOException { + private boolean doLISTRIGHTS(String tag, ImapPath path, String principal) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } boolean isOwner = false; try { - if (!principal.equals("anyone")) { + if (!"anyone".equals(principal)) { Account acct = Provisioning.getInstance().get(Key.AccountBy.name, principal); if (acct == null) { throw AccountServiceException.NO_SUCH_ACCOUNT(principal); @@ -3150,7 +3198,7 @@ boolean doLISTRIGHTS(String tag, ImapPath path, String principal) throws IOExcep return true; } - boolean doMYRIGHTS(String tag, ImapPath path) throws IOException { + private boolean doMYRIGHTS(String tag, ImapPath path) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { return true; } @@ -3180,7 +3228,7 @@ boolean doMYRIGHTS(String tag, ImapPath path) throws IOException { return true; } - boolean doCHECK(String tag) throws IOException { + private boolean doCHECK(String tag) throws IOException { if (!checkState(tag, State.SELECTED)) { return true; } @@ -3189,7 +3237,7 @@ boolean doCHECK(String tag) throws IOException { return true; } - boolean doCLOSE(String tag) throws IOException, ImapException { + private boolean doCLOSE(String tag) throws IOException, ImapException { if (!checkState(tag, State.SELECTED)) { return true; } @@ -3239,7 +3287,7 @@ boolean doCLOSE(String tag) throws IOException, ImapException { // mailbox and returns the server to the authenticated state. This command // performs the same actions as CLOSE, except that no messages are permanently // removed from the currently selected mailbox." - boolean doUNSELECT(String tag) throws IOException { + private boolean doUNSELECT(String tag) throws IOException { if (!checkState(tag, State.SELECTED)) { return true; } @@ -3249,9 +3297,8 @@ boolean doUNSELECT(String tag) throws IOException { return true; } - private final int SUGGESTED_DELETE_BATCH_SIZE = 30; - - boolean doEXPUNGE(String tag, boolean byUID, String sequenceSet) throws IOException, ImapException { + private boolean doEXPUNGE(String tag, boolean byUID, String sequenceSet) + throws IOException, ImapException { if (!checkState(tag, State.SELECTED)) { return true; } @@ -3305,11 +3352,10 @@ private boolean expungeMessages(String tag, ImapFolder i4folder, String sequence MailboxStore selectedMailbox = selectedFolderListener.getMailbox(); for (int i = 1, max = i4folder.getSize(); i <= max; i++) { ImapMessage i4msg = i4folder.getBySequence(i); - if (i4msg != null && !i4msg.isExpunged() && (i4msg.flags & Flag.BITMASK_DELETED) > 0) { - if (i4set == null || i4set.contains(i4msg)) { + if ( (i4msg != null && !i4msg.isExpunged() && (i4msg.flags & Flag.BITMASK_DELETED) > 0) && + (i4set == null || i4set.contains(i4msg))) { ids.add(i4msg.msgId); changed = true; - } } if (ids.size() >= (i == max ? 1 : SUGGESTED_DELETE_BATCH_SIZE)) { @@ -3339,29 +3385,20 @@ private boolean expungeMessages(String tag, ImapFolder i4folder, String sequence return changed; } - private static final int RETURN_MIN = 0x01; - private static final int RETURN_MAX = 0x02; - private static final int RETURN_ALL = 0x04; - private static final int RETURN_COUNT = 0x08; - private static final int RETURN_SAVE = 0x10; - - private static final int LARGEST_FOLDER_BATCH = 600; - public static final Set ITEM_TYPES = ImapMessage.SUPPORTED_TYPES; - - boolean doSEARCH(String tag, ImapSearch i4search, boolean byUID, Integer options) + protected boolean doSEARCH(String tag, ImapSearch i4search, boolean byUID, Integer options) throws IOException, ImapException { checkCommandThrottle(new SearchCommand(i4search, options)); return search(tag, "SEARCH", i4search, byUID, options, null); } - boolean doSORT(String tag, ImapSearch i4search, boolean byUID, Integer options, List order) - throws IOException, ImapException { + private boolean doSORT(String tag, ImapSearch i4search, boolean byUID, Integer options, + List order) throws IOException, ImapException { checkCommandThrottle(new SortCommand(i4search, options)); return search(tag, "SORT", i4search, byUID, options, order); } - boolean search(String tag, String command, ImapSearch i4search, boolean byUID, Integer options, List order) - throws IOException, ImapException { + private boolean search(String tag, String command, ImapSearch i4search, boolean byUID, Integer options, + List order) throws IOException, ImapException { if (!checkState(tag, State.SELECTED)) { return true; } @@ -3439,7 +3476,8 @@ boolean search(String tag, String command, ImapSearch i4search, boolean byUID, I } int size = hits.size(); - ImapMessage first = null, last = null; + ImapMessage first = null; + ImapMessage last = null; if (size != 0 && options != null && (options & (RETURN_MIN | RETURN_MAX)) != 0) { if (unsorted) { first = ((ImapMessageSet) hits).first(); @@ -3544,7 +3582,8 @@ private ZimbraQueryHitResults runSearch(ImapSearch i4search, ImapFolder i4folder return mbox.searchImap(getContext(), params); } - boolean doTHREAD(String tag, ImapSearch i4search, boolean byUID) throws IOException, ImapException { + private boolean doTHREAD(String tag, ImapSearch i4search, boolean byUID) + throws IOException, ImapException { if (!checkState(tag, State.SELECTED)) { return true; } @@ -3629,39 +3668,20 @@ boolean doTHREAD(String tag, ImapSearch i4search, boolean byUID) throws IOExcept return true; } - static final int FETCH_BODY = 0x0001; - static final int FETCH_BODYSTRUCTURE = 0x0002; - static final int FETCH_ENVELOPE = 0x0004; - static final int FETCH_FLAGS = 0x0008; - static final int FETCH_INTERNALDATE = 0x0010; - static final int FETCH_RFC822_SIZE = 0x0020; - static final int FETCH_BINARY_SIZE = 0x0040; - static final int FETCH_UID = 0x0080; - static final int FETCH_MODSEQ = 0x0100; - static final int FETCH_VANISHED = 0x0200; - static final int FETCH_MARK_READ = 0x1000; - - static final int FETCH_FROM_CACHE = FETCH_FLAGS | FETCH_UID; - static final int FETCH_FROM_MIME = FETCH_BODY | FETCH_BODYSTRUCTURE | FETCH_ENVELOPE; - - static final int FETCH_FAST = FETCH_FLAGS | FETCH_INTERNALDATE | FETCH_RFC822_SIZE; - static final int FETCH_ALL = FETCH_FAST | FETCH_ENVELOPE; - static final int FETCH_FULL = FETCH_ALL | FETCH_BODY; - - boolean doFETCH(String tag, String sequenceSet, int attributes, List parts, boolean byUID, - int changedSince) throws IOException, ImapException { + protected boolean doFETCH(String tag, String sequenceSet, int attributes, List parts, + boolean byUID, int changedSince) throws IOException, ImapException { checkCommandThrottle(new FetchCommand(sequenceSet, attributes, parts)); return fetch(tag, sequenceSet, attributes, parts, byUID, changedSince, true); } - boolean fetch(String tag, String sequenceSet, int attributes, List parts, boolean byUID, - int changedSince, boolean standalone) throws IOException, ImapException { + private boolean fetch(String tag, String sequenceSet, int attributes, List parts, + boolean byUID, int changedSince, boolean standalone) throws IOException, ImapException { return fetch(tag, sequenceSet, attributes, parts, byUID, changedSince, standalone, false /* allowOutOfRangeMsgSeq */); } - boolean fetch(String tag, String sequenceSet, int attributes, List parts, boolean byUID, - int changedSince, boolean standalone, boolean allowOutOfRangeMsgSeq) + private boolean fetch(String tag, String sequenceSet, int attributes, List parts, + boolean byUID, int changedSince, boolean standalone, boolean allowOutOfRangeMsgSeq) throws IOException, ImapException { if (!checkState(tag, State.SELECTED)) { return true; @@ -3995,7 +4015,7 @@ private void fetchStub(ImapMessage i4msg, ImapFolder i4folder, int attributes, L for (ImapPartSpecifier pspec : parts) { // pretending that all messages have 1 text part means we should return NIL for other FETCHes String pnum = pspec.getSectionPart(); - String value = (pnum.equals("") || pnum.equals("1")) ? (pspec.getCommand().equals("BINARY.SIZE") ? "0" : "\"\"") : "NIL"; + String value = ("".equals(pnum) || "1".equals(pnum)) ? (pspec.getCommand().equals("BINARY.SIZE") ? "0" : "\"\"") : "NIL"; result.print((empty ? "" : " ") + pspec + ' ' + value); empty = false; } } @@ -4013,11 +4033,7 @@ private void fetchStub(ImapMessage i4msg, ImapFolder i4folder, int attributes, L i4folder.undirtyMessage(i4msg); } - enum StoreAction { REPLACE, ADD, REMOVE } - - private final int SUGGESTED_BATCH_SIZE = 100; - - boolean doSTORE(String tag, String sequenceSet, List flagNames, StoreAction operation, boolean silent, + private boolean doSTORE(String tag, String sequenceSet, List flagNames, StoreAction operation, boolean silent, int modseq, boolean byUID) throws IOException, ImapException { checkCommandThrottle(new StoreCommand(sequenceSet, flagNames, operation, modseq)); if (!checkState(tag, State.SELECTED)) { @@ -4083,10 +4099,9 @@ boolean doSTORE(String tag, String sequenceSet, List flagNames, StoreAct if (!i4folder.getPath().isWritable(ACL.RIGHT_DELETE)) { throw ServiceException.PERM_DENIED("you do not have permission to set the \\Deleted flag"); } - } else if (i4flag.mPermanent) { - if (!i4folder.getPath().isWritable(ACL.RIGHT_WRITE)) { - throw ServiceException.PERM_DENIED("you do not have permission to set the " + i4flag.mName + " flag"); - } + } else if (i4flag.mPermanent && (!i4folder.getPath().isWritable(ACL.RIGHT_WRITE))) { + throw ServiceException.PERM_DENIED( + "you do not have permission to set the " + i4flag.mName + " flag"); } } } @@ -4234,12 +4249,11 @@ boolean doSTORE(String tag, String sequenceSet, List flagNames, StoreAct return true; } - private final int SUGGESTED_COPY_BATCH_SIZE = 50; - /** * @param path of target folder */ - boolean doCOPY(String tag, String sequenceSet, ImapPath path, boolean byUID) throws IOException, ImapException { + protected boolean doCOPY(String tag, String sequenceSet, ImapPath path, boolean byUID) + throws IOException, ImapException { checkCommandThrottle(new CopyCommand(sequenceSet, path)); if (!checkState(tag, State.SELECTED)) { return true; @@ -4518,57 +4532,57 @@ public void sendNotifications(boolean notifyExpunges, boolean flush) throws IOEx } } - void sendIdleUntagged() throws IOException { + protected void sendIdleUntagged() throws IOException { sendUntagged("NOOP", true); } - void sendOK(String tag, String response) throws IOException { + protected void sendOK(String tag, String response) throws IOException { consecutiveError = 0; sendResponse(tag, "OK " + (Strings.isNullOrEmpty(response) ? " " : response), true); } - void sendNO(String tag, String responsePattern, Object... args) throws IOException { + protected void sendNO(String tag, String responsePattern, Object... args) throws IOException { sendNO(tag, String.format(responsePattern, args)); } - void sendNO(String tag, String response) throws IOException { + protected void sendNO(String tag, String response) throws IOException { consecutiveError++; sendResponse(tag, "NO " + (Strings.isNullOrEmpty(response) ? " " : response), true); } //Bug 97697 - Move imap "BAD parse error" to debug level logging versus warn. - void sendBAD(String tag, String response) throws IOException { + protected void sendBAD(String tag, String response) throws IOException { consecutiveError++; ZimbraLog.imap.debug("BAD %s", response); sendResponse(tag, "BAD " + (Strings.isNullOrEmpty(response) ? " " : response), true); } - void sendBAD(String response) throws IOException { + protected void sendBAD(String response) throws IOException { consecutiveError++; ZimbraLog.imap.debug("BAD %s", response); sendResponse("*", "BAD " + (Strings.isNullOrEmpty(response) ? " " : response), true); } - void sendUntagged(String response) throws IOException { + protected void sendUntagged(String response) throws IOException { sendResponse("*", response, false); } - void sendUntagged(String response, boolean flush) throws IOException { + protected void sendUntagged(String response, boolean flush) throws IOException { sendResponse("*", response, flush); } - void sendContinuation(String response) throws IOException { + protected void sendContinuation(String response) throws IOException { sendResponse("+", response, true); } - void sendGreeting() throws IOException { + protected void sendGreeting() throws IOException { sendUntagged("OK " + config.getGreeting(), true); } - void sendBYE() { + protected void sendBYE() { sendBYE(config.getGoodbye()); } - void sendBYE(String msg) { + protected void sendBYE(String msg) { try { sendUntagged("BYE " + msg, true); } catch (IOException e) { From f5d0b564ddfc6c61bd2ce5bffde1014f4ab7db43 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 4 Sep 2017 18:38:38 +0100 Subject: [PATCH 012/142] ZCS-2344:SaveIMAPSubscriptionsRequest avoid null Previous code was throwing an NPE although I'm not 100% clear why --- .../zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java b/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java index 838d9e95a0c..837eae94f1d 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/SaveIMAPSubscriptionsRequest.java @@ -26,7 +26,8 @@ public class SaveIMAPSubscriptionsRequest { public Set getSubscriptions() { if (subscriptions == null) { - return Collections.unmodifiableSet(Sets.newHashSet()); + Set empty = Collections.emptySet(); + return empty; } return Collections.unmodifiableSet(subscriptions); } From 39ae3a380cbb0166251d1e7105147ad3635f7b42 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 4 Sep 2017 18:40:55 +0100 Subject: [PATCH 013/142] ZCS-2344:ImapRemoteSession unregister NPEs Was getting logs of NPEs because no listener was found for account by `unregisterFromRemoteServer()`. Preserved some logging in case we shouldn't be calling it under those circumstances. --- .../com/zimbra/cs/imap/ImapRemoteSession.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapRemoteSession.java b/store/src/java/com/zimbra/cs/imap/ImapRemoteSession.java index 45db14b704c..10054a74ed3 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapRemoteSession.java +++ b/store/src/java/com/zimbra/cs/imap/ImapRemoteSession.java @@ -21,6 +21,7 @@ import com.zimbra.client.ZMailbox; import com.zimbra.common.mailbox.BaseItemInfo; import com.zimbra.common.mailbox.MailItemType; +import com.zimbra.common.mailbox.MailboxStore; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.session.PendingModifications; @@ -92,7 +93,22 @@ protected boolean isRegisteredInCache() { private void unregisterFromRemoteServer() { try { - ImapServerListenerPool.getInstance().getForAccountId(mailbox.getAccountId()).removeListener(this); + MailboxStore mbs = mailbox; + if (mbs == null) { + ZimbraLog.imap.info( + "ImapRemoteSession.unregisterFromRemoteServer called but mailbox=null - %s\n%s", + this, ZimbraLog.getStackTrace(5)); + return; + } + ImapServerListener listener = + ImapServerListenerPool.getInstance().getForAccountId(mbs.getAccountId()); + if (listener == null) { + ZimbraLog.imap.info( + "ImapRemoteSession.unregisterFromRemoteServer called but listener=null - %s\n%s", + this, ZimbraLog.getStackTrace(5)); + return; + } + listener.removeListener(this); } catch (ServiceException e) { ZimbraLog.imap.error(e); } From 2abb0be09bc27f02df687e89b44ec47f96505d40 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 6 Sep 2017 13:49:15 +0100 Subject: [PATCH 014/142] ImapProxy PMD/Codacity suggestions --- .../java/com/zimbra/cs/imap/ImapProxy.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapProxy.java b/store/src/java/com/zimbra/cs/imap/ImapProxy.java index ec765606132..c9497475769 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapProxy.java +++ b/store/src/java/com/zimbra/cs/imap/ImapProxy.java @@ -56,7 +56,7 @@ public final class ImapProxy { private ImapConnection connection; private Thread idleThread; - ImapProxy(final ImapHandler handler, final ImapPath path) throws ServiceException { + protected ImapProxy(final ImapHandler handler, final ImapPath path) throws ServiceException { this.handler = handler; this.path = path; @@ -108,7 +108,7 @@ public final class ImapProxy { /** * For testing. */ - ImapProxy(InetSocketAddress remote, String username, String password, ImapHandler handler) + protected ImapProxy(InetSocketAddress remote, String username, String password, ImapHandler handler) throws IOException, LoginException { this.handler = handler; path = null; @@ -135,11 +135,11 @@ private IDInfo createIDInfo(ImapHandler handler) { return id; } - ImapPath getPath() { + protected ImapPath getPath() { return path; } - void dropConnection() { + protected void dropConnection() { ImapConnection conn = connection; connection = null; if (conn == null) @@ -158,7 +158,7 @@ void dropConnection() { * @return whether the SELECT was successful (i.e. it returned a tagged {@code OK} response) * @throws ImapProxyException network error with the remote IMAP server */ - boolean select(final String tag, final byte params, final QResyncInfo qri) + protected boolean select(final String tag, final byte params, final QResyncInfo qri) throws ImapProxyException, ServiceException { // FIXME: may need to send an ENABLE before the SELECT @@ -188,7 +188,7 @@ boolean select(final String tag, final byte params, final QResyncInfo qri) * Proxy STATUS command. * @param params - e.g. "(EXISTS RECENT)" */ - boolean status(final String tag, final String params) + protected boolean status(final String tag, final String params) throws ImapProxyException, ServiceException { String command = "STATUS"; StringBuilder select = new StringBuilder(100); @@ -208,7 +208,7 @@ boolean status(final String tag, final String params) * @throws ImapProxyException network error with the remote IMAP server * @throws IOException error on reading the request data */ - boolean idle(final ImapRequest req, final boolean begin) throws ImapProxyException, IOException { + protected boolean idle(final ImapRequest req, final boolean begin) throws ImapProxyException, IOException { if (begin == ImapHandler.IDLE_STOP) { // check state -- don't want to send DONE if we're somehow not in IDLE if (handler == null) { @@ -273,7 +273,7 @@ public void run() { * @throws ImapProxyException network error with the remote IMAP server * @throws IOException error on reading the request data */ - boolean proxy(final ImapRequest req) throws ImapProxyException, IOException { + protected boolean proxy(final ImapRequest req) throws ImapProxyException, IOException { proxyCommand(req.toByteArray(), true, false); return true; } @@ -286,7 +286,7 @@ boolean proxy(final ImapRequest req) throws ImapProxyException, IOException { * @return always true * @throws ImapProxyException network error with the remote IMAP server */ - boolean proxy(final String tag, final String command) throws ImapProxyException { + protected boolean proxy(final String tag, final String command) throws ImapProxyException { proxyCommand((tag + ' ' + command + "\r\n").getBytes(), true, false); return true; } @@ -296,7 +296,7 @@ boolean proxy(final String tag, final String command) throws ImapProxyException * * @throws ImapProxyException network error with the remote IMAP server */ - void fetchNotifications() throws ImapProxyException { + protected void fetchNotifications() throws ImapProxyException { String tag = connection == null ? "1" : connection.newTag(); proxyCommand((tag + " NOOP\r\n").getBytes(), false, false); } @@ -345,8 +345,12 @@ private boolean proxyCommand(byte[] payload, boolean includeTaggedResponse, bool StringBuilder debug = proxy && ZimbraLog.imap.isDebugEnabled() ? new StringBuilder(" pxy: ") : null; StringBuilder condition = new StringBuilder(10); - boolean quoted = false, escaped = false, space1 = false, space2 = false; - int c, literal = -1; + boolean quoted = false; + boolean escaped = false; + boolean space1 = false; + boolean space2 = false; + int c; + int literal = -1; while ((c = min.read()) != -1) { // check for success and also determine whether we should be paying attention to structure if (!space2) { @@ -432,7 +436,6 @@ else if (literal != -1 && c >= '0' && c <= '9') return success; } - public static final class ZimbraClientAuthenticator extends Authenticator { private String username, authtoken; private boolean complete; From 8db0a3d7996ce3738aab510db8391bcc74646b3d Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 6 Sep 2017 15:30:56 +0100 Subject: [PATCH 015/142] ZCS-2344:ImapTestBase.doLSubShouldSucceed and '/' After some research, determined that the '/' at the start of mailboxes in the "/home" namespace SHOULD be there - it comes from the "/home" prefix. The prefix for the personal namespace is "", so the mailbox names should not be prefixed with '/' --- .../com/zimbra/qa/unittest/ImapTestBase.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java index 9a04da3d4df..3bb0a01a7c4 100644 --- a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java +++ b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java @@ -357,6 +357,32 @@ protected List doListShouldSucceed(ImapConnection conn, String ref, St } } + /** + * Note, due to a slightly strange quirk, the expectedMboxNames should be prefixed '/' in the case + * where the mailboxes are in the Other Users' Namespace (i.e. start with "/home/"), otherwise, they + * should not have the '/' prefix. The "/" in that case comes from the Namespace prefix and NOT + * from the mailbox name. + * + * For another way of looking at it, it is worth comparing NAMESPACE and LIST command output from + * https://tools.ietf.org/html/rfc2342 - IMAP4 Namespace: + * C: A001 NAMESPACE + * S: * NAMESPACE (("" "/")) (("#Users/" "/")) NIL + * S: A001 OK NAMESPACE command completed + * C: A002 LIST "" "#Users/Mike/%" + * S: * LIST () "/" "#Users/Mike/INBOX" + * S: * LIST () "/" "#Users/Mike/Foo" + * S: A002 OK LIST command completed. + * + * with the Zimbra equivalent: + * + * C: ZIMBRA01 NAMESPACE + * S: * NAMESPACE (("" "/")) (("/home/" "/")) NIL + * S: ZIMBRA01 OK NAMESPACE completed + * C: ZIMBRA02 LIST "" "/home/other-user/*" + * S: * LIST (\HasChildren) "/" "/home/other-user/INBOX/shared" + * S: * LIST (\HasNoChildren) "/" "/home/other-user/INBOX/shared/subFolder" + * S: ZIMBRA02 OK LIST completed + */ protected List doLSubShouldSucceed(ImapConnection conn, String ref, String mailbox, List expectedMboxNames, String testDesc) throws IOException { @@ -367,22 +393,8 @@ protected List doLSubShouldSucceed(ImapConnection conn, String ref, St assertEquals(String.format( "%s:Number of entries in list returned for %s\n%s", testDesc, cmdDesc, listResult), expectedMboxNames.size(), listResult.size()); for (String mbox : expectedMboxNames) { - if (!listContains(listResult, mbox)) { - /* TODO we seem to include "/" at the start sometime and sometimes not. Investigate whether - * that is OK? - * e.g. Seen: - * C06 LSUB "" "*" - * * LSUB () "/" "INBOX" - * C07 OK LSUB completed - * and - * C07 LSUB "" "/home/user/*" - * * LSUB () "/" "/home/user/INBOX/shared" - * C07 OK LSUB completed - */ - String tMbox = (mbox.startsWith("/")) ? mbox.substring(1) : mbox; - assertTrue(String.format("%s:'%s' NOT in list returned by %s\n%s", - testDesc, mbox, cmdDesc, listResult), listContains(listResult, tMbox)); - } + assertTrue(String.format("%s:'%s' NOT in list returned by %s\n%s", + testDesc, mbox, cmdDesc, listResult), listContains(listResult, mbox)); } return listResult; } catch (CommandFailedException cfe) { From 075a74b8d9fa1dde0d5f574b3c57cf9bc4b7d6cc Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 6 Sep 2017 15:33:45 +0100 Subject: [PATCH 016/142] ZCS-2344:SharedImapTests correct mailbox names Use correct mailbox names when calling doLSubShouldSucceed. For mailboxes in the personal namespace, these should NOT start with '/' because the namespace prefix is "" but for the other users' namespace, the prefix is "/home/" so obviously the mailbox name must start with '/' --- .../zimbra/qa/unittest/SharedImapTests.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index 6792016b862..efadd10e05b 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -1376,15 +1376,17 @@ public void testSubscribeNested() throws IOException, ServiceException { TestUtil.getZMailbox(USER),Integer.toString(Mailbox.ID_FOLDER_INBOX), folderName); assertNotNull("Folder object from createFolder", folder); doLSubShouldSucceed(connection, "", "*", Lists.newArrayListWithExpectedSize(0), "before subscribe"); - doSubscribeShouldSucceed(connection, folder.getPath()); - doLSubShouldSucceed(connection, "", "*", Lists.newArrayList(folder.getPath()), "after subscribe"); + String imapMboxName = folder.getPath().substring(1); + doSubscribeShouldSucceed(connection, imapMboxName); + doLSubShouldSucceed(connection, "", "*", Lists.newArrayList(imapMboxName), "after subscribe"); } @Test(timeout=100000) public void testUnSubscribe() throws IOException, ServiceException { connection = connectAndSelectInbox(); String folderName = testId; - TestUtil.createFolder(TestUtil.getZMailbox(USER), folderName); + ZFolder folder = TestUtil.createFolder(TestUtil.getZMailbox(USER), folderName); + assertNotNull("Folder object from createFolder", folder); doLSubShouldSucceed(connection, "", "*", Lists.newArrayListWithExpectedSize(0), "before subscribe"); doSubscribeShouldSucceed(connection, folderName); doLSubShouldSucceed(connection, "", "*", Lists.newArrayList(folderName), "after subscribe"); @@ -1397,7 +1399,8 @@ public void homeNameSpaceSubscribe() throws ServiceException, IOException, Messa String sharedFolderName = String.format("INBOX/%s-shared", testId); String subFolder = sharedFolderName + "/subFolder"; ZMailbox userZmbox = TestUtil.getZMailbox(USER); - TestUtil.createFolder(userZmbox, "/" + sharedFolderName); + ZFolder folder = TestUtil.createFolder(userZmbox, "/" + sharedFolderName); + assertNotNull("Folder object from createFolder", folder); TestUtil.createFolder(userZmbox, "/" + subFolder); TestUtil.createAccount(SHAREE); connection = connectAndLogin(USER); @@ -1408,7 +1411,8 @@ public void homeNameSpaceSubscribe() throws ServiceException, IOException, Messa String underRemFolder = String.format("%s/subFolder", remFolder); String homePatt = String.format("/home/%s/*", USER); otherConnection = connectAndLogin(SHAREE); - doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayListWithExpectedSize(0), "before 1st subscribe"); + doLSubShouldSucceed(otherConnection, "", "*", + Lists.newArrayListWithExpectedSize(0), "before 1st subscribe"); doSubscribeShouldSucceed(otherConnection, "INBOX"); doSubscribeShouldSucceed(otherConnection, remFolder); doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX"), @@ -1434,16 +1438,18 @@ public void homeNameSpaceSubscribe() throws ServiceException, IOException, Messa public void mountpointSubscribe() throws ServiceException, IOException { TestUtil.createAccount(SHAREE); ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); + assertNotNull("Sharee ZMailbox", shareeZmbox); ZMailbox mbox = TestUtil.getZMailbox(USER); String remFolder = String.format("/INBOX/%s-shared", testId); String underRemFolder = String.format("%s/subFolder", remFolder); TestUtil.createFolder(mbox, remFolder); TestUtil.createFolder(mbox, underRemFolder); - String mp = String.format("/%s's %s-shared", USER, testId); + String mp = String.format("%s's %s-shared", USER, testId); String subMp = String.format("%s/subFolder", mp); - TestUtil.createMountpoint(mbox, remFolder, shareeZmbox, mp.substring(1)); + TestUtil.createMountpoint(mbox, remFolder, shareeZmbox, mp); otherConnection = connectAndLogin(SHAREE); - doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayListWithExpectedSize(0), "before 1st subscribe"); + doLSubShouldSucceed(otherConnection, "", "*", + Lists.newArrayListWithExpectedSize(0), "before 1st subscribe"); doSubscribeShouldSucceed(otherConnection, "INBOX"); doSubscribeShouldSucceed(otherConnection, mp); doLSubShouldSucceed(otherConnection, "", "*", Lists.newArrayList("INBOX", mp), From 4b49f3e360d2c02bbd10d7c5a7eba806db2284f8 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 7 Sep 2017 18:20:36 +0100 Subject: [PATCH 017/142] ZCS-2344:TestImapViaImapDaemon ImapConfigSettings Always call `restoreImapConfigSettings()` in `tearDown` Believe this is cause of sometimes getting `zimbraImapServerEnabled` set `FALSE` after run --- .../src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java b/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java index f7dc2160a7d..497d0eff064 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java +++ b/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java @@ -60,8 +60,8 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { super.sharedTearDown(); + restoreImapConfigSettings(); if (imapHostname != null) { - restoreImapConfigSettings(); TestUtil.flushImapDaemonCache(imapServer); getAdminConnection().reloadLocalConfig(); } From 53a60a8d89cfa8b3694b64fbb765fc1f435009b5 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 7 Sep 2017 18:34:47 +0100 Subject: [PATCH 018/142] ZCS-2344:ImapTestBase bad format/debugging * Fixed bad format string which didn't have enough %s in it. * Added debug cmds to log the save and restore of some settings --- .../src/java/com/zimbra/qa/unittest/ImapTestBase.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java index 3bb0a01a7c4..e8e4cd541f1 100644 --- a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java +++ b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java @@ -133,6 +133,10 @@ public static void saveImapConfigSettings() saved_imap_servers = imapServer.getReverseProxyUpstreamImapServers(); saved_imap_server_enabled = imapServer.isImapServerEnabled(); saved_imap_ssl_server_enabled = imapServer.isImapSSLServerEnabled(); + ZimbraLog.test.debug("Saved ImapConfigSettings %s=%s %s=%s %s=%s", + LC.imap_always_use_remote_store.key(), saved_imap_always_use_remote_store, + Provisioning.A_zimbraImapServerEnabled, saved_imap_server_enabled, + Provisioning.A_zimbraImapSSLServerEnabled, saved_imap_ssl_server_enabled); } /** expect this to be called by subclass @After method */ @@ -140,6 +144,10 @@ public static void restoreImapConfigSettings() throws ServiceException, DocumentException, ConfigException, IOException { getLocalServer(); if (imapServer != null) { + ZimbraLog.test.debug("Restoring ImapConfigSettings %s=%s %s=%s %s=%s", + LC.imap_always_use_remote_store.key(), saved_imap_always_use_remote_store, + Provisioning.A_zimbraImapServerEnabled, saved_imap_server_enabled, + Provisioning.A_zimbraImapSSLServerEnabled, saved_imap_ssl_server_enabled); imapServer.setReverseProxyUpstreamImapServers(saved_imap_servers); imapServer.setImapServerEnabled(saved_imap_server_enabled); imapServer.setImapSSLServerEnabled(saved_imap_ssl_server_enabled); @@ -352,7 +360,7 @@ protected List doListShouldSucceed(ImapConnection conn, String ref, St return listResult; } catch (CommandFailedException cfe) { String err = cfe.getError(); - fail(String.format("cmdDesc returned error '%s'", cmdDesc, err)); + fail(String.format("%s returned error '%s'", cmdDesc, err)); return null; } } From c5e16ef0f626ffc4ff313430604ce6d992e1783e Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 6 Sep 2017 10:33:28 +0100 Subject: [PATCH 019/142] ZCS-2488:New interface JmxStatsMBeanBase Used by `JmxServerStatsMBean` and new `JmxImapDaemonStatsMBean` Constructor of new `ZimbraPerf.Stats` uses this. --- .../zimbra/cs/stats/JmxStatsMBeanBase.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 store/src/java/com/zimbra/cs/stats/JmxStatsMBeanBase.java diff --git a/store/src/java/com/zimbra/cs/stats/JmxStatsMBeanBase.java b/store/src/java/com/zimbra/cs/stats/JmxStatsMBeanBase.java new file mode 100644 index 00000000000..cc42d0fe4d8 --- /dev/null +++ b/store/src/java/com/zimbra/cs/stats/JmxStatsMBeanBase.java @@ -0,0 +1,22 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.cs.stats; + +public interface JmxStatsMBeanBase { + public void reset(); +} \ No newline at end of file From 352b32f0f38ae5d6ea4dd5bb94d86f62d432b15c Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 5 Sep 2017 12:14:32 +0100 Subject: [PATCH 020/142] ZCS-2488:JmxImapDaemonStats* --- .../zimbra/cs/stats/JmxImapDaemonStats.java | 43 +++++++++++++++++++ .../cs/stats/JmxImapDaemonStatsMBean.java | 23 ++++++++++ 2 files changed, 66 insertions(+) create mode 100644 store/src/java/com/zimbra/cs/stats/JmxImapDaemonStats.java create mode 100644 store/src/java/com/zimbra/cs/stats/JmxImapDaemonStatsMBean.java diff --git a/store/src/java/com/zimbra/cs/stats/JmxImapDaemonStats.java b/store/src/java/com/zimbra/cs/stats/JmxImapDaemonStats.java new file mode 100644 index 00000000000..3cf33a79a8b --- /dev/null +++ b/store/src/java/com/zimbra/cs/stats/JmxImapDaemonStats.java @@ -0,0 +1,43 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.cs.stats; + +import com.zimbra.common.stats.DeltaCalculator; + +public class JmxImapDaemonStats implements JmxImapDaemonStatsMBean { + + private final DeltaCalculator imapDeltaCalc = new DeltaCalculator(ZimbraPerf.STOPWATCH_IMAP); + + JmxImapDaemonStats() { + } + + @Override + public long getImapRequests() { + return ZimbraPerf.STOPWATCH_IMAP.getCount(); + } + + @Override + public long getImapResponseMs() { + return (long) imapDeltaCalc.getRealtimeAverage(); + } + + @Override + public void reset() { + imapDeltaCalc.reset(); + } +} \ No newline at end of file diff --git a/store/src/java/com/zimbra/cs/stats/JmxImapDaemonStatsMBean.java b/store/src/java/com/zimbra/cs/stats/JmxImapDaemonStatsMBean.java new file mode 100644 index 00000000000..99116a599a0 --- /dev/null +++ b/store/src/java/com/zimbra/cs/stats/JmxImapDaemonStatsMBean.java @@ -0,0 +1,23 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.cs.stats; + +public interface JmxImapDaemonStatsMBean extends JmxStatsMBeanBase { + long getImapRequests(); + long getImapResponseMs(); +} From f9dc4d8058ffd9fafe9213daaca238290531fd40 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 6 Sep 2017 10:39:31 +0100 Subject: [PATCH 021/142] ZCS-2488:JmxServerStatsMBean use JmxStatsMBeanBase --- store/src/java/com/zimbra/cs/stats/JmxServerStatsMBean.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/src/java/com/zimbra/cs/stats/JmxServerStatsMBean.java b/store/src/java/com/zimbra/cs/stats/JmxServerStatsMBean.java index c81097815eb..033832538cc 100644 --- a/store/src/java/com/zimbra/cs/stats/JmxServerStatsMBean.java +++ b/store/src/java/com/zimbra/cs/stats/JmxServerStatsMBean.java @@ -17,7 +17,7 @@ package com.zimbra.cs.stats; -public interface JmxServerStatsMBean +public interface JmxServerStatsMBean extends JmxStatsMBeanBase { long getBlobInputStreamReads(); long getBlobInputStreamSeekRate(); From 4436040d788bedd4263eed61da4c88b2ac6466b0 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 5 Sep 2017 10:33:01 +0100 Subject: [PATCH 022/142] ZCS-2488:ZimbraPerf Imap Daemon stats Split up code a bit so that it can be used by both mailboxd and imap daemon --- .../java/com/zimbra/cs/imap/ImapDaemon.java | 5 +- .../java/com/zimbra/cs/stats/ZimbraPerf.java | 214 ++++++++++++------ 2 files changed, 146 insertions(+), 73 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapDaemon.java b/store/src/java/com/zimbra/cs/imap/ImapDaemon.java index bd461bfcd38..4d03890641d 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapDaemon.java +++ b/store/src/java/com/zimbra/cs/imap/ImapDaemon.java @@ -27,9 +27,8 @@ import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.store.StoreManager; -import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.stats.ZimbraPerf; +import com.zimbra.cs.store.StoreManager; public class ImapDaemon { @@ -105,7 +104,7 @@ public static void main(String[] args) { ImapDaemon daemon = new ImapDaemon(); int numStarted = daemon.startServers(); - ZimbraPerf.initialize(true); + ZimbraPerf.initializeForImapDaemon(); if(numStarted > 0) { Runtime.getRuntime().addShutdownHook(new Thread() { diff --git a/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java b/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java index 2f1bd354ac3..714cdfb8423 100644 --- a/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java +++ b/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java @@ -29,13 +29,13 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import javax.management.MBeanServer; import javax.management.ObjectName; +import com.google.common.collect.Maps; import com.zimbra.common.service.ServiceException; import com.zimbra.common.stats.Accumulator; import com.zimbra.common.stats.Counter; @@ -216,14 +216,14 @@ public class ZimbraPerf { private static int mailboxCacheSize; private static long mailboxCacheSizeTimestamp = 0; private static JmxServerStats jmxServerStats; - private static Map descriptions = new TreeMap(String.CASE_INSENSITIVE_ORDER); + private static JmxImapDaemonStats jmxImapDaemonStats; + private static Map descriptions = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); public static String getDescription(String statName) { return descriptions.get(statName); } - private static RealtimeStats realtimeStats = - new RealtimeStats(new String[] { + private static String[] mboxRealtimeStatsNames = new String[] { RTS_DB_POOL_SIZE, RTS_INNODB_BP_HIT_RATE, RTS_LMTP_CONN, RTS_LMTP_THREADS, RTS_POP_CONN, RTS_POP_THREADS, RTS_POP_SSL_CONN, RTS_POP_SSL_THREADS, @@ -239,9 +239,13 @@ public static String getDescription(String statName) { RTS_UCSERVICE_CACHE_SIZE, RTS_UCSERVICE_CACHE_HIT_RATE, RTS_ZIMLET_CACHE_SIZE, RTS_ZIMLET_CACHE_HIT_RATE, RTS_GROUP_CACHE_SIZE, RTS_GROUP_CACHE_HIT_RATE, - RTS_XMPP_CACHE_SIZE, RTS_XMPP_CACHE_HIT_RATE, - } - ); + RTS_XMPP_CACHE_SIZE, RTS_XMPP_CACHE_HIT_RATE + }; + private static String[] imapdRealtimeStatsNames = new String[] { + RTS_IMAP_CONN, RTS_IMAP_THREADS, RTS_IMAP_SSL_CONN, RTS_IMAP_SSL_THREADS + }; + + private static RealtimeStats realtimeStats = null; @Description("Number of messages received over LMTP") private static final String DC_LMTP_RCVD_MSGS = "lmtp_rcvd_msgs"; @@ -345,37 +349,8 @@ public static String getDescription(String statName) { @Description("Number of calendars (folders) in the calendar summary cache LRU in Java heap") private static final String DC_CALCACHE_LRU_SIZE = "calcache_lru_size"; - private static CopyOnWriteArrayList sAccumulators = - new CopyOnWriteArrayList( - new Accumulator[] { - new DeltaCalculator(COUNTER_LMTP_RCVD_MSGS).setTotalName(DC_LMTP_RCVD_MSGS), - new DeltaCalculator(COUNTER_LMTP_RCVD_BYTES).setTotalName(DC_LMTP_RCVD_BYTES), - new DeltaCalculator(COUNTER_LMTP_RCVD_RCPT).setTotalName(DC_LMTP_RCVD_RCPT), - new DeltaCalculator(COUNTER_LMTP_DLVD_MSGS).setTotalName(DC_LMTP_DLVD_MSGS), - new DeltaCalculator(COUNTER_LMTP_DLVD_BYTES).setTotalName(DC_LMTP_DLVD_BYTES), - new DeltaCalculator(STOPWATCH_DB_CONN).setCountName(DC_DB_CONN_COUNT).setAverageName(DC_DB_CONN_MS_AVG), - new DeltaCalculator(STOPWATCH_LDAP_DC).setCountName(DC_LDAP_DC_COUNT).setAverageName(DC_LDAP_DC_MS_AVG), - new DeltaCalculator(STOPWATCH_MBOX_ADD_MSG).setCountName(DC_MBOX_ADD_MSG_COUNT).setAverageName(DC_MBOX_ADD_MSG_MS_AVG), - new DeltaCalculator(STOPWATCH_MBOX_GET).setCountName(DC_MBOX_GET_COUNT).setAverageName(DC_MBOX_GET_MS_AVG), - new DeltaCalculator(COUNTER_MBOX_CACHE).setAverageName(DC_MBOX_CACHE), - new DeltaCalculator(COUNTER_MBOX_MSG_CACHE).setAverageName(DC_MBOX_MSG_CACHE), - new DeltaCalculator(COUNTER_MBOX_ITEM_CACHE).setAverageName(DC_MBOX_ITEM_CACHE), - new DeltaCalculator(STOPWATCH_SOAP).setCountName(DC_SOAP_COUNT).setAverageName(DC_SOAP_MS_AVG), - new DeltaCalculator(STOPWATCH_IMAP).setCountName(DC_IMAP_COUNT).setAverageName(DC_IMAP_MS_AVG), - new DeltaCalculator(STOPWATCH_POP).setCountName(DC_POP_COUNT).setAverageName(DC_POP_MS_AVG), - new DeltaCalculator(COUNTER_IDX_WRT).setAverageName(DC_IDX_WRT_AVG), - new DeltaCalculator(COUNTER_IDX_WRT_OPENED).setTotalName(DC_IDX_WRT_OPENED), - new DeltaCalculator(COUNTER_IDX_WRT_OPENED_CACHE_HIT).setTotalName(DC_IDX_WRT_OPENED_CACHE_HIT), - new DeltaCalculator(COUNTER_CALENDAR_CACHE_HIT).setAverageName(DC_CALCACHE_HIT), - new DeltaCalculator(COUNTER_CALENDAR_CACHE_MEM_HIT).setAverageName(DC_CALCACHE_MEM_HIT), - new DeltaCalculator(COUNTER_CALENDAR_CACHE_LRU_SIZE).setAverageName(DC_CALCACHE_LRU_SIZE), - new DeltaCalculator(COUNTER_IDX_BYTES_WRITTEN).setTotalName(DC_IDX_BYTES_WRITTEN).setAverageName(DC_IDX_BYTES_WRITTTEN_AVG), - new DeltaCalculator(COUNTER_IDX_BYTES_READ).setTotalName(DC_IDX_BYTES_READ).setAverageName(DC_IDX_BYTES_READ_AVG), - new DeltaCalculator(COUNTER_BLOB_INPUT_STREAM_READ).setTotalName(DC_BIS_READ), - new DeltaCalculator(COUNTER_BLOB_INPUT_STREAM_SEEK_RATE).setAverageName(DC_BIS_SEEK_RATE), - realtimeStats - } - ); + private static CopyOnWriteArrayList sAccumulators = null; + public enum ServerID {ZIMBRA, IMAP_DAEMON}; private static void initDescriptions() { descriptions = Collections.synchronizedMap(descriptions); @@ -422,8 +397,9 @@ public static Map getStats() { * names will not be output correctly into the logs */ public static void addRealtimeStatName(String name, String description) { - if (sIsInitialized) - throw new IllegalStateException("Cannot add stat name after ZimbraPerf.initialize() is called"); + if (sIsInitialized) { + throw new IllegalStateException("Cannot add stat name after ZimbraPerf has been initialized"); + } ZimbraLog.perf.debug("Adding realtime stat '%s': %s", name, description); realtimeStats.addName(name); descriptions.put(name, description); @@ -457,52 +433,143 @@ public static void addStatsCallback(RealtimeStatsCallback callback) { private static final long CSV_DUMP_FREQUENCY = Constants.MILLIS_PER_MINUTE; private static boolean sIsInitialized = false; + private static boolean isPrepared = false; + + /** + * MUST be called before anything else + * + * Some things need to be done before initialize is called but require some static variables to + * have already been setup. + * @param serverID + */ + public synchronized static void prepare(ServerID serverID) { + if (isPrepared) { + log.warn("Detected call to ZimbraPerf.prepare() after already prepared", new Exception()); + return; + } + if (sIsInitialized) { + throw new IllegalStateException( + "Must not call ZimbraPerf.prepare() after ZimbraPerf.initialize()"); + } + switch (serverID) { + case ZIMBRA: + realtimeStats = new RealtimeStats(mboxRealtimeStatsNames); + sAccumulators = new CopyOnWriteArrayList( + new Accumulator[] { + new DeltaCalculator(COUNTER_LMTP_RCVD_MSGS).setTotalName(DC_LMTP_RCVD_MSGS), + new DeltaCalculator(COUNTER_LMTP_RCVD_BYTES).setTotalName(DC_LMTP_RCVD_BYTES), + new DeltaCalculator(COUNTER_LMTP_RCVD_RCPT).setTotalName(DC_LMTP_RCVD_RCPT), + new DeltaCalculator(COUNTER_LMTP_DLVD_MSGS).setTotalName(DC_LMTP_DLVD_MSGS), + new DeltaCalculator(COUNTER_LMTP_DLVD_BYTES).setTotalName(DC_LMTP_DLVD_BYTES), + new DeltaCalculator(STOPWATCH_DB_CONN).setCountName(DC_DB_CONN_COUNT) + .setAverageName(DC_DB_CONN_MS_AVG), + new DeltaCalculator(STOPWATCH_LDAP_DC).setCountName(DC_LDAP_DC_COUNT) + .setAverageName(DC_LDAP_DC_MS_AVG), + new DeltaCalculator(STOPWATCH_MBOX_ADD_MSG).setCountName(DC_MBOX_ADD_MSG_COUNT) + .setAverageName(DC_MBOX_ADD_MSG_MS_AVG), + new DeltaCalculator(STOPWATCH_MBOX_GET).setCountName(DC_MBOX_GET_COUNT) + .setAverageName(DC_MBOX_GET_MS_AVG), + new DeltaCalculator(COUNTER_MBOX_CACHE).setAverageName(DC_MBOX_CACHE), + new DeltaCalculator(COUNTER_MBOX_MSG_CACHE).setAverageName(DC_MBOX_MSG_CACHE), + new DeltaCalculator(COUNTER_MBOX_ITEM_CACHE).setAverageName(DC_MBOX_ITEM_CACHE), + new DeltaCalculator(STOPWATCH_SOAP).setCountName(DC_SOAP_COUNT) + .setAverageName(DC_SOAP_MS_AVG), + new DeltaCalculator(STOPWATCH_IMAP).setCountName(DC_IMAP_COUNT) + .setAverageName(DC_IMAP_MS_AVG), + new DeltaCalculator(STOPWATCH_POP).setCountName(DC_POP_COUNT) + .setAverageName(DC_POP_MS_AVG), + new DeltaCalculator(COUNTER_IDX_WRT).setAverageName(DC_IDX_WRT_AVG), + new DeltaCalculator(COUNTER_IDX_WRT_OPENED).setTotalName(DC_IDX_WRT_OPENED), + new DeltaCalculator(COUNTER_IDX_WRT_OPENED_CACHE_HIT) + .setTotalName(DC_IDX_WRT_OPENED_CACHE_HIT), + new DeltaCalculator(COUNTER_CALENDAR_CACHE_HIT).setAverageName(DC_CALCACHE_HIT), + new DeltaCalculator(COUNTER_CALENDAR_CACHE_MEM_HIT) + .setAverageName(DC_CALCACHE_MEM_HIT), + new DeltaCalculator(COUNTER_CALENDAR_CACHE_LRU_SIZE) + .setAverageName(DC_CALCACHE_LRU_SIZE), + new DeltaCalculator(COUNTER_IDX_BYTES_WRITTEN) + .setTotalName(DC_IDX_BYTES_WRITTEN) + .setAverageName(DC_IDX_BYTES_WRITTTEN_AVG), + new DeltaCalculator(COUNTER_IDX_BYTES_READ) + .setTotalName(DC_IDX_BYTES_READ).setAverageName(DC_IDX_BYTES_READ_AVG), + new DeltaCalculator(COUNTER_BLOB_INPUT_STREAM_READ).setTotalName(DC_BIS_READ), + new DeltaCalculator(COUNTER_BLOB_INPUT_STREAM_SEEK_RATE) + .setAverageName(DC_BIS_SEEK_RATE), + realtimeStats + } + ); + break; + case IMAP_DAEMON: + realtimeStats = new RealtimeStats(imapdRealtimeStatsNames); + sAccumulators = new CopyOnWriteArrayList( + new Accumulator[] { + new DeltaCalculator(STOPWATCH_IMAP) + .setCountName(DC_IMAP_COUNT).setAverageName(DC_IMAP_MS_AVG), + realtimeStats + } + ); + break; + default: + } + isPrepared = true; + } - public synchronized static void initialize() { + public synchronized static void initialize(ServerID serverID) { + if (!isPrepared) { + throw new IllegalStateException("Must call prepare() before ZimbraPerf.initialize()"); + } if (sIsInitialized) { log.warn("Detected a second call to ZimbraPerf.initialize()", new Exception()); return; } initDescriptions(); + switch (serverID) { + case ZIMBRA: + initializeForMainZimbraJVM(); + break; + case IMAP_DAEMON: + initializeForImapDaemon(); + break; + default: + } + sIsInitialized = true; + } + private synchronized static void initializeForMainZimbraJVM() { addStatsCallback(new ServerStatsCallback()); addStatsCallback(new JettyStats()); - - StatsDumper.schedule(new MailboxdStats(), CSV_DUMP_FREQUENCY); - + // Initialize JMX + MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer(); + jmxServerStats = new JmxServerStats(); + try { + jmxServer.registerMBean(jmxServerStats, + new ObjectName("ZimbraCollaborationSuite:type=ServerStats")); + } catch (Exception e) { + ZimbraLog.perf.warn("Unable to register JMX interface.", e); + } + StatsDumper.schedule(new Stats("mailboxd.csv", sAccumulators, jmxServerStats), CSV_DUMP_FREQUENCY); StatsDumper.schedule(SOAP_TRACKER, CSV_DUMP_FREQUENCY); StatsDumper.schedule(IMAP_TRACKER, CSV_DUMP_FREQUENCY); StatsDumper.schedule(POP_TRACKER, CSV_DUMP_FREQUENCY); StatsDumper.schedule(LDAP_TRACKER, CSV_DUMP_FREQUENCY); StatsDumper.schedule(SYNC_TRACKER, CSV_DUMP_FREQUENCY); StatsDumper.schedule(SQL_TRACKER, CSV_DUMP_FREQUENCY); - ThreadStats threadStats = new ThreadStats("threads.csv"); StatsDumper.schedule(threadStats, CSV_DUMP_FREQUENCY); + } + private synchronized static void initializeForImapDaemon() { // Initialize JMX MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer(); - jmxServerStats = new JmxServerStats(); + jmxImapDaemonStats = new JmxImapDaemonStats(); try { - jmxServer.registerMBean(jmxServerStats, new ObjectName("ZimbraCollaborationSuite:type=ServerStats")); + jmxServer.registerMBean(jmxImapDaemonStats, new ObjectName("ZimbraImapDaemon:type=ServerStats")); } catch (Exception e) { ZimbraLog.perf.warn("Unable to register JMX interface.", e); } - - sIsInitialized = true; - } - - // feature Imap - public synchronized static void initialize(boolean val) { - if (sIsInitialized) { - log.warn("Detected a second call to ZimbraPerf.initialize()", new Exception()); - return; - } - initDescriptions(); - + StatsDumper.schedule(new Stats("imapd_stats.csv", sAccumulators, jmxImapDaemonStats), + CSV_DUMP_FREQUENCY); StatsDumper.schedule(IMAPD_TRACKER, CSV_DUMP_FREQUENCY); - - sIsInitialized = val; } /** @@ -523,21 +590,28 @@ static int getMailboxCacheSize() { } /** - * Scheduled task that writes a row to zimbrastats.csv with the latest - * Accumulator data. + * Scheduled task that writes a row to a CSV file with the latest Accumulator data. */ - private static final class MailboxdStats - implements StatsDumperDataSource - { + private static final class Stats implements StatsDumperDataSource { + private final String filename; + private final List accumulators; + private final JmxStatsMBeanBase statsBean; + + public Stats(String filename, List accumulators, JmxStatsMBeanBase statsBean) { + this.filename = filename; + this.accumulators = accumulators; + this.statsBean = statsBean; + } + @Override public String getFilename() { - return "mailboxd.csv"; + return filename; } @Override public String getHeader() { List columns = new ArrayList(); - for (Accumulator a : sAccumulators) { + for (Accumulator a : accumulators) { for (String column : a.getNames()) { columns.add(column); } @@ -548,7 +622,7 @@ public String getHeader() { @Override public Collection getDataLines() { List data = new ArrayList(); - for (Accumulator a : sAccumulators) { + for (Accumulator a : accumulators) { synchronized (a) { data.addAll(a.getData()); a.reset(); @@ -568,7 +642,7 @@ public Collection getDataLines() { retVal.add(line); // Piggyback off timer to reset realtime stats. - jmxServerStats.reset(); + statsBean.reset(); return retVal; } From 524c8ec6c4aa416d747cd4b9779bd18fa79ebdab Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 7 Sep 2017 16:56:15 +0100 Subject: [PATCH 023/142] ZCS-2488:ImapDaemon ZimbraPerf imapd_stats.csv * Setup ZimbraPerf things to collect stats * Ensure FileInputStream for IMAPD_LOG4J_CONFIG is closed after use * Print stacktrace of exception thrown rather than just printing the toString() --- store/src/java/com/zimbra/cs/imap/ImapDaemon.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapDaemon.java b/store/src/java/com/zimbra/cs/imap/ImapDaemon.java index 4d03890641d..8bbaeba6354 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapDaemon.java +++ b/store/src/java/com/zimbra/cs/imap/ImapDaemon.java @@ -29,6 +29,7 @@ import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.stats.ZimbraPerf; import com.zimbra.cs.store.StoreManager; +import com.zimbra.cs.util.MemoryStats; public class ImapDaemon { @@ -91,7 +92,9 @@ private void stopServers() { public static void main(String[] args) { try { Properties props = new Properties(); - props.load(new FileInputStream(IMAPD_LOG4J_CONFIG)); + try (FileInputStream fisLog4j = new FileInputStream(IMAPD_LOG4J_CONFIG)) { + props.load(fisLog4j); + } PropertyConfigurator.configure(props); String imapdClassStore=LC.imapd_class_store.value(); try { @@ -101,11 +104,13 @@ public static void main(String[] args) { } if(isZimbraImapEnabled()) { + ZimbraPerf.prepare(ZimbraPerf.ServerID.IMAP_DAEMON); + MemoryStats.startup(); + ZimbraPerf.initialize(ZimbraPerf.ServerID.IMAP_DAEMON); + ImapDaemon daemon = new ImapDaemon(); int numStarted = daemon.startServers(); - ZimbraPerf.initializeForImapDaemon(); - if(numStarted > 0) { Runtime.getRuntime().addShutdownHook(new Thread() { @Override @@ -125,6 +130,7 @@ public void run() { } } catch (Exception e) { System.err.println("ImapDaemon: " + e); + e.printStackTrace(System.err); } } From 675b1527b5c968e3b68606d7752e7e63dcc67092 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 7 Sep 2017 17:00:53 +0100 Subject: [PATCH 024/142] ZCS-2488:Zimbra - ZimbraPerf init changes --- store/src/java/com/zimbra/cs/util/Zimbra.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/store/src/java/com/zimbra/cs/util/Zimbra.java b/store/src/java/com/zimbra/cs/util/Zimbra.java index d59bc3f043a..c59a88a13c1 100644 --- a/store/src/java/com/zimbra/cs/util/Zimbra.java +++ b/store/src/java/com/zimbra/cs/util/Zimbra.java @@ -216,6 +216,8 @@ private static synchronized void startup(boolean forMailboxd) throws ServiceExce ZimbraApplication app = ZimbraApplication.getInstance(); + ZimbraPerf.prepare(ZimbraPerf.ServerID.ZIMBRA); + DbPool.startup(); app.initializeZimbraDb(forMailboxd); @@ -375,7 +377,7 @@ private static synchronized void startup(boolean forMailboxd) throws ServiceExce // should be last, so that other subsystems can add dynamic stats counters if (app.supports(ZimbraPerf.class.getName())) { - ZimbraPerf.initialize(); + ZimbraPerf.initialize(ZimbraPerf.ServerID.ZIMBRA); } } From 1e316814e1dca8f43abfd569e9de5547300230ea Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 7 Sep 2017 21:00:55 +0100 Subject: [PATCH 025/142] ZCS-2488:TestImapViaImapDaemon.imapdStatFiles Renamed test `testImapdStatFile` to `imapdStatFiles` and update to check for `imapd_stats.csv` as well as `imapd.csv` --- .../qa/unittest/TestImapViaImapDaemon.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java b/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java index 497d0eff064..84c71f3e5e7 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java +++ b/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java @@ -23,6 +23,7 @@ import com.zimbra.common.localconfig.LocalConfig; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.Log; +import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Provisioning.CacheEntry; import com.zimbra.cs.imap.ImapHandler; @@ -43,6 +44,8 @@ * The actual tests that are run are in {@link SharedImapTests} */ public class TestImapViaImapDaemon extends SharedImapTests { + private static String IMAPD_CSV_FILE = "/opt/zimbra/zmstat/imapd.csv"; + private static String IMAPD_CSV_STATS_FILE = "/opt/zimbra/zmstat/imapd_stats.csv"; @Before public void setUp() throws Exception { @@ -237,11 +240,28 @@ public void testZimbraCommandsNonAdminUser() throws Exception { } @Test - public void testImapdStatFile() throws Exception { - File testFile = new File("/opt/zimbra/zmstat/imapd.csv"); - - assertTrue("imapd.csv file does not exists", testFile.exists()); - assertTrue("imapd.csv file is empty", testFile.length()>0); + public void imapdStatFiles() throws Exception { + connection = this.connectAndSelectInbox(USER); + connection.logout(); + connection = null; + int max_time = 70 * 1000; // Files are updated every minute, so max wait a little bit longer + int sofar = 0; + File testFile = new File(IMAPD_CSV_FILE); + while (!testFile.exists() && (sofar < max_time)) { + ZimbraLog.test.debug("%s file does not exist after %s seconds", IMAPD_CSV_FILE, sofar / 1000); + Thread.sleep(1000); + sofar += 1000; + } + assertTrue(String.format("%s file does not exist", testFile.getCanonicalPath()), testFile.exists()); + assertTrue(String.format("%s file is unexpectedly empty", testFile.getCanonicalPath()), + testFile.length()>0); + testFile = new File(IMAPD_CSV_STATS_FILE); + if (!testFile.exists()) { + Thread.sleep(500); + } + assertTrue(String.format("%s file does not exist", testFile.getCanonicalPath()), testFile.exists()); + assertTrue(String.format("%s file is unexpectedly empty", testFile.getCanonicalPath()), + testFile.length()>0); } From 6fb58052abdd2d70f0460cc51fa8e301cadf7b1d Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 8 Sep 2017 12:17:57 +0100 Subject: [PATCH 026/142] PMD changes for Zimbra.java --- store/src/java/com/zimbra/cs/util/Zimbra.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/store/src/java/com/zimbra/cs/util/Zimbra.java b/store/src/java/com/zimbra/cs/util/Zimbra.java index c59a88a13c1..ea0103809a0 100644 --- a/store/src/java/com/zimbra/cs/util/Zimbra.java +++ b/store/src/java/com/zimbra/cs/util/Zimbra.java @@ -65,7 +65,6 @@ import com.zimbra.cs.stats.ZimbraPerf; import com.zimbra.cs.store.StoreManager; import com.zimbra.cs.zookeeper.CuratorManager; -import com.zimbra.cs.zookeeper.Service; import com.zimbra.znative.Util; /** @@ -77,7 +76,8 @@ public final class Zimbra { private static boolean sInited = false; private static boolean sIsMailboxd = false; private static String alwaysOnClusterId = null; - private static Service service = null; + private static final String HEAP_DUMP_JAVA_OPTION = "-xx:heapdumppath="; + public static Timer sTimer = new Timer("Timer-Zimbra", true); /** Sets system properties before the server fully starts up. Note that * there's a potential race condition if {@link FirstServlet} or another @@ -92,8 +92,6 @@ private static void setSystemProperties() { System.setProperty("mail.mime.multipart.allowempty", "true"); } - private static final String HEAP_DUMP_JAVA_OPTION = "-xx:heapdumppath="; - private static void validateJavaOptions() throws ServiceException { String options = LC.mailboxd_java_options.value(); if (options != null && options.toLowerCase().indexOf(HEAP_DUMP_JAVA_OPTION) > -1) { @@ -478,8 +476,6 @@ public static synchronized boolean started() { return sInited; } - public static Timer sTimer = new Timer("Timer-Zimbra", true); - /** * Logs the given message and shuts down the server. * From c2f11e6295ae6d36af7546d3750c5f368374d904 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 8 Sep 2017 12:18:06 +0100 Subject: [PATCH 027/142] PMD changes for ZimbraPerf.java --- .../java/com/zimbra/cs/stats/ZimbraPerf.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java b/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java index 714cdfb8423..b59128bdbc0 100644 --- a/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java +++ b/store/src/java/com/zimbra/cs/stats/ZimbraPerf.java @@ -59,13 +59,7 @@ */ public class ZimbraPerf { - @Target({ElementType.FIELD}) - @Retention(RetentionPolicy.RUNTIME) - private @interface Description { - String value(); - } - - static Log log = LogFactory.getLog(ZimbraPerf.class); + private static Log log = LogFactory.getLog(ZimbraPerf.class); @Description("Number of database connections in use") public static final String RTS_DB_POOL_SIZE = "db_pool_size"; @@ -219,10 +213,6 @@ public class ZimbraPerf { private static JmxImapDaemonStats jmxImapDaemonStats; private static Map descriptions = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); - public static String getDescription(String statName) { - return descriptions.get(statName); - } - private static String[] mboxRealtimeStatsNames = new String[] { RTS_DB_POOL_SIZE, RTS_INNODB_BP_HIT_RATE, RTS_LMTP_CONN, RTS_LMTP_THREADS, @@ -350,8 +340,28 @@ public static String getDescription(String statName) { private static final String DC_CALCACHE_LRU_SIZE = "calcache_lru_size"; private static CopyOnWriteArrayList sAccumulators = null; + + private static final long CSV_DUMP_FREQUENCY = Constants.MILLIS_PER_MINUTE; + private static boolean sIsInitialized = false; + private static boolean isPrepared = false; + /** + * The number of statements that were prepared, as reported by + * {@link DbPool.DbConnection#prepareStatement}. + */ + private static AtomicInteger sPrepareCount = new AtomicInteger(0); + public enum ServerID {ZIMBRA, IMAP_DAEMON}; + @Target({ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + private @interface Description { + String value(); + } + + public static String getDescription(String statName) { + return descriptions.get(statName); + } + private static void initDescriptions() { descriptions = Collections.synchronizedMap(descriptions); @@ -409,12 +419,6 @@ public static JmxServerStatsMBean getMonitoringStats() { return jmxServerStats; } - /** - * The number of statements that were prepared, as reported by - * {@link DbPool.DbConnection#prepareStatement}. - */ - private static AtomicInteger sPrepareCount = new AtomicInteger(0); - public static int getPrepareCount() { return sPrepareCount.get(); } @@ -431,10 +435,6 @@ public static void addStatsCallback(RealtimeStatsCallback callback) { realtimeStats.addCallback(callback); } - private static final long CSV_DUMP_FREQUENCY = Constants.MILLIS_PER_MINUTE; - private static boolean sIsInitialized = false; - private static boolean isPrepared = false; - /** * MUST be called before anything else * @@ -576,7 +576,7 @@ private synchronized static void initializeForImapDaemon() { * Returns the mailbox cache size. The real value is reread once a minute so that cache * performance is not affected. */ - static int getMailboxCacheSize() { + protected static int getMailboxCacheSize() { long now = System.currentTimeMillis(); if (now - mailboxCacheSizeTimestamp > Constants.MILLIS_PER_MINUTE) { try { From a351b54028cdbd7ddbd9d2e52d1462caf8b19d81 Mon Sep 17 00:00:00 2001 From: Shrikant Date: Fri, 8 Sep 2017 14:11:45 +0530 Subject: [PATCH 028/142] ZCS-1010:Add an attribute for comparator in case of valueComparison --- .../com/zimbra/common/soap/MailConstants.java | 1 + .../com/zimbra/soap/mail/type/FilterTest.java | 33 +- store/docs/soap-admin.txt | 12 + store/docs/soap.txt | 12 + .../zimbra/cs/filter/ValueComparisonTest.java | 586 ++++++++++++++++++ .../com/zimbra/cs/filter/SieveToSoap.java | 24 +- .../com/zimbra/cs/filter/SieveVisitor.java | 18 +- .../com/zimbra/cs/filter/SoapToSieve.java | 45 +- 8 files changed, 698 insertions(+), 33 deletions(-) create mode 100644 store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java diff --git a/common/src/java/com/zimbra/common/soap/MailConstants.java b/common/src/java/com/zimbra/common/soap/MailConstants.java index 86788339883..bb18d7e500b 100644 --- a/common/src/java/com/zimbra/common/soap/MailConstants.java +++ b/common/src/java/com/zimbra/common/soap/MailConstants.java @@ -679,6 +679,7 @@ private MailConstants() { public static final String A_STRING_COMPARISON = "stringComparison"; public static final String A_VALUE_COMPARISON = "valueComparison"; public static final String A_COUNT_COMPARISON = "countComparison"; + public static final String A_VALUE_COMPARISON_COMPARATOR = "valueComparisonComparator"; public static final String A_CASE_SENSITIVE = "caseSensitive"; public static final String A_NUMBER_COMPARISON = "numberComparison"; public static final String A_DATE_COMPARISON = "dateComparison"; diff --git a/soap/src/java/com/zimbra/soap/mail/type/FilterTest.java b/soap/src/java/com/zimbra/soap/mail/type/FilterTest.java index 91395409c78..18d3924c1e8 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/FilterTest.java +++ b/soap/src/java/com/zimbra/soap/mail/type/FilterTest.java @@ -138,6 +138,12 @@ public static class AddressTest extends FilterTest { @XmlAttribute(name=MailConstants.A_COUNT_COMPARISON /* countComparison */, required=false) private String countComparison; + /** + * @zm-api-field-tag value-comparison-comparator + * @zm-api-field-description value comparison comparator - i;ascii-numeric|i;ascii-casemap|i;octet + */ + @XmlAttribute(name=MailConstants.A_VALUE_COMPARISON_COMPARATOR /* valueComparisonComparator */, required=false) + private String valueComparisonComparator; public String getHeader() { return header; @@ -198,6 +204,14 @@ public void setCountComparison(String countComparison) { this.countComparison = countComparison; } + public String getValueComparisonComparator() { + return valueComparisonComparator; + } + + public void setValueComparisonComparator(String valueComparisonComparator) { + this.valueComparisonComparator = valueComparisonComparator; + } + @Override public String toString() { return Objects.toStringHelper(this) @@ -205,6 +219,7 @@ public String toString() { .add("part", part) .add("comparison", comparison) .add("valueComparison", valueComparison) + .add("valueComparisonComparator", valueComparisonComparator) .add("countComparison", countComparison) .add("caseSensitive", caseSensitive) .add("value", value) @@ -516,7 +531,7 @@ public String toString() { } @XmlAccessorType(XmlAccessType.NONE) - @JsonPropertyOrder({ "index", "negative", "header", "caseSensitive", "stringComparison", "valueComparison", "countComparison", "value" }) + @JsonPropertyOrder({ "index", "negative", "header", "caseSensitive", "stringComparison", "valueComparison","valueComparisonComparator", "countComparison", "value" }) public static final class HeaderTest extends FilterTest { // Comma separated list @@ -548,6 +563,13 @@ public static final class HeaderTest extends FilterTest { @XmlAttribute(name=MailConstants.A_COUNT_COMPARISON /* countComparison */, required=false) private String countComparison; + /** + * @zm-api-field-tag value-comparison-comparator + * @zm-api-field-description value comparison comparator - i;ascii-numeric|i;ascii-casemap|i;octet + */ + @XmlAttribute(name=MailConstants.A_VALUE_COMPARISON_COMPARATOR /* valueComparisonComparator */, required=false) + private String valueComparisonComparator; + /** * @zm-api-field-tag value * @zm-api-field-description Value @@ -625,12 +647,21 @@ public void setValue(String value) { this.value = value; } + public String getValueComparisonComparator() { + return valueComparisonComparator; + } + + public void setValueComparisonComparator(String valueComparisonComparator) { + this.valueComparisonComparator = valueComparisonComparator; + } + @Override public String toString() { return Objects.toStringHelper(this) .add("headers", headers) .add("stringComparison", stringComparison) .add("valueComparison", valueComparison) + .add("valueComparisonComparator", valueComparisonComparator) .add("countComparison", countComparison) .add("value", value) .add("caseSensitive", caseSensitive) diff --git a/store/docs/soap-admin.txt b/store/docs/soap-admin.txt index 0a7d68c0577..0895881c14d 100644 --- a/store/docs/soap-admin.txt +++ b/store/docs/soap-admin.txt @@ -2997,6 +2997,16 @@ Tests: + + + + + @@ -3009,6 +3019,8 @@ Tests: + + {method}+ diff --git a/store/docs/soap.txt b/store/docs/soap.txt index 43c75186d1f..dd37e36f54f 100644 --- a/store/docs/soap.txt +++ b/store/docs/soap.txt @@ -3259,6 +3259,16 @@ Tests: + + + + + @@ -3271,6 +3281,8 @@ Tests: + + {method}+ diff --git a/store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java b/store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java new file mode 100644 index 00000000000..c9707cbd91e --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java @@ -0,0 +1,586 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.HashMap; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.zimbra.common.account.Key; +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.MailConstants; +import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.MockProvisioning; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.cs.service.mail.GetFilterRules; +import com.zimbra.cs.service.mail.ModifyFilterRules; +import com.zimbra.cs.service.mail.ServiceTestUtil; +import com.zimbra.cs.util.XMLDiffChecker; + +public class ValueComparisonTest { + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + Provisioning prov = Provisioning.getInstance(); + prov.createAccount("test@zimbra.com", "secret", new HashMap()); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for header test having caseSensitive attribute with + * string comparison + * @throws Exception + */ + @Test + public void testHeaderTestStringComparisonCaseSensitivity() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element headerTest = filterTests.addNonUniqueElement(MailConstants.E_HEADER_TEST); + headerTest.addAttribute(MailConstants.A_HEADER, "subject"); + headerTest.addAttribute(MailConstants.A_STRING_COMPARISON, "contains"); + headerTest.addAttribute(MailConstants.A_CASE_SENSITIVE, "true"); + headerTest.addAttribute(MailConstants.A_VALUE, "Important"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (header :contains :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for address test having caseSensitive attribute with + * string comparison + * @throws Exception + */ + @Test + public void testAddressTestStringComparisonCaseSensitivity() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element addressTest = filterTests.addNonUniqueElement(MailConstants.E_ADDRESS_TEST); + addressTest.addAttribute(MailConstants.A_HEADER, "from"); + addressTest.addAttribute(MailConstants.A_STRING_COMPARISON, "contains"); + addressTest.addAttribute(MailConstants.A_CASE_SENSITIVE, "true"); + addressTest.addAttribute(MailConstants.A_VALUE, "abCD"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (address :all :contains :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for envelope test having caseSensitive attribute with + * string comparison + * @throws Exception + */ + @Test + public void testEnvelopeTestStringComparisonCaseSensitivity() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element envelopeTest = filterTests.addNonUniqueElement(MailConstants.E_ENVELOPE_TEST); + envelopeTest.addAttribute(MailConstants.A_HEADER, "from"); + envelopeTest.addAttribute(MailConstants.A_STRING_COMPARISON, "contains"); + envelopeTest.addAttribute(MailConstants.A_CASE_SENSITIVE, "true"); + envelopeTest.addAttribute(MailConstants.A_VALUE, "abCD"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (envelope :all :contains :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for header test having caseSensitive attribute with + * value comparison + * @throws Exception + */ + @Test + public void testHeaderTestValueComparisonCaseSensitivity() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element headerTest = filterTests.addNonUniqueElement(MailConstants.E_HEADER_TEST); + headerTest.addAttribute(MailConstants.A_HEADER, "subject"); + headerTest.addAttribute(MailConstants.A_VALUE_COMPARISON, "eq"); + headerTest.addAttribute(MailConstants.A_CASE_SENSITIVE, "true"); + headerTest.addAttribute(MailConstants.A_VALUE, "Important"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (header :value \"eq\" :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for address test having caseSensitive attribute with + * value comparison + * @throws Exception + */ + @Test + public void testAddressTestValueComparisonCaseSensitivity() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element addressTest = filterTests.addNonUniqueElement(MailConstants.E_ADDRESS_TEST); + addressTest.addAttribute(MailConstants.A_HEADER, "from"); + addressTest.addAttribute(MailConstants.A_VALUE_COMPARISON, "eq"); + addressTest.addAttribute(MailConstants.A_CASE_SENSITIVE, "true"); + addressTest.addAttribute(MailConstants.A_VALUE, "abCD"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (address :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for envelope test having caseSensitive attribute with + * value comparison + * @throws Exception + */ + @Test + public void testEnvelopeTestValueComparisonCaseSensitivity() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element envelopeTest = filterTests.addNonUniqueElement(MailConstants.E_ENVELOPE_TEST); + envelopeTest.addAttribute(MailConstants.A_HEADER, "from"); + envelopeTest.addAttribute(MailConstants.A_VALUE_COMPARISON, "eq"); + envelopeTest.addAttribute(MailConstants.A_CASE_SENSITIVE, "true"); + envelopeTest.addAttribute(MailConstants.A_VALUE, "abCD"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (envelope :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for header test having value comparison with + * valueComparisonComparator + * @throws Exception + */ + @Test + public void testHeaderTestValueComparisonComparator() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element headerTest = filterTests.addNonUniqueElement(MailConstants.E_HEADER_TEST); + headerTest.addAttribute(MailConstants.A_HEADER, "subject"); + headerTest.addAttribute(MailConstants.A_VALUE_COMPARISON, "eq"); + headerTest.addAttribute(MailConstants.A_VALUE_COMPARISON_COMPARATOR, "i;octet"); + headerTest.addAttribute(MailConstants.A_VALUE, "Important"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (header :value \"eq\" :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for address test having value comparison with + * valueComparisonComparator + * @throws Exception + */ + @Test + public void testAddressTestValueComparisonComparator() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element addressTest = filterTests.addNonUniqueElement(MailConstants.E_ADDRESS_TEST); + addressTest.addAttribute(MailConstants.A_HEADER, "from"); + addressTest.addAttribute(MailConstants.A_VALUE_COMPARISON, "eq"); + addressTest.addAttribute(MailConstants.A_VALUE_COMPARISON_COMPARATOR, "i;octet"); + addressTest.addAttribute(MailConstants.A_VALUE, "abCD"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (address :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests rule creation through ModifyFilterRulesRequest for envelope test having value comparison with + * valueComparisonComparator + * @throws Exception + */ + @Test + public void testEnvelopeTestValueComparisonComparator() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Element request = new Element.XMLElement(MailConstants.MODIFY_FILTER_RULES_REQUEST); + + Element rules = request.addNonUniqueElement(MailConstants.E_FILTER_RULES); + Element rule = rules.addNonUniqueElement(MailConstants.E_FILTER_RULE); + rule.addAttribute(MailConstants.A_ACTIVE, true); + rule.addAttribute(MailConstants.A_NAME, "Test1"); + Element filteraction = rule.addNonUniqueElement(MailConstants.E_FILTER_ACTIONS); + Element actionInto = filteraction.addNonUniqueElement(MailConstants.E_ACTION_FILE_INTO); + actionInto.addAttribute(MailConstants.A_FOLDER_PATH, "Junk"); + filteraction.addNonUniqueElement(MailConstants.E_ACTION_STOP); + Element filterTests = rule.addNonUniqueElement(MailConstants.E_FILTER_TESTS); + filterTests.addAttribute(MailConstants.A_CONDITION, "anyof"); + Element envelopeTest = filterTests.addNonUniqueElement(MailConstants.E_ENVELOPE_TEST); + envelopeTest.addAttribute(MailConstants.A_HEADER, "from"); + envelopeTest.addAttribute(MailConstants.A_VALUE_COMPARISON, "eq"); + envelopeTest.addAttribute(MailConstants.A_VALUE_COMPARISON_COMPARATOR, "i;octet"); + envelopeTest.addAttribute(MailConstants.A_VALUE, "abCD"); + + try { + new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(acct)); + } catch (ServiceException e) { + fail("This test is expected not to throw exception. "); + } + + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + expectedScript += "# Test1\n"; + expectedScript += "if anyof (envelope :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + expectedScript += " fileinto \"Junk\";\n"; + expectedScript += " stop;\n"; + expectedScript += "}\n"; + + ZimbraLog.filter.info(acct.getMailSieveScript()); + ZimbraLog.filter.info(expectedScript); + assertEquals(expectedScript, acct.getMailSieveScript()); + } + + /** + * Tests GetFilterRulesRequest for rule containing header test and caseSensitive attribute with + * value comparison + * @throws Exception + */ + @Test + public void testGetRuleHeaderTestValueComparisonCaseSensitivity() throws Exception { + try { + String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + filterScript += "if anyof (header :value \"eq\" :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; + filterScript += " fileinto \"Junk\";\n"; + filterScript += " stop;\n"; + filterScript += "}\n"; + + ZimbraLog.filter.info(filterScript); + + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + account.setMailSieveScript(filterScript); + + Element request = new Element.XMLElement(MailConstants.GET_FILTER_RULES_REQUEST); + Element response = new GetFilterRules().handle(request, ServiceTestUtil.getRequestContext(account)); + + String expectedSoapResponse = + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + +""; + ZimbraLog.filter.info(response.prettyPrint()); + XMLDiffChecker.assertXMLEquals(expectedSoapResponse, response.prettyPrint()); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } + + /** + * Tests GetFilterRulesRequest for rule containing address test and caseSensitive attribute with + * value comparison + * @throws Exception + */ + @Test + public void testGetRuleAddressTestValueComparisonCaseSensitivity() throws Exception { + try { + String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + filterScript += "if anyof (address :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + filterScript += " fileinto \"Junk\";\n"; + filterScript += " stop;\n"; + filterScript += "}\n"; + + ZimbraLog.filter.info(filterScript); + + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + account.setMailSieveScript(filterScript); + + Element request = new Element.XMLElement(MailConstants.GET_FILTER_RULES_REQUEST); + Element response = new GetFilterRules().handle(request, ServiceTestUtil.getRequestContext(account)); + + String expectedSoapResponse = + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + +""; + ZimbraLog.filter.info(response.prettyPrint()); + XMLDiffChecker.assertXMLEquals(expectedSoapResponse, response.prettyPrint()); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } + + /** + * Tests GetFilterRulesRequest for rule containing envelope test and caseSensitive attribute with + * value comparison + * @throws Exception + */ + @Test + public void testGetRuleEnvelopeTestValueComparisonCaseSensitivity() throws Exception { + try { + String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + filterScript += "if anyof (envelope :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; + filterScript += " fileinto \"Junk\";\n"; + filterScript += " stop;\n"; + filterScript += "}\n"; + + ZimbraLog.filter.info(filterScript); + + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + account.setMailSieveScript(filterScript); + + Element request = new Element.XMLElement(MailConstants.GET_FILTER_RULES_REQUEST); + Element response = new GetFilterRules().handle(request, ServiceTestUtil.getRequestContext(account)); + + String expectedSoapResponse = + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + +""; + ZimbraLog.filter.info(response.prettyPrint()); + XMLDiffChecker.assertXMLEquals(expectedSoapResponse, response.prettyPrint()); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } +} diff --git a/store/src/java/com/zimbra/cs/filter/SieveToSoap.java b/store/src/java/com/zimbra/cs/filter/SieveToSoap.java index 31ca69f3848..6d08958a003 100644 --- a/store/src/java/com/zimbra/cs/filter/SieveToSoap.java +++ b/store/src/java/com/zimbra/cs/filter/SieveToSoap.java @@ -288,7 +288,7 @@ protected void visitHeaderTest(Node node, VisitPhase phase, RuleProperties props @Override protected void visitHeaderTest(Node node, VisitPhase phase, RuleProperties props, - List headers, Sieve.ValueComparison comparison, boolean isCount, String value) { + List headers, Sieve.ValueComparison comparison, Sieve.Comparator comparator, boolean isCount, String value) { if (phase == VisitPhase.begin) { FilterTest.HeaderTest test = addTest(new FilterTest.HeaderTest(), props); test.setHeaders(Joiner.on(',').join(headers)); @@ -296,6 +296,12 @@ protected void visitHeaderTest(Node node, VisitPhase phase, RuleProperties props test.setCountComparison(comparison.toString()); } else { test.setValueComparison(comparison.toString()); + if (comparator != null) { + test.setValueComparisonComparator(comparator.toString()); + if (Sieve.Comparator.ioctet.equals(comparator)) { + test.setCaseSensitive(true); + } + } } test.setValue(value); } @@ -317,9 +323,9 @@ protected void visitMimeHeaderTest(Node node, VisitPhase phase, RuleProperties p @Override protected void visitAddressTest(Node node, VisitPhase phase, RuleProperties props, List headers, - Sieve.AddressPart part, Sieve.ValueComparison comparison, boolean isCount, String value) { + Sieve.AddressPart part, Sieve.ValueComparison comparison, Sieve.Comparator comparator, boolean isCount, String value) { FilterTest.AddressTest test = new FilterTest.AddressTest(); - visitAddress(test, phase, props, headers, part, comparison, isCount, value); + visitAddress(test, phase, props, headers, part, comparison, comparator, isCount, value); } @Override @@ -338,13 +344,13 @@ protected void visitEnvelopeTest(Node node, VisitPhase phase, RuleProperties pro @Override protected void visitEnvelopeTest(Node node, VisitPhase phase, RuleProperties props, List headers, - Sieve.AddressPart part, Sieve.ValueComparison comparison, boolean isCount, String value) { + Sieve.AddressPart part, Sieve.ValueComparison comparison, Sieve.Comparator comparator, boolean isCount, String value) { FilterTest.EnvelopeTest test = new FilterTest.EnvelopeTest(); - visitAddress(test, phase, props, headers, part, comparison, isCount, value); + visitAddress(test, phase, props, headers, part, comparison, comparator, isCount, value); } private void visitAddress(FilterTest.AddressTest test, VisitPhase phase, RuleProperties props, List headers, Sieve.AddressPart part, - Sieve.ValueComparison comparison, boolean isCount, String value) { + Sieve.ValueComparison comparison, Sieve.Comparator comparator, boolean isCount, String value) { if (test != null && phase == VisitPhase.begin) { addTest(test, props); test.setHeader(Joiner.on(',').join(headers)); @@ -353,6 +359,12 @@ private void visitAddress(FilterTest.AddressTest test, VisitPhase phase, RulePro test.setCountComparison(comparison.toString()); } else { test.setValueComparison(comparison.toString()); + if (comparator != null) { + test.setValueComparisonComparator(comparator.toString()); + if (Sieve.Comparator.ioctet.equals(comparator)) { + test.setCaseSensitive(true); + } + } } test.setValue(value); } diff --git a/store/src/java/com/zimbra/cs/filter/SieveVisitor.java b/store/src/java/com/zimbra/cs/filter/SieveVisitor.java index 1e964533845..a5898ad7dac 100644 --- a/store/src/java/com/zimbra/cs/filter/SieveVisitor.java +++ b/store/src/java/com/zimbra/cs/filter/SieveVisitor.java @@ -88,7 +88,7 @@ protected void visitHeaderTest(Node node, VisitPhase phase, RuleProperties props @SuppressWarnings("unused") protected void visitHeaderTest(Node node, VisitPhase phase, RuleProperties props, List headers, - Sieve.ValueComparison comparison, boolean isCount, String value) throws ServiceException { + Sieve.ValueComparison comparison, Sieve.Comparator comparator, boolean isCount, String value) throws ServiceException { // empty method } @@ -107,7 +107,7 @@ protected void visitAddressTest(Node node, VisitPhase phase, RuleProperties prop @SuppressWarnings("unused") protected void visitAddressTest(Node node, VisitPhase phase, RuleProperties props, List headers, - Sieve.AddressPart part, Sieve.ValueComparison comparison, boolean isCount, String value) + Sieve.AddressPart part, Sieve.ValueComparison comparison, Sieve.Comparator comparator, boolean isCount, String value) throws ServiceException { // empty method } @@ -119,7 +119,7 @@ protected void visitEnvelopeTest(Node node, VisitPhase phase, RuleProperties pro } protected void visitEnvelopeTest(Node node, VisitPhase phase, RuleProperties props, List headers, - Sieve.AddressPart part, Sieve.ValueComparison comparison, boolean isCount, String value) + Sieve.AddressPart part, Sieve.ValueComparison comparison, Sieve.Comparator comparator, boolean isCount, String value) throws ServiceException { // empty method } @@ -513,9 +513,9 @@ private void acceptTest(Node node, RuleProperties props) throws ServiceException if ("header".equalsIgnoreCase(nodeName)) { if (valueComparison != null) { - visitHeaderTest(node, VisitPhase.begin, props, headers, valueComparison, isCount, value); + visitHeaderTest(node, VisitPhase.begin, props, headers, valueComparison, comparator, isCount, value); accept(node, props); - visitHeaderTest(node, VisitPhase.end, props, headers, valueComparison, isCount, value); + visitHeaderTest(node, VisitPhase.end, props, headers, valueComparison, comparator, isCount, value); } else { visitHeaderTest(node, VisitPhase.begin, props, headers, comparison, caseSensitive, value); accept(node, props); @@ -577,10 +577,10 @@ private void acceptTest(Node node, RuleProperties props) throws ServiceException if ("envelope".equalsIgnoreCase(nodeName)) { if (valueComparison != null) { - visitEnvelopeTest(node, VisitPhase.begin, props, headers, part, valueComparison, isCount, + visitEnvelopeTest(node, VisitPhase.begin, props, headers, part, valueComparison, comparator, isCount, value); accept(node, props); - visitEnvelopeTest(node, VisitPhase.end, props, headers, part, valueComparison, isCount, value); + visitEnvelopeTest(node, VisitPhase.end, props, headers, part, valueComparison, comparator, isCount, value); } else { visitEnvelopeTest(node, VisitPhase.begin, props, headers, part, comparison, caseSensitive, value); @@ -589,9 +589,9 @@ private void acceptTest(Node node, RuleProperties props) throws ServiceException } } else { if (valueComparison != null) { - visitAddressTest(node, VisitPhase.begin, props, headers, part, valueComparison, isCount, value); + visitAddressTest(node, VisitPhase.begin, props, headers, part, valueComparison, comparator, isCount, value); accept(node, props); - visitAddressTest(node, VisitPhase.end, props, headers, part, valueComparison, isCount, value); + visitAddressTest(node, VisitPhase.end, props, headers, part, valueComparison, comparator, isCount, value); } else { visitAddressTest(node, VisitPhase.begin, props, headers, part, comparison, caseSensitive, value); diff --git a/store/src/java/com/zimbra/cs/filter/SoapToSieve.java b/store/src/java/com/zimbra/cs/filter/SoapToSieve.java index 809a415333b..ca89354d3db 100644 --- a/store/src/java/com/zimbra/cs/filter/SoapToSieve.java +++ b/store/src/java/com/zimbra/cs/filter/SoapToSieve.java @@ -388,12 +388,13 @@ private static String toSieve(FilterTest.HeaderTest test) throws ServiceExceptio if (StringUtils.isNotEmpty(test.getValueComparison())) { Sieve.ValueComparison comp = Sieve.ValueComparison.fromString(test.getValueComparison()); - return toSieve("header", header, comp, test.getValue(), false, null); + Sieve.Comparator valueComparisonComparator = Sieve.Comparator.fromString(test.getValueComparisonComparator()); + return toSieve("header", header, comp, valueComparisonComparator, test.isCaseSensitive(), test.getValue(), false, null); } if (StringUtils.isNotEmpty(test.getCountComparison())) { Sieve.ValueComparison comp = Sieve.ValueComparison.fromString(test.getCountComparison()); - return toSieve("header", header, comp, test.getValue(), true, null); + return toSieve("header", header, comp, null, false, test.getValue(), true, null); } return null; } @@ -412,20 +413,29 @@ private static String toSieve(String name, String header, Sieve.StringComparison return String.format(format, name, comp, header, FilterUtil.escape(value)); } - private static String toSieve(String name, String header, Sieve.ValueComparison comp, String value, boolean isCount, Sieve.AddressPart part) throws ServiceException { + private static String toSieve(String name, String header, Sieve.ValueComparison comp, Sieve.Comparator valueComparator, boolean caseSensitive, String value, boolean isCount, Sieve.AddressPart part) throws ServiceException { String countOrVal = isCount ? ":count" : ":value"; - boolean numeric = true; - try { - Integer.parseInt(value); - } catch (NumberFormatException e) { - numeric = false; - } - //for :count, iasciinumeric comparator will be used always. - //for :value, iasciinumeric comparator will be used if value is numeric else - //iasciicasemap will be used until comparator value can be set from soap api. - Sieve.Comparator comparator= Sieve.Comparator.iasciinumeric; - if (!numeric && !isCount) { - comparator= Sieve.Comparator.iasciicasemap; + Sieve.Comparator comparator; + if (valueComparator == null) { + boolean numeric = true; + try { + Integer.parseInt(value); + } catch (NumberFormatException e) { + numeric = false; + } + //for :count, iasciinumeric comparator will be used always + //for :value, if comparator value is not set in input, iasciinumeric comparator will be used if value is numeric + //else iasciicasemap will be used for case-insensitive and ioctet for case-sensitive + comparator = Sieve.Comparator.iasciinumeric; + if (!numeric && !isCount) { + if (caseSensitive) { + comparator = Sieve.Comparator.ioctet; + } else { + comparator = Sieve.Comparator.iasciicasemap; + } + } + } else { + comparator = valueComparator; } if (part == null) { String format = "%s " + countOrVal + " \"%s\" :comparator \"" + comparator + "\" %s \"%s\""; @@ -462,12 +472,13 @@ private static String formatAddress(FilterTest.AddressTest test, String testName if (StringUtils.isNotEmpty(test.getValueComparison())) { Sieve.ValueComparison comp = Sieve.ValueComparison.fromString(test.getValueComparison()); - return toSieve(testName, header, comp, test.getValue(), false, part); + Sieve.Comparator valueComparisonComparator = Sieve.Comparator.fromString(test.getValueComparisonComparator()); + return toSieve(testName, header, comp, valueComparisonComparator, test.isCaseSensitive(), test.getValue(), false, part); } if (StringUtils.isNotEmpty(test.getCountComparison())) { Sieve.ValueComparison comp = Sieve.ValueComparison.fromString(test.getCountComparison()); - return toSieve(testName, header, comp, test.getValue(), true, part); + return toSieve(testName, header, comp, null, false, test.getValue(), true, part); } return null; } From ca0eb1f0e6c989c449c1401d742ca73cf1cbc7fd Mon Sep 17 00:00:00 2001 From: Chinmay Pathak <15.chinmay@gmail.com> Date: Mon, 11 Sep 2017 17:54:44 +0530 Subject: [PATCH 029/142] ZCS-2727 : API to get the list of Contact backups Resolved review comments, added json support and unit test, updated soap.txt --- .../com/zimbra/common/soap/MailConstants.java | 6 + soap/src/java/com/zimbra/soap/JaxbUtil.java | 2 + .../message/GetContactBackupListRequest.java | 32 +++++ .../message/GetContactBackupListResponse.java | 97 +++++++++++++++ store/docs/soap.txt | 13 +++ .../mail/GetContactBackupListTest.java | 110 ++++++++++++++++++ .../cs/service/mail/GetContactBackupList.java | 52 +++++++++ .../zimbra/cs/service/mail/MailService.java | 1 + 8 files changed, 313 insertions(+) create mode 100644 soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListRequest.java create mode 100644 soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListResponse.java create mode 100644 store/src/java-test/com/zimbra/cs/service/mail/GetContactBackupListTest.java create mode 100644 store/src/java/com/zimbra/cs/service/mail/GetContactBackupList.java diff --git a/common/src/java/com/zimbra/common/soap/MailConstants.java b/common/src/java/com/zimbra/common/soap/MailConstants.java index bb18d7e500b..8d296e3bbb3 100644 --- a/common/src/java/com/zimbra/common/soap/MailConstants.java +++ b/common/src/java/com/zimbra/common/soap/MailConstants.java @@ -133,6 +133,10 @@ private MailConstants() { public static final String E_MODIFY_CONTACT_RESPONSE = "ModifyContactResponse"; public static final String E_GET_CONTACTS_REQUEST = "GetContactsRequest"; public static final String E_GET_CONTACTS_RESPONSE = "GetContactsResponse"; + public static final String E_GET_CONTACT_BACKUP_LIST_REQUEST = "GetContactBackupListRequest"; + public static final String E_GET_CONTACT_BACKUP_LIST_RESPONSE = "GetContactBackupListResponse"; + public static final String E_BACKUPS = "backups"; + public static final String E_BACKUP = "backup"; public static final String E_IMPORT_CONTACTS_REQUEST = "ImportContactsRequest"; public static final String E_IMPORT_CONTACTS_RESPONSE = "ImportContactsResponse"; public static final String E_EXPORT_CONTACTS_REQUEST = "ExportContactsRequest"; @@ -395,6 +399,8 @@ private MailConstants() { public static final QName EXPORT_CONTACTS_RESPONSE = QName.get(E_EXPORT_CONTACTS_RESPONSE, NAMESPACE); public static final QName CONTACT_ACTION_REQUEST = QName.get(E_CONTACT_ACTION_REQUEST, NAMESPACE); public static final QName CONTACT_ACTION_RESPONSE = QName.get(E_CONTACT_ACTION_RESPONSE, NAMESPACE); + public static final QName GET_CONTACT_BACKUP_LIST_REQUEST = QName.get(E_GET_CONTACT_BACKUP_LIST_REQUEST, NAMESPACE); + public static final QName GET_CONTACT_BACKUP_LIST_RESPONSE = QName.get(E_GET_CONTACT_BACKUP_LIST_RESPONSE, NAMESPACE); // notes public static final QName CREATE_NOTE_REQUEST = QName.get(E_CREATE_NOTE_REQUEST, NAMESPACE); public static final QName CREATE_NOTE_RESPONSE = QName.get(E_CREATE_NOTE_RESPONSE, NAMESPACE); diff --git a/soap/src/java/com/zimbra/soap/JaxbUtil.java b/soap/src/java/com/zimbra/soap/JaxbUtil.java index bef012f65fd..bac18380c2e 100644 --- a/soap/src/java/com/zimbra/soap/JaxbUtil.java +++ b/soap/src/java/com/zimbra/soap/JaxbUtil.java @@ -297,6 +297,8 @@ public final class JaxbUtil { com.zimbra.soap.mail.message.GetCalendarItemSummariesResponse.class, com.zimbra.soap.mail.message.GetCommentsRequest.class, com.zimbra.soap.mail.message.GetCommentsResponse.class, + com.zimbra.soap.mail.message.GetContactBackupListRequest.class, + com.zimbra.soap.mail.message.GetContactBackupListResponse.class, com.zimbra.soap.mail.message.GetContactsRequest.class, com.zimbra.soap.mail.message.GetContactsResponse.class, com.zimbra.soap.mail.message.GetConvRequest.class, diff --git a/soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListRequest.java b/soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListRequest.java new file mode 100644 index 00000000000..99c4c1666d9 --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListRequest.java @@ -0,0 +1,32 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.soap.mail.message; + +import javax.xml.bind.annotation.XmlRootElement; + +import com.zimbra.common.soap.MailConstants; + +/** + * @zm-api-command-auth-required true + * @zm-api-command-admin-auth-required false + * @zm-api-command-description Get list of available contact backups + */ +@XmlRootElement(name=MailConstants.E_GET_CONTACT_BACKUP_LIST_REQUEST) +public class GetContactBackupListRequest { + // empty request +} diff --git a/soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListResponse.java b/soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListResponse.java new file mode 100644 index 00000000000..4e7cc78a9e2 --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/message/GetContactBackupListResponse.java @@ -0,0 +1,97 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.soap.mail.message; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +import com.google.common.base.Objects; +import com.zimbra.common.soap.MailConstants; +import com.zimbra.common.util.StringUtil; +import com.zimbra.soap.json.jackson.annotate.ZimbraJsonArrayForWrapper; + +/** + * api to get list of available contact backups + */ +@XmlAccessorType(XmlAccessType.NONE) +@XmlRootElement(name = MailConstants.E_GET_CONTACT_BACKUP_LIST_RESPONSE) +public class GetContactBackupListResponse { + @ZimbraJsonArrayForWrapper + @XmlElementWrapper(name=MailConstants.E_BACKUPS /* backups */, required=false) + @XmlElement(name = MailConstants.E_BACKUP /* backup */, required = false) + private List backup; + + public GetContactBackupListResponse() { + this(null); + } + + /** + * @param backup + */ + public GetContactBackupListResponse(List backup) { + setBackup(backup); + } + + /** + * @return the backup + */ + public List getBackup() { + return backup; + } + + /** + * @param backup the backup to set + */ + public void setBackup(List backup) { + if (backup == null || backup.isEmpty()) { + this.backup = null; + } else { + this.backup = backup; + } + } + + /** + * @param backup the backup to add in the backup + */ + public void addBackup(String backup) { + if (!StringUtil.isNullOrEmpty(backup)) { + if (this.backup == null) { + this.backup = new ArrayList(); + } + this.backup.add(backup); + } + } + + public Objects.ToStringHelper addToStringInfo(Objects.ToStringHelper helper) { + return helper + .add("backup", backup); + } + + @Override + public String toString() { + return addToStringInfo(Objects.toStringHelper(this)).toString(); + } + + +} diff --git a/store/docs/soap.txt b/store/docs/soap.txt index dd37e36f54f..97cf1e629a8 100644 --- a/store/docs/soap.txt +++ b/store/docs/soap.txt @@ -4694,3 +4694,16 @@ If IMAP tracking is already enabled, does nothing. + +----------------------------- +Api to get list of available contact backup files + + + + [ + file1_name + file2_name + file3_name + ... + ] + \ No newline at end of file diff --git a/store/src/java-test/com/zimbra/cs/service/mail/GetContactBackupListTest.java b/store/src/java-test/com/zimbra/cs/service/mail/GetContactBackupListTest.java new file mode 100644 index 00000000000..3847c213b03 --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/service/mail/GetContactBackupListTest.java @@ -0,0 +1,110 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** Zimbra Collaboration Suite Server Copyright + * (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. You should have received a copy of the GNU General Public License + * along with this program. If not, see . ***** + * END LICENSE BLOCK ***** + */ +package com.zimbra.cs.service.mail; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.Maps; +import com.zimbra.common.account.Key; +import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.MailConstants; +import com.zimbra.common.soap.SoapProtocol; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.cs.service.AuthProvider; +import com.zimbra.cs.service.MockHttpServletRequest; +import com.zimbra.soap.MockSoapEngine; +import com.zimbra.soap.SoapEngine; +import com.zimbra.soap.SoapServlet; +import com.zimbra.soap.ZimbraSoapContext; + +import junit.framework.Assert; + +public class GetContactBackupListTest { + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + Provisioning prov = Provisioning.getInstance(); + Map attrs = Maps.newHashMap(); + prov.createAccount("test@zimbra.com", "secret", attrs); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + } + + @Test + public void testGetContactBackupListXML() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + + Element request = new Element.XMLElement(MailConstants.E_GET_CONTACT_BACKUP_LIST_REQUEST); + Element response = new GetContactBackupList().handle(request, ServiceTestUtil.getRequestContext(acct)); + + String expectedResponse = "\n" + + " \n" + + " file1.tgz\n" + + " file2.tgz\n" + + " file3.tgz\n" + + " file4.tgz\n" + + " \n" + + ""; + + Assert.assertEquals("GetContactBackupListResponse is not as expected", expectedResponse, response.prettyPrint()); + } + + @Test + public void testGetContactBackupListJSON() throws Exception { + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + + Map context = new HashMap(); + context.put(SoapEngine.ZIMBRA_CONTEXT, new ZimbraSoapContext(AuthProvider.getAuthToken(acct), acct.getId(), SoapProtocol.Soap12, SoapProtocol.SoapJS)); + context.put(SoapServlet.SERVLET_REQUEST, new MockHttpServletRequest("test".getBytes("UTF-8"), new URL("http://localhost:7070/service/FooRequest"), "")); + context.put(SoapEngine.ZIMBRA_ENGINE, new MockSoapEngine(new MailService())); + + + Element request = new Element.JSONElement(MailConstants.E_GET_CONTACT_BACKUP_LIST_REQUEST); + Element response = new GetContactBackupList().handle(request, context); + + String expectedResponse = "{\n" + + " \"backups\": [{\n" + + " \"backup\": [\n" + + " {\n" + + " \"_content\": \"file1.tgz\"\n" + + " },\n" + + " {\n" + + " \"_content\": \"file2.tgz\"\n" + + " },\n" + + " {\n" + + " \"_content\": \"file3.tgz\"\n" + + " },\n" + + " {\n" + + " \"_content\": \"file4.tgz\"\n" + + " }]\n" + + " }],\n" + + " \"_jsns\": \"urn:zimbraMail\"\n" + + "}"; + + Assert.assertEquals("GetContactBackupListResponse is not as expected", expectedResponse, response.prettyPrint()); + } +} diff --git a/store/src/java/com/zimbra/cs/service/mail/GetContactBackupList.java b/store/src/java/com/zimbra/cs/service/mail/GetContactBackupList.java new file mode 100644 index 00000000000..91e123d39db --- /dev/null +++ b/store/src/java/com/zimbra/cs/service/mail/GetContactBackupList.java @@ -0,0 +1,52 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.cs.service.mail; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.Element; +import com.zimbra.cs.account.Account; +import com.zimbra.soap.ZimbraSoapContext; +import com.zimbra.soap.mail.message.GetContactBackupListResponse; + +public final class GetContactBackupList extends MailDocumentHandler { + + @Override + public Element handle(Element request, Map context) throws ServiceException { + ZimbraSoapContext zsc = getZimbraSoapContext(context); + Account account = getRequestedAccount(zsc); + + List backup = getContactBackupList(account); + + GetContactBackupListResponse res = new GetContactBackupListResponse(backup); + return zsc.jaxbToElement(res); + } + + // TODO : Update this method along with contact backup functionality + private List getContactBackupList(Account account) { + List list = new ArrayList(); + list.add("file1.tgz"); + list.add("file2.tgz"); + list.add("file3.tgz"); + list.add("file4.tgz"); + return list; + } +} diff --git a/store/src/java/com/zimbra/cs/service/mail/MailService.java b/store/src/java/com/zimbra/cs/service/mail/MailService.java index 51eee417fb8..4ebd75100b0 100644 --- a/store/src/java/com/zimbra/cs/service/mail/MailService.java +++ b/store/src/java/com/zimbra/cs/service/mail/MailService.java @@ -97,6 +97,7 @@ public void registerHandlers(DocumentDispatcher dispatcher) { dispatcher.registerHandler(MailConstants.CONTACT_ACTION_REQUEST, new ContactAction()); dispatcher.registerHandler(MailConstants.EXPORT_CONTACTS_REQUEST, new ExportContacts()); dispatcher.registerHandler(MailConstants.IMPORT_CONTACTS_REQUEST, new ImportContacts()); + dispatcher.registerHandler(MailConstants.GET_CONTACT_BACKUP_LIST_REQUEST, new GetContactBackupList()); // notes if (LC.notes_enabled.booleanValue()) { From 12ea2a5dac203ce84dabce319503dfe703aeb6c3 Mon Sep 17 00:00:00 2001 From: Chinmay Pathak <15.chinmay@gmail.com> Date: Mon, 11 Sep 2017 17:48:48 +0530 Subject: [PATCH 030/142] ZCS-2388 : Removed null check. Made test filed required=true --- .../zimbra/soap/mail/type/FilterAction.java | 5 +---- .../admin/ModifyFilterRulesAdminTest.java | 20 ------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/soap/src/java/com/zimbra/soap/mail/type/FilterAction.java b/soap/src/java/com/zimbra/soap/mail/type/FilterAction.java index ddfd9fc7d1e..208327f2aa8 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/FilterAction.java +++ b/soap/src/java/com/zimbra/soap/mail/type/FilterAction.java @@ -682,7 +682,7 @@ public static class DeleteheaderAction extends FilterAction { * @zm-api-field-tag filterTests * @zm-api-field-description tests */ - @XmlElement(name=AdminConstants.E_TEST /* test */, required=false) + @XmlElement(name=AdminConstants.E_TEST /* test */, required=true) private EditheaderTest test; private DeleteheaderAction() { @@ -749,9 +749,6 @@ public void validateDeleteheaderAction() throws ServiceException { if (last != null && last && offset == null) { throw ServiceException.PARSE_ERROR(":index must be provided with :last", null); } - if (test == null) { - throw ServiceException.PARSE_ERROR(" is mandatory in action", null); - } test.validateEditheaderTest(); } diff --git a/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java b/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java index d214d30beba..50466ffe51b 100644 --- a/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java +++ b/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java @@ -245,26 +245,6 @@ public void testSoapToSieveDeleteheaderAction7() throws ServiceException, Except Assert.assertEquals(script, account.getAdminSieveScriptBefore()); } - // negative test case - @Test - public void testNegativeSoapToSieveDeleteheaderAction() throws ServiceException, Exception { - List values = new ArrayList(); - values.add("2"); - DeleteheaderAction action = new DeleteheaderAction(null, null, null); - FilterRule filterRule = new FilterRule("rule1", true); - filterRule.addFilterAction(action); - List filterRules = new ArrayList(); - filterRules.add(filterRule); - - RuleManager.clearCachedRules(account); - try { - RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - } catch (ServiceException se) { - Assert.assertEquals("service.PARSE_ERROR", se.getCode()); - Assert.assertTrue(se.getMessage().contains(" is mandatory in action")); - } - } - /******************replaceheader*********************/ @Test public void testSoapToSieveReplaceheaderActionBasic() throws ServiceException, Exception { From 43c6012c967d456ffd8ba43e15032613da6e5aed Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 8 Sep 2017 16:59:28 +0100 Subject: [PATCH 031/142] ZCS-2762:ImapTestBase.doListShouldSucceed improve * Added a `doListShouldSucceed` variant which takes the expected list of mailbox names and provides a good error if there are missing or extra mailboxes in the list * Added `checkConnection` and used it in multiple places so get a good error if call a method with an ImapConnection not setup yet. --- .../com/zimbra/qa/unittest/ImapTestBase.java | 101 ++++++++++++++++-- 1 file changed, 91 insertions(+), 10 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java index e8e4cd541f1..eaa098415b9 100644 --- a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java +++ b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java @@ -11,6 +11,7 @@ import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -22,6 +23,7 @@ import org.junit.rules.TestName; import com.google.common.base.Joiner; +import com.google.common.collect.Lists; import com.zimbra.common.localconfig.ConfigException; import com.zimbra.common.localconfig.LC; import com.zimbra.common.service.ServiceException; @@ -155,6 +157,11 @@ public static void restoreImapConfigSettings() TestUtil.setLCValue(LC.imap_always_use_remote_store, String.valueOf(saved_imap_always_use_remote_store)); } + public static void checkConnection(ImapConnection conn) { + assertNotNull("ImapConnection object should not be null", conn); + assertFalse("ImapConnection should not be closed", conn.isClosed()); + } + protected ImapConnection connect(String user) throws IOException { ImapConfig config = new ImapConfig(imapHostname); config.setPort(imapPort); @@ -201,6 +208,7 @@ protected ImapConnection getAdminConnection() throws Exception { } protected void doSelectShouldFail(ImapConnection conn, String folderName) throws IOException { + checkConnection(conn); MailboxInfo mbInfo = null; try { mbInfo = conn.select(folderName); @@ -214,6 +222,7 @@ protected void doSelectShouldFail(ImapConnection conn, String folderName) throws } protected MailboxInfo doSelectShouldSucceed(ImapConnection conn, String folderName) throws IOException { + checkConnection(conn); MailboxInfo mbInfo = null; try { mbInfo = conn.select(folderName); @@ -241,6 +250,7 @@ protected static class StatusExecutor { private Long expectedUnseen = null; protected MailboxInfo mbInfo = null; protected StatusExecutor(ImapConnection imapConn) { + checkConnection(imapConn); conn = imapConn; } protected StatusExecutor setExists(long expected) { expectedExists = expected; return this;}; @@ -274,6 +284,7 @@ protected MailboxInfo execShouldSucceed(String folderName, Object... params) thr protected Map doFetchShouldSucceed(ImapConnection conn, String range, String what, List expectedSubjects) throws IOException { + checkConnection(conn); try { Map mdMap = conn.fetch(range, what); assertNotNull(String.format("map returned by 'FETCH %s %s' should not be null", range, what), mdMap); @@ -322,6 +333,7 @@ protected void doRenameShouldSucceed(String origFolderName, String newFolderName } protected void doSubscribeShouldSucceed(ImapConnection imapConn, String folderName) { + checkConnection(imapConn); try { imapConn.subscribe(folderName); } catch (Exception e) { @@ -330,6 +342,7 @@ protected void doSubscribeShouldSucceed(ImapConnection imapConn, String folderNa } protected void doUnsubscribeShouldSucceed(ImapConnection imapConn, String folderName) { + checkConnection(imapConn); try { imapConn.unsubscribe(folderName); } catch (Exception e) { @@ -339,6 +352,7 @@ protected void doUnsubscribeShouldSucceed(ImapConnection imapConn, String folder protected void doListShouldFail(ImapConnection conn, String ref, String mailbox, String expected) throws IOException { + checkConnection(conn); try { conn.list(ref, mailbox); fail(String.format("'LIST \"%s\" \"%s\"' should have failed", ref, mailbox)); @@ -351,6 +365,7 @@ protected void doListShouldFail(ImapConnection conn, String ref, String mailbox, protected List doListShouldSucceed(ImapConnection conn, String ref, String mailbox, int expected) throws IOException { + checkConnection(conn); String cmdDesc = String.format("'%s \"%s\" \"%s\"'", CAtom.LIST, ref, mailbox); try { List listResult = conn.list(ref, mailbox); @@ -394,16 +409,11 @@ protected List doListShouldSucceed(ImapConnection conn, String ref, St protected List doLSubShouldSucceed(ImapConnection conn, String ref, String mailbox, List expectedMboxNames, String testDesc) throws IOException { + checkConnection(conn); String cmdDesc = String.format("'%s \"%s\" \"%s\"'", CAtom.LSUB, ref, mailbox); try { List listResult = conn.lsub(ref, mailbox); - assertNotNull(String.format("%s:list result from %s should not be null", testDesc, cmdDesc), listResult); - assertEquals(String.format( "%s:Number of entries in list returned for %s\n%s", - testDesc, cmdDesc, listResult), expectedMboxNames.size(), listResult.size()); - for (String mbox : expectedMboxNames) { - assertTrue(String.format("%s:'%s' NOT in list returned by %s\n%s", - testDesc, mbox, cmdDesc, listResult), listContains(listResult, mbox)); - } + checkListDataList(cmdDesc, testDesc, listResult, expectedMboxNames); return listResult; } catch (CommandFailedException cfe) { String err = cfe.getError(); @@ -412,16 +422,86 @@ protected List doLSubShouldSucceed(ImapConnection conn, String ref, St } } - protected boolean listContains(List listData, String folderName) { - for (ListData ld: listData) { - if (ld.getMailbox().equalsIgnoreCase(folderName)) { + protected List doListShouldSucceed(ImapConnection conn, String ref, String mailbox, + List expectedMboxNames, String testDesc) + throws IOException { + checkConnection(conn); + String cmdDesc = String.format("'%s \"%s\" \"%s\"'", CAtom.LIST, ref, mailbox); + try { + List listResult = conn.list(ref, mailbox); + checkListDataList(cmdDesc, testDesc, listResult, expectedMboxNames); + return listResult; + } catch (CommandFailedException cfe) { + String err = cfe.getError(); + fail(String.format("%s:%s returned error '%s'", testDesc, cmdDesc, err)); + return null; + } + } + + public void checkListDataList(String cmdDesc, String testDesc, List listResult, + List expectedMboxNames) throws IOException { + assertNotNull(String.format("%s:list result from %s should not be null", testDesc, cmdDesc), + listResult); + List actualMboxNames = mailboxNames(listResult); + List missingMboxNames = Lists.newArrayList(); + List extraMboxNames = Lists.newArrayList(); + for (String mbox : expectedMboxNames) { + if (!containsIgnoreCase(actualMboxNames, mbox)) { + missingMboxNames.add(mbox); + } + } + for (String mbox : actualMboxNames) { + if (!containsIgnoreCase(expectedMboxNames, mbox)) { + extraMboxNames.add(mbox); + } + } + if (!missingMboxNames.isEmpty() || !extraMboxNames.isEmpty()) { + StringBuilder sb = new StringBuilder(); + if (!missingMboxNames.isEmpty()) { + sb.append("\nMissing mailbox names:"); + sb.append(Joiner.on("\n ").join(missingMboxNames)); + } + if (!extraMboxNames.isEmpty()) { + sb.append("\nExtra mailbox names:"); + sb.append(Joiner.on("\n ").join(extraMboxNames)); + } + fail(String.format("%s:'%s' returned unexpected mailbox names %s\nList Result:%s", + testDesc, cmdDesc, sb, listResult)); + } + // Doubt if can get here but just in case + assertEquals(String.format( "%s:Number of entries in list returned for %s\n%s", + testDesc, cmdDesc, listResult), expectedMboxNames.size(), listResult.size()); + } + + public boolean containsIgnoreCase(List mboxNames, String mboxName) { + if (mboxNames == null) { + return false; + } + for (String mbox: mboxNames) { + if (mboxName.equalsIgnoreCase(mbox)) { return true; } } return false; } + public boolean listDataContains(List listData, String mboxName) { + return containsIgnoreCase(mailboxNames(listData), mboxName); + } + + public List mailboxNames(List listData) { + if (listData == null) { + return Collections.emptyList(); + } + List mboxes = Lists.newArrayListWithExpectedSize(listData.size()); + for (ListData ld: listData) { + mboxes.add(ld.getMailbox()); + } + return mboxes; + } + protected MessageData fetchMessage(ImapConnection conn, long uid) throws IOException { + checkConnection(conn); MessageData md = conn.uidFetch(uid, "(FLAGS BODY.PEEK[])"); assertNotNull(String.format( "`UID FETCH %s (FLAGS BODY.PEEK[])` returned no data - assume message not found", uid), md); @@ -483,6 +563,7 @@ public static Literal message(int size) throws IOException { protected void doAppend(ImapConnection conn, String folderName, int size, Flags flags, boolean fetchResult) throws IOException { + checkConnection(conn); assertTrue("expecting UIDPLUS capability", conn.hasCapability("UIDPLUS")); Date date = new Date(System.currentTimeMillis()); Literal msg = message(size); From 43fdbcccc1d03b544285b2eeed36b71ff9a35764 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 8 Sep 2017 17:02:51 +0100 Subject: [PATCH 032/142] ZCS-2762:SharedImapTests 1st better list checking * Renamed listContains listDataContains in ImapTestBase * `mountpointWithSubFolder()` changed so that detects extra mailbox name in list which is the problem for ZCS-2762 --- .../zimbra/qa/unittest/SharedImapTests.java | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index efadd10e05b..5a3e4020d4c 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -1959,21 +1959,25 @@ private SubFolderEnv(String sharedFolderName, String subFolder) @Test(timeout=100000) public void mountpointWithSubFolder() throws ServiceException, IOException, MessagingException { + String ref; + String searchPatt; + List listResult; + String sharedFolderName = String.format("INBOX/%s-shared", testId); String subFolder = sharedFolderName + "/subFolder"; TestUtil.createAccount(SHAREE); + otherConnection = connectAndLogin(SHAREE); + listResult = otherConnection.list("", "*"); + List baselineMboxNames = mailboxNames(listResult); + SubFolderEnv subFolderEnv = new SubFolderEnv(sharedFolderName, subFolder); ZMailbox userZmbox = TestUtil.getZMailbox(USER); ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); + String mountpointName = String.format("%s's %s-shared", USER, testId); String subMountpoint = mountpointName + "/subFolder"; String remoteFolderPath = "/" + sharedFolderName; TestUtil.createMountpoint(userZmbox, remoteFolderPath, shareeZmbox, mountpointName); - otherConnection = connectAndLogin(SHAREE); - - String ref; - String searchPatt; - List listResult; /* wild card at end should pick up top level and sub-folder */ searchPatt = mountpointName + "*"; @@ -2001,18 +2005,11 @@ public void mountpointWithSubFolder() throws ServiceException, IOException, Mess "'%s' mountpoint not in result of 'list \"\" \"%s\"'", subMountpoint, subMountpoint), subMountpoint, listResult.get(0).getMailbox()); + List expectedMboxNames = Lists.newArrayList(baselineMboxNames); + expectedMboxNames.add(mountpointName); + expectedMboxNames.add(subMountpoint); /* sub-folder should be in list of all folders */ - listResult = otherConnection.list("", "*"); - assertNotNull("list result for 'list \"\" \"*\"' should not be null", listResult); - boolean seenIt = false; - for (ListData listEnt : listResult) { - if (subMountpoint.equals(listEnt.getMailbox())) { - seenIt = true; - break; - } - } - assertTrue(String.format("'%s' mountpoint not in result of 'list \"\" \"*\"'", subMountpoint), seenIt); - + doListShouldSucceed(otherConnection, "", "*", expectedMboxNames, "List ALL including mountpoints"); doSelectShouldSucceed(otherConnection, mountpointName); doFetchShouldSucceed(otherConnection, "1:*", "(FLAGS ENVELOPE)", subFolderEnv.subjects); doSelectShouldSucceed(otherConnection, subMountpoint); @@ -2179,20 +2176,20 @@ public void testRenameParentFolder() throws Exception { connection.login(PASS); connection.create(childFolder2); List listResult = connection.list("", "*"); - assertTrue(listContains(listResult, parentFolder)); - assertTrue(listContains(listResult, childFolder1)); - assertTrue(listContains(listResult, childFolder2)); + assertTrue(listDataContains(listResult, parentFolder)); + assertTrue(listDataContains(listResult, childFolder1)); + assertTrue(listDataContains(listResult, childFolder2)); String newParentFolder = "renamed"; String newChildFolder1 = newParentFolder + "/child1"; String newChildFolder2 = newChildFolder1 + "/child2"; connection.rename(parentFolder, newParentFolder); listResult = connection.list("", "*"); - assertTrue(listContains(listResult, newParentFolder)); - assertTrue(listContains(listResult, newChildFolder1)); - assertTrue(listContains(listResult, newChildFolder2)); - assertFalse(listContains(listResult, parentFolder)); - assertFalse(listContains(listResult, childFolder1)); - assertFalse(listContains(listResult, childFolder2)); + assertTrue(listDataContains(listResult, newParentFolder)); + assertTrue(listDataContains(listResult, newChildFolder1)); + assertTrue(listDataContains(listResult, newChildFolder2)); + assertFalse(listDataContains(listResult, parentFolder)); + assertFalse(listDataContains(listResult, childFolder1)); + assertFalse(listDataContains(listResult, childFolder2)); } @Test(timeout=100000) From e8ec3be43c6b85c117ae5fd5eb89b0e48842785c Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 11 Sep 2017 17:21:59 +0100 Subject: [PATCH 033/142] ZCS-2762:ImapHandler folder double handling `imapStore.getVisibleFolders` for remote case includes sub-folders of mountpoints (unlike local case) - so they end up being handled twice Now filter these out. --- .../java/com/zimbra/cs/imap/ImapHandler.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/store/src/java/com/zimbra/cs/imap/ImapHandler.java b/store/src/java/com/zimbra/cs/imap/ImapHandler.java index 8ea752daff7..115aaaa7764 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapHandler.java +++ b/store/src/java/com/zimbra/cs/imap/ImapHandler.java @@ -54,6 +54,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.io.Closeables; +import com.zimbra.client.ZFolder; import com.zimbra.client.ZSharedFolder; import com.zimbra.common.account.Key; import com.zimbra.common.account.Key.AccountBy; @@ -2284,6 +2285,11 @@ private void accumulatePaths(ImapMailboxStore imapStore, String owner, ImapPath if (isMailFolders && (folderStore.isChatsFolder() || (folderStore.getName().equals ("Chats")))) { continue; } + /* In remote case, list includes children of mountpoints - filter them out here and instead + * tackle them via accumulatePaths in the owner mailbox. */ + if (!(folderStore instanceof MountpointStore) && isInMountpointHierarchy(folderStore)) { + continue; + } ImapPath path = relativeTo == null ? new ImapPath(owner, folderStore, credentials) : new ImapPath(owner, folderStore, relativeTo); if (path.isVisible()) { @@ -2301,6 +2307,21 @@ private void accumulatePaths(ImapMailboxStore imapStore, String owner, ImapPath } } + /** Note this only really works with ZFolders - but that is sufficient for current needs */ + private boolean isInMountpointHierarchy(FolderStore fldr) throws ServiceException { + if (fldr == null) { + return false; + } + if (fldr instanceof MountpointStore) { + return true; + } + if (fldr instanceof ZFolder) { + ZFolder zfldr = (ZFolder) fldr; + return isInMountpointHierarchy(zfldr.getParent()); + } + return false; + } + private static boolean pathMatches(String path, Pattern pattern) throws ServiceException { return AccessBoundedRegex.matches(path, pattern, From d7cb717279f0180106b27e64a78e141a7991d82a Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 11 Sep 2017 21:08:13 +0100 Subject: [PATCH 034/142] ZCS-2762:SharedImapTests More use of LIST wrapper Use the new `doListShouldSucceed` which takes a list of expected mailbox names more for tighter checking and failure reporting. --- .../zimbra/qa/unittest/SharedImapTests.java | 108 ++++++------------ 1 file changed, 33 insertions(+), 75 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index 5a3e4020d4c..a6cd78fe79c 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -1831,72 +1831,49 @@ public void listSharedFolderViaHome() throws ServiceException, IOException { String underRemFolder = String.format("%s/subFolder", remFolder); String homeFilter = String.format("/home/%s", USER); otherConnection = connectAndSelectInbox(SHAREE); - List listResult; - String ref; - String mailbox; doListShouldFail(otherConnection, "/home", "*", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/*", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/fred*", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/*fred", "LIST failed: wildcards not permitted in username"); - doListShouldSucceed(otherConnection, "", "INBOX", 1); // reset zimbraImapMaxConsecutiveError counter + // reset zimbraImapMaxConsecutiveError counter + doListShouldSucceed(otherConnection, "", "INBOX", Lists.newArrayList("INBOX"), "JUST INBOX #1"); doListShouldFail(otherConnection, "", "/home/pete*fred", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/*/", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/pete*/", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/pete*fred/", "LIST failed: wildcards not permitted in username"); - doListShouldSucceed(otherConnection, "", "INBOX", 1); // reset zimbraImapMaxConsecutiveError counter + // reset zimbraImapMaxConsecutiveError counter + doListShouldSucceed(otherConnection, "", "INBOX", Lists.newArrayList("INBOX"), "JUST INBOX #2"); doListShouldFail(otherConnection, "", "/home/*/INBOX", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/pete*/INBOX", "LIST failed: wildcards not permitted in username"); doListShouldFail(otherConnection, "", "/home/pete*fred/INBOX", "LIST failed: wildcards not permitted in username"); // LIST "" "/home/user/sharedFolderName" - listResult = doListShouldSucceed(otherConnection, "", remFolder, 1); + doListShouldSucceed(otherConnection, "", remFolder, Lists.newArrayList(remFolder), "JUST remFolder"); // 'LIST "/home" "user"' - should get: // * LIST (\NoSelect) "/" "/home/user" - listResult = doListShouldSucceed(otherConnection, "/home", USER, 1); + doListShouldSucceed(otherConnection, "/home", USER, + Lists.newArrayList(String.format("/home/%s", USER)), "JUST /home/user"); // 'LIST "/home" "user/*"' - ref = "/home"; - mailbox = USER + "/*"; - listResult = doListShouldSucceed(otherConnection, ref, mailbox, 2); - assertEquals(String.format( - "'%s' mailbox not in result of 'list \"%s\" \"%s\"'", remFolder, ref, mailbox), - remFolder, listResult.get(0).getMailbox()); - assertEquals(String.format( - "'%s' mailbox not in result of 'list \"%s\" \"%s\"'", underRemFolder, ref, mailbox), - underRemFolder, listResult.get(1).getMailbox()); + doListShouldSucceed(otherConnection, "/home", USER + "/*", + Lists.newArrayList(remFolder, underRemFolder), "all folders for user - 1"); // LIST "/home/user" "*" - ref = homeFilter; - mailbox = "*"; - listResult = doListShouldSucceed(otherConnection, ref, mailbox, 2); - assertEquals(String.format( - "'%s' mailbox not in result of 'list \"%s\" \"%s\"'", remFolder, ref, mailbox), - remFolder, listResult.get(0).getMailbox()); - assertEquals(String.format( - "'%s' mailbox not in result of 'list \"%s\" \"%s\"'", underRemFolder, ref, mailbox), - underRemFolder, listResult.get(1).getMailbox()); + doListShouldSucceed(otherConnection, homeFilter, "*", + Lists.newArrayList(remFolder, underRemFolder), "all folders for user - 2"); // 'LIST "/home" "user/INBOX"' - ref = "/home"; - mailbox = USER + "/INBOX"; - listResult = doListShouldSucceed(otherConnection, ref, mailbox, 0); + doListShouldSucceed(otherConnection, "/home", USER + "/INBOX", + Lists.newArrayList(), "unshared INBOX for user"); // LIST "/home/user" "sharedFolderName" - ref = homeFilter; - mailbox = sharedFolderName; - listResult = doListShouldSucceed(otherConnection, homeFilter, sharedFolderName, 1); - assertEquals(String.format( - "'%s' mailbox not in result of 'list \"%s\" \"%s\"'", remFolder, ref, mailbox), - remFolder, listResult.get(0).getMailbox()); + doListShouldSucceed(otherConnection, homeFilter, sharedFolderName, + Lists.newArrayList(remFolder), "shared folder for user"); // LIST "/home/user" "sharedFolderName/subFolder" - ref = homeFilter; - mailbox = underSharedFolderName; - listResult = doListShouldSucceed(otherConnection, homeFilter, underSharedFolderName, 1); - assertEquals(String.format( - "'%s' mailbox not in result of 'list \"%s\" \"%s\"'", underRemFolder, ref, mailbox), - underRemFolder, listResult.get(0).getMailbox()); + doListShouldSucceed(otherConnection, homeFilter, underSharedFolderName, + Lists.newArrayList(underRemFolder), "shared folder for user"); otherConnection.logout(); otherConnection = null; @@ -1913,13 +1890,11 @@ public void listMountpoint() throws ServiceException, IOException { String mountpointName = String.format("%s's %s-shared", USER, testId); TestUtil.createMountpoint(mbox, remoteFolderPath, shareeZmbox, mountpointName); otherConnection = connectAndLogin(SHAREE); - List listResult; // LIST "" "mountpointName" - listResult = doListShouldSucceed(otherConnection, "", mountpointName, 1); - assertEquals(String.format( - "'%s' mountpoint not in result of 'list \"\" \"%s\"'", mountpointName, mountpointName), - mountpointName, listResult.get(0).getMailbox()); + doListShouldSucceed(otherConnection, "", mountpointName, + Lists.newArrayList(mountpointName), "mountpoint"); + List listResult; listResult = otherConnection.list("", "*"); assertNotNull("list result 'list \"\" \"*\"' should not be null", listResult); boolean seenIt = false; @@ -1959,8 +1934,6 @@ private SubFolderEnv(String sharedFolderName, String subFolder) @Test(timeout=100000) public void mountpointWithSubFolder() throws ServiceException, IOException, MessagingException { - String ref; - String searchPatt; List listResult; String sharedFolderName = String.format("INBOX/%s-shared", testId); @@ -1980,30 +1953,16 @@ public void mountpointWithSubFolder() throws ServiceException, IOException, Mess TestUtil.createMountpoint(userZmbox, remoteFolderPath, shareeZmbox, mountpointName); /* wild card at end should pick up top level and sub-folder */ - searchPatt = mountpointName + "*"; - ref = ""; - listResult = doListShouldSucceed(otherConnection, ref, searchPatt, 2); - assertEquals(String.format( - "'%s' mountpoint not in result of 'list \"\" \"%s\"'", mountpointName, mountpointName), - mountpointName, listResult.get(0).getMailbox()); - assertEquals(String.format( - "'%s' mountpoint not in result of 'list \"\" \"%s\"'", subMountpoint, mountpointName), - subMountpoint, listResult.get(1).getMailbox()); + doListShouldSucceed(otherConnection, "", mountpointName + "*", + Lists.newArrayList(mountpointName, subMountpoint), "wildcard under MP"); /* exact match shouldn't pick up sub-folder */ - searchPatt = mountpointName; - listResult = doListShouldSucceed(otherConnection, ref, searchPatt, 1); - assertEquals(String.format( - "'%s' mountpoint not in result of 'list \"\" \"%s\"'", mountpointName, mountpointName), - mountpointName, listResult.get(0).getMailbox()); + doListShouldSucceed(otherConnection, "", mountpointName, + Lists.newArrayList(mountpointName), "JUST MP"); /* exact match on sub-folder should pick up just sub-folder */ - searchPatt = subMountpoint; - listResult = doListShouldSucceed(otherConnection, ref, searchPatt, 1); - listResult = otherConnection.list("", subMountpoint); - assertEquals(String.format( - "'%s' mountpoint not in result of 'list \"\" \"%s\"'", subMountpoint, subMountpoint), - subMountpoint, listResult.get(0).getMailbox()); + doListShouldSucceed(otherConnection, "", subMountpoint, + Lists.newArrayList(subMountpoint), "JUST subfolder of MP"); List expectedMboxNames = Lists.newArrayList(baselineMboxNames); expectedMboxNames.add(mountpointName); @@ -2042,8 +2001,9 @@ public void homeNameSpaceWithSubFolder() throws ServiceException, IOException, M String remFolder = String.format("/home/%s/%s", USER, sharedFolderName); String underRemFolder = String.format("%s/subFolder", remFolder); otherConnection = connectAndLogin(SHAREE); - doListShouldSucceed(otherConnection, "", remFolder, 1); - doListShouldSucceed(otherConnection, "", underRemFolder, 1); + doListShouldSucceed(otherConnection, "", remFolder, Lists.newArrayList(remFolder), "shared folder"); + doListShouldSucceed(otherConnection, "", underRemFolder, Lists.newArrayList(underRemFolder), + "subfolder of shared folder"); doSelectShouldSucceed(otherConnection, remFolder); doFetchShouldSucceed(otherConnection, "1:*", "(FLAGS ENVELOPE)", subFolderEnv.subjects); doSelectShouldSucceed(otherConnection, underRemFolder); @@ -2206,10 +2166,8 @@ public void savedSearch() throws ServiceException, IOException, MessagingExcepti connection = this.connectAndLogin(USER); List listResult; // LIST "" "mountpointName" - listResult = doListShouldSucceed(connection, "", folderName, 1); - assertEquals(String.format( - "'%s' mailbox not in result of 'list \"\" \"%s\"'", folderName, folderName), - folderName, listResult.get(0).getMailbox()); + doListShouldSucceed(connection, "", folderName, Lists.newArrayList(folderName), + "Just search folder"); listResult = connection.list("", "*"); assertNotNull("list result 'list \"\" \"*\"' should not be null", listResult); boolean seenIt = false; @@ -2261,8 +2219,8 @@ public void clashingHomeSubFolders() throws ServiceException, IOException, Messa otherConnection.create(remFolder2); doSelectShouldSucceed(otherConnection, remFolder1); doSelectShouldSucceed(otherConnection, remFolder2); - doListShouldSucceed(otherConnection, "", remFolder1, 1); - doListShouldSucceed(otherConnection, "", remFolder2, 1); + doListShouldSucceed(otherConnection, "", remFolder1, Lists.newArrayList(remFolder1), "shared 1"); + doListShouldSucceed(otherConnection, "", remFolder2, Lists.newArrayList(remFolder2), "shared 2"); otherConnection = connectAndLogin(USER); doSelectShouldSucceed(otherConnection, underSharedFolderName); otherConnection.logout(); From f616f10b8e6a8d7b0ed4574793c05e6ccc16fab6 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 11 Sep 2017 21:10:17 +0100 Subject: [PATCH 035/142] ZCS-2762:ImapTestBase del old doListShouldSucceed --- .../com/zimbra/qa/unittest/ImapTestBase.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java index eaa098415b9..7ae6a5d06d3 100644 --- a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java +++ b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java @@ -363,23 +363,6 @@ protected void doListShouldFail(ImapConnection conn, String ref, String mailbox, } } - protected List doListShouldSucceed(ImapConnection conn, String ref, String mailbox, int expected) - throws IOException { - checkConnection(conn); - String cmdDesc = String.format("'%s \"%s\" \"%s\"'", CAtom.LIST, ref, mailbox); - try { - List listResult = conn.list(ref, mailbox); - assertNotNull(String.format("list result %s should not be null", cmdDesc), listResult); - assertEquals(String.format( "Number of entries in list returned for %s", cmdDesc), - expected, listResult.size()); - return listResult; - } catch (CommandFailedException cfe) { - String err = cfe.getError(); - fail(String.format("%s returned error '%s'", cmdDesc, err)); - return null; - } - } - /** * Note, due to a slightly strange quirk, the expectedMboxNames should be prefixed '/' in the case * where the mailboxes are in the Other Users' Namespace (i.e. start with "/home/"), otherwise, they From d39ea30f2e55b4afbccebc9a186668fc1203e4cb Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Fri, 8 Sep 2017 20:19:39 +0900 Subject: [PATCH 036/142] ZCS-1858:declare extension in "require" command, Part 2 Support "require" command with the following capability strings for the Sieve extensions: capability | Extension -------------+------------------ "envelope" | RFC 5228 Test envelope "comparator-"| RFC 5228 "comparator-i;ascii-numeric" "relational" | RFC 5231 :count/:value match-type, and six relational-match operators "ereject" | RFC 5429 "reject" | RFC 5429 This fix makes it mandatory for the Sieve test/command above to declare the capability in "require" command. If the Sieve extension is used without declaration in the "require" command, the entire filter execution will be canceled and the message is delivered to the Inbox without any modification. ZCS-1858(2):declare extension in "require" command, Part 2 Add a copyright section to the ComparatorNumericTest.java ZCS-1858(3):declare extension in "require" command, Part 2 fixed codacy issues. --- .../com/zimbra/cs/filter/AddressTest.java | 3 +- .../zimbra/cs/filter/DeleteHeaderTest.java | 6 +- .../com/zimbra/cs/filter/EnvelopeTest.java | 6 +- .../com/zimbra/cs/filter/ErejectTest.java | 6 +- .../com/zimbra/cs/filter/HeaderTest.java | 4 +- .../zimbra/cs/filter/NotifyMailtoTest.java | 6 +- .../cs/filter/RelationalExtensionTest.java | 113 ++++++++++-------- .../zimbra/cs/filter/ReplaceHeaderTest.java | 6 +- .../com/zimbra/cs/filter/SetVariableTest.java | 4 +- .../cs/filter/JsieveConfigMapHandler.java | 2 + .../com/zimbra/cs/filter/SieveVisitor.java | 4 +- .../com/zimbra/cs/filter/SoapToSieve.java | 10 +- .../cs/filter/ZimbraComparatorUtils.java | 28 +++-- .../zimbra/cs/filter/jsieve/AddressTest.java | 30 ++--- .../filter/jsieve/ComparatorNumericTest.java | 34 ++++++ .../com/zimbra/cs/filter/jsieve/DateTest.java | 18 +-- .../cs/filter/jsieve/EditHeaderExtension.java | 4 +- .../zimbra/cs/filter/jsieve/EnvelopeTest.java | 34 +++--- .../com/zimbra/cs/filter/jsieve/Ereject.java | 7 +- .../zimbra/cs/filter/jsieve/HeaderTest.java | 61 +++------- .../jsieve/NotifyMethodCapabilityTest.java | 10 +- .../com/zimbra/cs/filter/jsieve/Reject.java | 4 + .../zimbra/cs/filter/jsieve/StringTest.java | 4 +- 23 files changed, 223 insertions(+), 181 deletions(-) create mode 100644 store/src/java/com/zimbra/cs/filter/jsieve/ComparatorNumericTest.java diff --git a/store/src/java-test/com/zimbra/cs/filter/AddressTest.java b/store/src/java-test/com/zimbra/cs/filter/AddressTest.java index b4f446d2c2b..0157c9d3e0b 100644 --- a/store/src/java-test/com/zimbra/cs/filter/AddressTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/AddressTest.java @@ -340,7 +340,8 @@ public void compareEmptyStringWithAsciiNumeric() { RuleManager.clearCachedRules(acct); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct); - String filterScript = "if address :is :comparator \"i;ascii-numeric\" \"To\" \"\" {" + String filterScript = "require [\"comparator-i;ascii-numeric\"];" + + "if address :is :comparator \"i;ascii-numeric\" \"To\" \"\" {" + " tag \"compareEmptyStringWithAsciiNumeric\";" + "}"; diff --git a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java index 33aea5ba016..c96e94924ee 100644 --- a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java @@ -431,7 +431,7 @@ null, new DeliveryContext(), @Test public void testDeleteHeaderWithNumericComparisionUsingValue() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + " deleteheader :value \"lt\" :comparator \"i;ascii-numeric\" \"X-Numeric-Header\" \"3\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -468,7 +468,7 @@ null, new DeliveryContext(), @Test public void testDeleteHeaderWithNumericComparisionUsingCount() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + " deleteheader :count \"ge\" :comparator \"i;ascii-numeric\" \"X-Numeric-Header\" \"3\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -845,7 +845,7 @@ null, new DeliveryContext(), @Test public void testDeleteHeaderWithValueComparisionForCasemapComparator() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\"];\n" + " deleteheader :value \"lt\" :comparator \"i;ascii-casemap\" \"X-Numeric-Header\" \"3\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); diff --git a/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java b/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java index 549c64cb90e..2df7e8605ac 100644 --- a/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java @@ -611,7 +611,7 @@ public void testOutgoingFilter() { @Test public void testCompareEmptyStringWithAsciiNumeric() { - String filterScript = "require \"envelope\";\n" + String filterScript = "require [\"envelope\", \"comparator-i;ascii-numeric\"];\n" + "if envelope :comparator \"i;ascii-numeric\" :all :is \"from\" \"\" {\n" + " tag \"testCompareEmptyStringWithAsciiNumeric envelope\";" + "}" @@ -652,7 +652,7 @@ public void testCompareEmptyStringWithAsciiNumeric() { @Test public void testTo_Alias() { - String filterScript = "require [\"variables\", \"envelope\"];\n" + String filterScript = "require [\"variables\", \"envelope\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "set \"rcptto\" \"unknown\";\n" + "if envelope :all :matches \"to\" \"*\" {\n" + " set \"rcptto\" \"${1}\";\n" @@ -707,7 +707,7 @@ public void testTo_Alias() { @Test public void testCountForEmptyFromHeader() { - String filterScript = "require \"envelope\";\n" + String filterScript = "require [\"envelope\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if envelope :count \"eq\" :comparator \"i;ascii-numeric\" :all \"FROM\" \"0\" {\n" + "tag \"0\";\n" + "}\n" diff --git a/store/src/java-test/com/zimbra/cs/filter/ErejectTest.java b/store/src/java-test/com/zimbra/cs/filter/ErejectTest.java index 91af3dbb02c..2ad000e5251 100644 --- a/store/src/java-test/com/zimbra/cs/filter/ErejectTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/ErejectTest.java @@ -106,7 +106,7 @@ public void setUp() throws Exception { public void test() { Account acct1 = null; Mailbox mbox1 = null; - + boolean isPassed = false; try { acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1); @@ -130,6 +130,7 @@ env, new DeliveryContext(), List items = mbox1.getItemIds(null, Mailbox.ID_FOLDER_INBOX) .getIds(MailItem.Type.MESSAGE); Assert.assertEquals(null, items); + isPassed = true; } catch (Exception ex) { fail("No exception should be thrown: " + ex.getMessage()); } @@ -139,6 +140,9 @@ env, new DeliveryContext(), } catch (Exception e) { fail("No exception should be thrown: " + e.getMessage()); } + if (!isPassed) { + fail("DeliveryServiceException/ErejectException should have been thrown, but no exception is thrown"); + } } /* diff --git a/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java index 67068414f20..6e6b475d2fe 100644 --- a/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java @@ -148,7 +148,7 @@ public void testNumericNegativeValueIs() { // The "X-Minus: -abc" is not a negative value, but positive infinity as it is just a string. @Test public void testNumericMinusCharacterValueIs() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :is :comparator \"i;ascii-numeric\" " + "[\"X-Minus\"] [\"\"] { tag \"Xminus\";}"; doTest(filterScript, "Xminus"); @@ -159,7 +159,7 @@ public void testNumericMinusCharacterValueIs() { // Hence the Subject text is treated as positive infinity, and so is an empty string @Test public void testNumericEmptyIs() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :is :comparator \"i;ascii-numeric\" " + "[\"Subject\"] [\"\"] { tag \"subject\";}"; doTest(filterScript, "subject"); diff --git a/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java b/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java index 1e6e85d681d..2809a5072a1 100644 --- a/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java @@ -977,7 +977,7 @@ public void testNotifyMethodCapability_OnlineYes() { @Test public void testNotifyMethodCapability_Relational() { String filterScript = - "require [\"enotify\", \"tag\", \"relational\"];\n" + "require [\"enotify\", \"tag\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if notify_method_capability :count \"eq\"\n" + " \"mailto:test2@zimbra.com\"\n" + " \"Online\"\n" @@ -1013,7 +1013,7 @@ public void testNotifyMethodCapability_Relational() { @Test public void testNotify_variable() { String filterScript = - "require [\"enotify\", \"tag\", \"variables\"];\n" + "require [\"enotify\", \"tag\", \"variables\", \"envelope\"];\n" + "if envelope :matches [\"To\"] \"*\" {set \"rcptto\" \"${1}\";}\n" + "if envelope :matches [\"From\"] \"*\" {set \"mailfrom\" \"${1}\";}\n" + "if header :matches \"Date\" \"*\" {set \"dateheader\" \"${1}\";}\n" @@ -1241,7 +1241,7 @@ public void testNotifyMailtoWithSpaceInHeaderName() { @Test public void testNotify_mimeVariables() { String filterScript = - "require [\"enotify\", \"tag\", \"variables\"];\n" + "require [\"enotify\", \"tag\", \"variables\", \"envelope\"];\n" + "if envelope :matches [\"To\"] \"*\" {set \"rcptto\" \"${1}\";}\n" + "if envelope :matches [\"From\"] \"*\" {set \"mailfrom\" \"${1}\";}\n" + "if anyof(not envelope :is [\"From\"] \"\") {\n" diff --git a/store/src/java-test/com/zimbra/cs/filter/RelationalExtensionTest.java b/store/src/java-test/com/zimbra/cs/filter/RelationalExtensionTest.java index 901c4e45f8d..7a5e12d0665 100644 --- a/store/src/java-test/com/zimbra/cs/filter/RelationalExtensionTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/RelationalExtensionTest.java @@ -72,47 +72,49 @@ public void setUp() throws Exception { @Test public void testCountAddressNumericGE1() { // RFC 5231 6. Example first example would evaluate to true - String filterScript = "if address :count \"ge\" :comparator \"i;ascii-numeric\" " - + "[\"to\", \"cc\"] [\"3\"] {" + "tag \"Priority\";}"; + String filterScript = "require [\"relational\", \"comparator-i;ascii-numeric\"];" + + "if address :count \"ge\" :comparator \"i;ascii-numeric\" " + + "[\"to\", \"cc\"] [\"3\"] { tag \"Priority\";}"; doTest(filterScript, "Priority"); } @Test public void testCountAddressNumericGE2() { // RFC 5231 6. Example second example would evaluate to false - String filterScript = "if anyof (address :count \"ge\" :comparator \"i;ascii-numeric\"\n" + String filterScript = "require [\"relational\", \"tag\", \"comparator-i;ascii-numeric\"];\n" + + "if anyof (address :count \"ge\" :comparator \"i;ascii-numeric\"\n" + "[\"to\"] [\"3\"],\n" + "address :count \"ge\" :comparator \"i;ascii-numeric\"\n" + "[\"cc\"] [\"3\"] )\n" - + "{" + "tag \"Priority\";}"; - doTest(filterScript, null); + + "{ tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test public void testCountHeaderNumericGE1() { // RFC 5231 6. Example third example would evaluate to false - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :count \"ge\" :comparator \"i;ascii-numeric\" " - + "[\"received\"] [\"3\"] {" + "tag \"Priority\";}"; - doTest(filterScript, null); + + "[\"received\"] [\"3\"] { tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test public void testCountHeaderNumericGE2() { // RFC 5231 6. Example fourth example would evaluate to true - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :count \"ge\" :comparator \"i;ascii-numeric\" " - + "[\"received\", \"subject\"] [\"3\"] {" + "tag \"Priority\";}"; + + "[\"received\", \"subject\"] [\"3\"] { tag \"Priority\";}"; doTest(filterScript, "Priority"); } @Test public void testCountHeaderNumericGE3() { // RFC 5231 6. Example fifth example would evaluate to false - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :count \"ge\" :comparator \"i;ascii-numeric\" " - + "[\"to\", \"cc\"] [\"3\"] {" + "tag \"Priority\";}"; - doTest(filterScript, null); + + "[\"to\", \"cc\"] [\"3\"] { tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test @@ -126,7 +128,7 @@ public void testValueAddressNumericGT() { // So the email address string of the To address (foo@example.com, baz@example.com) // will be treated as an empty string "", and it represents positive infinity. // Positive infinity is definitely grater than 1, so this test should return TRUE. - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if address :value \"gt\" :comparator \"i;ascii-numeric\" " + "[\"to\"] [\"0\"] {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); @@ -135,7 +137,8 @@ public void testValueAddressNumericGT() { @Test public void testValueAddressCasemapGT() { // "from" address starts with 'N'-'Z' - String filterScript = "if address :value \"gt\" :comparator \"i;ascii-casemap\" " + String filterScript = "require [\"relational\", \"tag\", \"comparator-i;ascii-numeric\"];\n" + + "if address :value \"gt\" :comparator \"i;ascii-casemap\" " + "[\"from\"] [\"M\"] {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); } @@ -143,16 +146,16 @@ public void testValueAddressCasemapGT() { @Test public void testValueHeaderNumericGT() { // RFC 5231 7. Extended Example (modified) - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :value \"gt\" :comparator \"i;ascii-numeric\" " - + "[\"x-priority\"] [\"3\"] {" + "tag \"Priority\";}"; - doTest(filterScript, null); + + "[\"x-priority\"] [\"3\"] { tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test public void testValueHeadeNumericrLT() { // RFC 5231 7. Extended Example - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :value \"lt\" :comparator \"i;ascii-numeric\" " + "[\"x-priority\"] [\"3\"] {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); @@ -161,7 +164,7 @@ public void testValueHeadeNumericrLT() { @Test public void testValueHeaderNumericLE() { // RFC 5231 7. Extended Example (modified) - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :value \"le\" :comparator \"i;ascii-numeric\" " + "[\"x-priority\"] [\"3\"] {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); @@ -170,7 +173,7 @@ public void testValueHeaderNumericLE() { @Test public void testValueHeaderNumericEQ() { // RFC 5231 7. Extended Example (modified) - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :value \"eq\" :comparator \"i;ascii-numeric\" " + "[\"x-priority\"] [\"1\"] {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); @@ -179,10 +182,10 @@ public void testValueHeaderNumericEQ() { @Test public void testValueHeaderNumericNE() { // RFC 5231 7. Extended Example (modified) - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :value \"ne\" :comparator \"i;ascii-numeric\" " - + "[\"x-priority\"] [\"1\"] {" + "tag \"Priority\";}"; - doTest(filterScript, null); + + "[\"x-priority\"] [\"1\"] { tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test @@ -207,7 +210,7 @@ public void testValueHeaderCasemapI18NGT() { public void testBadFormat_nokeys() { String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + "if header :value \"gt\" :comparator \"i;ascii-casemap\" " - + "[\"subject\"] :foo {" + "tag \"Priority\";}"; + + "[\"subject\"] :foo { tag \"Priority\";} else { tag \"No Priority\";}"; /* * The following error will occur: * org.apache.jsieve.exception.SyntaxException: Expecting a StringList of keys Line 2 column 1. @@ -219,7 +222,7 @@ public void testBadFormat_nokeys() { public void testBadFormat_noTestName() { String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + "if relational :value \"gt\" :comparator \"i;ascii-casemap\" " - + "[\"subject\"] [\"test\"] {" + "tag \"Priority\";}"; + + "[\"subject\"] [\"test\"] { tag \"Priority\";} else { tag \"No Priority\";}"; /* * The following error will occur: * org.apache.jsieve.exception.SyntaxException: Found unexpected arguments. Line 2 column 1. @@ -232,7 +235,8 @@ public void testCountEnvelopeToNumericEQ() { // RFC 5231 10. Security Considerations // An implementation MUST ensure that the test for envelope "to" only // reflects the delivery to the current user. - String filterScript = "if envelope :count \"eq\" :comparator \"i;ascii-numeric\" " + String filterScript = "require [\"envelope\", \"relational\", \"comparator-i;ascii-numeric\"];" + + "if envelope :count \"eq\" :comparator \"i;ascii-numeric\" " + "[\"TO\"] [\"1\"] {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); } @@ -246,16 +250,18 @@ public void testCountEnvelopeToNumericGT() { // to someone else. // The number of sample LMTP RCPT TO addresses is 2, but the number of // address to be evaluated for the "envelope" test should be 1. - String filterScript = "if envelope :count \"gt\" :comparator \"i;ascii-numeric\" " - + "[\"to\"] [\"1\"] {" + "tag \"Priority\";}"; - doTest(filterScript, null); + String filterScript = "require [\"envelope\", \"relational\", \"comparator-i;ascii-numeric\"];" + + "if envelope :count \"gt\" :comparator \"i;ascii-numeric\" " + + "[\"to\"] [\"1\"] { tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test public void testValueEnvelopeFromNumericGT() { // invalid comparison // See the comment on testValueAddressNumericGT. - String filterScript = "if envelope :value \"gt\" :comparator \"i;ascii-numeric\" " + String filterScript = "require [\"envelope\", \"relational\", \"comparator-i;ascii-numeric\"];" + + "if envelope :value \"gt\" :comparator \"i;ascii-numeric\" " + "[\"from\"] [\"1\"] {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); } @@ -263,9 +269,10 @@ public void testValueEnvelopeFromNumericGT() { @Test public void testValueEnvelopeCasemapGT() { // LMTP MAIL FROM envelope () does not start 'N'-'Z' - String filterScript = "if envelope :value \"gt\" :comparator \"i;ascii-casemap\" " - + "[\"from\"] [\"M\"] {" + "tag \"Priority\";}"; - doTest(filterScript, null); + String filterScript = "require [\"envelope\", \"relational\"];" + + "if envelope :value \"gt\" :comparator \"i;ascii-casemap\" " + + "[\"from\"] [\"M\"] { tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test @@ -273,7 +280,7 @@ public void testValueEnvelopeCasemap() { // LMTP MAIL FROM envelope () matchs the all upper case string // RFC 5228 Section 2.7.3. "i;ascii-casemap" comparator which treats uppercase and lowercase // characters in the US-ASCII subset of UTF-8 as the same - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"envelope\"];\n" + "if envelope :value \"eq\" :comparator \"i;ascii-casemap\" " + "[\"from\"] \"ABC@ZIMBRA.COM\" {" + "tag \"Priority\";}"; doTest(filterScript, "Priority"); @@ -283,16 +290,17 @@ public void testValueEnvelopeCasemap() { public void testValueEnvelopeOctet() { // LMTP MAIL FROM envelope () does not match the all upper case string // RFC 5228 Section 2.7.3. i;octet comparator simply compares octets - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"envelope\"];\n" + "if envelope :value \"eq\" :comparator \"i;octet\" " - + "[\"from\"] \"ABC@ZIMBRA.COM\" {" + "tag \"Priority\";}"; - doTest(filterScript, null); + + "[\"from\"] \"ABC@ZIMBRA.COM\" { tag \"Priority\";} else { tag \"No Priority\";}"; + doTest(filterScript, "No Priority"); } @Test public void testBadFormat_invalidEnvHeaderName() { - String filterScript = "if envelope :value \"gt\" :comparator \"i;ascii-casemap\" " - + "[\"AUTH\"] [\"M\"] {" + "tag \"Priority\";}"; + String filterScript = "require [\"envelope\", \"relational\"];" + + "if envelope :value \"gt\" :comparator \"i;ascii-casemap\" " + + "[\"AUTH\"] [\"M\"] {" + "tag \"Priority\";} else { tag \"No Priority\";}"; // The following error will occur: // org.apache.jsieve.exception.SyntaxException: Unexpected header name as a value for : 'AUTH' doTest(filterScript, null); @@ -300,7 +308,8 @@ public void testBadFormat_invalidEnvHeaderName() { @Test public void testValueEnvelopeFromNumeric_AllUpperCase() { - String filterScript = "IF ENVELOPE :COUNT \"EQ\" :COMPARATOR \"I;ASCII-NUMERIC\" " + String filterScript = "REQUIRE [\"envelope\", \"relational\", \"tag\", \"comparator-i;ascii-numeric\"];\n" + + "IF ENVELOPE :COUNT \"EQ\" :COMPARATOR \"I;ASCII-NUMERIC\" " + "[\"TO\"] [\"1\"] {" + "TAG \"Priority\";}"; doTest(filterScript, "Priority"); } @@ -309,10 +318,10 @@ public void testValueEnvelopeFromNumeric_AllUpperCase() { // and none of tag commands should be executed. @Test public void testValueHeaderNumericNegativeValue() { - String filterScript = "require [\"tag\", \"relational\"];\n" + String filterScript = "require [\"tag\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :value \"lt\" :comparator \"i;ascii-numeric\" " - + "[\"x-priority\"] [\"-1\"] { tag \"Priority\"; }" - + "tag \"Negative\""; + + "[\"x-priority\"] [\"-1\"] { tag \"Priority\"; } else { tag \"No Priority\";}" + + "tag \"Negative\";"; doTest(filterScript, null); } @@ -320,9 +329,9 @@ public void testValueHeaderNumericNegativeValue() { // and none of tag commands should be executed. @Test public void testValueAddressNumericNegativeValue() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if address :value \"lt\" :comparator \"i;ascii-numeric\" " - + "[\"to\"] [\"-1\"] { tag \"to\"; }" + + "[\"to\"] [\"-1\"] { tag \"to\"; } else { tag \"No To\";}" + "tag \"Negative\";"; doTest(filterScript, null); } @@ -331,9 +340,9 @@ public void testValueAddressNumericNegativeValue() { // and none of tag commands should be executed. @Test public void testValueEnvelopeFromNumericNegativeValue() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if envelope :value \"lt\" :comparator \"i;ascii-numeric\" " - + "[\"from\"] [\"-1\"] { tag \"from\"; }" + + "[\"from\"] [\"-1\"] { tag \"from\"; } else { tag \"No From\";}" + "tag \"Negative\";"; doTest(filterScript, null); } @@ -342,9 +351,9 @@ public void testValueEnvelopeFromNumericNegativeValue() { // and none of tag commands should be executed. @Test public void testCountHeaderNumericNegativeValue() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :count \"le\" :comparator \"i;ascii-numeric\" " - + "[\"received\"] [\"-3\"] { tag \"received\";}" + + "[\"received\"] [\"-3\"] { tag \"received\";} else { tag \"No Received\";}" + "tag \"Negative\";"; doTest(filterScript, null); } @@ -353,7 +362,7 @@ public void testCountHeaderNumericNegativeValue() { // and the tag command should not be executed. @Test public void testCountAddressNumericNegativeValue() { - String filterScript = "require [\"tag\", \"relational\"];\n" + String filterScript = "require [\"tag\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if address :count \"le\" :comparator \"i;ascii-numeric\" " + "[\"to\", \"cc\"] [\"-1\"] { tag \"Priority\"; }"; doTest(filterScript, null); @@ -363,7 +372,7 @@ public void testCountAddressNumericNegativeValue() { // and the tag command should not be executed. @Test public void testCountEnvelopeToNumericNegativeValue() { - String filterScript = "require [\"tag\", \"relational\"];\n" + String filterScript = "require [\"tag\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if envelope :count \"gt\" :comparator \"i;ascii-numeric\" " + "[\"to\"] [\"-1\"] { }" + "tag \"Priority\";"; diff --git a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java index ec4da45d70e..6f23c2971e3 100644 --- a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java @@ -554,7 +554,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderWithNumericComparisionUsingCount() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + " replaceheader :newname \"X-Numeric2-Header\" :count \"ge\" :comparator \"i;ascii-numeric\" \"X-Numeric-Header\" \"3\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -590,7 +590,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderWithXSpamScore() { try { - String filterScript = "require [\"editheader\", \"variables\"];\n" + String filterScript = "require [\"editheader\", \"variables\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if anyof(header :value \"ge\" :comparator \"i;ascii-numeric\" [\"X-Spam-Score\"] [\"80\"]) {" +" if exists \"Subject\" {" +" replaceheader :newvalue \"[SPAM]${1}\" :matches \"Subject\" \"*\";" @@ -1021,7 +1021,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderWithCaseMapComparatorUsingValue() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + " replaceheader :newname \"X-Test2-Header\" :newvalue \"0\" :value \"lt\" :comparator \"i;ascii-casemap\" \"X-Test-Header\" \"test2\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); diff --git a/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java b/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java index 77c8f046959..5bb75c86ef1 100644 --- a/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java @@ -644,7 +644,7 @@ public void testStringTest() { + "\n" + "Hello World."; RuleManager.clearCachedRules(account); - filterScript = "require [\"variables\"];\n" + filterScript = "require [\"variables\", \"comparator-i;ascii-numeric\"];\n" + "set :lower :upperfirst \"name\" \"Joe\";\n" + "if string :is :comparator \"i;ascii-numeric\" \"${name}\" [ \"Joe\", \"Hello\", \"User\" ]{\n" + " tag \"sales-1\";\n" @@ -1564,7 +1564,7 @@ public void testDollar2() { Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); RuleManager.clearCachedRules(account); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - filterScript = "require [\"variables\"];\n" + filterScript = "require [\"variables\", \"envelope\"];\n" + "set \"dollar\" \"$\";\n" + "set \"val\" \"xyz\";\n" + "if header :matches :comparator \"i;ascii-casemap\" \"Subject\" \"${dollar}${val}\" {\n" diff --git a/store/src/java/com/zimbra/cs/filter/JsieveConfigMapHandler.java b/store/src/java/com/zimbra/cs/filter/JsieveConfigMapHandler.java index d7a5e7e16e4..0906c3784f5 100644 --- a/store/src/java/com/zimbra/cs/filter/JsieveConfigMapHandler.java +++ b/store/src/java/com/zimbra/cs/filter/JsieveConfigMapHandler.java @@ -40,6 +40,7 @@ public class JsieveConfigMapHandler { public static final String CAPABILITY_REJECT = "reject"; public static final String CAPABILITY_ENOTIFY = "enotify"; public static final String CAPABILITY_EDITHEADER = "editheader"; + public static final String CAPABILITY_COMPARATOR_NUMERIC = "comparator-i;ascii-numeric"; /* * jSieve's command map @@ -115,6 +116,7 @@ private static Map createDefaultTestMap() { mTestMap.put("community_requests", com.zimbra.cs.filter.jsieve.CommunityRequestsTest.class.getName()); mTestMap.put("community_content", com.zimbra.cs.filter.jsieve.CommunityContentTest.class.getName()); mTestMap.put(CAPABILITY_RELATIONAL, com.zimbra.cs.filter.jsieve.RelationalTest.class.getName()); + mTestMap.put(CAPABILITY_COMPARATOR_NUMERIC, com.zimbra.cs.filter.jsieve.ComparatorNumericTest.class.getName()); mTestMap.put("string", com.zimbra.cs.filter.jsieve.StringTest.class.getName()); // The capability string associated with the 'notify' action is diff --git a/store/src/java/com/zimbra/cs/filter/SieveVisitor.java b/store/src/java/com/zimbra/cs/filter/SieveVisitor.java index a5898ad7dac..19a6ba186f7 100644 --- a/store/src/java/com/zimbra/cs/filter/SieveVisitor.java +++ b/store/src/java/com/zimbra/cs/filter/SieveVisitor.java @@ -541,8 +541,8 @@ private void acceptTest(Node node, RuleProperties props) throws ServiceException firstTagArgNode = (SieveNode) getNode(node, 0, 0); if (firstTagArgNode.getValue() instanceof TagArgument) { String firstArgStr = firstTagArgNode.getValue().toString(); - if (":count".equals(firstArgStr) || ":value".equals(firstArgStr)) { - if (":count".equals(firstArgStr)) { + if (HeaderConstants.COUNT.equalsIgnoreCase(firstArgStr) || HeaderConstants.VALUE.equalsIgnoreCase(firstArgStr)) { + if (HeaderConstants.COUNT.equalsIgnoreCase(firstArgStr)) { isCount = true; } valueComparison = Sieve.ValueComparison.valueOf(getValue(node, 0, 1, 0, 0)); diff --git a/store/src/java/com/zimbra/cs/filter/SoapToSieve.java b/store/src/java/com/zimbra/cs/filter/SoapToSieve.java index ca89354d3db..27aeb3576ac 100644 --- a/store/src/java/com/zimbra/cs/filter/SoapToSieve.java +++ b/store/src/java/com/zimbra/cs/filter/SoapToSieve.java @@ -31,6 +31,7 @@ import com.google.common.base.Strings; import com.zimbra.common.filter.Sieve; import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.HeaderConstants; import com.zimbra.common.util.StringUtil; import com.zimbra.common.util.ZimbraLog; import com.zimbra.soap.mail.type.EditheaderTest; @@ -49,6 +50,9 @@ public final class SoapToSieve { // end of line in sieve script public static final String END_OF_LINE = ";\n"; + public static final String requireCommon = "\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", " + + "\"variables\", \"log\", \"enotify\", \"envelope\", \"body\", " + + "\"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\""; public SoapToSieve(List rules) { this.rules = rules; @@ -57,7 +61,7 @@ public SoapToSieve(List rules) { public String getSieveScript() throws ServiceException { if (buffer == null) { buffer = new StringBuilder(); - buffer.append("require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"]" + END_OF_LINE); + buffer.append("require [" + requireCommon + "]" + END_OF_LINE); for (FilterRule rule : rules) { buffer.append('\n'); handleRule(rule); @@ -69,7 +73,7 @@ public String getSieveScript() throws ServiceException { public String getAdminSieveScript() throws ServiceException { if (buffer == null) { buffer = new StringBuilder(); - buffer.append("require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"]" + END_OF_LINE); + buffer.append("require [" + requireCommon + ", \"editheader\"]" + END_OF_LINE); for (FilterRule rule : rules) { buffer.append('\n'); handleRule(rule, true); @@ -414,7 +418,7 @@ private static String toSieve(String name, String header, Sieve.StringComparison } private static String toSieve(String name, String header, Sieve.ValueComparison comp, Sieve.Comparator valueComparator, boolean caseSensitive, String value, boolean isCount, Sieve.AddressPart part) throws ServiceException { - String countOrVal = isCount ? ":count" : ":value"; + String countOrVal = isCount ? HeaderConstants.COUNT : HeaderConstants.VALUE; Sieve.Comparator comparator; if (valueComparator == null) { boolean numeric = true; diff --git a/store/src/java/com/zimbra/cs/filter/ZimbraComparatorUtils.java b/store/src/java/com/zimbra/cs/filter/ZimbraComparatorUtils.java index 36caf56b28d..5c9c93239cf 100644 --- a/store/src/java/com/zimbra/cs/filter/ZimbraComparatorUtils.java +++ b/store/src/java/com/zimbra/cs/filter/ZimbraComparatorUtils.java @@ -16,6 +16,7 @@ */ package com.zimbra.cs.filter; +import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_RELATIONAL; import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; import static org.apache.jsieve.comparators.ComparatorNames.ASCII_CASEMAP_COMPARATOR; import static org.apache.jsieve.comparators.MatchTypeTags.CONTAINS_TAG; @@ -48,6 +49,7 @@ import com.zimbra.common.soap.HeaderConstants; import com.zimbra.cs.filter.jsieve.Counts; import com.zimbra.cs.filter.jsieve.Equals2; +import com.zimbra.cs.filter.jsieve.Require; import com.zimbra.cs.filter.jsieve.Values; public class ZimbraComparatorUtils { @@ -187,10 +189,13 @@ else if (matchType == null * @return true if the target value matches the condition * @throws SieveException */ - public static boolean match(String comparatorName, String matchType, String operator, + public static boolean match(MailAdapter mail, String comparatorName, String matchType, String operator, String matchTarget, String matchArgument, SieveContext context) throws SieveException { boolean isMatched = false; + if (mail instanceof ZimbraMailAdapter && ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(comparatorName)) { + Require.checkCapability(mail, ASCII_NUMERIC_COMPARATOR); + } if (IS_TAG.equals(matchType)) { isMatched = is(comparatorName, matchTarget, matchArgument, context); } else if (CONTAINS_TAG.equals(matchType)) { @@ -200,7 +205,7 @@ public static boolean match(String comparatorName, String matchType, String oper isMatched = ComparatorUtils.matches(comparatorName, matchTarget, matchArgument, context); } else if (HeaderConstants.VALUE.equals(matchType)) { - isMatched = values(comparatorName, operator, matchTarget, matchArgument, + isMatched = values(mail, comparatorName, operator, matchTarget, matchArgument, context); } return isMatched; @@ -217,10 +222,14 @@ public static boolean match(String comparatorName, String matchType, String oper * @return boolean result of "[# of matchTarget] [operator] [matchArgument]" * @throws LookupException * @throws FeatureException + * @throws SyntaxException thrown when "relational" and "comparator-i;ascii-numeric" are not declared in the "require" command. */ - public static boolean counts(String comparatorName, + public static boolean counts(MailAdapter mail, String comparatorName, String operator, List matchTarget, String matchArgument, - SieveContext context) throws LookupException, FeatureException { + SieveContext context) throws LookupException, FeatureException, SyntaxException { + if (mail instanceof ZimbraMailAdapter) { + Require.checkCapability((ZimbraMailAdapter) mail, CAPABILITY_RELATIONAL); + } Counts comparatorObj = (Counts) context.getComparatorManager().getComparator(comparatorName); return comparatorObj.counts(operator, matchTarget, matchArgument); } @@ -236,9 +245,13 @@ public static boolean counts(String comparatorName, * @return boolean result of "[lhs] [operator] [rhs]" * @throws LookupException * @throws FeatureException + * @throws SyntaxException */ - public static boolean values(String comparatorName, String operator, - String lhs, String rhs, SieveContext context) throws LookupException, FeatureException { + public static boolean values(MailAdapter mail, String comparatorName, String operator, + String lhs, String rhs, SieveContext context) throws LookupException, FeatureException, SyntaxException { + if (mail instanceof ZimbraMailAdapter) { + Require.checkCapability((ZimbraMailAdapter) mail, CAPABILITY_RELATIONAL); + } Values comparatorObj = (Values) context.getComparatorManager().getComparator(comparatorName); return comparatorObj.values(operator, lhs, rhs); } @@ -323,9 +336,10 @@ static public boolean matches(String string, String glob) * @param context not null * @return boolean * @throws FeatureException the number is negative value + * @throws SyntaxException */ public static boolean is(String comparatorName, String string1, - String string2, SieveContext context) throws LookupException, FeatureException { + String string2, SieveContext context) throws LookupException, FeatureException, SyntaxException { Equals2 comparatorObj = (Equals2) context.getComparatorManager().getComparator(comparatorName); return comparatorObj.equals2(string1, string2); } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java index 7d3e9f679aa..ad761d70219 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java @@ -121,7 +121,7 @@ private boolean match(MailAdapter mail, String addressPart, String comparator, if (HeaderConstants.COUNT.equals(matchType)) { for (final String key: keys) { - isMatched = ZimbraComparatorUtils.counts(comparator, + isMatched = ZimbraComparatorUtils.counts(mail, comparator, operator, headerValues, ZimbraComparatorUtils.getMatchKey(addressPart, key), context); if (isMatched) { break; @@ -130,26 +130,16 @@ private boolean match(MailAdapter mail, String addressPart, String comparator, } else { Iterator headerValuesIter = headerValues.iterator(); while (!isMatched && headerValuesIter.hasNext()) { - isMatched = match(comparator, matchType, - operator, (String)headerValuesIter.next(), keys, context); - } - } - return isMatched; - } + // Iterate over the keys looking for a match + String headerValue = (String)headerValuesIter.next(); + for (final String key: keys) { + isMatched = ZimbraComparatorUtils.match(mail, comparator, matchType, operator, + headerValue, key, context); + if (isMatched) { + break; + } + } - /** - * Compares the value of the specified address field with the operator - */ - private boolean match(String comparator, String matchType, String operator, - String headerValue, List keys, SieveContext context) - throws SieveException { - // Iterate over the keys looking for a match - boolean isMatched = false; - for (final String key: keys) { - isMatched = ZimbraComparatorUtils.match(comparator, matchType, operator, - headerValue, key, context); - if (isMatched) { - break; } } return isMatched; diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/ComparatorNumericTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/ComparatorNumericTest.java new file mode 100644 index 00000000000..5c893baba41 --- /dev/null +++ b/store/src/java/com/zimbra/cs/filter/jsieve/ComparatorNumericTest.java @@ -0,0 +1,34 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.filter.jsieve; + +import org.apache.jsieve.Arguments; +import org.apache.jsieve.SieveContext; +import org.apache.jsieve.exception.SieveException; +import org.apache.jsieve.exception.SyntaxException; +import org.apache.jsieve.mail.MailAdapter; +import org.apache.jsieve.tests.AbstractTest; + +import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_COMPARATOR_NUMERIC; + +public class ComparatorNumericTest extends AbstractTest { + @Override + protected boolean executeBasic(MailAdapter mail, Arguments arguments, + SieveContext context) throws SieveException { + throw new SyntaxException("Unexpected test " + CAPABILITY_COMPARATOR_NUMERIC); + } +} diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/DateTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/DateTest.java index ceaedafc8ec..fd0ade8108e 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/DateTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/DateTest.java @@ -64,15 +64,17 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, SieveConte if (argument instanceof TagArgument) { String tag = ((TagArgument) argument).getTag(); - if (tag.equals(BEFORE) || tag.equals(AFTER)) + if (tag.equals(BEFORE) || tag.equals(AFTER)) { comparator = tag; - else + } else { throw new SyntaxException( "Found unexpected: \"" + tag + "\""); + } } } - if (null == comparator) + if (null == comparator) { throw new SyntaxException("Expecting \"" + BEFORE + "\" or \"" + AFTER + "\""); + } // Second argument MUST be a date if (argumentsIter.hasNext()) @@ -88,13 +90,15 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, SieveConte } } } - if (null == date) + if (null == date) { throw new SyntaxException("Expecting a valid date (yyyyMMdd)"); + } // There MUST NOT be any further arguments - if (argumentsIter.hasNext()) - throw new SyntaxException("Found unexpected argument(s)"); - + if (argumentsIter.hasNext()) { + throw new SyntaxException("Found unexpected argument(s)"); + } + if (mail instanceof DummyMailAdapter) { return true; } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java b/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java index f2a6254fc75..324c8887780 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java @@ -415,9 +415,9 @@ public boolean matchCondition(ZimbraMailAdapter mailAdapter, Header header, List } if (this.valueTag) { - matchFound = ZimbraComparatorUtils.values(comparator, relationalComparator, unfoldedAndDecodedHeaderValue, value, context); + matchFound = ZimbraComparatorUtils.values(mailAdapter, comparator, relationalComparator, unfoldedAndDecodedHeaderValue, value, context); } else if (this.countTag) { - matchFound = ZimbraComparatorUtils.counts(comparator, relationalComparator, headerList, value, context); + matchFound = ZimbraComparatorUtils.counts(mailAdapter, comparator, relationalComparator, headerList, value, context); } else if (this.is && ComparatorUtils.is(this.comparator, unfoldedAndDecodedHeaderValue, value, context)) { matchFound = true; } else if (this.contains && ComparatorUtils.contains(this.comparator, unfoldedAndDecodedHeaderValue, value, context)) { diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java index 1c10bd71f61..b021289783e 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java @@ -17,6 +17,7 @@ package com.zimbra.cs.filter.jsieve; +import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_ENVELOPE; import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; import static org.apache.jsieve.comparators.ComparatorNames.ASCII_CASEMAP_COMPARATOR; import static org.apache.jsieve.comparators.MatchTypeTags.IS_TAG; @@ -66,6 +67,8 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, if (!(mail instanceof ZimbraMailAdapter)) { return false; } + ZimbraMailAdapter mailAdapter = (ZimbraMailAdapter) mail; + Require.checkCapability(mailAdapter, CAPABILITY_ENVELOPE); ZimbraComparatorUtils.TestParameters params = ZimbraComparatorUtils.parseTestArguments(mail, arguments, context); params.setKeys(HeaderTest.replaceVariables(params.getKeys(), mail)); @@ -75,9 +78,8 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, } if (MatchTypeTags.MATCHES_TAG.equals(params.getMatchType())) { - ZimbraMailAdapter zma = (ZimbraMailAdapter) mail; try { - HeaderTest.evaluateVarExp(zma, params.getHeaderNames(), HeaderTest.SourceType.ENVELOPE, params.getKeys()); + HeaderTest.evaluateVarExp(mailAdapter, params.getHeaderNames(), HeaderTest.SourceType.ENVELOPE, params.getKeys()); } catch (MessagingException e) { throw new SieveException("Exception occured while evaluating variable expression.", e); } @@ -152,7 +154,7 @@ private boolean match(MailAdapter mail, String addressPart, String comparator, if (HeaderConstants.COUNT.equals(matchType)) { for (final String key: keys) { - isMatched = ZimbraComparatorUtils.counts(comparator, + isMatched = ZimbraComparatorUtils.counts(mail, comparator, operator, headerValues, ZimbraComparatorUtils.getMatchKey(addressPart, key), context); if (isMatched) { break; @@ -169,8 +171,15 @@ private boolean match(MailAdapter mail, String addressPart, String comparator, } else { normalizedKeys = keys; } - isMatched = match(comparator, matchType, operator, (String)headerValuesIter.next(), normalizedKeys, - context); + String headerValue = (String)headerValuesIter.next(); + // Iterate over the keys looking for a match + for (final String key: keys) { + isMatched = ZimbraComparatorUtils.match(mail, comparator, matchType, operator, + headerValue, key, context); + if (isMatched) { + break; + } + } } } @@ -215,19 +224,4 @@ private String getMatchAddressPart(String addressPart, String email) { } return matchAddress; } - - private boolean match(String comparator, String matchType, String operator, - String headerValue, List keys, SieveContext context) - throws SieveException { - // Iterate over the keys looking for a match - boolean isMatched = false; - for (final String key: keys) { - isMatched = ZimbraComparatorUtils.match(comparator, matchType, operator, - headerValue, key, context); - if (isMatched) { - break; - } - } - return isMatched; - } } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/Ereject.java b/store/src/java/com/zimbra/cs/filter/jsieve/Ereject.java index adcb2fca685..5825bd00a1b 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/Ereject.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/Ereject.java @@ -16,6 +16,8 @@ */ package com.zimbra.cs.filter.jsieve; +import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_EREJECT; + import org.apache.jsieve.Arguments; import org.apache.jsieve.Block; import org.apache.jsieve.SieveContext; @@ -34,7 +36,10 @@ protected Object executeBasic(MailAdapter mail, Arguments arguments, Block block if (!(mail instanceof ZimbraMailAdapter)) { return null; } - ((ZimbraMailAdapter) mail).setDiscardActionPresent(); + ZimbraMailAdapter mailAdapter = (ZimbraMailAdapter) mail; + Require.checkCapability(mailAdapter, CAPABILITY_EREJECT); + + mailAdapter.setDiscardActionPresent(); final String message = ((StringListArgument) arguments.getArgumentList().get(0)).getList().get(0); mail.addAction(new ActionEreject(message)); return null; diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java index 4a4f961ced9..f46845e5fc7 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java @@ -228,7 +228,7 @@ protected boolean match(MailAdapter mail, String comparator, String matchType, headerValues.addAll(mail.getMatchingHeader((String) headerNamesIter.next())); } for (final String key: keys) { - isMatched = ZimbraComparatorUtils.counts(comparator, + isMatched = ZimbraComparatorUtils.counts(mail, comparator, operator, headerValues, key, context); if (isMatched) { break; @@ -236,52 +236,29 @@ protected boolean match(MailAdapter mail, String comparator, String matchType, } } else { while (!isMatched && headerNamesIter.hasNext()) { - isMatched = match(comparator, matchType, operator, - mail.getMatchingHeader((String) headerNamesIter.next()), - keys, context); + List headerValues = mail.getMatchingHeader((String) headerNamesIter.next()); + if (headerValues.isEmpty()) { + isMatched = false; + } else { + // Compares each header value to each key. + Iterator headerValuesIter = headerValues.iterator(); + while (!isMatched && headerValuesIter.hasNext()) { + String headerValue = (String) headerValuesIter.next(); + // Iterate over the keys looking for a match + for (final String key: keys) { + isMatched = ZimbraComparatorUtils.match(mail, comparator, matchType, operator, + headerValue, key, context); + if (isMatched) { + break; + } + } + } + } } } return isMatched; } - /** - * Traverses the values set of the specific header field(s) to check the filter key - */ - protected boolean match(String comparator, String matchType, String operator, - List headerValues, List keys, SieveContext context) - throws SieveException { - if (headerValues.isEmpty()) { - return false; - } - - // Iterate over the header values looking for a match - boolean isMatched = false; - Iterator headerValuesIter = headerValues.iterator(); - while (!isMatched && headerValuesIter.hasNext()) { - isMatched = match(comparator, matchType, operator, - (String) headerValuesIter.next(), keys, context); - } - return isMatched; - } - - /** - * Compares each header value to each key. - */ - protected boolean match(String comparator, String matchType, - String operator, String headerValue, List keys, SieveContext context) - throws SieveException { - // Iterate over the keys looking for a match - boolean isMatched = false; - for (final String key: keys) { - isMatched = ZimbraComparatorUtils.match(comparator, matchType, operator, - headerValue, key, context); - if (isMatched) { - break; - } - } - return isMatched; - } - protected boolean match(MailAdapter mail, String comparator, String matchType, List headerNames, List keys, SieveContext context) throws SieveException { if (mail instanceof DummyMailAdapter) { diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMethodCapabilityTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMethodCapabilityTest.java index 7ee9f6d574f..c4e993f6af4 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMethodCapabilityTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMethodCapabilityTest.java @@ -192,7 +192,7 @@ else if (matchType == null throw context.getCoordinate().syntaxException( "Found unexpected arguments"); } - return test(comparator, matchType, operator, uri, capability, keys, context); + return test(mail, comparator, matchType, operator, uri, capability, keys, context); } @Override @@ -200,7 +200,7 @@ protected void validateArguments(Arguments arguments, SieveContext context) { // override validation -- it's already done in executeBasic above } - private boolean test(String comparator, String matchType, String operator, + private boolean test(MailAdapter mail, String comparator, String matchType, String operator, String uri, String capability, List keys, SieveContext context) throws SieveException { if (null == uri || null == capability) { return false; @@ -216,7 +216,7 @@ private boolean test(String comparator, String matchType, String operator, } if (HeaderConstants.COUNT.equalsIgnoreCase(matchType)) { - return testCount(keys, comparator, operator, context); + return testCount(mail, keys, comparator, operator, context); } // There is no way to detect the online/offline status of the recipient. // The test always returns "maybe" for the "mailto" notification method @@ -230,11 +230,11 @@ private boolean test(String comparator, String matchType, String operator, return false; } - private boolean testCount(List keys, String comparator, String operator, SieveContext context) throws SieveException { + private boolean testCount(MailAdapter mail, List keys, String comparator, String operator, SieveContext context) throws SieveException { List values = Arrays.asList(CAPABILITY_MAYBE); boolean isMatched = false; for (String key : keys) { - isMatched = ZimbraComparatorUtils.counts(comparator, + isMatched = ZimbraComparatorUtils.counts(mail, comparator, operator, values, key, context); if (isMatched) { break; diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/Reject.java b/store/src/java/com/zimbra/cs/filter/jsieve/Reject.java index 170d45d911b..6039824329c 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/Reject.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/Reject.java @@ -20,6 +20,8 @@ import com.zimbra.cs.filter.FilterUtil; import com.zimbra.cs.filter.ZimbraMailAdapter; +import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_REJECT; + import org.apache.jsieve.Arguments; import org.apache.jsieve.Block; import org.apache.jsieve.SieveContext; @@ -42,6 +44,8 @@ protected Object executeBasic(MailAdapter mail, Arguments arguments, Block block return null; } ZimbraMailAdapter mailAdapter = (ZimbraMailAdapter) mail; + Require.checkCapability(mailAdapter, CAPABILITY_REJECT); + Account account = null; account = mailAdapter.getAccount(); if (account.isSieveRejectMailEnabled()) { diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java index 5b486b4f676..c7fcee99831 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java @@ -226,7 +226,7 @@ private boolean match(MailAdapter mail, String comparator, String matchType, Str sourceValues.removeAll(Arrays.asList("", null)); keyIter = keyValues.iterator(); while (!isMatched && keyIter.hasNext()) { - isMatched = ZimbraComparatorUtils.counts(comparator, + isMatched = ZimbraComparatorUtils.counts(mail, comparator, operator, sourceValues, keyIter.next(), context); } } else { @@ -235,7 +235,7 @@ private boolean match(MailAdapter mail, String comparator, String matchType, Str String source = sourceIter.next(); keyIter = keyValues.iterator(); while(!isMatched && keyIter.hasNext()) { - isMatched = ZimbraComparatorUtils.match(comparator, matchType, operator, + isMatched = ZimbraComparatorUtils.match(mail, comparator, matchType, operator, source, keyIter.next(), context); } } From a372807d8e5af0746228614e18ed4ccd45481e05 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Fri, 8 Sep 2017 14:55:47 -0700 Subject: [PATCH 037/142] ZCS-2683: add upport for ustom DataImport implementation Also add test for default and new behavior --- .../soap/admin/type/DataSourceType.java | 2 +- .../cs/datasource/DataSourceManagerTest.java | 120 ++++++++++++++++++ store/src/java-test/datasource-test.xml | 68 ++++++++++ .../com/zimbra/cs/account/DataSource.java | 2 + .../cs/datasource/DataSourceManager.java | 17 +++ 5 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java create mode 100644 store/src/java-test/datasource-test.xml diff --git a/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java b/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java index a4564a5f323..8bf5b08a300 100644 --- a/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java +++ b/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java @@ -26,7 +26,7 @@ @XmlEnum public enum DataSourceType { // case must match protocol - pop3, imap, caldav, contacts, yab, rss, cal, gal, xsync, tagmap; + pop3, imap, caldav, contacts, yab, rss, cal, gal, xsync, tagmap, custom; public static DataSourceType fromString(String s) throws ServiceException { try { diff --git a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java new file mode 100644 index 00000000000..b77f73da037 --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java @@ -0,0 +1,120 @@ +package com.zimbra.cs.datasource; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.DataSource; +import com.zimbra.cs.account.DataSource.DataImport; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.datasource.imap.ImapSync; +import com.zimbra.cs.gal.GalImport; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.soap.admin.type.DataSourceType; + +public class DataSourceManagerTest { + private Account testAccount = null; + private String CUSTOM_DS_ID = "testCustomDS"; + private String POP3_DS_ID = "testPop3DS"; + private String IMAP_DS_ID = "testImap3DS"; + private String CALDAV_DS_ID = "CalDavDS"; + private String RSS_DS_ID = "RSSDataSource"; + private String CAL_DS_ID = "CalDataSource"; + private String GAL_DS_ID = "GALDataSource"; + + private String CUSTOM_DS_NAME = "TestCustomDataSource"; + private String POP3_DS_NAME = "TestPop3DataSource"; + private String IMAP_DS_NAME = "TestImapDataSource"; + private String CALDAV_DS_NAME = "TestCalDavDataSource"; + private String RSS_DS_NAME = "TestRSSDataSource"; + private String CAL_DS_NAME = "TestCalDataSource"; + private String GAL_DS_NAME = "TestGALDataSource"; + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + String serverDir = MailboxTestUtil.getZimbraServerDir(""); + FileUtils.copyFileToDirectory(new File(serverDir + "src/java-test/datasource-test.xml"), new File(serverDir + "build/zimbra/conf/datasource.xml"), false); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + Provisioning prov = Provisioning.getInstance(); + testAccount = prov.createAccount("test@zimbra.com", "secret", new HashMap()); + } + + @After + public void tearDown() throws Exception { + MailboxTestUtil.clearData(); + } + + @Test + public void testGetDataImportWithDefaultClass() throws ServiceException { + Map testAttrs = new HashMap(); + testAttrs.put(Provisioning.A_zimbraDataSourceDomain, "zimbra.com"); + testAttrs.put(Provisioning.A_zimbraDataSourcePort, "1234"); + testAttrs.put(Provisioning.A_zimbraDataSourceHost, "localhost"); + testAttrs.put(Provisioning.A_zimbraDataSourceUsername, "test"); + testAttrs.put(Provisioning.A_zimbraDataSourcePassword, "test"); + + DataSource ds = new DataSource(testAccount, DataSourceType.pop3, POP3_DS_NAME, POP3_DS_ID, testAttrs, null); + DataImport di = DataSourceManager.getInstance().getDataImport(ds); + assertNotNull("DataImport should not be NULL", di); + assertTrue("DataImport for 'pop3' should be Pop3Sync", di instanceof Pop3Sync); + + ds = new DataSource(testAccount, DataSourceType.imap, IMAP_DS_NAME, IMAP_DS_ID, testAttrs, null); + di = DataSourceManager.getInstance().getDataImport(ds); + assertNotNull("DataImport should not be NULL", di); + assertTrue("DataImport for 'imap' should be ImapSync", di instanceof ImapSync); + + ds = new DataSource(testAccount, DataSourceType.caldav, CALDAV_DS_NAME, CALDAV_DS_ID, testAttrs, null); + di = DataSourceManager.getInstance().getDataImport(ds); + assertNotNull("DataImport should not be NULL", di); + assertTrue("DataImport for 'caldav' should be CalDavDataImport", di instanceof CalDavDataImport); + + ds = new DataSource(testAccount, DataSourceType.rss, RSS_DS_NAME, RSS_DS_ID, testAttrs, null); + di = DataSourceManager.getInstance().getDataImport(ds); + assertNotNull("DataImport should not be NULL", di); + assertTrue("DataImport for 'rss' should be RssImport", di instanceof RssImport); + + ds = new DataSource(testAccount, DataSourceType.cal, CAL_DS_NAME, CAL_DS_ID, testAttrs, null); + di = DataSourceManager.getInstance().getDataImport(ds); + assertNotNull("DataImport should not be NULL", di); + assertTrue("DataImport for 'cal' should be RssImport", di instanceof RssImport); + + ds = new DataSource(testAccount, DataSourceType.gal, GAL_DS_NAME, GAL_DS_ID, testAttrs, null); + di = DataSourceManager.getInstance().getDataImport(ds); + assertNotNull("DataImport should not be NULL", di); + assertTrue("DataImport for 'gal' should be GalImport", di instanceof GalImport); + } + + @Test + public void testGetDataImportCustomClass() throws ServiceException { + Map testAttrs = new HashMap(); + testAttrs.put(Provisioning.A_zimbraDataSourceDomain, "zimbra.com"); + testAttrs.put(Provisioning.A_zimbraDataSourceImportClassName, "com.zimbra.cs.datasource.DataSourceManagerTest.TestDSImport"); + DataSource ds = new DataSource(testAccount, DataSourceType.custom, CUSTOM_DS_NAME, CUSTOM_DS_ID, testAttrs, null); + assertNotNull("DataSource should not be NULL", ds); + DataImport di = DataSourceManager.getInstance().getDataImport(ds); + assertNull("should not be able to instantiate non existent DataImport class", di); + + testAttrs.put(Provisioning.A_zimbraDataSourceImportClassName, "com.zimbra.cs.gal.GalImport"); + ds = new DataSource(testAccount, DataSourceType.custom, CUSTOM_DS_NAME, CUSTOM_DS_ID, testAttrs, null); + assertNotNull("DataSource should not be NULL", ds); + di = DataSourceManager.getInstance().getDataImport(ds); + assertNotNull("DataImport should not be NULL", di); + assertTrue("DataImport for 'custom' should be GalImport", di instanceof GalImport); + } + } diff --git a/store/src/java-test/datasource-test.xml b/store/src/java-test/datasource-test.xml new file mode 100644 index 00000000000..c6fb101dbc6 --- /dev/null +++ b/store/src/java-test/datasource-test.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/store/src/java/com/zimbra/cs/account/DataSource.java b/store/src/java/com/zimbra/cs/account/DataSource.java index e89e72ffcce..e2e2f49b4db 100644 --- a/store/src/java/com/zimbra/cs/account/DataSource.java +++ b/store/src/java/com/zimbra/cs/account/DataSource.java @@ -154,6 +154,8 @@ public boolean isSslEnabled() { public String getOauthRefreshToken() { return getAttr(Provisioning.A_zimbraDataSourceOAuthRefreshToken); } + public String getDataSourceImportClassName() { return getAttr(Provisioning.A_zimbraDataSourceImportClassName); } + public String getDomain() { String domain = getAttr(Provisioning.A_zimbraDataSourceDomain, null); if (domain == null) { diff --git a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java index b017b8d2614..e71d8aa8b80 100644 --- a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java +++ b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java @@ -216,6 +216,23 @@ public DataImport getDataImport(DataSource ds, boolean test) throws ServiceExcep } catch (Exception x) { ZimbraLog.datasource.warn("Failed instantiating xsync class: %s", ds, x); } + case custom: + try { + String className = ds.getDataSourceImportClassName(); + if (className != null && className.length() > 0) { + Class cmdClass; + try { + cmdClass = Class.forName(className); + } catch (ClassNotFoundException x) { + cmdClass = ExtensionUtil.findClass(className); + } + Constructor constructor = cmdClass.getConstructor(new Class[] {DataSource.class}); + return (DataImport) constructor.newInstance(ds); + } + } catch (Exception x) { + ZimbraLog.datasource.warn("Failed instantiating custom class: %s", ds, x); + } + return null; default: // yab is handled by OfflineDataSourceManager throw new IllegalArgumentException("Unknown data import type: " + ds.getType()); From 398d10fd60c1ddd4a3fd038658d8f5a6ee513d86 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Fri, 8 Sep 2017 15:22:46 -0700 Subject: [PATCH 038/142] Remove unused import --- .../com/zimbra/cs/datasource/DataSourceManagerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java index b77f73da037..2a074f7010f 100644 --- a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java +++ b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java @@ -4,7 +4,6 @@ import java.io.File; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.apache.commons.io.FileUtils; From 789d3e354b2897db1daaf6355056d7d534fbfb4e Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 12 Sep 2017 01:02:08 +0000 Subject: [PATCH 039/142] add null check and warning for missing DataImport class --- .../cs/datasource/DataSourceManager.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java index e71d8aa8b80..91e9240d4a5 100644 --- a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java +++ b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java @@ -210,8 +210,12 @@ public DataImport getDataImport(DataSource ds, boolean test) throws ServiceExcep } catch (ClassNotFoundException x) { cmdClass = ExtensionUtil.findClass(className); } - Constructor constructor = cmdClass.getConstructor(new Class[] {DataSource.class}); - return (DataImport) constructor.newInstance(ds); + if(cmdClass != null) { + Constructor constructor = cmdClass.getConstructor(new Class[] {DataSource.class}); + return (DataImport) constructor.newInstance(ds); + } + ZimbraLog.datasource.warn("Could not find custom DataImport class: %s. Check your classpath.", className); + return null; } } catch (Exception x) { ZimbraLog.datasource.warn("Failed instantiating xsync class: %s", ds, x); @@ -226,11 +230,15 @@ public DataImport getDataImport(DataSource ds, boolean test) throws ServiceExcep } catch (ClassNotFoundException x) { cmdClass = ExtensionUtil.findClass(className); } - Constructor constructor = cmdClass.getConstructor(new Class[] {DataSource.class}); - return (DataImport) constructor.newInstance(ds); + if(cmdClass != null) { + Constructor constructor = cmdClass.getConstructor(new Class[] {DataSource.class}); + return (DataImport) constructor.newInstance(ds); + } + ZimbraLog.datasource.warn("Could not find custom DataImport class: %s. Check your classpath.", className); + return null; } } catch (Exception x) { - ZimbraLog.datasource.warn("Failed instantiating custom class: %s", ds, x); + ZimbraLog.datasource.warn("Caught an exception while instantiating custom class: %s", ds, x); } return null; default: From 2a9278fc6394bfad1cc651b5463b7b7c0997aee0 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 11 Sep 2017 20:09:24 +0000 Subject: [PATCH 040/142] init datasource LC for tests --- .../com/zimbra/cs/mailbox/MailboxTestUtil.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/store/src/java-test/com/zimbra/cs/mailbox/MailboxTestUtil.java b/store/src/java-test/com/zimbra/cs/mailbox/MailboxTestUtil.java index 7d6cc2ec005..498972928a6 100644 --- a/store/src/java-test/com/zimbra/cs/mailbox/MailboxTestUtil.java +++ b/store/src/java-test/com/zimbra/cs/mailbox/MailboxTestUtil.java @@ -91,16 +91,23 @@ public static void initProvisioning(String zimbraServerDir) throws Exception { System.setProperty("log4j.configuration", "log4j-test.properties"); System.setProperty("zimbra.config", zimbraServerDir + "src/java-test/localconfig-test.xml"); LC.reload(); - + //substitute test TZ file String timezonefilePath = zimbraServerDir + "src/java-test/timezones-test.ics"; File d = new File(timezonefilePath); if (!d.exists()) { - throw new FileNotFoundException("timezones.ics not found."); + throw new FileNotFoundException("timezones-test.ics not found in " + timezonefilePath); } LC.timezone_file.setDefault(timezonefilePath); LC.zimbra_rights_directory.setDefault(StringUtils.removeEnd(zimbraServerDir, "/") +"-conf" + "/conf/rights"); LC.zimbra_attrs_directory.setDefault(zimbraServerDir + "conf/attrs"); LC.zimbra_tmp_directory.setDefault(zimbraServerDir + "tmp"); + //substitute test DS config file + String dsfilePath = zimbraServerDir + "src/java-test/datasource-test.xml"; + d = new File(dsfilePath); + if (!d.exists()) { + throw new FileNotFoundException("datasource-test.xml not found in " + dsfilePath); + } + LC.data_source_config.setDefault(dsfilePath); // default MIME handlers are now set up in MockProvisioning constructor Provisioning.setInstance(new MockProvisioning()); } From 8ff77427cb7ca4e5c986c27e6c3a4884a759a6a6 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 12 Sep 2017 13:39:48 -0700 Subject: [PATCH 041/142] add license block --- .../cs/datasource/DataSourceManagerTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java index 2a074f7010f..0ca62fde8a6 100644 --- a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java +++ b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java @@ -1,3 +1,20 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + package com.zimbra.cs.datasource; import static org.junit.Assert.*; From e442acfdcd97d1b81659e69c9f9dde0523ead676 Mon Sep 17 00:00:00 2001 From: Sneha Patil Date: Mon, 11 Sep 2017 21:03:52 +0530 Subject: [PATCH 042/142] ZCS-2730:API to restore a selected contact backup file --- .../com/zimbra/common/soap/MailConstants.java | 8 + soap/src/java/com/zimbra/soap/JaxbUtil.java | 6 +- .../mail/message/RestoreContactsRequest.java | 54 +++++++ .../mail/message/RestoreContactsResponse.java | 44 ++++++ store/docs/rest.txt | 2 +- store/docs/soap.txt | 17 +- store/ivy.xml | 1 + store/src/java-test/backup_dummy_test.tgz | 0 .../cs/service/mail/RestoreContactsTest.java | 112 +++++++++++++ .../zimbra/cs/service/mail/MailService.java | 3 + .../cs/service/mail/RestoreContacts.java | 147 ++++++++++++++++++ 11 files changed, 391 insertions(+), 3 deletions(-) create mode 100644 soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java create mode 100644 soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java create mode 100644 store/src/java-test/backup_dummy_test.tgz create mode 100644 store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java create mode 100644 store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java diff --git a/common/src/java/com/zimbra/common/soap/MailConstants.java b/common/src/java/com/zimbra/common/soap/MailConstants.java index 8d296e3bbb3..6521753be20 100644 --- a/common/src/java/com/zimbra/common/soap/MailConstants.java +++ b/common/src/java/com/zimbra/common/soap/MailConstants.java @@ -1339,4 +1339,12 @@ private MailConstants() { public static final String OP_INHERIT = "inherit"; public static final String OP_MUTE = "mute"; public static final String OP_RESET_IMAP_UID = "resetimapuid"; + + // Contacts API + public static final String E_RESTORE_CONTACTS_REQUEST = "RestoreContactsRequest"; + public static final String E_RESTORE_CONTACTS_RESPONSE = "RestoreContactsResponse"; + public static final QName RESTORE_CONTACTS_REQUEST = QName.get(E_RESTORE_CONTACTS_REQUEST, NAMESPACE); + public static final QName RESTORE_CONTACTS_RESPONSE = QName.get(E_RESTORE_CONTACTS_RESPONSE, NAMESPACE); + public static final String A_CONTACTS_BACKUP_FILE_NAME = "contactsBackupFileName"; + public static final String A_CONTACTS_BACKUP_FOLDER_NAME = "ContactsBackup"; } diff --git a/soap/src/java/com/zimbra/soap/JaxbUtil.java b/soap/src/java/com/zimbra/soap/JaxbUtil.java index bac18380c2e..2adf23b8403 100644 --- a/soap/src/java/com/zimbra/soap/JaxbUtil.java +++ b/soap/src/java/com/zimbra/soap/JaxbUtil.java @@ -1114,7 +1114,11 @@ public final class JaxbUtil { com.zimbra.soap.mail.message.GetLastItemIdInMailboxRequest.class, com.zimbra.soap.mail.message.GetLastItemIdInMailboxResponse.class, com.zimbra.soap.mail.message.BeginTrackingIMAPRequest.class, - com.zimbra.soap.mail.message.BeginTrackingIMAPResponse.class + com.zimbra.soap.mail.message.BeginTrackingIMAPResponse.class, + + //Contacts API + com.zimbra.soap.mail.message.RestoreContactsRequest.class, + com.zimbra.soap.mail.message.RestoreContactsResponse.class }; try { diff --git a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java new file mode 100644 index 00000000000..07d369f4e30 --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java @@ -0,0 +1,54 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.soap.mail.message; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +import com.google.common.base.Objects; +import com.zimbra.common.soap.MailConstants; + +@XmlAccessorType(XmlAccessType.NONE) +@XmlRootElement(name = MailConstants.E_RESTORE_CONTACTS_REQUEST) +public class RestoreContactsRequest { + + /** + * @zm-api-field-tag contact-backup + * @zm-api-field-description Filename of contact backup file + */ + @XmlAttribute(name = MailConstants.A_CONTACTS_BACKUP_FILE_NAME, required = true) + private String contactsBackupFileName; + + public String getContactsBackupFileName() { + return contactsBackupFileName; + } + + public void setContactsBackupFileName(String contactsBackupFileName) { + this.contactsBackupFileName = contactsBackupFileName; + } + + public Objects.ToStringHelper addToStringInfo(Objects.ToStringHelper helper) { + return helper.add("contactsBackupFileName", contactsBackupFileName); + } + + @Override + public String toString() { + return addToStringInfo(Objects.toStringHelper(this)).toString(); + } +} diff --git a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java new file mode 100644 index 00000000000..7635c21c46c --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java @@ -0,0 +1,44 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.soap.mail.message; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +import com.zimbra.common.soap.MailConstants; + +@XmlAccessorType(XmlAccessType.NONE) +@XmlRootElement(name = MailConstants.E_RESTORE_CONTACTS_RESPONSE) +public class RestoreContactsResponse { + + /** + * @zm-api-field-tag status + * @zm-api-field-description Restore request status + */ + @XmlAttribute(name = MailConstants.A_STATUS, required = true) + private String status; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} diff --git a/store/docs/rest.txt b/store/docs/rest.txt index 49dbf98fa58..5ea7983865b 100644 --- a/store/docs/rest.txt +++ b/store/docs/rest.txt @@ -52,7 +52,7 @@ URL ------------------------------------------------------------ http://server/home/[~][{username}]/[{folder}]?[{query-params}] - fmt={ics, csv, etc} + fmt={ics, csv, ldif etc} id={item-id} list={item-id}*[,{item-id}] imap_id={item-imap-id} (must also specify folder) diff --git a/store/docs/soap.txt b/store/docs/soap.txt index 97cf1e629a8..02ac478381e 100644 --- a/store/docs/soap.txt +++ b/store/docs/soap.txt @@ -4695,6 +4695,21 @@ If IMAP tracking is already enabled, does nothing. +----------------------------- +API to restore contact backup file from the contact backup list + + + +Note: First, retrieve the contact backup file name with GetContactBackupList Soap API, +then send that file name in 'contactsBackupFileName' parameter of RestoreContactsRequest. +RestoreContactsRequest will search for file inside 'ContactsBackup' briefcase folder +and if found, will restore it. + + + + +{status} = SUCCESS | FAILURE; + ----------------------------- Api to get list of available contact backup files @@ -4706,4 +4721,4 @@ Api to get list of available contact backup files file3_name ... ] - \ No newline at end of file + diff --git a/store/ivy.xml b/store/ivy.xml index 59b312ed8ac..917835ea5a9 100644 --- a/store/ivy.xml +++ b/store/ivy.xml @@ -70,6 +70,7 @@ + diff --git a/store/src/java-test/backup_dummy_test.tgz b/store/src/java-test/backup_dummy_test.tgz new file mode 100644 index 00000000000..e69de29bb2d diff --git a/store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java b/store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java new file mode 100644 index 00000000000..23244b79b59 --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java @@ -0,0 +1,112 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.service.mail; + +import java.io.ByteArrayInputStream; +import java.util.Map; + +import org.apache.http.StatusLine; +import org.apache.http.HttpResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.google.common.collect.Maps; +import com.zimbra.common.account.Key; +import com.zimbra.common.mime.MimeConstants; +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.MailConstants; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.Folder; +import com.zimbra.cs.mailbox.MailItem; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.MailboxManager; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.store.file.FileBlobStore; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ RestoreContacts.class, HttpResponse.class, StatusLine.class, + FileBlobStore.class }) +@PowerMockIgnore({ "javax.crypto.*", "javax.xml.bind.annotation.*" }) +public class RestoreContactsTest { + + private Account acct = null; + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + Provisioning prov = Provisioning.getInstance(); + + Map attrs = Maps.newHashMap(); + prov.createAccount("test@zimbra.com", "secret", attrs); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + } + + @Test + public void testRestore() throws Exception { + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct); + Folder folder = mbox.createFolder(null, "Briefcase/ContactsBackup", + new Folder.FolderOptions().setDefaultView(MailItem.Type.DOCUMENT)); + OperationContext octxt = new OperationContext(acct); + // Upload the contacts backup file to ContactsBackup folder in briefcase + mbox.createDocument(octxt, folder.getId(), "backup_dummy_test.tgz", + MimeConstants.CT_APPLICATION_ZIMBRA_DOC, "author", "description", + new ByteArrayInputStream("dummy data".getBytes())); + HttpResponse httpResponse = PowerMockito.mock(HttpResponse.class); + StatusLine httpStatusLine = PowerMockito.mock(StatusLine.class); + Mockito.when(httpStatusLine.getStatusCode()).thenReturn(200); + Mockito.when(httpResponse.getStatusLine()).thenReturn(httpStatusLine); + PowerMockito.stub(PowerMockito.method(RestoreContacts.class, "httpPostBackup")) + .toReturn(httpResponse); + PowerMockito.stub(PowerMockito.method(FileBlobStore.class, "getBlobPath", Mailbox.class, + int.class, int.class, short.class)).toReturn("/"); + // RestoreContactRequest with valid backup file name + Element request = new Element.XMLElement(MailConstants.RESTORE_CONTACTS_REQUEST); + request.addAttribute("contactsBackupFileName", "backup_dummy_test.tgz"); + Map context = ServiceTestUtil.getRequestContext(acct); + Element response = new RestoreContacts().handle(request, context); + String expectedResponse = ""; + Assert.assertEquals(expectedResponse, response.prettyPrint()); + try { + // RestoreContactRequest with non-existing backup file name + Element request2 = new Element.XMLElement(MailConstants.RESTORE_CONTACTS_REQUEST); + request2.addAttribute("contactsBackupFileName", "backup_dummy_test_non_existing.tgz"); + new RestoreContacts().handle(request2, context); + Assert.fail("ServiceException was expected"); + } catch (ServiceException e) { + Assert.assertEquals("invalid request: No such file: backup_dummy_test_non_existing.tgz", + e.getMessage()); + Assert.assertEquals("service.INVALID_REQUEST", e.getCode()); + + } + } +} diff --git a/store/src/java/com/zimbra/cs/service/mail/MailService.java b/store/src/java/com/zimbra/cs/service/mail/MailService.java index 4ebd75100b0..192961a21ad 100644 --- a/store/src/java/com/zimbra/cs/service/mail/MailService.java +++ b/store/src/java/com/zimbra/cs/service/mail/MailService.java @@ -229,5 +229,8 @@ public void registerHandlers(DocumentDispatcher dispatcher) { dispatcher.registerHandler(MailConstants.GET_LAST_ITEM_ID_IN_MAILBOX_REQUEST, new GetLastItemIdInMailbox()); dispatcher.registerHandler(MailConstants.GET_MODIFIED_ITEMS_IDS_REQUEST, new GetModifiedItemsIDs()); dispatcher.registerHandler(MailConstants.RESET_RECENT_MESSAGE_COUNT_REQUEST, new ResetRecentMessageCount()); + + // Contacts API + dispatcher.registerHandler(MailConstants.RESTORE_CONTACTS_REQUEST, new RestoreContacts()); } } diff --git a/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java b/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java new file mode 100644 index 00000000000..6d68cfea7c8 --- /dev/null +++ b/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java @@ -0,0 +1,147 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.service.mail; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.http.HttpResponse; +import org.apache.http.client.CookieStore; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.mime.MultipartEntity; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.cookie.BasicClientCookie; +import org.eclipse.jetty.http.HttpStatus; + +import com.zimbra.common.mime.MimeConstants; +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.MailConstants; +import com.zimbra.common.util.ZimbraCookie; +import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.AuthToken; +import com.zimbra.cs.account.AuthTokenException; +import com.zimbra.cs.mailbox.Document; +import com.zimbra.cs.mailbox.Folder; +import com.zimbra.cs.mailbox.MailItem; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.service.UserServlet; +import com.zimbra.cs.store.file.FileBlobStore; +import com.zimbra.soap.SoapServlet; +import com.zimbra.soap.ZimbraSoapContext; +import com.zimbra.soap.mail.message.RestoreContactsRequest; +import com.zimbra.soap.mail.message.RestoreContactsResponse; + +public class RestoreContacts extends MailDocumentHandler { + + public enum ContactRestoreStatus { + SUCCESS, FAILURE; + } + + @Override + public Element handle(Element request, Map context) throws ServiceException { + ZimbraSoapContext zsc = getZimbraSoapContext(context); + Mailbox mbox = getRequestedMailbox(zsc); + OperationContext octxt = getOperationContext(zsc, context); + RestoreContactsRequest req = zsc.elementToJaxb(request); + String contactBackupFileName = req.getContactsBackupFileName(); + // if folder does not exist, SoapFault is thrown by getFolderByName() itself. + Folder folder = mbox.getFolderByName(octxt, Mailbox.ID_FOLDER_BRIEFCASE, + MailConstants.A_CONTACTS_BACKUP_FOLDER_NAME); + ZimbraLog.contact.debug("Backup folder exists. Searching for %s.", contactBackupFileName); + List itemList = mbox.getItemList(octxt, MailItem.Type.DOCUMENT, folder.getId()); + RestoreContactsResponse response = new RestoreContactsResponse(); + boolean mailItemFound = false; + HttpResponse httpResponse = null; + for (MailItem item : itemList) { + if (item instanceof Document) { + Document doc = (Document) item; + if (doc.getName().equals(contactBackupFileName)) { + mailItemFound = true; + Object servReq = context.get(SoapServlet.SERVLET_REQUEST); + String realm = "https://"; + HttpServletRequest httpRequest = null; + if (servReq instanceof HttpServletRequest) { + httpRequest = (HttpServletRequest) servReq; + realm = httpRequest.isSecure() ? "https://" : "http://"; + } + String url = realm + getLocalHost() + "/service/home/" + + mbox.getAccount().getName() + "/?" + UserServlet.QP_FMT + "=tgz&" + + UserServlet.QP_TYPES + "=contact&" + MimeConstants.P_CHARSET + "=UTF-8"; + CookieStore cookieStore = new BasicCookieStore(); + AuthToken authToken = octxt.getAuthToken(); + BasicClientCookie cookie = null; + try { + cookie = new BasicClientCookie(ZimbraCookie.COOKIE_ZM_AUTH_TOKEN, authToken.getEncoded()); + cookie.setPath("/"); + cookie.setDomain(mbox.getAccount().getDomainName()); + cookieStore.addCookie(cookie); + } catch (AuthTokenException e) { + throw ServiceException.FAILURE("Failed to get authentication token", e); + } + File file = new File(FileBlobStore.getBlobPath(mbox, doc.getId(), + doc.getSavedSequence(), Short.valueOf(doc.getLocator()))); + if (!file.exists()) { + throw ServiceException + .INVALID_REQUEST("File does not exist: " + contactBackupFileName, null); + } + ZimbraLog.contact.debug("Backup file found. Restoring contacts in %s.", + contactBackupFileName); + httpResponse = httpPostBackup(file, url, cookieStore); + break; + } + } + } + if (!mailItemFound) { + throw ServiceException.INVALID_REQUEST("No such file: " + contactBackupFileName, null); + } + ContactRestoreStatus status = httpResponse.getStatusLine().getStatusCode() == HttpStatus.OK_200 ? ContactRestoreStatus.SUCCESS : ContactRestoreStatus.FAILURE; + if ("SUCCESS".equals(status)) { + ZimbraLog.contact.debug("Restore operation for %s completed successfully", + contactBackupFileName); + } else { + ZimbraLog.contact.info("Restore operation for %s failed. Http respose status: %s", + contactBackupFileName, httpResponse.getStatusLine()); + } + response.setStatus(status.name()); + return zsc.jaxbToElement(response); + } + + public static HttpResponse httpPostBackup(File file, String url, CookieStore cookieStore) throws ServiceException { + HttpResponse httpResponse = null; + HttpClient http = HttpClientBuilder.create().setDefaultCookieStore(cookieStore) + .build(); + HttpPost post = new HttpPost(url); + MultipartEntity multipart = new MultipartEntity(); + multipart.addPart("file", new FileBody(file)); + post.setEntity(multipart); + try { + httpResponse = http.execute(post); + } catch (IOException e) { + throw ServiceException.FAILURE("Failed to execute contact restore request", null); + } + return httpResponse; + } +} From d89fd2816e790762ed1f7fde4179d143e08aefea Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Tue, 12 Sep 2017 13:46:46 +0530 Subject: [PATCH 043/142] ZCS-2746 Marking forwarded message as read --- .../common/account/ZAttrProvisioning.java | 8 + store/conf/attrs/zimbra-attrs.xml | 7 + store/ivy.xml | 16 +- .../cs/filter/IncomingMessageHandlerTest.java | 242 ++++++++++++++++++ .../com/zimbra/cs/account/ZAttrAccount.java | 72 ++++++ .../java/com/zimbra/cs/account/ZAttrCos.java | 72 ++++++ .../cs/filter/IncomingMessageHandler.java | 11 +- .../java/com/zimbra/cs/mailbox/Mailbox.java | 9 +- 8 files changed, 428 insertions(+), 9 deletions(-) create mode 100644 store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index e1a91011f84..494854432df 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -6531,6 +6531,14 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc @ZAttr(id=1127) public static final String A_zimbraFeatureMAPIConnectorEnabled = "zimbraFeatureMAPIConnectorEnabled"; + /** + * Mark messages sent to a forwarding address as read + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public static final String A_zimbraFeatureMarkMailForwardedAsRead = "zimbraFeatureMarkMailForwardedAsRead"; + /** * Whether to enable Zimbra Mobile Gateway feature * diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index 041443225bf..b0dd5bb26f6 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9563,4 +9563,11 @@ TODO: delete them permanently from here Received,DKIM-Signature,Authentication-Results,Received-SPF,Message-ID,Content-Type,Content-Disposition,Content-Transfer-Encoding,MIME-Version,Auto-Submitted Comma separated list of sieve immutable headers + + + FALSE + Mark messages sent to a forwarding address as read + + + diff --git a/store/ivy.xml b/store/ivy.xml index 917835ea5a9..b7223e3dc02 100644 --- a/store/ivy.xml +++ b/store/ivy.xml @@ -5,13 +5,15 @@ - - - - - - - + + + + + + + + + diff --git a/store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java b/store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java new file mode 100644 index 00000000000..21638947cf0 --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java @@ -0,0 +1,242 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite, Network Edition. + * Copyright (C) 2013, 2014 Zimbra, Inc. All Rights Reserved. + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.filter; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.account.ldap.LdapProvisioning; +import com.zimbra.cs.filter.jsieve.ActionFlag; +import com.zimbra.cs.mailbox.DeliveryContext; +import com.zimbra.cs.mailbox.DeliveryOptions; +import com.zimbra.cs.mailbox.Flag; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.Message; +import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.mime.ParsedMessage; + +/** + * @author zimbra + * + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ Provisioning.class }) +@PowerMockIgnore({"javax.xml.parsers.*", "org.apache.log4j.*", "org.xml.sax.*", "org.w3c.dom.*"}) +public class IncomingMessageHandlerTest { + + @Mock + private Provisioning prov = PowerMockito.mock(LdapProvisioning.class); + + @Before + public void setUp() { + PowerMockito.mockStatic(Provisioning.class); + PowerMockito.when(Provisioning.getInstance()).thenReturn(prov); + } + + + @Test + public void testImplicitKeepWhenForwardFeatureEnabledAndReadFlagSet() { + try { + OperationContext octxt = EasyMock.createMock(OperationContext.class); + DeliveryContext dctxt = EasyMock.createMock(DeliveryContext.class); + String recipientsAddress = "user1@email.com"; + int size = 100; + int defaultFolderId = 2; + boolean noICal = false; + Mailbox mailbox = new MockMailbox(); + IncomingMessageHandler messageHandler = new IncomingMessageHandler(octxt, dctxt, + mailbox, recipientsAddress, null, size, defaultFolderId, noICal); + Account acct = mailbox.getAccount(); + acct.setPrefMailForwardingAddress("forwar@zimbra.com"); + acct.setFeatureMarkMailForwardedAsRead(true); + acct.setFeatureMailForwardingEnabled(true); + List actions = new ArrayList(); + String[] tags = { "yellow" }; + + Message msg = messageHandler.implicitKeep(actions, tags); + assertEquals(0, msg.getFlagBitmask()); + } catch (ServiceException e) { + Assert.fail("No Exception should be thrown."); + } + + } + + @Test + public void testImplicitKeepWhenForwardFeatureEnabledButReadFlagNotSet() { + try { + OperationContext octxt = EasyMock.createMock(OperationContext.class); + DeliveryContext dctxt = EasyMock.createMock(DeliveryContext.class); + String recipientsAddress = "user1@email.com"; + int size = 100; + int defaultFolderId = 2; + boolean noICal = false; + Mailbox mailbox = new MockMailbox(); + + IncomingMessageHandler messageHandler = new IncomingMessageHandler(octxt, dctxt, + mailbox, recipientsAddress, null, size, defaultFolderId, noICal); + + Account acct = mailbox.getAccount(); + acct.setPrefMailForwardingAddress("forwar@zimbra.com"); + acct.setFeatureMarkMailForwardedAsRead(false); + acct.setFeatureMailForwardingEnabled(true); + List actions = new ArrayList(); + String[] tags = { "yellow" }; + + Message msg = messageHandler.implicitKeep(actions, tags); + assertEquals(Flag.BITMASK_UNREAD, msg.getFlagBitmask()); + } catch (ServiceException e) { + Assert.fail("No Exception should be thrown."); + } + + } + + @Test + public void testImplicitKeepWhenForwardFeatureDisabled() { + try { + OperationContext octxt = EasyMock.createMock(OperationContext.class); + DeliveryContext dctxt = EasyMock.createMock(DeliveryContext.class); + String recipientsAddress = "user1@email.com"; + int size = 100; + int defaultFolderId = 2; + boolean noICal = false; + Mailbox mailbox = new MockMailbox(); + + IncomingMessageHandler messageHandler = new IncomingMessageHandler(octxt, dctxt, + mailbox, recipientsAddress, null, size, defaultFolderId, noICal); + + Account acct = mailbox.getAccount(); + acct.setFeatureMarkMailForwardedAsRead(false); + acct.setFeatureMailForwardingEnabled(false); + List actions = new ArrayList(); + String[] tags = { "yellow" }; + + Message msg = messageHandler.implicitKeep(actions, tags); + assertEquals(Flag.BITMASK_UNREAD, msg.getFlagBitmask()); + } catch (ServiceException e) { + Assert.fail("No Exception should be thrown."); + } + + } + + public Account getAccount() throws ServiceException { + + HashMap attrs; + attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraId, UUID.randomUUID().toString()); + Account acctLocal = new MockAccount("test@zimbra.com", null, attrs, attrs, prov); + + return acctLocal; + } + + public class MockAccount extends Account { + + private boolean zimbraFeatureMarkMailForwardedAsRead; + private String prefMailForwardingAddress; + private boolean zimbraFeatureMailForwardingEnabled; + + /** + * @param name + * @param id + * @param attrs + * @param defaults + * @param prov + */ + public MockAccount(String name, String id, Map attrs, + Map defaults, Provisioning prov) { + super(name, id, attrs, defaults, prov); + } + + public boolean isFeatureAntispamEnabled() { + return false; + } + + public String getPrefMailForwardingAddress() { + return this.prefMailForwardingAddress; + } + + public boolean isFeatureMailForwardingEnabled() { + return this.zimbraFeatureMailForwardingEnabled; + } + + public boolean isFeatureMarkMailForwardedAsRead() { + return zimbraFeatureMarkMailForwardedAsRead; + } + + @Override + public void setFeatureMarkMailForwardedAsRead(boolean zimbraFeatureMarkMailForwardedAsRead) + throws ServiceException { + this.zimbraFeatureMarkMailForwardedAsRead = zimbraFeatureMarkMailForwardedAsRead; + } + + @Override + public void setPrefMailForwardingAddress(String zimbraPrefMailForwardingAddress) + throws ServiceException { + this.prefMailForwardingAddress = zimbraPrefMailForwardingAddress; + } + + @Override + public void setFeatureMailForwardingEnabled(boolean zimbraFeatureMailForwardingEnabled) + throws ServiceException { + this.zimbraFeatureMailForwardingEnabled = zimbraFeatureMailForwardingEnabled; + } + } + + public class MockMailbox extends Mailbox { + + private Account account; + /** + * @param data + */ + protected MockMailbox() { + + HashMap attrs; + attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraId, UUID.randomUUID().toString()); + account = new MockAccount("test@zimbra.com", null, attrs, attrs, prov); + } + + @Override + public Account getAccount() throws ServiceException { + return account; + } + + @Override + public String getAccountId() { + return "test"; + } + + @Override + public Message addMessage(OperationContext octxt, ParsedMessage pm, DeliveryOptions dopt, + DeliveryContext dctxt) throws IOException, ServiceException { + + Message msg = PowerMockito.mock(Message.class); + PowerMockito.when(msg.getFlagBitmask()).thenReturn(dopt.getFlags()); + return msg; + } + } + +} diff --git a/store/src/java/com/zimbra/cs/account/ZAttrAccount.java b/store/src/java/com/zimbra/cs/account/ZAttrAccount.java index a6894d5572d..61c01cb99cd 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrAccount.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrAccount.java @@ -16107,6 +16107,78 @@ public Map unsetFeatureManageZimlets(Map attrs) { return attrs; } + /** + * Mark messages sent to a forwarding address as read + * + * @return zimbraFeatureMarkMailForwardedAsRead, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public boolean isFeatureMarkMailForwardedAsRead() { + return getBooleanAttr(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, false, true); + } + + /** + * Mark messages sent to a forwarding address as read + * + * @param zimbraFeatureMarkMailForwardedAsRead new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public void setFeatureMarkMailForwardedAsRead(boolean zimbraFeatureMarkMailForwardedAsRead) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, zimbraFeatureMarkMailForwardedAsRead ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Mark messages sent to a forwarding address as read + * + * @param zimbraFeatureMarkMailForwardedAsRead new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public Map setFeatureMarkMailForwardedAsRead(boolean zimbraFeatureMarkMailForwardedAsRead, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, zimbraFeatureMarkMailForwardedAsRead ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Mark messages sent to a forwarding address as read + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public void unsetFeatureMarkMailForwardedAsRead() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Mark messages sent to a forwarding address as read + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public Map unsetFeatureMarkMailForwardedAsRead(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, ""); + return attrs; + } + /** * Whether to enable Zimbra Mobile Gateway feature * diff --git a/store/src/java/com/zimbra/cs/account/ZAttrCos.java b/store/src/java/com/zimbra/cs/account/ZAttrCos.java index ae65e618c6c..732c2c29515 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrCos.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrCos.java @@ -11055,6 +11055,78 @@ public Map unsetFeatureManageZimlets(Map attrs) { return attrs; } + /** + * Mark messages sent to a forwarding address as read + * + * @return zimbraFeatureMarkMailForwardedAsRead, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public boolean isFeatureMarkMailForwardedAsRead() { + return getBooleanAttr(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, false, true); + } + + /** + * Mark messages sent to a forwarding address as read + * + * @param zimbraFeatureMarkMailForwardedAsRead new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public void setFeatureMarkMailForwardedAsRead(boolean zimbraFeatureMarkMailForwardedAsRead) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, zimbraFeatureMarkMailForwardedAsRead ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Mark messages sent to a forwarding address as read + * + * @param zimbraFeatureMarkMailForwardedAsRead new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public Map setFeatureMarkMailForwardedAsRead(boolean zimbraFeatureMarkMailForwardedAsRead, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, zimbraFeatureMarkMailForwardedAsRead ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Mark messages sent to a forwarding address as read + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public void unsetFeatureMarkMailForwardedAsRead() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Mark messages sent to a forwarding address as read + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2123) + public Map unsetFeatureMarkMailForwardedAsRead(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, ""); + return attrs; + } + /** * Whether to enable Zimbra Mobile Gateway feature * diff --git a/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java b/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java index b923f41b9d5..8991280f2a6 100644 --- a/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java +++ b/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java @@ -26,6 +26,7 @@ import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.Account; import com.zimbra.cs.filter.jsieve.ActionFlag; import com.zimbra.cs.filter.jsieve.ErejectException; import com.zimbra.cs.lmtpserver.LmtpEnvelope; @@ -133,7 +134,15 @@ private Message addMessage(int folderId, Collection flagActions, Str throws ServiceException { try { DeliveryOptions dopt = new DeliveryOptions().setFolderId(folderId).setNoICal(noICal).setRecipientEmail(recipientAddress); - dopt.setFlags(FilterUtil.getFlagBitmask(flagActions, Flag.BITMASK_UNREAD)).setTags(tags); + Account account = mailbox.getAccount(); + if (account.getPrefMailForwardingAddress() != null && account.isFeatureMailForwardingEnabled() + && account.isFeatureMarkMailForwardedAsRead()) { + ZimbraLog.mailbox.debug("Marking forwarded message as read."); + dopt.setFlags(FilterUtil.getFlagBitmask(flagActions, 0)).setTags(tags); + + } else { + dopt.setFlags(FilterUtil.getFlagBitmask(flagActions, Flag.BITMASK_UNREAD)).setTags(tags); + } return mailbox.addMessage(octxt, parsedMessage, dopt, dctxt); } catch (IOException e) { throw ServiceException.FAILURE("Unable to add incoming message", e); diff --git a/store/src/java/com/zimbra/cs/mailbox/Mailbox.java b/store/src/java/com/zimbra/cs/mailbox/Mailbox.java index 70fa5548916..6fd5654497d 100644 --- a/store/src/java/com/zimbra/cs/mailbox/Mailbox.java +++ b/store/src/java/com/zimbra/cs/mailbox/Mailbox.java @@ -762,7 +762,14 @@ protected Mailbox(MailboxData data) { // index init done in open() lock = new MailboxLock(data.accountId, this); } - + + /** Introduced only for unit testing */ + protected Mailbox() { + mId = -1; + index = null; + lock = null; + } + public void setGalSyncMailbox(boolean galSyncMailbox) { this.galSyncMailbox = galSyncMailbox; } From 02cec8a21bb6960c2d9ccb0fff026d8184d71005 Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Wed, 13 Sep 2017 17:31:20 +0900 Subject: [PATCH 044/142] ZCS-1858(2):declare extension in "require" command, Part 2 Fixed the unit test com.zimbra.cs.filter.ValueComparisonTest. --- .../zimbra/cs/filter/ValueComparisonTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java b/store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java index c9707cbd91e..7b1e625bce6 100644 --- a/store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/ValueComparisonTest.java @@ -85,7 +85,7 @@ public void testHeaderTestStringComparisonCaseSensitivity() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (header :contains :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -129,7 +129,7 @@ public void testAddressTestStringComparisonCaseSensitivity() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (address :all :contains :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -173,7 +173,7 @@ public void testEnvelopeTestStringComparisonCaseSensitivity() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (envelope :all :contains :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -217,7 +217,7 @@ public void testHeaderTestValueComparisonCaseSensitivity() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (header :value \"eq\" :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -261,7 +261,7 @@ public void testAddressTestValueComparisonCaseSensitivity() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (address :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -305,7 +305,7 @@ public void testEnvelopeTestValueComparisonCaseSensitivity() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (envelope :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -349,7 +349,7 @@ public void testHeaderTestValueComparisonComparator() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (header :value \"eq\" :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -393,7 +393,7 @@ public void testAddressTestValueComparisonComparator() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (address :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -437,7 +437,7 @@ public void testEnvelopeTestValueComparisonComparator() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (envelope :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -457,7 +457,7 @@ public void testEnvelopeTestValueComparisonComparator() throws Exception { @Test public void testGetRuleHeaderTestValueComparisonCaseSensitivity() throws Exception { try { - String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; filterScript += "if anyof (header :value \"eq\" :comparator \"i;octet\" [\"subject\"] \"Important\") {\n"; filterScript += " fileinto \"Junk\";\n"; filterScript += " stop;\n"; @@ -502,7 +502,7 @@ public void testGetRuleHeaderTestValueComparisonCaseSensitivity() throws Excepti @Test public void testGetRuleAddressTestValueComparisonCaseSensitivity() throws Exception { try { - String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; filterScript += "if anyof (address :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; filterScript += " fileinto \"Junk\";\n"; filterScript += " stop;\n"; @@ -547,7 +547,7 @@ public void testGetRuleAddressTestValueComparisonCaseSensitivity() throws Except @Test public void testGetRuleEnvelopeTestValueComparisonCaseSensitivity() throws Exception { try { - String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String filterScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"envelope\", \"body\", \"ereject\", \"reject\", \"relational\", \"comparator-i;ascii-numeric\"];\n\n"; filterScript += "if anyof (envelope :value \"eq\" :all :comparator \"i;octet\" [\"from\"] \"abCD\") {\n"; filterScript += " fileinto \"Junk\";\n"; filterScript += " stop;\n"; From 66e74b042dbf52e23670384b9b49fd5f85d4743f Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Tue, 12 Sep 2017 21:22:40 +0900 Subject: [PATCH 045/142] ZCS-1870:Multi-byte text in a long line gets garbled [Problem] Currently when the mail server receives the SendMsg request whose message's mime parts have following characteristics, the mail server transfers the outgoing message to the SMTP server with the header "Content-Transfer-Encoding: binary". - If that mime part is not an attachment or its Content-Type's primary type is "text". - If that mime part contains non-ASCII characters more than 25% of the part size. - If that mime part has a line which is longer than MAX_LINE_OCTETS (900). Because the MTA (Postfix) does not support the "Content- Transfer-Encoding: binary", Postfix treats such mime part as "7bit", and folds a long line into 998 characters without consideration of multi-byte characters. As a result, the multi-byte character which CRLF is inserted in the middle of the byte-string gets garbled. [History] This bug was introduced by the Bug 86352 (a redirected message was garbled when the original message consisted of the multi-byte characters but didn't have a Content-Transfer-Encoding header). During the fix of Bug 86352, when a mime-part did not have CTE header, and the mime contents matched the above conditions, the "Content-Transfer-Encoding: binary" was inserted. Correctly, it should have 7bit or 8bit, because the content is still formatted in the line-oriented mime-part. [Fix] (1) If the mime-part is matched with the condition above, and if it is sent via SnedMail, ZCS will put "Content-Transfer-Encoding: base64". (2) When ZCS redirects such a message, and if the original message does not have any Content-Transfer-Encoding header, then ZCS will add "Content-Transfer-Encoding: 8bit" before redirecting. Although 7bit is a default value of the CTE defined in the RFC, 8bit is chosen for the pattern (2), because: - Most of the MTA servers, including Postfix, support 8BITMIME extension. - 8bit is a super-set of the 7bit. --- .../common/zmime/ZMimeBodyPartTest.java | 12 ++--- .../zimbra/common/zmime/ZMimeBodyPart.java | 4 +- .../zimbra/cs/filter/RedirectCopyTest.java | 50 +++++++++++++++++-- store/src/java/com/zimbra/cs/mime/Mime.java | 9 +++- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/common/src/java-test/com/zimbra/common/zmime/ZMimeBodyPartTest.java b/common/src/java-test/com/zimbra/common/zmime/ZMimeBodyPartTest.java index 626049af987..75fbf361a46 100644 --- a/common/src/java-test/com/zimbra/common/zmime/ZMimeBodyPartTest.java +++ b/common/src/java-test/com/zimbra/common/zmime/ZMimeBodyPartTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2011, 2012, 2013, 2014, 2016 Synacor, Inc. + * Copyright (C) 2011, 2012, 2013, 2014, 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -16,6 +16,7 @@ */ package com.zimbra.common.zmime; +import org.apache.commons.lang.StringUtils; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -84,10 +85,9 @@ public void encoding() throws Exception { testEncodingSelection("single NUL", "cyb\u0000le illus.", ZTransferEncoding.QUOTED_PRINTABLE); testEncodingSelection("single control char", "ESCAPE ME \u001B", ZTransferEncoding.SEVEN_BIT); - StringBuilder sb = new StringBuilder(1000); - for (int i = 0; i < 1000; i++) { - sb.append("X"); - } - testEncodingSelection("line too long", sb.toString(), ZTransferEncoding.QUOTED_PRINTABLE); + testEncodingSelection("line too long (ascii)", StringUtils.leftPad("", 1000, "X"), ZTransferEncoding.QUOTED_PRINTABLE); + testEncodingSelection("line too long (JIS)", new String(StringUtils.leftPad("", 1000, "あ").getBytes("ISO-2022-JP")), ZTransferEncoding.QUOTED_PRINTABLE); + testEncodingSelection("line too long (utf-8)", new String(StringUtils.leftPad("", 1000, "あ").getBytes("UTF-8")), ZTransferEncoding.BASE64); + testEncodingSelection("line too long (shift-jis)", new String(StringUtils.leftPad("", 1000, "あ").getBytes("Shift-JIS")), ZTransferEncoding.BASE64); } } diff --git a/common/src/java/com/zimbra/common/zmime/ZMimeBodyPart.java b/common/src/java/com/zimbra/common/zmime/ZMimeBodyPart.java index 5d96890e652..37dcb69f844 100644 --- a/common/src/java/com/zimbra/common/zmime/ZMimeBodyPart.java +++ b/common/src/java/com/zimbra/common/zmime/ZMimeBodyPart.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2011, 2012, 2013, 2014, 2016 Synacor, Inc. + * Copyright (C) 2011, 2012, 2013, 2014, 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -412,7 +412,7 @@ String getEncoding(boolean isAttachment, boolean isText) { } else if (toolong == 0) { return "8bit"; //section 6.2 of RFC2045 } else { - return "binary"; + return "base64"; } } } diff --git a/store/src/java-test/com/zimbra/cs/filter/RedirectCopyTest.java b/store/src/java-test/com/zimbra/cs/filter/RedirectCopyTest.java index d19ae5737e9..9b13222ce30 100644 --- a/store/src/java-test/com/zimbra/cs/filter/RedirectCopyTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/RedirectCopyTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2016 Synacor, Inc. + * Copyright (C) 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -16,10 +16,11 @@ */ package com.zimbra.cs.filter; -import static org.junit.Assert.*; import java.util.List; import java.util.Map; import java.util.UUID; + +import org.apache.commons.lang.StringUtils; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; @@ -93,7 +94,7 @@ mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), Assert.assertEquals(2, notifyMsg.getFolderId()); } catch (Exception e) { e.printStackTrace(); - fail("No exception should be thrown"); + Assert.fail("No exception should be thrown"); } } @@ -123,7 +124,7 @@ mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), Assert.assertEquals(2, msg.getFolderId()); } catch (Exception e) { e.printStackTrace(); - fail("No exception should be thrown"); + Assert.fail("No exception should be thrown"); } } @@ -147,7 +148,46 @@ mbox, new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); } catch (Exception e) { e.printStackTrace(); - fail("No exception should be thrown"); + Assert.fail("No exception should be thrown"); + } + } + + /* + * Redirect a message whose body text consists of some non-ascii characters, + * but it does not have a proper Content-Transfer-Encoding header. + */ + @Test + public void testPlainRedirectMimeMsg1() { + String filterScript = "require [\"copy\", \"fileinto\"];\n" + + "redirect \"test3@zimbra.com\";\n"; + try { + Account account2 = Provisioning.getInstance().get(Key.AccountBy.name, + "test2@zimbra.com"); + Account account3 = Provisioning.getInstance().get(Key.AccountBy.name, + "test3@zimbra.com"); + RuleManager.clearCachedRules(account2); + Mailbox mbox2 = MailboxManager.getInstance().getMailboxByAccount(account2); + Mailbox mbox3 = MailboxManager.getInstance().getMailboxByAccount(account3); + account2.setMailSieveScript(filterScript); + String body = StringUtils.leftPad("", 999, "あ"); + + String rawReal = "From: test1@zimbra.com\n" + "To: test2@zimbra.com\n" + + "Subject: Test\n" + "\n" + body; + RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox2), + mbox2, new ParsedMessage(rawReal.getBytes("Shift_JIS"), false), 0, account2.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + + // verify the redirected message + Integer item = mbox3.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE).get(0); + Message redirectMsg = mbox3.getMessageById(null, item); + Assert.assertEquals(body.substring(0, 150), redirectMsg.getFragment().substring(0, 150)); + String[] headers = redirectMsg.getMimeMessage().getHeader("Content-Transfer-Encoding"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals("8bit", headers[0]); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail("No exception should be thrown"); } } } \ No newline at end of file diff --git a/store/src/java/com/zimbra/cs/mime/Mime.java b/store/src/java/com/zimbra/cs/mime/Mime.java index f6edf2b41da..ff799bc9596 100644 --- a/store/src/java/com/zimbra/cs/mime/Mime.java +++ b/store/src/java/com/zimbra/cs/mime/Mime.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -668,6 +668,13 @@ public static Reader getContentAsReader(MimePart textPart, String defaultCharset public static void recursiveRepairTransferEncoding(MimeMessage mm) throws MessagingException, IOException { for (MPartInfo mpi : listParts(mm, null)) { + String cte = mpi.mPart.getHeader("Content-Transfer-Encoding", null); + String ct = getContentType(mpi.mPart); + if (StringUtil.isNullOrEmpty(cte) && + !ct.equals(MimeConstants.CT_MESSAGE_RFC822) && + !ct.startsWith(MimeConstants.CT_MULTIPART_PREFIX)) { + mpi.mPart.addHeader("Content-Transfer-Encoding", "8bit"); + } repairTransferEncoding(mpi.mPart); } } From 3fac17bfd60f3174c54271deeb4575a4beea86b5 Mon Sep 17 00:00:00 2001 From: Sneha Patil Date: Thu, 14 Sep 2017 10:56:26 +0530 Subject: [PATCH 046/142] ZCS-2730:Fixed RestoreContactsResponse status --- .../mail/message/RestoreContactsResponse.java | 15 --------------- .../cs/service/mail/RestoreContactsTest.java | 2 +- .../zimbra/cs/service/mail/RestoreContacts.java | 11 ++++------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java index 7635c21c46c..1071e285c98 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsResponse.java @@ -18,7 +18,6 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import com.zimbra.common.soap.MailConstants; @@ -27,18 +26,4 @@ @XmlRootElement(name = MailConstants.E_RESTORE_CONTACTS_RESPONSE) public class RestoreContactsResponse { - /** - * @zm-api-field-tag status - * @zm-api-field-description Restore request status - */ - @XmlAttribute(name = MailConstants.A_STATUS, required = true) - private String status; - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } } diff --git a/store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java b/store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java index 23244b79b59..0c73c2b0727 100644 --- a/store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java +++ b/store/src/java-test/com/zimbra/cs/service/mail/RestoreContactsTest.java @@ -94,7 +94,7 @@ public void testRestore() throws Exception { request.addAttribute("contactsBackupFileName", "backup_dummy_test.tgz"); Map context = ServiceTestUtil.getRequestContext(acct); Element response = new RestoreContacts().handle(request, context); - String expectedResponse = ""; + String expectedResponse = ""; Assert.assertEquals(expectedResponse, response.prettyPrint()); try { // RestoreContactRequest with non-existing backup file name diff --git a/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java b/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java index 6d68cfea7c8..ee02531c655 100644 --- a/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java +++ b/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java @@ -56,10 +56,6 @@ public class RestoreContacts extends MailDocumentHandler { - public enum ContactRestoreStatus { - SUCCESS, FAILURE; - } - @Override public Element handle(Element request, Map context) throws ServiceException { ZimbraSoapContext zsc = getZimbraSoapContext(context); @@ -117,15 +113,16 @@ public Element handle(Element request, Map context) throws Servi if (!mailItemFound) { throw ServiceException.INVALID_REQUEST("No such file: " + contactBackupFileName, null); } - ContactRestoreStatus status = httpResponse.getStatusLine().getStatusCode() == HttpStatus.OK_200 ? ContactRestoreStatus.SUCCESS : ContactRestoreStatus.FAILURE; - if ("SUCCESS".equals(status)) { + + if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.OK_200) { ZimbraLog.contact.debug("Restore operation for %s completed successfully", contactBackupFileName); } else { ZimbraLog.contact.info("Restore operation for %s failed. Http respose status: %s", contactBackupFileName, httpResponse.getStatusLine()); + throw ServiceException + .FAILURE("Failed to restore contacts backup " + contactBackupFileName, null); } - response.setStatus(status.name()); return zsc.jaxbToElement(response); } From bdccc160e2354b573d75e36983cb97e5b834eae1 Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Fri, 15 Sep 2017 18:24:06 +0900 Subject: [PATCH 047/142] ZCS-1858(3):declare extension in "require" command, Part 2 Fixed unit tests - Added capability strings in "require". - Fixed mal-formatted script, and initialized the filter setting so that the filter can be tested successfully regardless of the executing order. --- .../com/zimbra/cs/filter/AddressTest.java | 8 ++++---- .../zimbra/cs/filter/DeleteHeaderTest.java | 6 +++--- .../com/zimbra/cs/filter/EnvelopeTest.java | 2 +- .../com/zimbra/cs/filter/HeaderTest.java | 8 ++++---- .../zimbra/cs/filter/ReplaceHeaderTest.java | 19 +++++++++++-------- .../com/zimbra/cs/filter/SetVariableTest.java | 11 +++++++---- 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/store/src/java-test/com/zimbra/cs/filter/AddressTest.java b/store/src/java-test/com/zimbra/cs/filter/AddressTest.java index 0157c9d3e0b..37ea10746a7 100644 --- a/store/src/java-test/com/zimbra/cs/filter/AddressTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/AddressTest.java @@ -364,7 +364,7 @@ public void testNumericNegativeValueIs() { RuleManager.clearCachedRules(acct); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct); - String filterScript = "require \"tag\";\n" + String filterScript = "require [\"tag\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if address :count \"lt\" :comparator \"i;ascii-numeric\" \"To\" \"-1\" {" + " tag \"compareAsciiNumericNegativeValue\";" + "}"; @@ -388,7 +388,7 @@ public void compareHeaderNameWithLeadingSpaces() { RuleManager.clearCachedRules(acct); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct); - String filterScript = "require [\"tag\"];\n" + String filterScript = "require [\"tag\", \"comparator-i;ascii-numeric\"];\n" + "if address :is :comparator \"i;ascii-numeric\" \" To\" \"test1@zimbra.com\" {" + " tag \"t1\";" + "}" @@ -413,7 +413,7 @@ public void compareHeaderNameWithTrailingSpaces() { RuleManager.clearCachedRules(acct); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct); - String filterScript = "require [\"tag\"];\n" + String filterScript = "require [\"tag\", \"comparator-i;ascii-numeric\"];\n" + "if address :is :comparator \"i;ascii-numeric\" \"To \" \"test1@zimbra.com\" {" + " tag \"t2\";" + "}" @@ -438,7 +438,7 @@ public void compareHeaderNameWithLeadingAndTrailingSpaces() { RuleManager.clearCachedRules(acct); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct); - String filterScript = "require [\"tag\"];\n" + String filterScript = "require [\"tag\", \"comparator-i;ascii-numeric\"];\n" + "if address :is :comparator \"i;ascii-numeric\" \" To \" \"test1@zimbra.com\" {" + " tag \"t3\";" + "}" diff --git a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java index c96e94924ee..a41f64b6d8c 100644 --- a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java @@ -918,7 +918,7 @@ null, new DeliveryContext(), @Test public void testDeleteNoValuePattern() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + " deleteheader :count \"gt\" :comparator \"i;ascii-numeric\" \"Subject\" \"\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -995,7 +995,7 @@ null, new DeliveryContext(), @Test public void testDeleteHeaderCountNegative() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "deleteheader :count \"le\" :comparator \"i;ascii-numeric\" \"X-Numeric-Header\" \"-1\";\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); Mailbox mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1); @@ -1086,7 +1086,7 @@ public void testDeleteHeaderAsciiNumbericIsComparator() { + "\tby edge01e.zimbra.com (Postfix) with ESMTP id 9245B13575C;\n" + "\tFri, 24 Jun 2016 01:45:31 -0400 (EDT)\n" + "Subject: 1\n" + "to: test@zimbra.com\n"; - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"comparator-i;ascii-numeric\"];\n" + "deleteheader :is :comparator \"i;ascii-numeric\" \"Subject\" \"1\";\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); Mailbox mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1); diff --git a/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java b/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java index 2df7e8605ac..e8c7c5510b5 100644 --- a/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java @@ -750,7 +750,7 @@ public void testCountForEmptyFromHeader() { @Test public void testNumericNegativeValueCount() { - String filterScript = "require [\"envelope\", \"tag\", \"relational\"];\n" + String filterScript = "require [\"envelope\", \"tag\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if envelope :all :count \"lt\" :comparator \"i;ascii-numeric\" \"to\" \"-1\" {\n" + " tag \"To\";\n" + "}"; diff --git a/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java index 6e6b475d2fe..a68a881f4d1 100644 --- a/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java @@ -116,7 +116,7 @@ public void testEmptyHeaderEmptyKey() { // and none of tag commands should be executed. @Test public void testNumericNegativeValueValue() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :value \"ge\" :comparator \"i;ascii-numeric\" " + "[\"X-Spam-score\"] [\"500\"] { tag \"XSpamScore\";}" + "tag \"Negative\";"; @@ -127,8 +127,8 @@ public void testNumericNegativeValueValue() { // and none of tag commands should be executed. @Test public void testNumericNegativeValueCounts() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" - + "if header :counts \"ge\" :comparator \"i;ascii-numeric\" " + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + + "if header :count \"ge\" :comparator \"i;ascii-numeric\" " + "[\"Received\"] [\"-1\"] { tag \"Received\";}" + "tag \"Negative\";"; doTest(filterScript, null); @@ -138,7 +138,7 @@ public void testNumericNegativeValueCounts() { // and none of tag commands should be executed. @Test public void testNumericNegativeValueIs() { - String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\"];\n" + String filterScript = "require [\"fileinto\", \"tag\", \"flag\", \"log\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "if header :is :comparator \"i;ascii-numeric\" " + "[\"X-Spam-score\"] [\"-5\"] { tag \"XSpamScore\";}" + "tag \"Negative\";"; diff --git a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java index 6f23c2971e3..0c13ec03fe9 100644 --- a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java @@ -519,7 +519,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderWithNumericComparisionUsingValue() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + " replaceheader :newname \"X-Numeric2-Header\" :newvalue \"0\" :value \"lt\" :comparator \"i;ascii-numeric\" \"X-Numeric-Header\" \"3\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -1095,7 +1095,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderWithEmptyHeaderNewName() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\"];\n" + " replaceheader :newname \"\" :newvalue \"0\" :value \"lt\" :comparator \"i;ascii-casemap\" \"X-Test-Header\" \"test2\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -1132,7 +1132,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderWithSinlgeSpaceAsHeaderNewName() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\"];\n" + " replaceheader :newname \" \" :newvalue \"0\" :value \"lt\" :comparator \"i;ascii-casemap\" \"X-Test-Header\" \"test2\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -1168,7 +1168,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderWithMultipleSpacesAsHeaderNewName() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\"];\n" + " replaceheader :newname \" \" :newvalue \"0\" :value \"lt\" :comparator \"i;ascii-casemap\" \"X-Test-Header\" \"test2\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -1204,7 +1204,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderStartingWithSpacesAsHeaderNewName() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\"];\n" + " replaceheader :newname \" asdf\" :newvalue \"0\" :value \"lt\" :comparator \"i;ascii-casemap\" \"X-Test-Header\" \"test2\" \r\n" + " ;\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); @@ -1276,7 +1276,7 @@ null, new DeliveryContext(), @Test public void testReplaceHeaderValueNegative() { try { - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"relational\", \"comparator-i;ascii-numeric\"];\n" + "replaceheader :newname \"X-Numeric2-Header\" :newvalue \"0\" :value \"lt\" :comparator \"i;ascii-numeric\" \"X-Numeric-Header\" \"-3\";\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); Mailbox mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1); @@ -1460,7 +1460,7 @@ public void testReplaceHeaderAsciiNumbericIsComparator() { + "\tby edge01e.zimbra.com (Postfix) with ESMTP id 9245B13575C;\n" + "\tFri, 24 Jun 2016 01:45:31 -0400 (EDT)\n" + "Subject: 1\n" + "to: test@zimbra.com\n"; - String filterScript = "require [\"editheader\"];\n" + String filterScript = "require [\"editheader\", \"comparator-i;ascii-numeric\"];\n" + "replaceheader :newvalue \"New Value\" :is :comparator \"i;ascii-numeric\" \"Subject\" \"1\";\n"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); Mailbox mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1); @@ -1552,7 +1552,7 @@ public void replaceHeaderSieveEditHeaderEnabledTrue() { public void replaceHeaderSieveEditHeaderEnabledFalse() { try { String filterScript = "require [\"editheader\"];\n" - + "replaceheader :newvalue \"my subject\" :contains \"Subject\" \"example\""; + + "replaceheader :newvalue \"my subject\" :contains \"Subject\" \"example\";"; Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); Mailbox mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1); RuleManager.clearCachedRules(acct1); @@ -1591,6 +1591,9 @@ public void replaceHeaderUserSieveScript() { Mailbox mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1); RuleManager.clearCachedRules(acct1); acct1.setSieveEditHeaderEnabled(true); + acct1.unsetAdminSieveScriptBefore(); + acct1.unsetMailSieveScript(); + acct1.unsetAdminSieveScriptAfter(); acct1.setMailSieveScript(filterScript); RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox1), mbox1, new ParsedMessage(sampleBaseMsg.getBytes(), false), 0, acct1.getName(), null, diff --git a/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java b/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java index 5bb75c86ef1..8696e9519d6 100644 --- a/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java @@ -2059,7 +2059,8 @@ public void testNegativeVarIndex() { RuleManager.clearCachedRules(account); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - filterScript = "if header :matches :comparator \"i;ascii-casemap\" \"Subject\" \"*C*a*c*ple*oo *ge*yo 123 *56*89 sie*e*t\" { " + filterScript = "require \"variables\";" + + "if header :matches :comparator \"i;ascii-casemap\" \"Subject\" \"*C*a*c*ple*oo *ge*yo 123 *56*89 sie*e*t\" { " + "tag \"${-1}\";}"; account.setMailSieveScript(filterScript); @@ -2091,7 +2092,8 @@ public void testOutofRangeVarIndex() { RuleManager.clearCachedRules(account); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - filterScript = "if header :matches :comparator \"i;ascii-casemap\" \"Subject\" \"*C*a*c*ple*oo *ge*yo 123 *56*89 sie*e*t\" { " + filterScript = "require \"variables\";" + + "if header :matches :comparator \"i;ascii-casemap\" \"Subject\" \"*C*a*c*ple*oo *ge*yo 123 *56*89 sie*e*t\" { " + "tag \"${10}\";}"; account.setMailSieveScript(filterScript); @@ -2123,7 +2125,8 @@ public void testOutofRangeVarIndexWithLeadingZeroes() { RuleManager.clearCachedRules(account); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - filterScript = "if header :matches :comparator \"i;ascii-casemap\" \"Subject\" \"*C*a*c*ple*oo *ge*yo 123 *56*89 sie*e*t\" { " + filterScript = "require \"variables\";" + + "if header :matches :comparator \"i;ascii-casemap\" \"Subject\" \"*C*a*c*ple*oo *ge*yo 123 *56*89 sie*e*t\" { " + "tag \"${0010}\";}"; account.setMailSieveScript(filterScript); @@ -2272,7 +2275,7 @@ public void testStringNumericNegativeTest() { Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - filterScript = "require [\"variables\", \"tag\"];\n" + filterScript = "require [\"variables\", \"tag\", \"comparator-i;ascii-numeric\"];\n" + "set \"negative\" \"-123\";\n" + "if string :is :comparator \"i;ascii-numeric\" \"${negative}\" \"-123\" {\n" + " tag \"negative\";\n" From 414b89f29b6bb28fd30ca7c9944938a49b5b1004 Mon Sep 17 00:00:00 2001 From: Chinmay Pathak <15.chinmay@gmail.com> Date: Fri, 15 Sep 2017 12:22:16 +0530 Subject: [PATCH 048/142] ZCS-2728 : Add 2 LDAP attributes for Contacts backup functionality Fixed type --- .../common/account/ZAttrProvisioning.java | 24 ++ store/conf/attrs/zimbra-attrs.xml | 14 ++ .../com/zimbra/cs/account/ZAttrConfig.java | 224 ++++++++++++++++++ .../com/zimbra/cs/account/ZAttrServer.java | 224 ++++++++++++++++++ .../callback/ContactBackupFeature.java | 41 ++++ 5 files changed, 527 insertions(+) create mode 100644 store/src/java/com/zimbra/cs/account/callback/ContactBackupFeature.java diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index 494854432df..e3b5f2670be 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -6232,6 +6232,30 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc @ZAttr(id=806) public static final String A_zimbraFeatureConfirmationPageEnabled = "zimbraFeatureConfirmationPageEnabled"; + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public static final String A_zimbraFeatureContactBackupFrequency = "zimbraFeatureContactBackupFrequency"; + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public static final String A_zimbraFeatureContactBackupLifeTime = "zimbraFeatureContactBackupLifeTime"; + /** * whether detailed contact search UI is enabled * diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index b0dd5bb26f6..c1b1f38f8b6 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9569,5 +9569,19 @@ TODO: delete them permanently from here Mark messages sent to a forwarding address as read + + 1d + + Sleep time between subsequent contact backups. 0 means that contact + backup is disabled. + + + + + 15d + + Duration for which the backups should be preserved. + + diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index cd730448c04..333391fe5d1 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -15786,6 +15786,230 @@ public Map unsetExternalShareInvitationUrlExpiration(MapUse getFeatureContactBackupFrequencyAsString to access value as a string. + * + * @see #getFeatureContactBackupFrequencyAsString() + * + * @return zimbraFeatureContactBackupFrequency in millseconds, or 86400000 (1d) if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public long getFeatureContactBackupFrequency() { + return getTimeInterval(Provisioning.A_zimbraFeatureContactBackupFrequency, 86400000L, true); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @return zimbraFeatureContactBackupFrequency, or "1d" if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public String getFeatureContactBackupFrequencyAsString() { + return getAttr(Provisioning.A_zimbraFeatureContactBackupFrequency, "1d", true); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @param zimbraFeatureContactBackupFrequency new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public void setFeatureContactBackupFrequency(String zimbraFeatureContactBackupFrequency) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, zimbraFeatureContactBackupFrequency); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @param zimbraFeatureContactBackupFrequency new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public Map setFeatureContactBackupFrequency(String zimbraFeatureContactBackupFrequency, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, zimbraFeatureContactBackupFrequency); + return attrs; + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public void unsetFeatureContactBackupFrequency() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public Map unsetFeatureContactBackupFrequency(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, ""); + return attrs; + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + *

Use getFeatureContactBackupLifeTimeAsString to access value as a string. + * + * @see #getFeatureContactBackupLifeTimeAsString() + * + * @return zimbraFeatureContactBackupLifeTime in millseconds, or 1296000000 (15d) if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public long getFeatureContactBackupLifeTime() { + return getTimeInterval(Provisioning.A_zimbraFeatureContactBackupLifeTime, 1296000000L, true); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @return zimbraFeatureContactBackupLifeTime, or "15d" if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public String getFeatureContactBackupLifeTimeAsString() { + return getAttr(Provisioning.A_zimbraFeatureContactBackupLifeTime, "15d", true); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureContactBackupLifeTime new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public void setFeatureContactBackupLifeTime(String zimbraFeatureContactBackupLifeTime) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, zimbraFeatureContactBackupLifeTime); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureContactBackupLifeTime new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public Map setFeatureContactBackupLifeTime(String zimbraFeatureContactBackupLifeTime, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, zimbraFeatureContactBackupLifeTime); + return attrs; + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public void unsetFeatureContactBackupLifeTime() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public Map unsetFeatureContactBackupLifeTime(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, ""); + return attrs; + } + /** * Whether to display the distribution list folder in address book * diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index 0050ef5dd21..595861f5de4 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -8769,6 +8769,230 @@ public Map unsetExternalAccountStatusCheckInterval(MapUse getFeatureContactBackupFrequencyAsString to access value as a string. + * + * @see #getFeatureContactBackupFrequencyAsString() + * + * @return zimbraFeatureContactBackupFrequency in millseconds, or 86400000 (1d) if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public long getFeatureContactBackupFrequency() { + return getTimeInterval(Provisioning.A_zimbraFeatureContactBackupFrequency, 86400000L, true); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @return zimbraFeatureContactBackupFrequency, or "1d" if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public String getFeatureContactBackupFrequencyAsString() { + return getAttr(Provisioning.A_zimbraFeatureContactBackupFrequency, "1d", true); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @param zimbraFeatureContactBackupFrequency new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public void setFeatureContactBackupFrequency(String zimbraFeatureContactBackupFrequency) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, zimbraFeatureContactBackupFrequency); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @param zimbraFeatureContactBackupFrequency new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public Map setFeatureContactBackupFrequency(String zimbraFeatureContactBackupFrequency, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, zimbraFeatureContactBackupFrequency); + return attrs; + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public void unsetFeatureContactBackupFrequency() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Sleep time between subsequent contact backups. 0 means that contact + * backup is disabled. . Must be in valid duration format: + * {digits}{time-unit}. digits: 0-9, time-unit: [hmsd]|ms. h - hours, m - + * minutes, s - seconds, d - days, ms - milliseconds. If time unit is not + * specified, the default is s(seconds). + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2124) + public Map unsetFeatureContactBackupFrequency(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupFrequency, ""); + return attrs; + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + *

Use getFeatureContactBackupLifeTimeAsString to access value as a string. + * + * @see #getFeatureContactBackupLifeTimeAsString() + * + * @return zimbraFeatureContactBackupLifeTime in millseconds, or 1296000000 (15d) if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public long getFeatureContactBackupLifeTime() { + return getTimeInterval(Provisioning.A_zimbraFeatureContactBackupLifeTime, 1296000000L, true); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @return zimbraFeatureContactBackupLifeTime, or "15d" if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public String getFeatureContactBackupLifeTimeAsString() { + return getAttr(Provisioning.A_zimbraFeatureContactBackupLifeTime, "15d", true); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureContactBackupLifeTime new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public void setFeatureContactBackupLifeTime(String zimbraFeatureContactBackupLifeTime) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, zimbraFeatureContactBackupLifeTime); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureContactBackupLifeTime new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public Map setFeatureContactBackupLifeTime(String zimbraFeatureContactBackupLifeTime, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, zimbraFeatureContactBackupLifeTime); + return attrs; + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public void unsetFeatureContactBackupLifeTime() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Duration for which the backups should be preserved. . Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2125) + public Map unsetFeatureContactBackupLifeTime(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureContactBackupLifeTime, ""); + return attrs; + } + /** * Maximum size in bytes for file uploads * diff --git a/store/src/java/com/zimbra/cs/account/callback/ContactBackupFeature.java b/store/src/java/com/zimbra/cs/account/callback/ContactBackupFeature.java new file mode 100644 index 00000000000..4409966af81 --- /dev/null +++ b/store/src/java/com/zimbra/cs/account/callback/ContactBackupFeature.java @@ -0,0 +1,41 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.account.callback; + +import java.util.Map; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.AttributeCallback; +import com.zimbra.cs.account.Entry; + +public class ContactBackupFeature extends AttributeCallback { + + @SuppressWarnings("rawtypes") + @Override + public void preModify(CallbackContext context, String attrName, Object attrValue, Map attrsToModify, Entry entry) + throws ServiceException { + // TODO Populate while implementing contact backup feature + + } + + @Override + public void postModify(CallbackContext context, String attrName, Entry entry) { + // TODO Populate while implementing contact backup feature + + } + +} From 2666f783ef73dbfacc8db3ff76f40a4bdd50a060 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 12 Sep 2017 19:49:06 +0100 Subject: [PATCH 049/142] ZCS-2383:IMAP SEARCH BODY shared folder tests --- .../com/zimbra/qa/unittest/ImapTestBase.java | 39 ++++++++ .../zimbra/qa/unittest/SharedImapTests.java | 96 ++++++++++++++++--- 2 files changed, 121 insertions(+), 14 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java index 7ae6a5d06d3..7016dde65a2 100644 --- a/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java +++ b/store/src/java/com/zimbra/qa/unittest/ImapTestBase.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -36,6 +37,7 @@ import com.zimbra.cs.imap.ImapProxy.ZimbraClientAuthenticator; import com.zimbra.cs.mailclient.CommandFailedException; import com.zimbra.cs.mailclient.auth.AuthenticatorFactory; +import com.zimbra.cs.mailclient.imap.AppendMessage; import com.zimbra.cs.mailclient.imap.AppendResult; import com.zimbra.cs.mailclient.imap.Body; import com.zimbra.cs.mailclient.imap.CAtom; @@ -544,6 +546,43 @@ public static Literal message(int size) throws IOException { return new Literal(file, true); } + protected static Literal literal(String s) { + return new Literal(bytes(s)); + } + + protected static byte[] bytes(String s) { + try { + return s.getBytes("UTF8"); + } catch (UnsupportedEncodingException e) { + fail("UTF8 encoding not supported"); + } + return null; + } + + protected AppendResult doAppend(ImapConnection conn, String folderName, String subject, String body, + Flags flags, boolean fetchResult) { + checkConnection(conn); + assertTrue("expecting UIDPLUS capability", conn.hasCapability("UIDPLUS")); + String msg = simpleMessage(subject, body); + Date date = new Date(System.currentTimeMillis()); + AppendMessage am = new AppendMessage(flags, date, literal(msg)); + try { + AppendResult res = conn.append(folderName, am); + assertNotNull("result of append command should not be null", res); + if (fetchResult) { + doSelectShouldSucceed(conn, folderName); + MessageData md = fetchMessage(conn, res.getUid()); + byte[] b = getBody(md); + assertArrayEquals("FETCH content not same as APPENDed content", msg.getBytes(), b); + } + return res; + } catch (IOException e) { + ZimbraLog.test.info("Exception thrown trying to append", e); + fail("Exception thrown trying to append:" + e.getMessage()); + } + return null; + } + protected void doAppend(ImapConnection conn, String folderName, int size, Flags flags, boolean fetchResult) throws IOException { checkConnection(conn); diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index a6cd78fe79c..2a50489c1d1 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -9,7 +9,6 @@ import static org.junit.Assert.fail; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -1803,19 +1802,6 @@ private String url(String mbox, AppendResult res) { mbox, res.getUidValidity(), res.getUid()); } - private static Literal literal(String s) { - return new Literal(bytes(s)); - } - - private static byte[] bytes(String s) { - try { - return s.getBytes("UTF8"); - } catch (UnsupportedEncodingException e) { - fail("UTF8 encoding not supported"); - } - return null; - } - @Test(timeout=100000) public void listSharedFolderViaHome() throws ServiceException, IOException { TestUtil.createAccount(SHAREE); @@ -2229,6 +2215,88 @@ public void clashingHomeSubFolders() throws ServiceException, IOException, Messa doSelectShouldSucceed(otherConnection, underSharedFolderName); } + @Test(timeout=100000) + public void searchBodyHomeShare() throws ServiceException, IOException { + List matches; + TestUtil.createAccount(SHAREE); + connection = super.connectAndLogin(USER); + String sharedFolderName = "INBOX/share"; + connection.create(sharedFolderName); + String underSharedFolderName = String.format("%s/subFolder", sharedFolderName); + connection.create(underSharedFolderName); + String topBody = "Orange\nApple\nPear\nPlum Nectarine"; + String subBody = "Green\nBlack\nBlue\nPurple Silver"; + doAppend(connection, sharedFolderName, "in share directly under inbox", topBody, (Flags) null, + true /* do fetch to check content */); + doAppend(connection, sharedFolderName, "in share directly under inbox", "nothing much", (Flags) null, + true /* do fetch to check content */); + doAppend(connection, underSharedFolderName, "in subFolder", subBody, (Flags) null, + true /* do fetch to check content */); + doAppend(connection, underSharedFolderName, "in subFolder", "even less interesting", (Flags) null, + true /* do fetch to check content */); + doSelectShouldSucceed(connection, sharedFolderName); + matches = connection.search((Object[]) new String[] { "BODY Pear" } ); + assertEquals("Number of matches in top level for owner", 1, matches.size()); + connection.setacl(sharedFolderName, SHAREE, "lrswickxteda"); + connection.logout(); + connection = null; + String remFolder = String.format("/home/%s/%s", USER, sharedFolderName); + String underRemFolder = String.format("%s/subFolder", remFolder); + otherConnection = connectAndLogin(SHAREE); + doSelectShouldSucceed(otherConnection, remFolder); + matches = otherConnection.search((Object[]) new String[] { "BODY Pear" } ); + assertEquals("Number of matches in top level", 1, matches.size()); + assertEquals("ID of matching message in top level", Long.valueOf(1), matches.get(0)); + doSelectShouldSucceed(otherConnection, underRemFolder); + matches = otherConnection.search((Object[]) new String[] { "BODY Purple" } ); + assertEquals("Number of matches in subFolder", 1, matches.size()); + assertEquals("ID of matching message in subFolder", Long.valueOf(1), matches.get(0)); + otherConnection.logout(); + otherConnection = null; + } + + @Test(timeout=100000) + public void searchBodyMountpoint() throws ServiceException, IOException { + String sharedFolder = "INBOX/share"; + String subFolder = sharedFolder + "/subFolder"; + String mountpoint = String.format("shared-", testInfo.getMethodName()); + String subMountpoint = mountpoint + "/subFolder"; + TestUtil.createAccount(SHAREE); + ZMailbox userZmbox = TestUtil.getZMailbox(USER); + ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); + + TestUtil.createMountpoint(userZmbox, "/" + sharedFolder, shareeZmbox, mountpoint); + TestUtil.createFolder(userZmbox, "/" + subFolder); + List matches; + connection = super.connectAndLogin(USER); + String topBody = "Orange\nApple\nPear\nPlum Nectarine"; + String subBody = "Green\nBlack\nBlue\nPurple Silver"; + doAppend(connection, sharedFolder, "in share directly under inbox", topBody, (Flags) null, + true /* do fetch to check content */); + doAppend(connection, sharedFolder, "in share directly under inbox", "nothing much", (Flags) null, + true /* do fetch to check content */); + doAppend(connection, subFolder, "in subFolder", subBody, (Flags) null, + true /* do fetch to check content */); + doAppend(connection, subFolder, "in subFolder", "even less interesting", (Flags) null, + true /* do fetch to check content */); + doSelectShouldSucceed(connection, subFolder); + matches = connection.search((Object[]) new String[] { "BODY Black" } ); + assertEquals("Number of matches in top level for owner", 1, matches.size()); + connection.logout(); + connection = null; + otherConnection = connectAndLogin(SHAREE); + doSelectShouldSucceed(otherConnection, mountpoint); + matches = otherConnection.search((Object[]) new String[] { "BODY Pear" } ); + assertEquals("Number of matches in top level", 1, matches.size()); + assertEquals("ID of matching message in top level", Long.valueOf(1), matches.get(0)); + doSelectShouldSucceed(otherConnection, subMountpoint); + matches = otherConnection.search((Object[]) new String[] { "BODY Black" } ); + assertEquals("Number of matches in subFolder", 1, matches.size()); + assertEquals("ID of matching message in subFolder", Long.valueOf(1), matches.get(0)); + otherConnection.logout(); + otherConnection = null; + } + protected void flushCacheIfNecessary() throws Exception { // overridden by tests running against imapd } From 745cfaece5a160d1f6dea06b03299cdb3fe44c1e Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 13 Sep 2017 16:31:34 +0100 Subject: [PATCH 050/142] ZCS-2383:ImapDaemon init WellKnownTimeZones `ImapHandler.runSearch` does: TimeZone tz = acct == null ? null : WellKnownTimeZones.getTimeZoneById(acct.getAttr(Provisioning.A_zimbraPrefTimeZoneId)); so requires `WellKnownTimeZones` to have loaded the timezone definitions, otherwise the search code doesn't provide a timezone when searching which in the delegated remote case, leads to a GetInfoRequest to get the account's chosen timezone which is disallowed. --- store/src/java/com/zimbra/cs/imap/ImapDaemon.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/store/src/java/com/zimbra/cs/imap/ImapDaemon.java b/store/src/java/com/zimbra/cs/imap/ImapDaemon.java index 8bbaeba6354..492d598051c 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapDaemon.java +++ b/store/src/java/com/zimbra/cs/imap/ImapDaemon.java @@ -17,12 +17,14 @@ package com.zimbra.cs.imap; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; import org.apache.log4j.PropertyConfigurator; +import com.zimbra.common.calendar.WellKnownTimeZones; import com.zimbra.common.localconfig.LC; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; @@ -108,6 +110,15 @@ public static void main(String[] args) { MemoryStats.startup(); ZimbraPerf.initialize(ZimbraPerf.ServerID.IMAP_DAEMON); + String tzFilePath = LC.timezone_file.value(); + try { + File tzFile = new File(tzFilePath); + WellKnownTimeZones.loadFromFile(tzFile); + } catch (Throwable t) { + ZimbraLog.imap.error("Unable to load timezones from %s.", tzFilePath, t); + errorExit("ImapDaemon: imapd service was unable to intialize timezones EXITING."); + } + ImapDaemon daemon = new ImapDaemon(); int numStarted = daemon.startServers(); From d02064f4d7b8ce73f2288eaa90452f4e1c8971ad Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Mon, 11 Sep 2017 18:55:36 -0500 Subject: [PATCH 051/142] ZCS-2537 noop: whitespace --- .../cs/service/admin/AddAccountLogger.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java index a68655927d1..24fa6b5c156 100644 --- a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java +++ b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java @@ -40,28 +40,28 @@ /** * Adds a custom logger for the given account. - * + * * @author bburtin */ public class AddAccountLogger extends AdminDocumentHandler { static String CATEGORY_ALL = "all"; - + @Override public Element handle(Element request, Map context) throws ServiceException { ZimbraSoapContext zsc = getZimbraSoapContext(context); - + Server localServer = Provisioning.getInstance().getLocalServer(); checkRight(zsc, context, localServer, Admin.R_manageAccountLogger); - + // Look up account Account account = getAccountFromLoggerRequest(request); - + Element eLogger = request.getElement(AdminConstants.E_LOGGER); String category = eLogger.getAttribute(AdminConstants.A_CATEGORY); String sLevel = eLogger.getAttribute(AdminConstants.A_LEVEL); - + // Handle level. Level level = null; try { @@ -71,7 +71,7 @@ public Element handle(Element request, Map context) sLevel, StringUtil.join(",", Level.values())); throw ServiceException.INVALID_REQUEST(error, null); } - + // Handle category. Collection loggers; if (category.equalsIgnoreCase(CATEGORY_ALL)) { @@ -93,20 +93,20 @@ public Element handle(Element request, Map context) .addAttribute(AdminConstants.A_CATEGORY, log.getCategory()) .addAttribute(AdminConstants.A_LEVEL, level.name()); } - + return response; } - + /** * Returns the Account object based on the <id> or <account> - * element owned by the given request element. + * element owned by the given request element. */ static Account getAccountFromLoggerRequest(Element request) throws ServiceException { Account account = null; Provisioning prov = Provisioning.getInstance(); Element idElement = request.getOptionalElement(AdminConstants.E_ID); - + if (idElement != null) { // Handle deprecated element. ZimbraLog.soap.info("The <%s> element is deprecated for <%s>. Use <%s> instead.", @@ -127,7 +127,7 @@ static Account getAccountFromLoggerRequest(Element request) } return account; } - + @Override public void docRights(List relatedRights, List notes) { relatedRights.add(Admin.R_manageAccountLogger); From 27d16f9b5906c8085e4a6f9234e6338a9700f272 Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Thu, 14 Sep 2017 11:06:52 -0500 Subject: [PATCH 052/142] ZCS-2537 use explicit imports --- store/src/java/com/zimbra/cs/imap/ImapHandler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/store/src/java/com/zimbra/cs/imap/ImapHandler.java b/store/src/java/com/zimbra/cs/imap/ImapHandler.java index 115aaaa7764..e4a832523b9 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapHandler.java +++ b/store/src/java/com/zimbra/cs/imap/ImapHandler.java @@ -79,6 +79,8 @@ import com.zimbra.common.util.AccessBoundedRegex; import com.zimbra.common.util.Constants; import com.zimbra.common.util.DateUtil; +import com.zimbra.common.util.Log; +import com.zimbra.common.util.LogFactory; import com.zimbra.common.util.Pair; import com.zimbra.common.util.StringUtil; import com.zimbra.common.util.ZimbraLog; From 1cc997dac533c521917dc2d83230efc2586f47cb Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Mon, 11 Sep 2017 18:57:22 -0500 Subject: [PATCH 053/142] ZCS-2537 change return type of getPreferredIMAPServers --- .../java/com/zimbra/cs/account/Provisioning.java | 13 ++++++++++--- store/src/java/com/zimbra/cs/imap/ImapHandler.java | 10 +++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/store/src/java/com/zimbra/cs/account/Provisioning.java b/store/src/java/com/zimbra/cs/account/Provisioning.java index c8f2bba114b..0bd8e08be1f 100644 --- a/store/src/java/com/zimbra/cs/account/Provisioning.java +++ b/store/src/java/com/zimbra/cs/account/Provisioning.java @@ -1514,17 +1514,24 @@ public static boolean canUseLocalIMAP(Account account) throws ServiceException { } } - public static List getPreferredIMAPServers(Account account) throws ServiceException { + public static List getPreferredIMAPServers(Account account) throws ServiceException { + Provisioning prov = getInstance(); + Server homeServer = account.getServer(); if(homeServer == null) { return Collections.emptyList(); } String[] upstreamIMAPServers = homeServer.getReverseProxyUpstreamImapServers(); + List imapServers = new ArrayList(); if(upstreamIMAPServers != null && upstreamIMAPServers.length > 0) { - return Arrays.asList(upstreamIMAPServers); + for (String server: upstreamIMAPServers) { + imapServers.add(prov.getServerByServiceHostname(server)); + } } else { - return Arrays.asList(account.getMailHost()); + imapServers.add(prov.getServerByServiceHostname(account.getMailHost())); } + + return imapServers; } public static List getIMAPDaemonServersForLocalServer() throws ServiceException { diff --git a/store/src/java/com/zimbra/cs/imap/ImapHandler.java b/store/src/java/com/zimbra/cs/imap/ImapHandler.java index e4a832523b9..1e3817c58fa 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapHandler.java +++ b/store/src/java/com/zimbra/cs/imap/ImapHandler.java @@ -1667,12 +1667,16 @@ private ImapCredentials startSession(Account account, EnabledHack hack, String t } if(!Provisioning.canUseLocalIMAP(account) && !ZimbraAuthenticator.MECHANISM.equals(mechanism)) { - List preferredServers = Provisioning.getPreferredIMAPServers(account); - ZimbraLog.imap.info("%s failed; mechanism: %s. Should be contacting one of these hosts: %s ", command, mechanism, String.join(", ", preferredServers)); + List preferredServers = Provisioning.getPreferredIMAPServers(account); + List preferredServerHostnames = new ArrayList(); + for (Server server: preferredServers){ + preferredServerHostnames.add(server.getServiceHostname()); + } + ZimbraLog.imap.info("%s failed; mechanism: %s. Should be contacting one of these hosts: %s ", command, mechanism, String.join(", ", preferredServerHostnames)); if (!extensionEnabled("LOGIN_REFERRALS") || preferredServers.isEmpty()) { sendNO(tag, "%s failed (wrong host)", command); } else { - sendNO(tag, "[REFERRAL imap://%s@%s/] %s failed", URLEncoder.encode(account.getName(), "utf-8"), preferredServers.get(0), command); + sendNO(tag, "[REFERRAL imap://%s@%s/] %s failed", URLEncoder.encode(account.getName(), "utf-8"), preferredServers.get(0).getServiceHostname(), command); } return null; } From d48589a1344e170ad17c8bd6ff3a734f64051571 Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Mon, 11 Sep 2017 18:59:17 -0500 Subject: [PATCH 054/142] ZCS-2537 create ZIMBRA_ADD_ACCOUNT_LOGGER CAtom --- store/src/java/com/zimbra/cs/mailclient/imap/CAtom.java | 1 + 1 file changed, 1 insertion(+) diff --git a/store/src/java/com/zimbra/cs/mailclient/imap/CAtom.java b/store/src/java/com/zimbra/cs/mailclient/imap/CAtom.java index 9c1f9a38083..d6ea609d0df 100644 --- a/store/src/java/com/zimbra/cs/mailclient/imap/CAtom.java +++ b/store/src/java/com/zimbra/cs/mailclient/imap/CAtom.java @@ -43,6 +43,7 @@ UNSUBSCRIBE, APPEND, CATENATE, URL, F_ANSWERED("\\Answered"), F_NOSELECT("\\Noselect"), F_MARKED("\\Marked"), F_UNMARKED("\\Unmarked"), F_STAR("\\*"), UNKNOWN(""), /* zimbra-specific commands */ + ZIMBRA_ADD_ACCOUNT_LOGGER("X-ZIMBRA-ADD-ACCOUNT-LOGGER"), ZIMBRA_FLUSHCACHE("X-ZIMBRA-FLUSHCACHE"), ZIMBRA_RELOADLC("X-ZIMBRA-RELOADLC"); private final Atom atom; From 18d7674d3959b65c4672d2a4641fe90446ddd80e Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Thu, 14 Sep 2017 11:42:14 -0500 Subject: [PATCH 055/142] ZCS-2537 refactor account logger into handler + response --- .../cs/service/admin/AddAccountLogger.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java index 24fa6b5c156..1874e586ef9 100644 --- a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java +++ b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java @@ -68,33 +68,43 @@ public Element handle(Element request, Map context) level = Level.valueOf(sLevel.toLowerCase()); } catch (IllegalArgumentException e) { String error = String.format("Invalid level: %s. Valid values are %s.", - sLevel, StringUtil.join(",", Level.values())); + sLevel, StringUtil.join(",", Level.values())); throw ServiceException.INVALID_REQUEST(error, null); } + if (!category.equalsIgnoreCase(CATEGORY_ALL) && !LogFactory.logExists(category)) { + throw ServiceException.INVALID_REQUEST("Log category " + category + " does not exist.", null); + } + + Collection loggers = addAccountLogger(account, category, level); + + // Build response. + Element response = zsc.createElement(AdminConstants.ADD_ACCOUNT_LOGGER_RESPONSE); + for (Log log : loggers) { + response.addElement(AdminConstants.E_LOGGER) + .addAttribute(AdminConstants.A_CATEGORY, log.getCategory()) + .addAttribute(AdminConstants.A_LEVEL, level.name()); + } + + return response; + } + + public static Collection addAccountLogger(Account account, String category, Level level) { // Handle category. Collection loggers; if (category.equalsIgnoreCase(CATEGORY_ALL)) { loggers = LogFactory.getAllLoggers(); } else { - if (!LogFactory.logExists(category)) { - throw ServiceException.INVALID_REQUEST("Log category " + category + " does not exist.", null); - } loggers = Arrays.asList(LogFactory.getLog(category)); } - // Add custom loggers. - Element response = zsc.createElement(AdminConstants.ADD_ACCOUNT_LOGGER_RESPONSE); for (Log log : loggers) { ZimbraLog.misc.info("Adding custom logger: account=%s, category=%s, level=%s", - account.getName(), category, level); + account.getName(), category, level); log.addAccountLogger(account.getName(), level); - response.addElement(AdminConstants.E_LOGGER) - .addAttribute(AdminConstants.A_CATEGORY, log.getCategory()) - .addAttribute(AdminConstants.A_LEVEL, level.name()); - } + } - return response; + return loggers; } /** From 3f2e26f33e34803ccedc468e4a077d9bc79c896b Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Mon, 11 Sep 2017 19:00:01 -0500 Subject: [PATCH 056/142] ZCS-2537 implement ImapConnection.addAccountLogger --- .../java/com/zimbra/cs/mailclient/imap/ImapConnection.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/store/src/java/com/zimbra/cs/mailclient/imap/ImapConnection.java b/store/src/java/com/zimbra/cs/mailclient/imap/ImapConnection.java index af4d21fedac..7fc97a55f98 100644 --- a/store/src/java/com/zimbra/cs/mailclient/imap/ImapConnection.java +++ b/store/src/java/com/zimbra/cs/mailclient/imap/ImapConnection.java @@ -743,6 +743,11 @@ public String toString() { config.getHost(), config.getPort(), config.getSecurity(), state, mailbox == null ? "null" : mailbox.getName()); } + public void addAccountLogger(Account account, String category, String level) throws IOException { + ImapRequest req = newRequest(CAtom.ZIMBRA_ADD_ACCOUNT_LOGGER, account.getName(), category, level); + req.sendCheckStatus(); + } + public void flushCache(String cacheTypes) throws IOException { Object[] typeParams = new Object[] { cacheTypes.split(",") }; ImapRequest req = newRequest(CAtom.ZIMBRA_FLUSHCACHE, typeParams); From a1f3adbe72d602b54cbf6fce2ae9f824200a7f45 Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Mon, 11 Sep 2017 19:04:08 -0500 Subject: [PATCH 057/142] ZCS-2537 implement X-ZIMBRA-ADD-ACCOUNT-LOGGER handler --- .../java/com/zimbra/cs/imap/ImapHandler.java | 52 +++++++++++++++++++ .../cs/service/admin/AddAccountLogger.java | 2 + 2 files changed, 54 insertions(+) diff --git a/store/src/java/com/zimbra/cs/imap/ImapHandler.java b/store/src/java/com/zimbra/cs/imap/ImapHandler.java index 1e3817c58fa..9006ed0493b 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapHandler.java +++ b/store/src/java/com/zimbra/cs/imap/ImapHandler.java @@ -46,6 +46,7 @@ import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; +import com.zimbra.cs.service.admin.AddAccountLogger; import org.dom4j.DocumentException; import com.google.common.base.Charsets; @@ -991,6 +992,15 @@ protected boolean executeRequest(ImapRequest req) throws IOException, ImapExcept } else if (command.equals("X-ZIMBRA-RELOADLC")) { checkEOF(tag, req); return doRELOADLC(tag); + } else if (command.equals("X-ZIMBRA-ADD-ACCOUNT-LOGGER")) { + req.skipSpace(); + String accountString = req.readAstring(); + req.skipSpace(); + String category = req.readAstring(); + req.skipSpace(); + String level = req.readAstring(); + checkEOF(tag, req); + return doADDACCOUNTLOGGER(tag, accountString, category, level); } break; } @@ -1487,6 +1497,48 @@ private boolean checkZimbraAdminAuth() { } + private boolean doADDACCOUNTLOGGER(String tag, String id, String category, String sLevel) throws IOException { + ZimbraLog.imap.info("Adding account level logger for '%s' category: %s level %s", id, category, sLevel); + + if (!checkState(tag, State.AUTHENTICATED)) { + return true; + } else if (!checkZimbraAdminAuth()) { + sendNO(tag, "must be authenticated as admin with X-ZIMBRA auth mechanism"); + return true; + } + + try { + Account account = Provisioning.getInstance().get(AccountBy.name, id); + if (account == null || !account.isAccountStatusActive()) { + ZimbraLog.imap.warn("target account missing or not active; dropping connection"); + sendNO(tag, "must specify an actual account"); + return true; + } + + // Handle level. + Log.Level level = null; + try { + level = Log.Level.valueOf(sLevel.toLowerCase()); + } catch (IllegalArgumentException e) { + String error = String.format("Invalid level: %s. Valid values are %s.", + sLevel, StringUtil.join(",", Log.Level.values())); + ZimbraLog.imap.warn(error); + sendNO(tag, "FATAL: " + error); + return true; + } + + AddAccountLogger.addAccountLogger(account, category, level); + + } catch (ServiceException e) { + ZimbraLog.imap.warn("error checking target account status; dropping connection", e); + sendNO(tag, "must specify an actual account"); + return false; + } + + sendOK(tag, "ADDACCOUNTLOGGER completed"); + return true; + } + private boolean doFLUSHCACHE(String tag, List types, List entries) throws IOException { if (!checkState(tag, State.AUTHENTICATED)) { diff --git a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java index 1874e586ef9..2e9ac63fe14 100644 --- a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java +++ b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java @@ -32,6 +32,8 @@ import com.zimbra.cs.account.Account; import com.zimbra.cs.account.AccountServiceException; import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.account.Server; +import com.zimbra.cs.service.AuthProvider; import com.zimbra.common.account.Key.AccountBy; import com.zimbra.cs.account.Server; import com.zimbra.cs.account.accesscontrol.AdminRight; From 3d5af4c7979236440afa262bd5fb84987fce4dbc Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Mon, 11 Sep 2017 19:13:28 -0500 Subject: [PATCH 058/142] ZCS-2537 notify remote imapd of account level logging requests --- .../cs/service/admin/AddAccountLogger.java | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java index 2e9ac63fe14..752ca58b077 100644 --- a/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java +++ b/store/src/java/com/zimbra/cs/service/admin/AddAccountLogger.java @@ -16,11 +16,13 @@ */ package com.zimbra.cs.service.admin; +import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import com.zimbra.common.localconfig.LC; import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.AdminConstants; import com.zimbra.common.soap.Element; @@ -35,9 +37,9 @@ import com.zimbra.cs.account.Server; import com.zimbra.cs.service.AuthProvider; import com.zimbra.common.account.Key.AccountBy; -import com.zimbra.cs.account.Server; import com.zimbra.cs.account.accesscontrol.AdminRight; import com.zimbra.cs.account.accesscontrol.Rights.Admin; +import com.zimbra.cs.mailclient.imap.ImapConnection; import com.zimbra.soap.ZimbraSoapContext; /** @@ -80,6 +82,8 @@ public Element handle(Element request, Map context) Collection loggers = addAccountLogger(account, category, level); + addAccountLoggerOnImapServers(account, category, sLevel); + // Build response. Element response = zsc.createElement(AdminConstants.ADD_ACCOUNT_LOGGER_RESPONSE); for (Log log : loggers) { @@ -109,6 +113,39 @@ public static Collection addAccountLogger(Account account, String category, return loggers; } + public static void addAccountLoggerOnImapServers(Account account, String category, String level) { + List imapServers; + try { + imapServers = Provisioning.getPreferredIMAPServers(account); + } catch (ServiceException e) { + ZimbraLog.imap.warn("unable to fetch list of imapd servers", e); + return; + } + for (Server server: imapServers) { + addAccountLoggerOnImapServer(server, account, category, level); + } + } + + public static void addAccountLoggerOnImapServer(Server server, Account account, String category, String level) + { + ImapConnection connection = null; + try { + connection = ImapConnection.getZimbraConnection(server, LC.zimbra_ldap_user.value(), AuthProvider.getAdminAuthToken()); + } catch (ServiceException e) { + ZimbraLog.imap.warn("unable to connect to imapd server '%s' to issue X-ZIMBRA-ADD-ACCOUNT-LOGGER request", server.getServiceHostname(), e); + return; + } + try { + ZimbraLog.imap.debug("issuing X-ZIMBRA-ADD-ACCOUNT-LOGGER request to imapd server '%s' for account '%s'", server.getServiceHostname(), account.getName()); + connection.addAccountLogger(account, category, level); + } catch (IOException e) + { + ZimbraLog.imap.warn("failed to enable account level logging for account '%s' on server '%s'", account.getName(), server.getServiceHostname(), e); + } finally { + connection.close(); + } + } + /** * Returns the Account object based on the <id> or <account> * element owned by the given request element. From af9388afc3f314a084dc4fdadd8b60637d995667 Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Wed, 13 Sep 2017 14:40:57 -0500 Subject: [PATCH 059/142] ZCS-2537 RunUnitTestsRequest test for AddAccountLogger --- .../qa/unittest/TestImapViaImapDaemon.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java b/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java index 84c71f3e5e7..3fc141a74fe 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java +++ b/store/src/java/com/zimbra/qa/unittest/TestImapViaImapDaemon.java @@ -98,6 +98,36 @@ public void testClearDaemonCacheWrongAuthenticator() throws Exception { } } + @Test + public void testAddAccountLoggerWrongAuthenticator() throws Exception { + connection = connect(); + Account account = TestUtil.getAccount(USER); + try { + connection.addAccountLogger(account, "zimbra.imap", "trace"); + fail("should not be able to add an account logger without authenticating"); + } catch (CommandFailedException cfe) { + assertEquals("must be in AUTHENTICATED or SELECTED state", cfe.getError()); + } + connection.login(PASS); + try { + connection.addAccountLogger(account, "zimbra.imap", "trace"); + fail("should not be able to add an account logger without using X-ZIMBRA auth mechanism"); + } catch (CommandFailedException cfe) { + assertEquals("must be authenticated as admin with X-ZIMBRA auth mechanism", cfe.getError()); + } + } + + @Test + public void testAddAccountLogger() throws Exception { + connection = getAdminConnection(); + Account account = TestUtil.getAccount(USER); + try { + connection.addAccountLogger(account, "zimbra.imap", "trace"); + } catch (CommandFailedException cfe) { + fail("Couldn't add an account logger - " + cfe.getMessage()); + } + } + private void tryConnect(boolean shouldSucceed, String message) throws Exception { try { connection = connect(USER); From 1d46f7f4062db478295c9382e872a45d44680eda Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Fri, 8 Sep 2017 16:35:14 -0700 Subject: [PATCH 060/142] update to JUnit4 --- .../unittest/server/TestDataSourceServer.java | 86 ++++++------------- 1 file changed, 28 insertions(+), 58 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index 6927537a617..de504924252 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -16,13 +16,18 @@ */ package com.zimbra.qa.unittest.server; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; import com.zimbra.client.ZFolder; import com.zimbra.client.ZImapDataSource; import com.zimbra.client.ZMailbox; -import com.zimbra.cs.account.Account; -import com.zimbra.cs.account.Cos; import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.account.Server; import com.zimbra.cs.datasource.DataSourceManager; @@ -31,55 +36,32 @@ import com.zimbra.cs.mailbox.ScheduledTask; import com.zimbra.qa.unittest.TestUtil; import com.zimbra.soap.type.DataSource.ConnectionType; +public class TestDataSourceServer { -public class TestDataSourceServer extends TestCase { + @Rule + public TestName testInfo = new TestName(); - private static final String USER_NAME = "user1"; - private static final String TEST_USER_NAME = "testdatasource"; - private static final String NAME_PREFIX = TestDataSourceServer.class.getSimpleName(); - - private String mOriginalAccountPollingInterval; - private String mOriginalAccountPop3PollingInterval; - private String mOriginalAccountImapPollingInterval; - - private String mOriginalCosPollingInterval; - private String mOriginalCosPop3PollingInterval; - private String mOriginalCosImapPollingInterval; + protected static String USER_NAME = null; + protected String testId; - public void setUp() - throws Exception { + @Before + public void setUp() throws Exception { + testId = String.format("%s-%s-%d", this.getClass().getSimpleName(), testInfo.getMethodName(), (int)Math.abs(Math.random()*100)); + USER_NAME = String.format("%s-user", testId).toLowerCase(); cleanUp(); - - // Remember original polling intervals. - Account account = TestUtil.getAccount(USER_NAME); - Cos cos = account.getCOS(); - mOriginalAccountPollingInterval = account.getAttr(Provisioning.A_zimbraDataSourcePollingInterval, false); - if (mOriginalAccountPollingInterval == null) { - mOriginalAccountPollingInterval = ""; - } - mOriginalAccountPop3PollingInterval = account.getAttr(Provisioning.A_zimbraDataSourcePop3PollingInterval, false); - if (mOriginalAccountPop3PollingInterval == null) { - mOriginalAccountPop3PollingInterval = ""; - } - mOriginalAccountImapPollingInterval = account.getAttr(Provisioning.A_zimbraDataSourceImapPollingInterval, false); - if (mOriginalAccountImapPollingInterval == null) { - mOriginalAccountImapPollingInterval = ""; - } - - mOriginalCosPollingInterval = cos.getAttr(Provisioning.A_zimbraDataSourcePollingInterval, ""); - mOriginalCosPop3PollingInterval = cos.getAttr(Provisioning.A_zimbraDataSourcePop3PollingInterval, ""); - mOriginalCosImapPollingInterval = cos.getAttr(Provisioning.A_zimbraDataSourceImapPollingInterval, ""); + TestUtil.createAccount(USER_NAME); } - + + @Test public void testScheduling() throws Exception { // Create data source. ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); - ZFolder folder = TestUtil.createFolder(zmbox, "/" + NAME_PREFIX + "-testScheduling"); + ZFolder folder = TestUtil.createFolder(zmbox, "/testScheduling"); Provisioning prov = Provisioning.getInstance(); Server server = prov.getLocalServer(); int port = server.getImapBindPort(); - ZImapDataSource zds = new ZImapDataSource(NAME_PREFIX + " testScheduling", true, "localhost", port, + ZImapDataSource zds = new ZImapDataSource("testScheduling", true, "localhost", port, "user2", "test123", folder.getId(), ConnectionType.cleartext); String dsId = zmbox.createDataSource(zds); @@ -122,26 +104,14 @@ private void checkSchedule(Mailbox mbox, String dataSourceId, Integer intervalMi } } - public void tearDown() - throws Exception { - // Reset original polling intervals. - Account account = TestUtil.getAccount(USER_NAME); - Cos cos = account.getCOS(); - - account.setDataSourcePollingInterval(mOriginalAccountPollingInterval); - account.setDataSourcePop3PollingInterval(mOriginalAccountPop3PollingInterval); - account.setDataSourceImapPollingInterval(mOriginalAccountImapPollingInterval); - - cos.setDataSourcePollingInterval(mOriginalCosPollingInterval); - cos.setDataSourcePop3PollingInterval(mOriginalCosPop3PollingInterval); - cos.setDataSourceImapPollingInterval(mOriginalCosImapPollingInterval); - + @After + public void tearDown() throws Exception { cleanUp(); } - public void cleanUp() - throws Exception { - TestUtil.deleteAccount(TEST_USER_NAME); - TestUtil.deleteTestData(USER_NAME, NAME_PREFIX); + private void cleanUp() throws Exception { + if (USER_NAME != null) { + TestUtil.deleteAccountIfExists(USER_NAME); + } } } From 881480adbf6763930e7b5dc6e09f43ebef474062 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 11 Sep 2017 20:07:38 +0000 Subject: [PATCH 061/142] add ability to run single test with the same environment as test-all --- build-common.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build-common.xml b/build-common.xml index abab979b12c..72166127db0 100644 --- a/build-common.xml +++ b/build-common.xml @@ -434,7 +434,10 @@ - + + + + From d3b9f4e40121195d614f2fd84e6f06dfa81bf319 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 11 Sep 2017 20:09:03 +0000 Subject: [PATCH 062/142] add support for a generic datasource --- .../com/zimbra/client/ZCalDataSource.java | 2 +- .../java/com/zimbra/client/ZDataSource.java | 48 ++++++++++++++++--- .../com/zimbra/client/ZGetInfoResult.java | 2 + .../com/zimbra/client/ZImapDataSource.java | 2 +- .../com/zimbra/client/ZPop3DataSource.java | 2 +- .../com/zimbra/client/ZRssDataSource.java | 7 ++- .../soap/account/message/GetInfoResponse.java | 1 + .../com/zimbra/soap/type/DataSources.java | 5 ++ 8 files changed, 57 insertions(+), 12 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZCalDataSource.java b/client/src/java/com/zimbra/client/ZCalDataSource.java index 40571f7f769..2eb3f38e0e3 100644 --- a/client/src/java/com/zimbra/client/ZCalDataSource.java +++ b/client/src/java/com/zimbra/client/ZCalDataSource.java @@ -25,7 +25,7 @@ import com.zimbra.soap.type.CalDataSource; import com.zimbra.soap.type.DataSources; -public class ZCalDataSource implements ZDataSource, ToZJSONObject { +public class ZCalDataSource extends ZDataSource implements ToZJSONObject { private CalDataSource data; diff --git a/client/src/java/com/zimbra/client/ZDataSource.java b/client/src/java/com/zimbra/client/ZDataSource.java index 86e4da2c0df..d4dee330cd0 100644 --- a/client/src/java/com/zimbra/client/ZDataSource.java +++ b/client/src/java/com/zimbra/client/ZDataSource.java @@ -17,15 +17,49 @@ package com.zimbra.client; -import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.MailConstants; +import com.zimbra.soap.admin.type.DataSourceType; +import com.zimbra.soap.type.DataSource; +import com.zimbra.soap.type.DataSources; + +public class ZDataSource { + private DataSource data; -public interface ZDataSource { + public ZDataSource() { + } + + public ZDataSource(DataSource data) { + this.data = DataSources.newDataSource(data); + } - public Element toElement(Element parent); - public Element toIdElement(Element parent); + public Element toElement(Element parent) { + Element src = parent.addNonUniqueElement(MailConstants.E_DS); + src.addAttribute(MailConstants.A_ID, data.getId()); + src.addAttribute(MailConstants.A_NAME, data.getName()); + src.addAttribute(MailConstants.A_DS_IS_ENABLED, data.isEnabled()); + src.addAttribute(MailConstants.A_DS_HOST, data.getHost()); + src.addAttribute(MailConstants.A_DS_PORT, data.getPort()); + src.addAttribute(MailConstants.A_DS_USERNAME, data.getUsername()); + src.addAttribute(MailConstants.A_DS_PASSWORD, data.getPassword()); + src.addAttribute(MailConstants.A_FOLDER, data.getFolderId()); + src.addAttribute(MailConstants.A_DS_CONNECTION_TYPE, data.getConnectionType().name()); + return src; + } + + public Element toIdElement(Element parent) { + Element src = parent.addElement(MailConstants.E_DS); + src.addAttribute(MailConstants.A_ID, getId()); + return src; + } - public DataSourceType getType(); - public String getName(); - public String getId(); + public DataSourceType getType() { + return DataSourceType.custom; + } + public String getName() { + return data.getName(); + } + public String getId() { + return data.getId(); + } } diff --git a/client/src/java/com/zimbra/client/ZGetInfoResult.java b/client/src/java/com/zimbra/client/ZGetInfoResult.java index 342e1b932ee..9d2f71963b7 100644 --- a/client/src/java/com/zimbra/client/ZGetInfoResult.java +++ b/client/src/java/com/zimbra/client/ZGetInfoResult.java @@ -106,6 +106,8 @@ public List getDataSources() { newList.add(new ZCalDataSource((CalDataSource) ds)); } else if (ds instanceof RssDataSource) { newList.add(new ZRssDataSource((RssDataSource) ds)); + } else { + newList.add(new ZDataSource(ds)); } } return newList; diff --git a/client/src/java/com/zimbra/client/ZImapDataSource.java b/client/src/java/com/zimbra/client/ZImapDataSource.java index 2c32dd3ca12..1ef08d8df99 100644 --- a/client/src/java/com/zimbra/client/ZImapDataSource.java +++ b/client/src/java/com/zimbra/client/ZImapDataSource.java @@ -27,7 +27,7 @@ import com.zimbra.soap.type.DataSources; import com.zimbra.soap.type.ImapDataSource; -public class ZImapDataSource implements ZDataSource, ToZJSONObject { +public class ZImapDataSource extends ZDataSource implements ToZJSONObject { private ImapDataSource data; diff --git a/client/src/java/com/zimbra/client/ZPop3DataSource.java b/client/src/java/com/zimbra/client/ZPop3DataSource.java index 0201926639a..54a25cdfcca 100644 --- a/client/src/java/com/zimbra/client/ZPop3DataSource.java +++ b/client/src/java/com/zimbra/client/ZPop3DataSource.java @@ -29,7 +29,7 @@ import com.zimbra.soap.type.DataSources; import com.zimbra.soap.type.Pop3DataSource; -public class ZPop3DataSource implements ZDataSource, ToZJSONObject { +public class ZPop3DataSource extends ZDataSource implements ToZJSONObject { private Pop3DataSource data; diff --git a/client/src/java/com/zimbra/client/ZRssDataSource.java b/client/src/java/com/zimbra/client/ZRssDataSource.java index 0ee008d2009..86c8e4c26d9 100644 --- a/client/src/java/com/zimbra/client/ZRssDataSource.java +++ b/client/src/java/com/zimbra/client/ZRssDataSource.java @@ -26,7 +26,7 @@ import com.zimbra.soap.type.RssDataSource; -public class ZRssDataSource implements ZDataSource, ToZJSONObject { +public class ZRssDataSource extends ZDataSource implements ToZJSONObject { private RssDataSource data; @@ -40,15 +40,18 @@ public ZRssDataSource(String name, String folderId, boolean enabled) { public ZRssDataSource(RssDataSource data) { this.data = DataSources.newRssDataSource(data); } - + + @Override public String getId() { return data.getId(); } + @Override public String getName() { return data.getName(); } + @Override public DataSourceType getType() { return DataSourceType.rss; } diff --git a/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java b/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java index 7d8cb598da3..ea9100be129 100644 --- a/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java +++ b/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java @@ -249,6 +249,7 @@ public final class GetInfoResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=AccountRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=AccountGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=AccountCalDataSource.class), + @XmlElement(name=MailConstants.E_DS /* dsrc */, type=AccountDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=AccountUnknownDataSource.class) }) private List dataSources = Lists.newArrayList(); diff --git a/soap/src/java/com/zimbra/soap/type/DataSources.java b/soap/src/java/com/zimbra/soap/type/DataSources.java index 45983ef5990..48da8260975 100644 --- a/soap/src/java/com/zimbra/soap/type/DataSources.java +++ b/soap/src/java/com/zimbra/soap/type/DataSources.java @@ -18,12 +18,17 @@ package com.zimbra.soap.type; import com.zimbra.soap.account.type.AccountCalDataSource; +import com.zimbra.soap.account.type.AccountDataSource; import com.zimbra.soap.account.type.AccountImapDataSource; import com.zimbra.soap.account.type.AccountPop3DataSource; import com.zimbra.soap.account.type.AccountRssDataSource; public class DataSources { + public static DataSource newDataSource(DataSource data) { + return new AccountDataSource(data); + } + public static Pop3DataSource newPop3DataSource() { return new AccountPop3DataSource(); } From a3b35fab31c268e3f525057f9677b7cdf1fa29e2 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 11 Sep 2017 20:10:49 +0000 Subject: [PATCH 063/142] add test for custom DS class --- .../com/zimbra/cs/datasource/DataSourceManagerTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java index 0ca62fde8a6..3834617a59b 100644 --- a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java +++ b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java @@ -60,8 +60,6 @@ public class DataSourceManagerTest { @BeforeClass public static void init() throws Exception { MailboxTestUtil.initServer(); - String serverDir = MailboxTestUtil.getZimbraServerDir(""); - FileUtils.copyFileToDirectory(new File(serverDir + "src/java-test/datasource-test.xml"), new File(serverDir + "build/zimbra/conf/datasource.xml"), false); } @Before From d0b07b135d61999e5978e47f6f3bcda5b96eab2a Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 11 Sep 2017 20:11:29 +0000 Subject: [PATCH 064/142] allow creating a custom datasource --- .../com/zimbra/cs/account/ldap/entry/LdapDataSource.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java b/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java index 9fb7c0c8ddd..6b74f49bd3e 100644 --- a/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java +++ b/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java @@ -18,17 +18,16 @@ import java.util.List; -import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.AttributeClass; import com.zimbra.cs.account.DataSource; import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.ldap.IAttributes.CheckBinary; import com.zimbra.cs.ldap.LdapException; import com.zimbra.cs.ldap.ZAttributes; -import com.zimbra.cs.ldap.IAttributes.CheckBinary; -import com.zimbra.cs.ldap.ZSearchResultEntry; +import com.zimbra.soap.admin.type.DataSourceType; /** * @@ -63,6 +62,8 @@ public static String getObjectClass(DataSourceType type) { return AttributeClass.OC_zimbraRssDataSource; case gal: return AttributeClass.OC_zimbraGalDataSource; + case custom: + return AttributeClass.OC_zimbraDataSource; default: return null; } @@ -86,6 +87,8 @@ else if (attr.contains(AttributeClass.OC_zimbraRssDataSource)) return DataSourceType.rss; else if (attr.contains(AttributeClass.OC_zimbraGalDataSource)) return DataSourceType.gal; + else if (attr.contains(AttributeClass.OC_zimbraDataSource)) + return DataSourceType.custom; else throw ServiceException.FAILURE("unable to determine data source type from object class", null); } From 1be876a75bbf9727e90507f4e6a7002cdf0e9700 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 11 Sep 2017 21:53:57 +0000 Subject: [PATCH 065/142] implement creating custom datasource via SOAP --- .../com/zimbra/client/ZCalDataSource.java | 24 +++++++ .../java/com/zimbra/client/ZDataSource.java | 66 +++++++++++++------ .../com/zimbra/client/ZImapDataSource.java | 29 +++++++- .../src/java/com/zimbra/client/ZMailbox.java | 54 ++++++++------- .../com/zimbra/client/ZPop3DataSource.java | 31 ++++++++- .../com/zimbra/client/ZRssDataSource.java | 25 ++++++- .../soap/mail/type/CalDataSourceNameOrId.java | 11 ++++ .../soap/mail/type/DataSourceNameOrId.java | 13 +++- .../mail/type/Pop3DataSourceNameOrId.java | 11 ++++ .../soap/mail/type/RssDataSourceNameOrId.java | 11 ++++ .../com/zimbra/soap/type/DataSources.java | 4 ++ .../unittest/server/TestDataSourceServer.java | 38 +++++++++-- 12 files changed, 264 insertions(+), 53 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZCalDataSource.java b/client/src/java/com/zimbra/client/ZCalDataSource.java index 2eb3f38e0e3..6de4827e736 100644 --- a/client/src/java/com/zimbra/client/ZCalDataSource.java +++ b/client/src/java/com/zimbra/client/ZCalDataSource.java @@ -22,7 +22,13 @@ import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.SystemUtil; +import com.zimbra.soap.mail.type.CalDataSourceNameOrId; +import com.zimbra.soap.mail.type.DataSourceNameOrId; +import com.zimbra.soap.mail.type.ImapDataSourceNameOrId; +import com.zimbra.soap.mail.type.MailCalDataSource; +import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.type.CalDataSource; +import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSources; public class ZCalDataSource extends ZDataSource implements ToZJSONObject { @@ -60,6 +66,7 @@ public boolean isEnabled() { return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); } + @Deprecated public Element toElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_CAL); src.addAttribute(MailConstants.A_ID, data.getId()); @@ -69,12 +76,29 @@ public Element toElement(Element parent) { return src; } + @Deprecated public Element toIdElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_CAL); src.addAttribute(MailConstants.A_ID, getId()); return src; } + @Override + public DataSource toJaxb() { + MailCalDataSource jaxbObject = new MailCalDataSource(); + jaxbObject.setId(data.getId()); + jaxbObject.setName(data.getName()); + jaxbObject.setFolderId(data.getFolderId()); + jaxbObject.setEnabled(data.isEnabled()); + return jaxbObject; + } + + @Override + public DataSourceNameOrId toJaxbNameOrId() { + CalDataSourceNameOrId jaxbObject = CalDataSourceNameOrId.createForId(data.getId()); + return jaxbObject; + } + public ZJSONObject toZJSONObject() throws JSONException { ZJSONObject zjo = new ZJSONObject(); zjo.put("id", data.getId()); diff --git a/client/src/java/com/zimbra/client/ZDataSource.java b/client/src/java/com/zimbra/client/ZDataSource.java index d4dee330cd0..7d95b8b6d2d 100644 --- a/client/src/java/com/zimbra/client/ZDataSource.java +++ b/client/src/java/com/zimbra/client/ZDataSource.java @@ -17,9 +17,11 @@ package com.zimbra.client; -import com.zimbra.common.soap.Element; -import com.zimbra.common.soap.MailConstants; +import java.util.List; + +import com.zimbra.soap.account.type.AccountDataSource; import com.zimbra.soap.admin.type.DataSourceType; +import com.zimbra.soap.mail.type.DataSourceNameOrId; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSources; @@ -29,28 +31,26 @@ public class ZDataSource { public ZDataSource() { } - public ZDataSource(DataSource data) { - this.data = DataSources.newDataSource(data); + public ZDataSource(String name) { + data = DataSources.newDataSource(); + data.setName(name); } - - public Element toElement(Element parent) { - Element src = parent.addNonUniqueElement(MailConstants.E_DS); - src.addAttribute(MailConstants.A_ID, data.getId()); - src.addAttribute(MailConstants.A_NAME, data.getName()); - src.addAttribute(MailConstants.A_DS_IS_ENABLED, data.isEnabled()); - src.addAttribute(MailConstants.A_DS_HOST, data.getHost()); - src.addAttribute(MailConstants.A_DS_PORT, data.getPort()); - src.addAttribute(MailConstants.A_DS_USERNAME, data.getUsername()); - src.addAttribute(MailConstants.A_DS_PASSWORD, data.getPassword()); - src.addAttribute(MailConstants.A_FOLDER, data.getFolderId()); - src.addAttribute(MailConstants.A_DS_CONNECTION_TYPE, data.getConnectionType().name()); - return src; + + public ZDataSource(String name, String importClass) { + data = DataSources.newDataSource(); + data.setImportClass(importClass); + data.setName(name); } - public Element toIdElement(Element parent) { - Element src = parent.addElement(MailConstants.E_DS); - src.addAttribute(MailConstants.A_ID, getId()); - return src; + public ZDataSource(String name, String importClass, Iterable attributes) { + data = DataSources.newDataSource(); + data.setImportClass(importClass); + data.setAttributes(attributes); + data.setName(name); + } + + public ZDataSource(DataSource data) { + this.data = DataSources.newDataSource(data); } public DataSourceType getType() { @@ -62,4 +62,28 @@ public String getName() { public String getId() { return data.getId(); } + public String getImportClass() { + return data.getImportClass(); + } + public List getAttributes() { + return data.getAttributes(); + } + public DataSource toJaxb() { + AccountDataSource jaxbObject = new AccountDataSource(); + jaxbObject.setId(data.getId()); + jaxbObject.setName(data.getName()); + jaxbObject.setHost(data.getHost()); + jaxbObject.setPort(data.getPort()); + jaxbObject.setUsername(data.getUsername()); + jaxbObject.setPassword(data.getPassword()); + jaxbObject.setFolderId(data.getFolderId()); + jaxbObject.setConnectionType(data.getConnectionType()); + jaxbObject.setImportOnly(data.isImportOnly()); + return jaxbObject; + } + + public DataSourceNameOrId toJaxbNameOrId() { + DataSourceNameOrId jaxbObject = DataSourceNameOrId.createForId(data.getId()); + return jaxbObject; + } } diff --git a/client/src/java/com/zimbra/client/ZImapDataSource.java b/client/src/java/com/zimbra/client/ZImapDataSource.java index 1ef08d8df99..f1fdad75a31 100644 --- a/client/src/java/com/zimbra/client/ZImapDataSource.java +++ b/client/src/java/com/zimbra/client/ZImapDataSource.java @@ -18,11 +18,15 @@ import org.json.JSONException; -import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.SystemUtil; +import com.zimbra.soap.admin.type.DataSourceType; +import com.zimbra.soap.mail.type.DataSourceNameOrId; +import com.zimbra.soap.mail.type.ImapDataSourceNameOrId; +import com.zimbra.soap.mail.type.MailImapDataSource; +import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSource.ConnectionType; import com.zimbra.soap.type.DataSources; import com.zimbra.soap.type.ImapDataSource; @@ -63,6 +67,7 @@ public ZImapDataSource(String name, boolean enabled, String host, int port, this(name,enabled,host,port,username,password,folderid,connectionType,false); } + @Deprecated public Element toElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_IMAP); src.addAttribute(MailConstants.A_ID, data.getId()); @@ -84,6 +89,28 @@ public Element toIdElement(Element parent) { return src; } + @Override + public DataSource toJaxb() { + MailImapDataSource jaxbObject = new MailImapDataSource(); + jaxbObject.setId(data.getId()); + jaxbObject.setName(data.getName()); + jaxbObject.setHost(data.getHost()); + jaxbObject.setPort(data.getPort()); + jaxbObject.setUsername(data.getUsername()); + jaxbObject.setPassword(data.getPassword()); + jaxbObject.setFolderId(data.getFolderId()); + jaxbObject.setConnectionType(data.getConnectionType()); + jaxbObject.setImportOnly(data.isImportOnly()); + jaxbObject.setEnabled(data.isEnabled()); + return jaxbObject; + } + + @Override + public DataSourceNameOrId toJaxbNameOrId() { + ImapDataSourceNameOrId jaxbObject = ImapDataSourceNameOrId.createForId(data.getId()); + return jaxbObject; + } + public DataSourceType getType() { return DataSourceType.imap; } public String getId() { return data.getId(); } diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index 069780a7446..18eb048af4d 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -157,12 +157,16 @@ import com.zimbra.soap.account.type.AuthToken; import com.zimbra.soap.account.type.InfoSection; import com.zimbra.soap.base.SpecifyContact; +import com.zimbra.soap.mail.message.ImportDataRequest; import com.zimbra.soap.mail.message.BeginTrackingIMAPRequest; import com.zimbra.soap.mail.message.CheckSpellingRequest; import com.zimbra.soap.mail.message.CheckSpellingResponse; import com.zimbra.soap.mail.message.CreateContactRequest; +import com.zimbra.soap.mail.message.CreateDataSourceRequest; +import com.zimbra.soap.mail.message.CreateDataSourceResponse; import com.zimbra.soap.mail.message.CreateSearchFolderRequest; import com.zimbra.soap.mail.message.CreateSearchFolderResponse; +import com.zimbra.soap.mail.message.DeleteDataSourceRequest; import com.zimbra.soap.mail.message.GetAppointmentRequest; import com.zimbra.soap.mail.message.GetAppointmentResponse; import com.zimbra.soap.mail.message.GetDataSourcesRequest; @@ -188,6 +192,8 @@ import com.zimbra.soap.mail.message.ListIMAPSubscriptionsRequest; import com.zimbra.soap.mail.message.ListIMAPSubscriptionsResponse; import com.zimbra.soap.mail.message.ModifyContactRequest; +import com.zimbra.soap.mail.message.ModifyDataSourceRequest; +import com.zimbra.soap.mail.message.ModifyDataSourceResponse; import com.zimbra.soap.mail.message.ModifyFilterRulesRequest; import com.zimbra.soap.mail.message.ModifyOutgoingFilterRulesRequest; import com.zimbra.soap.mail.message.OpenIMAPFolderRequest; @@ -196,6 +202,8 @@ import com.zimbra.soap.mail.message.RecordIMAPSessionResponse; import com.zimbra.soap.mail.message.ResetRecentMessageCountRequest; import com.zimbra.soap.mail.message.SaveIMAPSubscriptionsRequest; +import com.zimbra.soap.mail.message.TestDataSourceRequest; +import com.zimbra.soap.mail.message.TestDataSourceResponse; import com.zimbra.soap.mail.type.ActionResult; import com.zimbra.soap.mail.type.ActionSelector; import com.zimbra.soap.mail.type.ContactSpec; @@ -4665,9 +4673,11 @@ public void modifyIdentity(ZIdentity identity) throws ServiceException { * @return the new data source id */ public String createDataSource(ZDataSource source) throws ServiceException { - Element req = newRequestElement(MailConstants.CREATE_DATA_SOURCE_REQUEST); - source.toElement(req); - return invoke(req).listElements().get(0).getAttribute(MailConstants.A_ID); + CreateDataSourceRequest req = new CreateDataSourceRequest(); + DataSource jaxbObj = source.toJaxb(); + req.setDataSource(jaxbObj); + CreateDataSourceResponse resp = (CreateDataSourceResponse)invokeJaxb(req); + return resp.getDataSource().getId(); } /** @@ -4676,17 +4686,13 @@ public String createDataSource(ZDataSource source) throws ServiceException { * @return null on success, or the error string on failure */ public String testDataSource(ZDataSource source) throws ServiceException { - Element req = newRequestElement(MailConstants.TEST_DATA_SOURCE_REQUEST); - source.toElement(req); - Element resp = invoke(req); - List children = resp.listElements(); - if (children.size() == 0) { - return MailConstants.TEST_DATA_SOURCE_RESPONSE + " has no child elements"; - } - Element dsEl = children.get(0); - boolean success = dsEl.getAttributeBool(MailConstants.A_DS_SUCCESS, false); - if (!success) { - return resp.getAttribute(MailConstants.A_DS_ERROR, "error"); + TestDataSourceRequest req = new TestDataSourceRequest(); + DataSource jaxbObj = source.toJaxb(); + req.setDataSource(jaxbObj); + TestDataSourceResponse resp = (TestDataSourceResponse)invokeJaxb(req); + boolean success = resp.getSuccess(); + if(!success) { + return resp.getError(); } else { return null; } @@ -4704,6 +4710,8 @@ public List getAllDataSources() throws ServiceException { result.add(new ZCalDataSource((CalDataSource) ds)); } else if (ds instanceof RssDataSource) { result.add(new ZRssDataSource((RssDataSource) ds)); + } else { + result.add(new ZDataSource(ds)); } } return result; @@ -4724,15 +4732,15 @@ public ZDataSource getDataSourceById(String id) throws ServiceException { } public void modifyDataSource(ZDataSource source) throws ServiceException { - Element req = newRequestElement(MailConstants.MODIFY_DATA_SOURCE_REQUEST); - source.toElement(req); - invoke(req); + ModifyDataSourceRequest req = new ModifyDataSourceRequest(); + req.setDataSource(source.toJaxb()); + invokeJaxb(req); } public void deleteDataSource(ZDataSource source) throws ServiceException { - Element req = newRequestElement(MailConstants.DELETE_DATA_SOURCE_REQUEST); - source.toIdElement(req); - invoke(req); + DeleteDataSourceRequest req = new DeleteDataSourceRequest(); + req.addDataSource(source.toJaxbNameOrId()); + invokeJaxb(req); } public ZFilterRules getIncomingFilterRules() throws ServiceException { @@ -4786,11 +4794,11 @@ public void deleteDataSource(Key.DataSourceBy by, String key) throws ServiceExce } public void importData(List sources) throws ServiceException { - Element req = newRequestElement(MailConstants.IMPORT_DATA_REQUEST); + ImportDataRequest req = new ImportDataRequest(); for (ZDataSource src : sources) { - src.toIdElement(req); + req.addDataSource(src.toJaxbNameOrId()); } - invoke(req); + invokeJaxb(req); } public static class ZImportStatus { diff --git a/client/src/java/com/zimbra/client/ZPop3DataSource.java b/client/src/java/com/zimbra/client/ZPop3DataSource.java index 54a25cdfcca..20ec97ac7c4 100644 --- a/client/src/java/com/zimbra/client/ZPop3DataSource.java +++ b/client/src/java/com/zimbra/client/ZPop3DataSource.java @@ -19,12 +19,17 @@ import org.json.JSONException; -import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.SystemUtil; import com.zimbra.common.util.ZimbraLog; import com.zimbra.soap.account.type.AccountPop3DataSource; +import com.zimbra.soap.admin.type.DataSourceType; +import com.zimbra.soap.mail.type.CalDataSourceNameOrId; +import com.zimbra.soap.mail.type.DataSourceNameOrId; +import com.zimbra.soap.mail.type.MailPop3DataSource; +import com.zimbra.soap.mail.type.Pop3DataSourceNameOrId; +import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSource.ConnectionType; import com.zimbra.soap.type.DataSources; import com.zimbra.soap.type.Pop3DataSource; @@ -52,6 +57,7 @@ public ZPop3DataSource(String name, boolean enabled, String host, int port, setLeaveOnServer(leaveOnServer); } + @Deprecated public Element toElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_POP3); src.addAttribute(MailConstants.A_ID, data.getId()); @@ -68,12 +74,35 @@ public Element toElement(Element parent) { return src; } + @Deprecated public Element toIdElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_POP3); src.addAttribute(MailConstants.A_ID, getId()); return src; } + @Override + public DataSource toJaxb() { + MailPop3DataSource jaxbObject = new MailPop3DataSource(); + jaxbObject.setId(data.getId()); + jaxbObject.setName(data.getName()); + jaxbObject.setHost(data.getHost()); + jaxbObject.setPort(data.getPort()); + jaxbObject.setUsername(data.getUsername()); + jaxbObject.setPassword(data.getPassword()); + jaxbObject.setFolderId(data.getFolderId()); + jaxbObject.setConnectionType(data.getConnectionType()); + jaxbObject.setLeaveOnServer(data.isLeaveOnServer()); + jaxbObject.setEnabled(data.isEnabled()); + return jaxbObject; + } + + @Override + public DataSourceNameOrId toJaxbNameOrId() { + Pop3DataSourceNameOrId jaxbObject = Pop3DataSourceNameOrId.createForId(data.getId()); + return jaxbObject; + } + public DataSourceType getType() { return DataSourceType.pop3; } public String getId() { return data.getId(); } diff --git a/client/src/java/com/zimbra/client/ZRssDataSource.java b/client/src/java/com/zimbra/client/ZRssDataSource.java index 86c8e4c26d9..c4a1657b0b2 100644 --- a/client/src/java/com/zimbra/client/ZRssDataSource.java +++ b/client/src/java/com/zimbra/client/ZRssDataSource.java @@ -18,10 +18,15 @@ import org.json.JSONException; -import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.SystemUtil; +import com.zimbra.soap.admin.type.DataSourceType; +import com.zimbra.soap.mail.type.DataSourceNameOrId; +import com.zimbra.soap.mail.type.MailRssDataSource; +import com.zimbra.soap.mail.type.Pop3DataSourceNameOrId; +import com.zimbra.soap.mail.type.RssDataSourceNameOrId; +import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSources; import com.zimbra.soap.type.RssDataSource; @@ -64,6 +69,7 @@ public boolean isEnabled() { return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); } + @Deprecated public Element toElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_RSS); src.addAttribute(MailConstants.A_ID, data.getId()); @@ -73,12 +79,29 @@ public Element toElement(Element parent) { return src; } + @Deprecated public Element toIdElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_RSS); src.addAttribute(MailConstants.A_ID, getId()); return src; } + @Override + public DataSource toJaxb() { + MailRssDataSource jaxbObject = new MailRssDataSource(); + jaxbObject.setId(data.getId()); + jaxbObject.setName(data.getName()); + jaxbObject.setFolderId(data.getFolderId()); + jaxbObject.setEnabled(data.isEnabled()); + return jaxbObject; + } + + @Override + public DataSourceNameOrId toJaxbNameOrId() { + RssDataSourceNameOrId jaxbObject = RssDataSourceNameOrId.createForId(data.getId()); + return jaxbObject; + } + public ZJSONObject toZJSONObject() throws JSONException { ZJSONObject zjo = new ZJSONObject(); zjo.put("id", data.getId()); diff --git a/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceNameOrId.java b/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceNameOrId.java index 783f277d812..a96c4bbe1aa 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceNameOrId.java +++ b/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceNameOrId.java @@ -22,4 +22,15 @@ @XmlAccessorType(XmlAccessType.NONE) public class CalDataSourceNameOrId extends DataSourceNameOrId { + public static CalDataSourceNameOrId createForName(String name) { + CalDataSourceNameOrId obj = new CalDataSourceNameOrId(); + obj.setName(name); + return obj; + } + + public static CalDataSourceNameOrId createForId(String id) { + CalDataSourceNameOrId obj = new CalDataSourceNameOrId(); + obj.setId(id); + return obj; + } } diff --git a/soap/src/java/com/zimbra/soap/mail/type/DataSourceNameOrId.java b/soap/src/java/com/zimbra/soap/mail/type/DataSourceNameOrId.java index 3c450b7ea9f..06754012807 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/DataSourceNameOrId.java +++ b/soap/src/java/com/zimbra/soap/mail/type/DataSourceNameOrId.java @@ -17,6 +17,17 @@ package com.zimbra.soap.mail.type; -abstract public class DataSourceNameOrId +public class DataSourceNameOrId extends NameOrId { + public static DataSourceNameOrId createForName(String name) { + DataSourceNameOrId obj = new DataSourceNameOrId(); + obj.setName(name); + return obj; + } + + public static DataSourceNameOrId createForId(String id) { + DataSourceNameOrId obj = new DataSourceNameOrId(); + obj.setId(id); + return obj; + } } diff --git a/soap/src/java/com/zimbra/soap/mail/type/Pop3DataSourceNameOrId.java b/soap/src/java/com/zimbra/soap/mail/type/Pop3DataSourceNameOrId.java index 673cbf0d3f5..2a42a83d4c9 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/Pop3DataSourceNameOrId.java +++ b/soap/src/java/com/zimbra/soap/mail/type/Pop3DataSourceNameOrId.java @@ -22,4 +22,15 @@ @XmlAccessorType(XmlAccessType.NONE) public class Pop3DataSourceNameOrId extends DataSourceNameOrId { + public static Pop3DataSourceNameOrId createForName(String name) { + Pop3DataSourceNameOrId obj = new Pop3DataSourceNameOrId(); + obj.setName(name); + return obj; + } + + public static Pop3DataSourceNameOrId createForId(String id) { + Pop3DataSourceNameOrId obj = new Pop3DataSourceNameOrId(); + obj.setId(id); + return obj; + } } diff --git a/soap/src/java/com/zimbra/soap/mail/type/RssDataSourceNameOrId.java b/soap/src/java/com/zimbra/soap/mail/type/RssDataSourceNameOrId.java index 145c7a03590..957c123a411 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/RssDataSourceNameOrId.java +++ b/soap/src/java/com/zimbra/soap/mail/type/RssDataSourceNameOrId.java @@ -22,4 +22,15 @@ @XmlAccessorType(XmlAccessType.NONE) public class RssDataSourceNameOrId extends DataSourceNameOrId { + public static RssDataSourceNameOrId createForName(String name) { + RssDataSourceNameOrId obj = new RssDataSourceNameOrId(); + obj.setName(name); + return obj; + } + + public static RssDataSourceNameOrId createForId(String id) { + RssDataSourceNameOrId obj = new RssDataSourceNameOrId(); + obj.setId(id); + return obj; + } } diff --git a/soap/src/java/com/zimbra/soap/type/DataSources.java b/soap/src/java/com/zimbra/soap/type/DataSources.java index 48da8260975..2d6036ec190 100644 --- a/soap/src/java/com/zimbra/soap/type/DataSources.java +++ b/soap/src/java/com/zimbra/soap/type/DataSources.java @@ -29,6 +29,10 @@ public static DataSource newDataSource(DataSource data) { return new AccountDataSource(data); } + public static DataSource newDataSource() { + return new AccountDataSource(); + } + public static Pop3DataSource newPop3DataSource() { return new AccountPop3DataSource(); } diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index de504924252..a56a11964f4 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -16,8 +16,9 @@ */ package com.zimbra.qa.unittest.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; + +import java.util.ArrayList; import org.junit.After; import org.junit.Before; @@ -25,6 +26,7 @@ import org.junit.Test; import org.junit.rules.TestName; +import com.zimbra.client.ZDataSource; import com.zimbra.client.ZFolder; import com.zimbra.client.ZImapDataSource; import com.zimbra.client.ZMailbox; @@ -53,9 +55,35 @@ public void setUp() throws Exception { } @Test - public void testScheduling() - throws Exception { - // Create data source. + public void testCustomDS() throws Exception { + String DSName = "testCustomDS"; + String importClassName = "some.data.source.ClassName"; + ArrayList attrs = new ArrayList(); + String stringAttr = "somestringattr"; + String jsonAttr = "{\"someVar\":\"someValue\"}"; + String colonAttr = "someProp:someVal"; + attrs.add(stringAttr); + attrs.add(jsonAttr); + attrs.add(colonAttr); + ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); + ZDataSource zds = new ZDataSource(DSName, importClassName, attrs); + String dsId = zmbox.createDataSource(zds); + assertNotNull("should get an id for new DataSource", dsId); + assertFalse("DataSource id should not be empty", dsId.isEmpty()); + ZDataSource ds = TestUtil.getDataSource(zmbox, DSName); + assertNotNull("should retrieve a non-null DataSource", ds); + assertEquals("Data source name should be " + DSName, ds.getName(), DSName); + assertNotNull("new DataSource should have an import class", ds.getImportClass()); + assertEquals("expecting import class " + importClassName, importClassName, ds.getImportClass()); + assertNotNull("new DataSource should have attributes", ds.getAttributes()); + assertFalse("new DataSource attributes should not be empty", ds.getAttributes().isEmpty()); + assertTrue("expecting to find attribute with value " + stringAttr, ds.getAttributes().contains(stringAttr)); + assertTrue("expecting to find attribute with value " + jsonAttr, ds.getAttributes().contains(jsonAttr)); + assertTrue("expecting to find attribute with value " + colonAttr, ds.getAttributes().contains(colonAttr)); + } + + @Test + public void testScheduling() throws Exception { ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); ZFolder folder = TestUtil.createFolder(zmbox, "/testScheduling"); Provisioning prov = Provisioning.getInstance(); From 4d1d477f886e5d159683beeb391c8d5697b26d80 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 11 Sep 2017 23:45:58 +0000 Subject: [PATCH 066/142] add oauth refresh token and URL to DS properties even though zimbra-attrs XML says that zimbraDataSourceOAuthRefreshToken and zimbraDataSourceOAuthRefreshTokenUrl are attributes of imapDatasource, th eimplementation in com.zimbra.cs.account.DataSource allows setting these attributes on any DS object --- .../java/com/zimbra/client/ZDataSource.java | 31 ++++++++++++++++++- .../soap/account/type/AccountDataSource.java | 20 ++++++++++++ .../com/zimbra/soap/type/DataSources.java | 4 +-- .../unittest/server/TestDataSourceServer.java | 10 ++++-- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZDataSource.java b/client/src/java/com/zimbra/client/ZDataSource.java index 7d95b8b6d2d..acb1cc60950 100644 --- a/client/src/java/com/zimbra/client/ZDataSource.java +++ b/client/src/java/com/zimbra/client/ZDataSource.java @@ -26,7 +26,7 @@ import com.zimbra.soap.type.DataSources; public class ZDataSource { - private DataSource data; + private AccountDataSource data; public ZDataSource() { } @@ -86,4 +86,33 @@ public DataSourceNameOrId toJaxbNameOrId() { DataSourceNameOrId jaxbObject = DataSourceNameOrId.createForId(data.getId()); return jaxbObject; } + + public ZDataSource setAttributes(Iterable attrs) { + if(data != null) { + data.setAttributes(attrs); + } + return this; + } + + public ZDataSource setRefreshToken(String val) { + if(data != null) { + data.setRefreshToken(val); + } + return this; + } + + public ZDataSource setRefreshTokenURL(String val) { + if(data != null) { + data.setRefreshTokenUrl(val); + } + return this; + } + + public String getRefreshToken() { + return data == null ? null : data.getRefreshToken(); + } + + public String getRefreshTokenUrl() { + return data == null ? null : data.getRefreshTokenUrl(); + } } diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java index 0dec69dbbc7..7b6176de2ab 100644 --- a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java +++ b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java @@ -209,6 +209,19 @@ public class AccountDataSource @XmlElement(name=MailConstants.E_ATTRIBUTE /* a */, required=false) private List attributes = Lists.newArrayList(); + /** + * @zm-api-field-tag data-source-refreshToken + * @zm-api-field-description refresh token for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) + private String refreshToken; + + /** + * @zm-api-field-tag data-source-refreshTokenUrl + * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) + private String refreshTokenUrl; public AccountDataSource() { } @@ -357,6 +370,11 @@ public ConnectionType getConnectionType() { public void setConnectionType(ConnectionType connectionType) { this.adsConnectionType = AdsConnectionType.CT_TO_ACT.apply(connectionType); } + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } + public String getRefreshToken() { return refreshToken; } + + public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } + public String getRefreshTokenUrl() { return refreshTokenUrl; } public Objects.ToStringHelper addToStringInfo( Objects.ToStringHelper helper) { @@ -382,6 +400,8 @@ public Objects.ToStringHelper addToStringInfo( .add("importClass", importClass) .add("failingSince", failingSince) .add("lastError", lastError) + .add("refreshToken", refreshToken) + .add("refreshTokenUrl", refreshTokenUrl) .add("attributes", attributes); } diff --git a/soap/src/java/com/zimbra/soap/type/DataSources.java b/soap/src/java/com/zimbra/soap/type/DataSources.java index 2d6036ec190..34578f7d5e3 100644 --- a/soap/src/java/com/zimbra/soap/type/DataSources.java +++ b/soap/src/java/com/zimbra/soap/type/DataSources.java @@ -25,11 +25,11 @@ public class DataSources { - public static DataSource newDataSource(DataSource data) { + public static AccountDataSource newDataSource(DataSource data) { return new AccountDataSource(data); } - public static DataSource newDataSource() { + public static AccountDataSource newDataSource() { return new AccountDataSource(); } diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index a56a11964f4..c12f1519c95 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -65,8 +65,10 @@ public void testCustomDS() throws Exception { attrs.add(stringAttr); attrs.add(jsonAttr); attrs.add(colonAttr); + String refreshToken = "refresh-token"; + String refreshTokenUrl = "https://this.is.where.you/?refresh=the&token"; ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); - ZDataSource zds = new ZDataSource(DSName, importClassName, attrs); + ZDataSource zds = new ZDataSource(DSName, importClassName, attrs).setRefreshToken(refreshToken).setRefreshTokenURL(refreshTokenUrl); String dsId = zmbox.createDataSource(zds); assertNotNull("should get an id for new DataSource", dsId); assertFalse("DataSource id should not be empty", dsId.isEmpty()); @@ -74,7 +76,11 @@ public void testCustomDS() throws Exception { assertNotNull("should retrieve a non-null DataSource", ds); assertEquals("Data source name should be " + DSName, ds.getName(), DSName); assertNotNull("new DataSource should have an import class", ds.getImportClass()); - assertEquals("expecting import class " + importClassName, importClassName, ds.getImportClass()); + assertEquals("expecting import class: " + importClassName, importClassName, ds.getImportClass()); + assertNotNull("new DataSource should have a refresh token", ds.getRefreshToken()); + assertEquals("expecting refresh token: " + refreshToken, refreshToken, ds.getRefreshToken()); + assertNotNull("new DataSource should have a refresh token URL", ds.getRefreshTokenUrl()); + assertEquals("expecting refresh token URL: " + refreshTokenUrl, refreshTokenUrl, ds.getRefreshTokenUrl()); assertNotNull("new DataSource should have attributes", ds.getAttributes()); assertFalse("new DataSource attributes should not be empty", ds.getAttributes().isEmpty()); assertTrue("expecting to find attribute with value " + stringAttr, ds.getAttributes().contains(stringAttr)); From ce534baa2f160b7e7cb89043e13c8386ececc605 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 12 Sep 2017 00:33:46 +0000 Subject: [PATCH 067/142] remove unused imports --- client/src/java/com/zimbra/client/ZCalDataSource.java | 4 +--- client/src/java/com/zimbra/client/ZMailbox.java | 3 +-- client/src/java/com/zimbra/client/ZRssDataSource.java | 1 - .../com/zimbra/cs/datasource/DataSourceManagerTest.java | 6 +++--- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZCalDataSource.java b/client/src/java/com/zimbra/client/ZCalDataSource.java index 6de4827e736..fa08c57f818 100644 --- a/client/src/java/com/zimbra/client/ZCalDataSource.java +++ b/client/src/java/com/zimbra/client/ZCalDataSource.java @@ -18,15 +18,13 @@ import org.json.JSONException; -import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.SystemUtil; +import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.soap.mail.type.CalDataSourceNameOrId; import com.zimbra.soap.mail.type.DataSourceNameOrId; -import com.zimbra.soap.mail.type.ImapDataSourceNameOrId; import com.zimbra.soap.mail.type.MailCalDataSource; -import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.type.CalDataSource; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSources; diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index 18eb048af4d..857b2685bb9 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -157,7 +157,6 @@ import com.zimbra.soap.account.type.AuthToken; import com.zimbra.soap.account.type.InfoSection; import com.zimbra.soap.base.SpecifyContact; -import com.zimbra.soap.mail.message.ImportDataRequest; import com.zimbra.soap.mail.message.BeginTrackingIMAPRequest; import com.zimbra.soap.mail.message.CheckSpellingRequest; import com.zimbra.soap.mail.message.CheckSpellingResponse; @@ -187,13 +186,13 @@ import com.zimbra.soap.mail.message.IMAPCopyResponse; import com.zimbra.soap.mail.message.ImportContactsRequest; import com.zimbra.soap.mail.message.ImportContactsResponse; +import com.zimbra.soap.mail.message.ImportDataRequest; import com.zimbra.soap.mail.message.ItemActionRequest; import com.zimbra.soap.mail.message.ItemActionResponse; import com.zimbra.soap.mail.message.ListIMAPSubscriptionsRequest; import com.zimbra.soap.mail.message.ListIMAPSubscriptionsResponse; import com.zimbra.soap.mail.message.ModifyContactRequest; import com.zimbra.soap.mail.message.ModifyDataSourceRequest; -import com.zimbra.soap.mail.message.ModifyDataSourceResponse; import com.zimbra.soap.mail.message.ModifyFilterRulesRequest; import com.zimbra.soap.mail.message.ModifyOutgoingFilterRulesRequest; import com.zimbra.soap.mail.message.OpenIMAPFolderRequest; diff --git a/client/src/java/com/zimbra/client/ZRssDataSource.java b/client/src/java/com/zimbra/client/ZRssDataSource.java index c4a1657b0b2..27bcfa8ab55 100644 --- a/client/src/java/com/zimbra/client/ZRssDataSource.java +++ b/client/src/java/com/zimbra/client/ZRssDataSource.java @@ -24,7 +24,6 @@ import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.soap.mail.type.DataSourceNameOrId; import com.zimbra.soap.mail.type.MailRssDataSource; -import com.zimbra.soap.mail.type.Pop3DataSourceNameOrId; import com.zimbra.soap.mail.type.RssDataSourceNameOrId; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSources; diff --git a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java index 3834617a59b..d5591ee0b36 100644 --- a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java +++ b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java @@ -17,13 +17,13 @@ package com.zimbra.cs.datasource; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; -import java.io.File; import java.util.HashMap; import java.util.Map; -import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; From bdbf5fed3167e8c45b5f8b25d5ac2f745a59e86f Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 12 Sep 2017 00:54:10 +0000 Subject: [PATCH 068/142] fix imports --- client/src/java/com/zimbra/client/ZPop3DataSource.java | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/java/com/zimbra/client/ZPop3DataSource.java b/client/src/java/com/zimbra/client/ZPop3DataSource.java index 20ec97ac7c4..7c82f946f85 100644 --- a/client/src/java/com/zimbra/client/ZPop3DataSource.java +++ b/client/src/java/com/zimbra/client/ZPop3DataSource.java @@ -25,7 +25,6 @@ import com.zimbra.common.util.ZimbraLog; import com.zimbra.soap.account.type.AccountPop3DataSource; import com.zimbra.soap.admin.type.DataSourceType; -import com.zimbra.soap.mail.type.CalDataSourceNameOrId; import com.zimbra.soap.mail.type.DataSourceNameOrId; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.Pop3DataSourceNameOrId; From c9481724679661a24cec3d1909db6d9a50b0179b Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 12 Sep 2017 13:29:40 -0700 Subject: [PATCH 069/142] remove tabs --- build-common.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-common.xml b/build-common.xml index 72166127db0..226a7fb6c90 100644 --- a/build-common.xml +++ b/build-common.xml @@ -434,7 +434,7 @@ - + From 59298477c064e3a9fadf24cf20595c2b2fbcd2b2 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 12 Sep 2017 13:30:07 -0700 Subject: [PATCH 070/142] allow creating an empty Jaxb DataSource --- client/src/java/com/zimbra/client/ZDataSource.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/client/src/java/com/zimbra/client/ZDataSource.java b/client/src/java/com/zimbra/client/ZDataSource.java index acb1cc60950..4f6092de974 100644 --- a/client/src/java/com/zimbra/client/ZDataSource.java +++ b/client/src/java/com/zimbra/client/ZDataSource.java @@ -29,6 +29,7 @@ public class ZDataSource { private AccountDataSource data; public ZDataSource() { + data = DataSources.newDataSource(); } public ZDataSource(String name) { @@ -59,12 +60,24 @@ public DataSourceType getType() { public String getName() { return data.getName(); } + public void setName(String name) { + data.setName(name); + } + public void setFolderId(String name) { + data.setFolderId(name); + } public String getId() { return data.getId(); } + public void setId(String id) { + data.setId(id); + } public String getImportClass() { return data.getImportClass(); } + public void setImportClass(String importClass) { + data.setImportClass(importClass); + } public List getAttributes() { return data.getAttributes(); } From 45c0bd207c17110539f0e8a1dbca52bce78ec43c Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 12 Sep 2017 13:30:47 -0700 Subject: [PATCH 071/142] prevent NPEs on accessing jaxb props via ZDataSource --- client/src/java/com/zimbra/client/ZMailbox.java | 2 +- store/src/java/com/zimbra/qa/unittest/TestImapImport.java | 2 +- .../src/java/com/zimbra/qa/unittest/TestImapOneWayImport.java | 2 +- store/src/java/com/zimbra/qa/unittest/TestPop3Import.java | 2 +- store/src/java/com/zimbra/qa/unittest/TestUtil.java | 4 ++-- .../com/zimbra/qa/unittest/server/TestDataSourceServer.java | 3 ++- .../com/zimbra/qa/unittest/server/TestPop3ImportServer.java | 2 +- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index 857b2685bb9..68c5e045626 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -4723,7 +4723,7 @@ public List getAllDataSources() throws ServiceException { */ public ZDataSource getDataSourceById(String id) throws ServiceException { for (ZDataSource ds : getAllDataSources()) { - if (ds.getId().equals(id)) { + if (ds.getId() != null && ds.getId().equals(id)) { return ds; } } diff --git a/store/src/java/com/zimbra/qa/unittest/TestImapImport.java b/store/src/java/com/zimbra/qa/unittest/TestImapImport.java index b752bd39ce4..3aba25604cb 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestImapImport.java +++ b/store/src/java/com/zimbra/qa/unittest/TestImapImport.java @@ -103,7 +103,7 @@ public void setUp() throws Exception { String id = mLocalMbox.createDataSource(mDataSource); mDataSource = null; for (ZDataSource ds : mLocalMbox.getAllDataSources()) { - if (ds.getId().equals(id)) { + if (ds.getId() != null && ds.getId().equals(id)) { mDataSource = ds; } } diff --git a/store/src/java/com/zimbra/qa/unittest/TestImapOneWayImport.java b/store/src/java/com/zimbra/qa/unittest/TestImapOneWayImport.java index 78721e0b9bf..e1432d115d6 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestImapOneWayImport.java +++ b/store/src/java/com/zimbra/qa/unittest/TestImapOneWayImport.java @@ -93,7 +93,7 @@ public void setUp() throws Exception { String id = mLocalMbox.createDataSource(mDataSource); mDataSource = null; for (ZDataSource ds : mLocalMbox.getAllDataSources()) { - if (ds.getId().equals(id)) { + if (ds.getId() != null && ds.getId().equals(id)) { mDataSource = ds; } } diff --git a/store/src/java/com/zimbra/qa/unittest/TestPop3Import.java b/store/src/java/com/zimbra/qa/unittest/TestPop3Import.java index ccb70dab8da..9ed195df02f 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestPop3Import.java +++ b/store/src/java/com/zimbra/qa/unittest/TestPop3Import.java @@ -200,7 +200,7 @@ private ZPop3DataSource getZDataSource() throws Exception { ZMailbox mbox = TestUtil.getZMailbox(USER_NAME); List dataSources = mbox.getAllDataSources(); for (ZDataSource ds : dataSources) { - if (ds.getName().equals(DATA_SOURCE_NAME)) { + if (ds.getName() != null && ds.getName().equals(DATA_SOURCE_NAME)) { return (ZPop3DataSource) ds; } } diff --git a/store/src/java/com/zimbra/qa/unittest/TestUtil.java b/store/src/java/com/zimbra/qa/unittest/TestUtil.java index 1b1a3237655..21f9f9fd980 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestUtil.java +++ b/store/src/java/com/zimbra/qa/unittest/TestUtil.java @@ -783,7 +783,7 @@ public static void deleteTestData(String userName, String subjectSubstring) thro // Delete data sources List dataSources = mbox.getAllDataSources(); for (ZDataSource ds : dataSources) { - if (ds.getName().contains(subjectSubstring)) { + if (ds.getName() != null && ds.getName().contains(subjectSubstring)) { mbox.deleteDataSource(ds); } } @@ -1164,7 +1164,7 @@ public static ZMountpoint createMountpoint(ZMailbox remoteMbox, String remotePat */ public static ZDataSource getDataSource(ZMailbox mbox, String name) throws ServiceException { for (ZDataSource ds : mbox.getAllDataSources()) { - if (ds.getName().equals(name)) { + if (ds.getName() != null && ds.getName().equals(name)) { return ds; } } diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index c12f1519c95..532cb68ff46 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -70,10 +70,11 @@ public void testCustomDS() throws Exception { ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); ZDataSource zds = new ZDataSource(DSName, importClassName, attrs).setRefreshToken(refreshToken).setRefreshTokenURL(refreshTokenUrl); String dsId = zmbox.createDataSource(zds); - assertNotNull("should get an id for new DataSource", dsId); + assertNotNull("DataSource should have an ID", dsId); assertFalse("DataSource id should not be empty", dsId.isEmpty()); ZDataSource ds = TestUtil.getDataSource(zmbox, DSName); assertNotNull("should retrieve a non-null DataSource", ds); + assertNotNull("DataSource should have a name", ds.getName()); assertEquals("Data source name should be " + DSName, ds.getName(), DSName); assertNotNull("new DataSource should have an import class", ds.getImportClass()); assertEquals("expecting import class: " + importClassName, importClassName, ds.getImportClass()); diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestPop3ImportServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestPop3ImportServer.java index d097cc439ae..60ffcc204aa 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestPop3ImportServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestPop3ImportServer.java @@ -191,7 +191,7 @@ private ZPop3DataSource getZDataSource() throws Exception { ZMailbox mbox = TestUtil.getZMailbox(USER_NAME); List dataSources = mbox.getAllDataSources(); for (ZDataSource ds : dataSources) { - if (ds.getName().equals(DATA_SOURCE_NAME)) { + if (ds.getName() != null && ds.getName().equals(DATA_SOURCE_NAME)) { return (ZPop3DataSource) ds; } } From ae4fbbd83a99567df3d0335711b65eb2e112e3ba Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Mon, 18 Sep 2017 12:29:35 +0900 Subject: [PATCH 072/142] ZCS-1858(4):declare extension in "require" command, Part 2 Additional fixes for the following Sieve commands without comparator-i;ascii-numeric. * header test with no match type (implicit :is) * address test with no match type (implicit :is) * envelope test with no match type (implicit :is) * deleteheader * replaceheader * mime_header (Zimbra special) * body (Zimbra special) And "string" test needs to check the "variables" capability in the require list. --- .../com/zimbra/cs/filter/AddressTest.java | 39 ++++- .../com/zimbra/cs/filter/BodyTest.java | 42 ++++- .../zimbra/cs/filter/DeleteHeaderTest.java | 28 +++- .../com/zimbra/cs/filter/EnvelopeTest.java | 45 +++++- .../com/zimbra/cs/filter/HeaderTest.java | 38 +++++ .../com/zimbra/cs/filter/MimeHeaderTest.java | 147 ++++++++++++++++++ .../zimbra/cs/filter/ReplaceHeaderTest.java | 31 +++- .../com/zimbra/cs/filter/SetVariableTest.java | 37 +++++ .../zimbra/cs/filter/jsieve/AddressTest.java | 11 +- .../com/zimbra/cs/filter/jsieve/BodyTest.java | 11 +- .../zimbra/cs/filter/jsieve/DeleteHeader.java | 5 + .../zimbra/cs/filter/jsieve/EnvelopeTest.java | 9 +- .../zimbra/cs/filter/jsieve/HeaderTest.java | 17 +- .../cs/filter/jsieve/MimeHeaderTest.java | 7 +- .../cs/filter/jsieve/ReplaceHeader.java | 5 + .../zimbra/cs/filter/jsieve/StringTest.java | 2 + 16 files changed, 457 insertions(+), 17 deletions(-) create mode 100644 store/src/java-test/com/zimbra/cs/filter/MimeHeaderTest.java diff --git a/store/src/java-test/com/zimbra/cs/filter/AddressTest.java b/store/src/java-test/com/zimbra/cs/filter/AddressTest.java index 37ea10746a7..9792f2050db 100644 --- a/store/src/java-test/com/zimbra/cs/filter/AddressTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/AddressTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2014, 2016 Synacor, Inc. + * Copyright (C) 2014, 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -522,4 +522,41 @@ public void testMalencodedHeader() throws Exception { fail("No exception should be thrown" + e); } } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() throws Exception { + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + String filterScript = "require [\"tag\"];" + + "if address :comparator \"i;ascii-numeric\" \"To\" \"test1@zimbra.com\" {\n" + + " tag \"is\";\n" + + "} else {\n" + + " tag \"not is\";\n" + + "}"; + try { + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + + account.unsetAdminSieveScriptBefore(); + account.unsetMailSieveScript(); + account.unsetAdminSieveScriptAfter(); + account.setMailSieveScript(filterScript); + List ids = RuleManager.applyRulesToIncomingMessage( + new OperationContext(mbox), mbox, + new ParsedMessage("To: test1@zimbra.com\nSubject: example\n".getBytes(), false), 0, + account.getName(), + new DeliveryContext(), + Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(null, ArrayUtil.getFirstElement(msg.getTags())); + } catch (Exception e) { + fail("No exception should be thrown " + e); + } + } } diff --git a/store/src/java-test/com/zimbra/cs/filter/BodyTest.java b/store/src/java-test/com/zimbra/cs/filter/BodyTest.java index 78644d05592..6b512076002 100644 --- a/store/src/java-test/com/zimbra/cs/filter/BodyTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/BodyTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2016 Synacor, Inc. + * Copyright (C) 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -16,6 +16,8 @@ */ package com.zimbra.cs.filter; +import static org.junit.Assert.fail; + import java.util.HashMap; import java.util.List; @@ -24,6 +26,7 @@ import org.junit.BeforeClass; import org.junit.Test; +import com.zimbra.common.util.ArrayUtil; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.MockProvisioning; import com.zimbra.cs.account.Provisioning; @@ -107,4 +110,41 @@ private void test(String script, String message) throws Exception { Message msg = mbox.getMessageById(null, ids.get(0).getId()); Assert.assertTrue(msg.isTagged(FlagInfo.FLAGGED)); } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() throws Exception { + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + String filterScript = "require [\"tag\"];" + + "if body :contains :comparator \"i;ascii-numeric\" \"Sample message\" {\n" + + " tag \"contains\";\n" + + "} else {\n" + + " tag \"not contains\";\n" + + "}"; + try { + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + + account.unsetAdminSieveScriptBefore(); + account.unsetMailSieveScript(); + account.unsetAdminSieveScriptAfter(); + account.setMailSieveScript(filterScript); + List ids = RuleManager.applyRulesToIncomingMessage( + new OperationContext(mbox), mbox, + new ParsedMessage("To: test1@zimbra.com\nSubject: test\n\nSample message".getBytes(), false), 0, + account.getName(), + new DeliveryContext(), + Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(null, ArrayUtil.getFirstElement(msg.getTags())); + } catch (Exception e) { + fail("No exception should be thrown " + e); + } + } } diff --git a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java index a41f64b6d8c..3e942f8bf34 100644 --- a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2016 Synacor, Inc. + * Copyright (C) 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -1321,4 +1321,30 @@ mbox, new ParsedMessage("X-Mal-Encoded-Header: =?ABC?A?GyRCJFskMhsoQg==?=".getBy fail("No exception should be thrown" + e); } } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() throws Exception { + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + String script = "require [\"editheader\"];\n" + + "deleteheader :comparator \"i;ascii-numeric\" \"X-Header\" \"example\";"; + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + RuleManager.clearCachedRules(account); + account.setSieveEditHeaderEnabled(true); + account.setAdminSieveScriptBefore(script); + account.setMailSieveScript(script); + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage("X-Header: example".getBytes(), false), 0, + account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Message message = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertNotNull(message.getMimeMessage().getHeader("X-Header")); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } } \ No newline at end of file diff --git a/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java b/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java index e8c7c5510b5..14f4b42a419 100644 --- a/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/EnvelopeTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2016 Synacor, Inc. + * Copyright (C) 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -1007,4 +1007,47 @@ public void testAllDomainLocalIs() { fail("No exception should be thrown: " + e); } } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() throws Exception { + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + String filterScript = "require [\"envelope\"];" + + "if envelope :comparator \"i;ascii-numeric\" \"To\" \"xyz@zimbra.com\" {\n" + + " tag \"is\";\n" + + "} else {\n" + + " tag \"not is\";\n" + + "}"; + LmtpEnvelope env = new LmtpEnvelope(); + LmtpAddress sender = new LmtpAddress("", new String[] { "BODY", "SIZE" }, null); + LmtpAddress recipient = new LmtpAddress("", null, null); + env.setSender(sender); + env.addLocalRecipient(recipient); + + try { + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + + account.unsetAdminSieveScriptBefore(); + account.unsetMailSieveScript(); + account.unsetAdminSieveScriptAfter(); + account.setMailSieveScript(filterScript); + List ids = RuleManager.applyRulesToIncomingMessage( + new OperationContext(mbox), mbox, + new ParsedMessage(sampleMsg.getBytes(), false), 0, + account.getName(), env, + new DeliveryContext(), + Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(null, ArrayUtil.getFirstElement(msg.getTags())); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } } diff --git a/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java index a68a881f4d1..8eac937c06a 100644 --- a/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/HeaderTest.java @@ -443,4 +443,42 @@ public void testMalencodedHeader() throws Exception { fail("No exception should be thrown" + e); } } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() throws Exception { + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + String filterScript = "require [\"tag\"];" + + "if header :comparator \"i;ascii-numeric\" \"Subject\" \"こんにちは\" {\n" + + " tag \"is\";\n" + + "} else {\n" + + " tag \"not is\";\n" + + "}"; + try { + LmtpEnvelope env = setEnvelopeInfo(); + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + + account.unsetAdminSieveScriptBefore(); + account.unsetMailSieveScript(); + account.unsetAdminSieveScriptAfter(); + account.setMailSieveScript(filterScript); + List ids = RuleManager.applyRulesToIncomingMessage( + new OperationContext(mbox), mbox, + new ParsedMessage(sampleMsg.getBytes(), false), 0, + account.getName(), env, + new DeliveryContext(), + Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(null, ArrayUtil.getFirstElement(msg.getTags())); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } } diff --git a/store/src/java-test/com/zimbra/cs/filter/MimeHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/MimeHeaderTest.java new file mode 100644 index 00000000000..4449264198e --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/filter/MimeHeaderTest.java @@ -0,0 +1,147 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.filter; + +import static org.junit.Assert.fail; + +import java.util.HashMap; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.zimbra.common.util.ArrayUtil; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.MockProvisioning; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.DeliveryContext; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.MailboxManager; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.cs.mailbox.Message; +import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.mime.ParsedMessage; +import com.zimbra.cs.service.util.ItemId; + +public class MimeHeaderTest { + private static String sampleMsg = "from: xyz@example.com\n" + + "Subject: test message\n" + + "to: foo@example.com, baz@example.com\n" + + "cc: qux@example.com\n" + + "Subject: Bonjour\n" + + "MIME-Version: 1.0\n" + + "Content-Type: multipart/mixed; boundary=\"----=_Part_64_1822363563.1505482033554\"\n" + + "\n" + + "------=_Part_64_1822363563.1505482033554\n" + + "Content-Type: text/plain; charset=utf-8\n" + + "Content-Transfer-Encoding: 7bit\n" + + "\n" + + "Test message 2\n" + + "------=_Part_64_1822363563.1505482033554\n" + + "Content-Type: message/rfc822\n" + + "Content-Disposition: attachment\n" + + "\n" + + "Date: Fri, 15 Sep 2017 22:26:43 +0900 (JST)\n" + + "From: admin@synacorjapan.com\n" + + "To: user1 \n" + + "Message-ID: <523389747.44.1505482003470.JavaMail.zimbra@synacorjapan.com>\n" + + "Subject: Hello\n" + + "MIME-Version: 1.0\n" + + "Content-Type: multipart/alternative; boundary=\"=_37c6ca38-873e-4a06-ad29-25a254075e83\"\n" + + "\n" + + "--=_37c6ca38-873e-4a06-ad29-25a254075e83\n" + + "Content-Type: text/plain; charset=utf-8\n" + + "Content-Transfer-Encoding: 7bit\n" + + "\n" + + "This is a sample email\n" + + "\n" + + "--=_37c6ca38-873e-4a06-ad29-25a254075e83\n" + + "Content-Type: text/html; charset=utf-8\n" + + "Content-Transfer-Encoding: 7bit\n" + + "\n" + + "

Test message
\n" + + "--=_37c6ca38-873e-4a06-ad29-25a254075e83--\n" + + "\n" + + "------=_Part_64_1822363563.1505482033554--\n"; + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + Provisioning prov = Provisioning.getInstance(); + prov.createAccount("test@zimbra.com", "secret", new HashMap()); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + } + + @Test + public void test() throws Exception { + // Default match type :is is used. + String filterScript = "require [\"tag\", \"comparator-i;ascii-numeric\"];" + + "if mime_header :comparator \"i;ascii-numeric\" \"Subject\" \"Hello\" {\n" + + " tag \"is\";\n" + + "} else {\n" + + " tag \"not is\";\n" + + "}"; + doTest(filterScript, "is"); + } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() throws Exception { + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + String filterScript = "require [\"tag\"];" + + "if mime_header :comparator \"i;ascii-numeric\" \"Subject\" \"Hello\" {\n" + + " tag \"is\";\n" + + "} else {\n" + + " tag \"not is\";\n" + + "}"; + doTest(filterScript, null); + } + + private void doTest(String filterScript, String expected) throws Exception { + try { + Account account = Provisioning.getInstance().getAccount( + MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + + account.unsetAdminSieveScriptBefore(); + account.unsetMailSieveScript(); + account.unsetAdminSieveScriptAfter(); + account.setMailSieveScript(filterScript); + List ids = RuleManager.applyRulesToIncomingMessage( + new OperationContext(mbox), mbox, + new ParsedMessage(sampleMsg.getBytes(), false), 0, + account.getName(), + new DeliveryContext(), + Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(expected, ArrayUtil.getFirstElement(msg.getTags())); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } +} diff --git a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java index 0c13ec03fe9..81fb41f856f 100644 --- a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2016 Synacor, Inc. + * Copyright (C) 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -1701,4 +1701,33 @@ mbox, new ParsedMessage("X-Mal-Encoded-Header: =?ABC?A?GyRCJFskMhsoQg==?=".getBy fail("No exception should be thrown" + e); } } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() throws Exception { + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + String script = "require [\"editheader\"];\n" + + "replaceheader :newvalue \"20\" :comparator \"i;ascii-numeric\" \"X-Numeric-Header\" \"2\";"; + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + RuleManager.clearCachedRules(account); + account.setSieveEditHeaderEnabled(true); + account.setAdminSieveScriptBefore(script); + account.setMailSieveScript(script); + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(sampleBaseMsg.getBytes(), false), 0, + account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Message message = mbox.getMessageById(null, ids.get(0).getId()); + String[] headers = message.getMimeMessage().getHeader("X-Numeric-Header"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals("2", headers[0]); + } catch (Exception e) { + fail("No exception should be thrown" + e); + } + } } \ No newline at end of file diff --git a/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java b/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java index 8696e9519d6..2d540a6b91d 100644 --- a/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/SetVariableTest.java @@ -2414,4 +2414,41 @@ public void testNoRequireDeclaration() { fail("No exception should be thrown: " + e); } } + + /* + * The ascii-numeric comparator should be looked up in the list of the "require". + */ + @Test + public void testMissingComparatorNumericDeclaration() { + try { + Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + + // Default match type :is is used. + // No "comparator-i;ascii-numeric" capability text in the require command + filterScript = "require \"variables\";" + + "set \"state\" \"1\";\n" + + "if string :comparator \"i;ascii-numeric\" \"${state}\" \"1\" {\n" + + " tag \"is\";\n" + + "} else {\n" + + " tag \"not is\";\n" + + "}\n"; + + account.setMailSieveScript(filterScript); + String raw = "From: sender@zimbra.com\n" + + "To: test1@zimbra.com\n" + + "Subject: test"; + + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, + new ParsedMessage(raw.getBytes(), false), 0, account.getName(), new DeliveryContext(), + Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(null, ArrayUtil.getFirstElement(msg.getTags())); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java index ad761d70219..24ddb74e324 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/AddressTest.java @@ -16,6 +16,7 @@ */ package com.zimbra.cs.filter.jsieve; +import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; import static org.apache.jsieve.comparators.MatchTypeTags.IS_TAG; import static org.apache.jsieve.tests.AddressPartTags.ALL_TAG; import static org.apache.jsieve.tests.AddressPartTags.LOCALPART_TAG; @@ -78,6 +79,14 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, throw new SieveException("Exception occured while evaluating variable expression.", e); } } + if (params.getMatchType() == null) { + params.setMatchType(IS_TAG); + } + params.setComparator(ZimbraComparatorUtils.getComparator(params.getComparator(), params.getMatchType())); + if (ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(params.getComparator())) { + Require.checkCapability((ZimbraMailAdapter) mail, ASCII_NUMERIC_COMPARATOR); + } + if (HeaderConstants.COUNT.equals(params.getMatchType()) || HeaderConstants.VALUE.equals(params.getMatchType()) || IS_TAG.equalsIgnoreCase(params.getMatchType())) { return match(mail, (params.getAddressPart() == null ? ALL_TAG : params.getAddressPart()), @@ -90,7 +99,7 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, return match(mail, (params.getAddressPart() == null ? ALL_TAG : params.getAddressPart()), ZimbraComparatorUtils.getComparator(params.getComparator(), params.getMatchType()), - (params.getMatchType() == null ? IS_TAG : params.getMatchType()), + params.getMatchType(), params.getHeaderNames(), params.getKeys(), context); } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/BodyTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/BodyTest.java index db21c26e5e8..d6c4211fb67 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/BodyTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/BodyTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -44,6 +44,9 @@ import org.apache.jsieve.tests.AbstractTest; import javax.mail.Part; + +import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; + import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -98,7 +101,11 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, SieveConte if (argument instanceof StringListArgument) { StringListArgument strList = (StringListArgument) argument; try { - caseSensitive = Sieve.Comparator.ioctet == Sieve.Comparator.fromString(strList.getList().get(0)); + String comparator = strList.getList().get(0); + if (ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(comparator) && mail instanceof ZimbraMailAdapter) { + Require.checkCapability((ZimbraMailAdapter) mail, ASCII_NUMERIC_COMPARATOR); + } + caseSensitive = Sieve.Comparator.ioctet == Sieve.Comparator.fromString(comparator); } catch (ServiceException e) { throw new SyntaxException(e.getMessage()); } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/DeleteHeader.java b/store/src/java/com/zimbra/cs/filter/jsieve/DeleteHeader.java index 628f2715e6c..6d94c018f74 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/DeleteHeader.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/DeleteHeader.java @@ -17,6 +17,8 @@ package com.zimbra.cs.filter.jsieve; import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_EDITHEADER; +import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; + import java.util.List; import java.util.Enumeration; import java.util.HashSet; @@ -55,6 +57,9 @@ protected Object executeBasic(MailAdapter mail, Arguments args, Block block, Sie return null; } ZimbraMailAdapter mailAdapter = (ZimbraMailAdapter) mail; + if (ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(ehe.getComparator())) { + Require.checkCapability((ZimbraMailAdapter) mail, ASCII_NUMERIC_COMPARATOR); + } Require.checkCapability(mailAdapter, CAPABILITY_EDITHEADER); if (!mailAdapter.getAccount().isSieveEditHeaderEnabled()) { mailAdapter.setDeleteHeaderPresent(true); diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java index b021289783e..624fd14ded6 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/EnvelopeTest.java @@ -84,6 +84,13 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, throw new SieveException("Exception occured while evaluating variable expression.", e); } } + if (params.getMatchType() == null) { + params.setMatchType(IS_TAG); + } + params.setComparator(ZimbraComparatorUtils.getComparator(params.getComparator(), params.getMatchType())); + if (ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(params.getComparator())) { + Require.checkCapability(mailAdapter, ASCII_NUMERIC_COMPARATOR); + } if (HeaderConstants.COUNT.equals(params.getMatchType()) || HeaderConstants.VALUE.equals(params.getMatchType()) || IS_TAG.equals(params.getMatchType())) { return match(mail, @@ -97,7 +104,7 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, return match(mail, (params.getAddressPart() == null ? ALL_TAG : params.getAddressPart()), ZimbraComparatorUtils.getComparator(params.getComparator(), params.getMatchType()), - (params.getMatchType() == null ? IS_TAG : params.getMatchType()), + params.getMatchType(), params.getHeaderNames(), params.getKeys(), context); } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java index f46845e5fc7..54dcdd17662 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/HeaderTest.java @@ -16,6 +16,7 @@ */ package com.zimbra.cs.filter.jsieve; +import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; import static org.apache.jsieve.comparators.MatchTypeTags.CONTAINS_TAG; import static org.apache.jsieve.comparators.MatchTypeTags.IS_TAG; import static org.apache.jsieve.comparators.MatchTypeTags.MATCHES_TAG; @@ -176,16 +177,18 @@ else if (matchType == null "Found unexpected arguments"); } + if (null == matchType) { + matchType = IS_TAG; + } + comparator = ZimbraComparatorUtils.getComparator(comparator, matchType); + if (ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(comparator) && mail instanceof ZimbraMailAdapter) { + Require.checkCapability((ZimbraMailAdapter) mail, ASCII_NUMERIC_COMPARATOR); + } if (matchType != null && (HeaderConstants.COUNT.equalsIgnoreCase(matchType) || HeaderConstants.VALUE.equalsIgnoreCase(matchType) || IS_TAG.equalsIgnoreCase(matchType))) { - return match(mail, - ZimbraComparatorUtils.getComparator(comparator, matchType), - matchType, operator, headerNames, keys, context); + return match(mail, comparator, matchType, operator, headerNames, keys, context); } else { - return match(mail, - ZimbraComparatorUtils.getComparator(comparator, matchType), - (matchType == null ? IS_TAG : matchType), - headerNames, keys, context); + return match(mail, comparator, matchType, headerNames, keys, context); } } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/MimeHeaderTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/MimeHeaderTest.java index 2980ae45447..1e01d8f9fc3 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/MimeHeaderTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/MimeHeaderTest.java @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** * Zimbra Collaboration Suite Server - * Copyright (C) 2010, 2013, 2014, 2016 Synacor, Inc. + * Copyright (C) 2010, 2013, 2014, 2016, 2017 Synacor, Inc. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, @@ -17,6 +17,8 @@ package com.zimbra.cs.filter.jsieve; +import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -48,6 +50,9 @@ protected boolean match(MailAdapter mail, String comparator, return false; } ZimbraMailAdapter zma = (ZimbraMailAdapter) mail; + if (ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(comparator)) { + Require.checkCapability(zma, ASCII_NUMERIC_COMPARATOR); + } // Iterate over the header names looking for a match boolean isMatched = false; Iterator headerNamesIter = headerNames.iterator(); diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/ReplaceHeader.java b/store/src/java/com/zimbra/cs/filter/jsieve/ReplaceHeader.java index 12c82e34039..edd8371c13f 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/ReplaceHeader.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/ReplaceHeader.java @@ -17,6 +17,8 @@ package com.zimbra.cs.filter.jsieve; import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_EDITHEADER; +import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; + import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; @@ -59,6 +61,9 @@ protected Object executeBasic(MailAdapter mail, Arguments arguments, return null; } ZimbraMailAdapter mailAdapter = (ZimbraMailAdapter) mail; + if (ASCII_NUMERIC_COMPARATOR.equalsIgnoreCase(ehe.getComparator())) { + Require.checkCapability((ZimbraMailAdapter) mail, ASCII_NUMERIC_COMPARATOR); + } Require.checkCapability(mailAdapter, CAPABILITY_EDITHEADER); if (!mailAdapter.getAccount().isSieveEditHeaderEnabled()) { mailAdapter.setReplaceHeaderPresent(true); diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java b/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java index c7fcee99831..37ee9e91dca 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/StringTest.java @@ -16,6 +16,7 @@ */ package com.zimbra.cs.filter.jsieve; +import static com.zimbra.cs.filter.JsieveConfigMapHandler.CAPABILITY_VARIABLES; import static com.zimbra.cs.filter.jsieve.ComparatorName.ASCII_NUMERIC_COMPARATOR; import static org.apache.jsieve.comparators.ComparatorNames.ASCII_CASEMAP_COMPARATOR; import static org.apache.jsieve.comparators.MatchTypeTags.CONTAINS_TAG; @@ -72,6 +73,7 @@ protected boolean executeBasic(MailAdapter mail, Arguments arguments, SieveConte } ZimbraMailAdapter mailAdapter = (ZimbraMailAdapter) mail; + Require.checkCapability(mailAdapter, CAPABILITY_VARIABLES); String matchType = null; String comparator = null; From 9fd27af5566398b48aacf6e83e9df58c35dac86f Mon Sep 17 00:00:00 2001 From: Chinmay Pathak <15.chinmay@gmail.com> Date: Mon, 18 Sep 2017 11:37:42 +0530 Subject: [PATCH 073/142] ZCS-2728 : Removing domainAdminModifiable flag --- store/conf/attrs/zimbra-attrs.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index c1b1f38f8b6..627098d9133 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9569,7 +9569,7 @@ TODO: delete them permanently from here Mark messages sent to a forwarding address as read - + 1d Sleep time between subsequent contact backups. 0 means that contact @@ -9577,7 +9577,7 @@ TODO: delete them permanently from here - + 15d Duration for which the backups should be preserved. From a21aa8a4612118149ad314a30c010f9d54d752e7 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Sun, 17 Sep 2017 15:45:14 +0530 Subject: [PATCH 074/142] ZCS-2746 Reworked the fix --- .../cs/filter/IncomingMessageHandlerTest.java | 242 ------------------ .../com/zimbra/cs/mailbox/MailboxTest.java | 34 +++ .../cs/filter/IncomingMessageHandler.java | 11 +- .../java/com/zimbra/cs/mailbox/Mailbox.java | 25 +- 4 files changed, 51 insertions(+), 261 deletions(-) delete mode 100644 store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java diff --git a/store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java b/store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java deleted file mode 100644 index 21638947cf0..00000000000 --- a/store/src/java-test/com/zimbra/cs/filter/IncomingMessageHandlerTest.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * ***** BEGIN LICENSE BLOCK ***** - * Zimbra Collaboration Suite, Network Edition. - * Copyright (C) 2013, 2014 Zimbra, Inc. All Rights Reserved. - * ***** END LICENSE BLOCK ***** - */ -package com.zimbra.cs.filter; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.easymock.EasyMock; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.zimbra.common.service.ServiceException; -import com.zimbra.cs.account.Account; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.account.ldap.LdapProvisioning; -import com.zimbra.cs.filter.jsieve.ActionFlag; -import com.zimbra.cs.mailbox.DeliveryContext; -import com.zimbra.cs.mailbox.DeliveryOptions; -import com.zimbra.cs.mailbox.Flag; -import com.zimbra.cs.mailbox.Mailbox; -import com.zimbra.cs.mailbox.Message; -import com.zimbra.cs.mailbox.OperationContext; -import com.zimbra.cs.mime.ParsedMessage; - -/** - * @author zimbra - * - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({ Provisioning.class }) -@PowerMockIgnore({"javax.xml.parsers.*", "org.apache.log4j.*", "org.xml.sax.*", "org.w3c.dom.*"}) -public class IncomingMessageHandlerTest { - - @Mock - private Provisioning prov = PowerMockito.mock(LdapProvisioning.class); - - @Before - public void setUp() { - PowerMockito.mockStatic(Provisioning.class); - PowerMockito.when(Provisioning.getInstance()).thenReturn(prov); - } - - - @Test - public void testImplicitKeepWhenForwardFeatureEnabledAndReadFlagSet() { - try { - OperationContext octxt = EasyMock.createMock(OperationContext.class); - DeliveryContext dctxt = EasyMock.createMock(DeliveryContext.class); - String recipientsAddress = "user1@email.com"; - int size = 100; - int defaultFolderId = 2; - boolean noICal = false; - Mailbox mailbox = new MockMailbox(); - IncomingMessageHandler messageHandler = new IncomingMessageHandler(octxt, dctxt, - mailbox, recipientsAddress, null, size, defaultFolderId, noICal); - Account acct = mailbox.getAccount(); - acct.setPrefMailForwardingAddress("forwar@zimbra.com"); - acct.setFeatureMarkMailForwardedAsRead(true); - acct.setFeatureMailForwardingEnabled(true); - List actions = new ArrayList(); - String[] tags = { "yellow" }; - - Message msg = messageHandler.implicitKeep(actions, tags); - assertEquals(0, msg.getFlagBitmask()); - } catch (ServiceException e) { - Assert.fail("No Exception should be thrown."); - } - - } - - @Test - public void testImplicitKeepWhenForwardFeatureEnabledButReadFlagNotSet() { - try { - OperationContext octxt = EasyMock.createMock(OperationContext.class); - DeliveryContext dctxt = EasyMock.createMock(DeliveryContext.class); - String recipientsAddress = "user1@email.com"; - int size = 100; - int defaultFolderId = 2; - boolean noICal = false; - Mailbox mailbox = new MockMailbox(); - - IncomingMessageHandler messageHandler = new IncomingMessageHandler(octxt, dctxt, - mailbox, recipientsAddress, null, size, defaultFolderId, noICal); - - Account acct = mailbox.getAccount(); - acct.setPrefMailForwardingAddress("forwar@zimbra.com"); - acct.setFeatureMarkMailForwardedAsRead(false); - acct.setFeatureMailForwardingEnabled(true); - List actions = new ArrayList(); - String[] tags = { "yellow" }; - - Message msg = messageHandler.implicitKeep(actions, tags); - assertEquals(Flag.BITMASK_UNREAD, msg.getFlagBitmask()); - } catch (ServiceException e) { - Assert.fail("No Exception should be thrown."); - } - - } - - @Test - public void testImplicitKeepWhenForwardFeatureDisabled() { - try { - OperationContext octxt = EasyMock.createMock(OperationContext.class); - DeliveryContext dctxt = EasyMock.createMock(DeliveryContext.class); - String recipientsAddress = "user1@email.com"; - int size = 100; - int defaultFolderId = 2; - boolean noICal = false; - Mailbox mailbox = new MockMailbox(); - - IncomingMessageHandler messageHandler = new IncomingMessageHandler(octxt, dctxt, - mailbox, recipientsAddress, null, size, defaultFolderId, noICal); - - Account acct = mailbox.getAccount(); - acct.setFeatureMarkMailForwardedAsRead(false); - acct.setFeatureMailForwardingEnabled(false); - List actions = new ArrayList(); - String[] tags = { "yellow" }; - - Message msg = messageHandler.implicitKeep(actions, tags); - assertEquals(Flag.BITMASK_UNREAD, msg.getFlagBitmask()); - } catch (ServiceException e) { - Assert.fail("No Exception should be thrown."); - } - - } - - public Account getAccount() throws ServiceException { - - HashMap attrs; - attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraId, UUID.randomUUID().toString()); - Account acctLocal = new MockAccount("test@zimbra.com", null, attrs, attrs, prov); - - return acctLocal; - } - - public class MockAccount extends Account { - - private boolean zimbraFeatureMarkMailForwardedAsRead; - private String prefMailForwardingAddress; - private boolean zimbraFeatureMailForwardingEnabled; - - /** - * @param name - * @param id - * @param attrs - * @param defaults - * @param prov - */ - public MockAccount(String name, String id, Map attrs, - Map defaults, Provisioning prov) { - super(name, id, attrs, defaults, prov); - } - - public boolean isFeatureAntispamEnabled() { - return false; - } - - public String getPrefMailForwardingAddress() { - return this.prefMailForwardingAddress; - } - - public boolean isFeatureMailForwardingEnabled() { - return this.zimbraFeatureMailForwardingEnabled; - } - - public boolean isFeatureMarkMailForwardedAsRead() { - return zimbraFeatureMarkMailForwardedAsRead; - } - - @Override - public void setFeatureMarkMailForwardedAsRead(boolean zimbraFeatureMarkMailForwardedAsRead) - throws ServiceException { - this.zimbraFeatureMarkMailForwardedAsRead = zimbraFeatureMarkMailForwardedAsRead; - } - - @Override - public void setPrefMailForwardingAddress(String zimbraPrefMailForwardingAddress) - throws ServiceException { - this.prefMailForwardingAddress = zimbraPrefMailForwardingAddress; - } - - @Override - public void setFeatureMailForwardingEnabled(boolean zimbraFeatureMailForwardingEnabled) - throws ServiceException { - this.zimbraFeatureMailForwardingEnabled = zimbraFeatureMailForwardingEnabled; - } - } - - public class MockMailbox extends Mailbox { - - private Account account; - /** - * @param data - */ - protected MockMailbox() { - - HashMap attrs; - attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraId, UUID.randomUUID().toString()); - account = new MockAccount("test@zimbra.com", null, attrs, attrs, prov); - } - - @Override - public Account getAccount() throws ServiceException { - return account; - } - - @Override - public String getAccountId() { - return "test"; - } - - @Override - public Message addMessage(OperationContext octxt, ParsedMessage pm, DeliveryOptions dopt, - DeliveryContext dctxt) throws IOException, ServiceException { - - Message msg = PowerMockito.mock(Message.class); - PowerMockito.when(msg.getFlagBitmask()).thenReturn(dopt.getFlags()); - return msg; - } - } - -} diff --git a/store/src/java-test/com/zimbra/cs/mailbox/MailboxTest.java b/store/src/java-test/com/zimbra/cs/mailbox/MailboxTest.java index 88521c39f60..3c9a79c8836 100644 --- a/store/src/java-test/com/zimbra/cs/mailbox/MailboxTest.java +++ b/store/src/java-test/com/zimbra/cs/mailbox/MailboxTest.java @@ -580,6 +580,40 @@ public void getVisibleFolders() throws Exception { Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(MockProvisioning.DEFAULT_ACCOUNT_ID); mbox.getVisibleFolders(new OperationContext(mbox)); } + + + @Test + public void testLocalMsgReadStatusForForMailForwards() throws Exception { + Provisioning prov = Provisioning.getInstance(); + Map attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMailForwardingEnabled, "TRUE"); + attrs.put(Provisioning.A_zimbraPrefMailForwardingAddress, "user@zimbra.com"); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, "TRUE"); + Account acct = prov.createAccount("user@zimbra.com", "secret", attrs); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(acct.getId()); + + DeliveryOptions dopt = new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX); + dopt.setFlags(Flag.BITMASK_UNREAD); + Message message = mbox.addMessage(null, new ParsedMessage("From: test1-1@sub1.zimbra.com".getBytes(), false), dopt, null); + Assert.assertEquals(false, message.isUnread()); + } + + @Test + public void testLocalMsgReadStatusForForMailForwardsWhenMarkAsReadIsFalse() throws Exception { + Provisioning prov = Provisioning.getInstance(); + Map attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureMailForwardingEnabled, "TRUE"); + attrs.put(Provisioning.A_zimbraPrefMailForwardingAddress, "user2@zimbra.com"); + attrs.put(Provisioning.A_zimbraFeatureMarkMailForwardedAsRead, "FALSE"); + Account acct = prov.createAccount("user@zimbra.com", "secret", attrs); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(acct.getId()); + + DeliveryOptions dopt = new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX); + dopt.setFlags(Flag.BITMASK_UNREAD); + Message message = mbox.addMessage(null, new ParsedMessage("From: test1-1@sub1.zimbra.com".getBytes(), false), dopt, null); + Assert.assertEquals(true, message.isUnread()); + + } /** * @throws java.lang.Exception diff --git a/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java b/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java index 8991280f2a6..b923f41b9d5 100644 --- a/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java +++ b/store/src/java/com/zimbra/cs/filter/IncomingMessageHandler.java @@ -26,7 +26,6 @@ import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; -import com.zimbra.cs.account.Account; import com.zimbra.cs.filter.jsieve.ActionFlag; import com.zimbra.cs.filter.jsieve.ErejectException; import com.zimbra.cs.lmtpserver.LmtpEnvelope; @@ -134,15 +133,7 @@ private Message addMessage(int folderId, Collection flagActions, Str throws ServiceException { try { DeliveryOptions dopt = new DeliveryOptions().setFolderId(folderId).setNoICal(noICal).setRecipientEmail(recipientAddress); - Account account = mailbox.getAccount(); - if (account.getPrefMailForwardingAddress() != null && account.isFeatureMailForwardingEnabled() - && account.isFeatureMarkMailForwardedAsRead()) { - ZimbraLog.mailbox.debug("Marking forwarded message as read."); - dopt.setFlags(FilterUtil.getFlagBitmask(flagActions, 0)).setTags(tags); - - } else { - dopt.setFlags(FilterUtil.getFlagBitmask(flagActions, Flag.BITMASK_UNREAD)).setTags(tags); - } + dopt.setFlags(FilterUtil.getFlagBitmask(flagActions, Flag.BITMASK_UNREAD)).setTags(tags); return mailbox.addMessage(octxt, parsedMessage, dopt, dctxt); } catch (IOException e) { throw ServiceException.FAILURE("Unable to add incoming message", e); diff --git a/store/src/java/com/zimbra/cs/mailbox/Mailbox.java b/store/src/java/com/zimbra/cs/mailbox/Mailbox.java index 6fd5654497d..8fdcbc822a4 100644 --- a/store/src/java/com/zimbra/cs/mailbox/Mailbox.java +++ b/store/src/java/com/zimbra/cs/mailbox/Mailbox.java @@ -236,6 +236,7 @@ import com.zimbra.cs.service.FeedManager; import com.zimbra.cs.service.mail.CopyActionResult; import com.zimbra.cs.service.mail.ItemActionHelper; +import com.zimbra.cs.service.mail.SendDeliveryReport; import com.zimbra.cs.service.util.ItemData; import com.zimbra.cs.service.util.ItemId; import com.zimbra.cs.service.util.SpamHandler; @@ -763,13 +764,6 @@ protected Mailbox(MailboxData data) { lock = new MailboxLock(data.accountId, this); } - /** Introduced only for unit testing */ - protected Mailbox() { - mId = -1; - index = null; - lock = null; - } - public void setGalSyncMailbox(boolean galSyncMailbox) { this.galSyncMailbox = galSyncMailbox; } @@ -6000,7 +5994,6 @@ private Message addMessage(OperationContext octxt, ParsedMessage pm, int folderI String[] tags, int conversationId, String rcptEmail, Message.DraftInfo dinfo, CustomMetadata customData, DeliveryContext dctxt) throws IOException, ServiceException { - // and then actually add the message long start = ZimbraPerf.STOPWATCH_MBOX_ADD_MSG.start(); @@ -6062,12 +6055,26 @@ private Message addMessage(OperationContext octxt, ParsedMessage pm, int folderI } StagedBlob staged = sm.stage(blob, this); + + Account account = this.getAccount(); + boolean localMsgMarkedRead = false; + if (account.getPrefMailForwardingAddress() != null && account.isFeatureMailForwardingEnabled() + && account.isFeatureMarkMailForwardedAsRead()) { + ZimbraLog.mailbox.debug("Marking forwarded message as read."); + flags = flags & ~Flag.BITMASK_UNREAD; + localMsgMarkedRead = true; + } + lock.lock(); try { try { - return addMessageInternal(octxt, pm, folderId, noICal, flags, tags, conversationId, + Message message = addMessageInternal(octxt, pm, folderId, noICal, flags, tags, conversationId, rcptEmail, dinfo, customData, dctxt, staged); + if (localMsgMarkedRead && account.getPrefMailSendReadReceipts().isAlways()) { + SendDeliveryReport.sendReport(account, message, true, null, null); + } + return message; } finally { if (deleteIncoming) { sm.quietDelete(dctxt.getIncomingBlob()); From 22273cba8789171110b2f28681d71e1310447b7d Mon Sep 17 00:00:00 2001 From: Sneha Patil Date: Mon, 18 Sep 2017 11:37:49 +0530 Subject: [PATCH 075/142] ZCS-2730:Adding resolve request parameter --- .../com/zimbra/common/soap/MailConstants.java | 1 + .../mail/message/RestoreContactsRequest.java | 38 ++++++++++++++++++- store/docs/soap.txt | 10 +++-- .../cs/service/mail/RestoreContacts.java | 8 ++++ 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/common/src/java/com/zimbra/common/soap/MailConstants.java b/common/src/java/com/zimbra/common/soap/MailConstants.java index 6521753be20..82f6bd6379b 100644 --- a/common/src/java/com/zimbra/common/soap/MailConstants.java +++ b/common/src/java/com/zimbra/common/soap/MailConstants.java @@ -1346,5 +1346,6 @@ private MailConstants() { public static final QName RESTORE_CONTACTS_REQUEST = QName.get(E_RESTORE_CONTACTS_REQUEST, NAMESPACE); public static final QName RESTORE_CONTACTS_RESPONSE = QName.get(E_RESTORE_CONTACTS_RESPONSE, NAMESPACE); public static final String A_CONTACTS_BACKUP_FILE_NAME = "contactsBackupFileName"; + public static final String A_CONTACTS_RESTORE_RESOLVE = "resolve"; public static final String A_CONTACTS_BACKUP_FOLDER_NAME = "ContactsBackup"; } diff --git a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java index 07d369f4e30..c5848e118d6 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java @@ -16,12 +16,16 @@ */ package com.zimbra.soap.mail.message; +import java.util.Arrays; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlEnum; import javax.xml.bind.annotation.XmlRootElement; import com.google.common.base.Objects; +import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.MailConstants; @XmlAccessorType(XmlAccessType.NONE) @@ -35,6 +39,38 @@ public class RestoreContactsRequest { @XmlAttribute(name = MailConstants.A_CONTACTS_BACKUP_FILE_NAME, required = true) private String contactsBackupFileName; + /** + * @zm-api-field-tag resolve + * @zm-api-field-description restore resolve action + */ + @XmlAttribute(name=MailConstants.A_CONTACTS_RESTORE_RESOLVE /* resolve */, required=false) + private Resolve resolve; + + public Resolve getResolve() { + return resolve; + } + + public void setResolve(Resolve resolve) { + this.resolve = resolve; + } + + @XmlEnum + public static enum Resolve { + ignore, modify, replace, reset; + + public static Resolve fromString(String value) throws ServiceException { + if (value == null) { + return null; + } + try { + return Resolve.valueOf(value); + } catch (IllegalArgumentException e) { + throw ServiceException.INVALID_REQUEST( + "Invalid value: " + value + ", valid values: " + Arrays.asList(Resolve.values()), null); + } + } + } + public String getContactsBackupFileName() { return contactsBackupFileName; } @@ -44,7 +80,7 @@ public void setContactsBackupFileName(String contactsBackupFileName) { } public Objects.ToStringHelper addToStringInfo(Objects.ToStringHelper helper) { - return helper.add("contactsBackupFileName", contactsBackupFileName); + return helper.add("contactsBackupFileName", contactsBackupFileName).add("resolve", resolve); } @Override diff --git a/store/docs/soap.txt b/store/docs/soap.txt index 02ac478381e..2aaef1bbfa9 100644 --- a/store/docs/soap.txt +++ b/store/docs/soap.txt @@ -4697,19 +4697,21 @@ If IMAP tracking is already enabled, does nothing. ----------------------------- API to restore contact backup file from the contact backup list - + +{restore_resolve} = ignore | modify | reset | replace + Note: First, retrieve the contact backup file name with GetContactBackupList Soap API, then send that file name in 'contactsBackupFileName' parameter of RestoreContactsRequest. RestoreContactsRequest will search for file inside 'ContactsBackup' briefcase folder and if found, will restore it. +The 'resolve' parameter is optional. It supports ignore, modify, reset, replace options in +import Rest API. By default, the resolve action is 'reset'. - + -{status} = SUCCESS | FAILURE; - ----------------------------- Api to get list of available contact backup files diff --git a/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java b/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java index ee02531c655..9a5c6723ffb 100644 --- a/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java +++ b/store/src/java/com/zimbra/cs/service/mail/RestoreContacts.java @@ -52,6 +52,7 @@ import com.zimbra.soap.SoapServlet; import com.zimbra.soap.ZimbraSoapContext; import com.zimbra.soap.mail.message.RestoreContactsRequest; +import com.zimbra.soap.mail.message.RestoreContactsRequest.Resolve; import com.zimbra.soap.mail.message.RestoreContactsResponse; public class RestoreContacts extends MailDocumentHandler { @@ -63,6 +64,7 @@ public Element handle(Element request, Map context) throws Servi OperationContext octxt = getOperationContext(zsc, context); RestoreContactsRequest req = zsc.elementToJaxb(request); String contactBackupFileName = req.getContactsBackupFileName(); + Resolve resolve = req.getResolve(); // if folder does not exist, SoapFault is thrown by getFolderByName() itself. Folder folder = mbox.getFolderByName(octxt, Mailbox.ID_FOLDER_BRIEFCASE, MailConstants.A_CONTACTS_BACKUP_FOLDER_NAME); @@ -83,10 +85,16 @@ public Element handle(Element request, Map context) throws Servi httpRequest = (HttpServletRequest) servReq; realm = httpRequest.isSecure() ? "https://" : "http://"; } + if(resolve == null) { + resolve = Resolve.reset; + } String url = realm + getLocalHost() + "/service/home/" + mbox.getAccount().getName() + "/?" + UserServlet.QP_FMT + "=tgz&" + UserServlet.QP_TYPES + "=contact&" + MimeConstants.P_CHARSET + "=UTF-8"; CookieStore cookieStore = new BasicCookieStore(); + if (resolve != Resolve.ignore) { + url = url + "&" + MailConstants.A_CONTACTS_RESTORE_RESOLVE + "=" + resolve; + } AuthToken authToken = octxt.getAuthToken(); BasicClientCookie cookie = null; try { From f57b864e397e4fe129c4fcb0a8d1ed867aae3d27 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Sun, 17 Sep 2017 19:29:36 +0530 Subject: [PATCH 076/142] ZCS-2772 Fixing failing test and exclusion test list --- build-common.xml | 53 ++----------------- .../admin/ModifyFilterRulesAdminTest.java | 35 ++++++------ .../service/mail/ModifyFilterRulesTest.java | 13 ++--- 3 files changed, 28 insertions(+), 73 deletions(-) diff --git a/build-common.xml b/build-common.xml index 226a7fb6c90..1c6f5cd4523 100644 --- a/build-common.xml +++ b/build-common.xml @@ -316,56 +316,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java b/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java index 50466ffe51b..8b265f7746e 100644 --- a/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java +++ b/store/src/java-test/com/zimbra/cs/service/admin/ModifyFilterRulesAdminTest.java @@ -19,6 +19,7 @@ import com.zimbra.cs.filter.RuleManager; import com.zimbra.cs.filter.RuleManager.AdminFilterType; import com.zimbra.cs.filter.RuleManager.FilterType; +import com.zimbra.cs.filter.SoapToSieve; import com.zimbra.cs.mailbox.MailboxTestUtil; import com.zimbra.cs.service.admin.AdminDocumentHandler.AccountHarvestingCheckerBase; import com.zimbra.soap.ZimbraSoapContext; @@ -62,7 +63,7 @@ public void testSoapToSieveAddheaderActionWithoutLast() throws ServiceException, RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "addheader \"X-New-Header\" \"Test vallue\";\n"; @@ -80,7 +81,7 @@ public void testSoapToSieveAddheaderActionWithLast() throws ServiceException, Ex RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "addheader :last \"X-New-Header\" \"Test vallue\";\n"; @@ -100,7 +101,7 @@ public void testSoapToSieveDeleteheaderActionBasic() throws ServiceException, Ex RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "deleteheader \"X-Test-Header\";\n"; @@ -123,7 +124,7 @@ public void testSoapToSieveDeleteheaderAction2() throws ServiceException, Except RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "deleteheader :comparator \"i;ascii-casemap\" :is \"X-Test-Header\" \"Test value\";\n"; @@ -148,7 +149,7 @@ public void testSoapToSieveDeleteheaderAction3() throws ServiceException, Except RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "deleteheader :comparator \"i;ascii-casemap\" :is \"X-Test-Header\" [ \"Value1\", \"Value2\", \"Value3\" ];\n"; @@ -172,7 +173,7 @@ public void testSoapToSieveDeleteheaderAction4() throws ServiceException, Except RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "deleteheader :comparator \"i;octet\" :contains \"X-Test-Header\" [ \"Value1\", \"Value2\", \"Value3\" ];\n"; @@ -194,7 +195,7 @@ public void testSoapToSieveDeleteheaderAction5() throws ServiceException, Except RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "deleteheader :value \"ge\" :comparator \"i;ascii-numeric\" \"X-Test-Header\" \"2\";\n"; @@ -216,7 +217,7 @@ public void testSoapToSieveDeleteheaderAction6() throws ServiceException, Except RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "deleteheader :value \"ge\" :comparator \"i;ascii-numeric\" \"X-Test-Header\" \"2\";\n"; @@ -238,7 +239,7 @@ public void testSoapToSieveDeleteheaderAction7() throws ServiceException, Except RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "deleteheader :count \"ge\" :comparator \"i;ascii-numeric\" \"X-Test-Header\" \"2\";\n"; @@ -258,7 +259,7 @@ public void testSoapToSieveReplaceheaderActionBasic() throws ServiceException, E RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "replaceheader :newvalue \"[test] ${1}\" \"X-Test-Header\";\n"; @@ -281,7 +282,7 @@ public void testSoapToSieveReplaceheaderAction2() throws ServiceException, Excep RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script ="require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "replaceheader :newvalue \"[test] ${1}\" :comparator \"i;ascii-casemap\" :is \"X-Test-Header\" \"Test value\";\n"; @@ -306,7 +307,7 @@ public void testSoapToSieveReplaceheaderAction3() throws ServiceException, Excep RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "replaceheader :newvalue \"[test] ${1}\" :comparator \"i;ascii-casemap\" :is \"X-Test-Header\" [ \"Value1\", \"Value2\", \"Value3\" ];\n"; @@ -330,7 +331,7 @@ public void testSoapToSieveReplaceheaderAction4() throws ServiceException, Excep RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "replaceheader :newvalue \"[test] ${1}\" :comparator \"i;octet\" :contains \"X-Test-Header\" [ \"Value1\", \"Value2\", \"Value3\" ];\n"; @@ -352,7 +353,7 @@ public void testSoapToSieveReplaceheaderAction5() throws ServiceException, Excep RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "replaceheader :newvalue \"[test] ${1}\" :value \"ge\" :comparator \"i;ascii-numeric\" \"X-Test-Header\" \"2\";\n"; @@ -374,7 +375,7 @@ public void testSoapToSieveReplaceheaderAction6() throws ServiceException, Excep RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "replaceheader :newvalue \"[test] ${1}\" :value \"ge\" :comparator \"i;ascii-numeric\" \"X-Test-Header\" \"2\";\n"; @@ -396,10 +397,10 @@ public void testSoapToSieveReplaceheaderAction7() throws ServiceException, Excep RuleManager.clearCachedRules(account); RuleManager.setAdminRulesFromXML(account, filterRules, FilterType.INCOMING, AdminFilterType.BEFORE); - String script = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\", \"editheader\"];\n\n" + String script = "require [" + SoapToSieve.requireCommon + ", \"editheader\"];\n\n" + "# rule1\n" + "replaceheader :newname \"X-Test-Header-New\" :newvalue \"[test] ${1}\" :count \"ge\" :comparator \"i;ascii-numeric\" \"X-Test-Header\" \"2\";\n"; Assert.assertEquals(script, account.getAdminSieveScriptBefore()); } -} \ No newline at end of file +} diff --git a/store/src/java-test/com/zimbra/cs/service/mail/ModifyFilterRulesTest.java b/store/src/java-test/com/zimbra/cs/service/mail/ModifyFilterRulesTest.java index a34472448e9..149b9b570b8 100644 --- a/store/src/java-test/com/zimbra/cs/service/mail/ModifyFilterRulesTest.java +++ b/store/src/java-test/com/zimbra/cs/service/mail/ModifyFilterRulesTest.java @@ -40,6 +40,7 @@ import com.zimbra.cs.account.MockProvisioning; import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.filter.RuleManager; +import com.zimbra.cs.filter.SoapToSieve; import com.zimbra.cs.mailbox.MailboxTestUtil; import com.zimbra.soap.mail.type.FilterAction; import com.zimbra.soap.mail.type.FilterRule; @@ -126,7 +127,7 @@ public void testBug71036_NonNestedIfSingleRule() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [" + SoapToSieve.requireCommon + "];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (header :contains [\"subject\"] \"important\") {\n"; expectedScript += " fileinto \"Junk\";\n"; @@ -186,7 +187,7 @@ public void testBug71036_MultiNestedIfSingleRule() throws Exception { fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [" + SoapToSieve.requireCommon + "];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (header :contains [\"subject\"] \"important\") {\n"; expectedScript += " if anyof (header :is [\"subject\"] \"confifential\") {\n"; @@ -281,7 +282,7 @@ public void testBug71036_NestedIfMultiRulesWithMultiConditions() throws Exceptio fail("This test is expected not to throw exception. "); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [" + SoapToSieve.requireCommon + "];\n\n"; expectedScript += "# Test1\n"; expectedScript += "if anyof (header :contains [\"Subject\"] \"important\") {\n"; expectedScript += " if allof (header :is [\"Subject\"] \"confifential\",\n"; @@ -504,7 +505,7 @@ public void testFilterVariables() { Element request = Element.parseXML(xml); new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(account)); - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n" + + String expectedScript = "require [" + SoapToSieve.requireCommon + "];\n" + "\n" + "# t60\n" + "set \"var\" \"testTag\";\n" + @@ -566,7 +567,7 @@ public void testFilterVariablesForMatchVariables() { Element request = Element.parseXML(xml); new ModifyFilterRules().handle(request, ServiceTestUtil.getRequestContext(account)); - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n" + + String expectedScript = "require [" + SoapToSieve.requireCommon + "];\n" + "\n" + "# t60\n" + "set \"var\" \"testTag\";\n" + @@ -697,7 +698,7 @@ public void testZCS1173SingleIfNoAllofAnyofRule() throws Exception { fail("This test is expected not to throw exception. " + e); } - String expectedScript = "require [\"fileinto\", \"copy\", \"reject\", \"tag\", \"flag\", \"variables\", \"log\", \"enotify\"];\n\n"; + String expectedScript = "require [" + SoapToSieve.requireCommon + "];\n\n"; expectedScript += "# null\n"; expectedScript += "if allof (header :contains [\"subject\"] \"123\",\n"; expectedScript += " header :contains [\"X-Header\"] \"456\") {\n"; From 9479167abcee63e882d079ddb4f99210ab8f0825 Mon Sep 17 00:00:00 2001 From: Sneha Patil Date: Mon, 18 Sep 2017 16:30:15 +0530 Subject: [PATCH 077/142] ZCS-2730:adding resolve api-field-description --- .../zimbra/soap/mail/message/RestoreContactsRequest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java index c5848e118d6..c8c8d6ddf6e 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/RestoreContactsRequest.java @@ -41,7 +41,14 @@ public class RestoreContactsRequest { /** * @zm-api-field-tag resolve - * @zm-api-field-description restore resolve action + * @zm-api-field-description Restore resolve action - one of ignore|modify|replace|reset
+ * Default value - reset
+ *
    + *
  • ignore - In case of conflict, ignore the existing contact. Create new contact from backup file. + *
  • modify - In case of conflict, merge the existing contact with contact in backup file. + *
  • replace - In case of conflict, replace the existing contact with contact in backup file. + *
  • reset - Delete all existing contacts and restore contacts from backup file. + *
*/ @XmlAttribute(name=MailConstants.A_CONTACTS_RESTORE_RESOLVE /* resolve */, required=false) private Resolve resolve; From 0722cee8ac3e9aa7de0357ace8ccf85d9873e1ce Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Fri, 15 Sep 2017 14:28:44 -0700 Subject: [PATCH 078/142] allow oauth tokens in dataSource objects --- .../java/com/zimbra/client/ZDataSource.java | 33 +++++++++++++++++++ .../soap/account/type/AccountDataSource.java | 33 +++++++++++++++++++ store/conf/attrs/zimbra-attrs.xml | 8 ++--- .../unittest/server/TestDataSourceServer.java | 16 ++++++++- 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZDataSource.java b/client/src/java/com/zimbra/client/ZDataSource.java index 4f6092de974..b269ade0dea 100644 --- a/client/src/java/com/zimbra/client/ZDataSource.java +++ b/client/src/java/com/zimbra/client/ZDataSource.java @@ -121,6 +121,27 @@ public ZDataSource setRefreshTokenURL(String val) { return this; } + public ZDataSource setOAuthToken(String val) { + if(data != null) { + data.setOAuthToken(val); + } + return this; + } + + public ZDataSource setClientId(String val) { + if(data != null) { + data.setClientId(val); + } + return this; + } + + public ZDataSource setClientSecret(String val) { + if(data != null) { + data.setClientSecret(val); + } + return this; + } + public String getRefreshToken() { return data == null ? null : data.getRefreshToken(); } @@ -128,4 +149,16 @@ public String getRefreshToken() { public String getRefreshTokenUrl() { return data == null ? null : data.getRefreshTokenUrl(); } + + public String getOAuthToken() { + return data == null ? null : data.getOAuthToken(); + } + + public String getClientId() { + return data == null ? null : data.getClientId(); + } + + public String getClientSecret() { + return data == null ? null : data.getClientSecret(); + } } diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java index 7b6176de2ab..382e4a988b8 100644 --- a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java +++ b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java @@ -209,6 +209,13 @@ public class AccountDataSource @XmlElement(name=MailConstants.E_ATTRIBUTE /* a */, required=false) private List attributes = Lists.newArrayList(); + /** + * @zm-api-field-tag data-source-oauthToken + * @zm-api-field-description oauthToken for data source + */ + @XmlAttribute(name=MailConstants.A_DS_OAUTH_TOKEN /* oauthToken */, required=false) + private String oauthToken; + /** * @zm-api-field-tag data-source-refreshToken * @zm-api-field-description refresh token for refreshing data source oauth token @@ -223,6 +230,20 @@ public class AccountDataSource @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) private String refreshTokenUrl; + /** + * @zm-api-field-tag data-source-clientId + * @zm-api-field-description client Id for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_CLIENT_ID /* clientId */, required = false) + private String clientId; + + /** + * @zm-api-field-tag data-source-clientSecret + * @zm-api-field-description client secret for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_CLIENT_SECRET /* clientSecret */, required = false) + private String clientSecret; + public AccountDataSource() { } @@ -370,12 +391,21 @@ public ConnectionType getConnectionType() { public void setConnectionType(ConnectionType connectionType) { this.adsConnectionType = AdsConnectionType.CT_TO_ACT.apply(connectionType); } + public void setOAuthToken(String oauthToken) { this.oauthToken = oauthToken; } + public String getOAuthToken() { return oauthToken; } + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } public String getRefreshToken() { return refreshToken; } public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } public String getRefreshTokenUrl() { return refreshTokenUrl; } + public void setClientId(String clientId) { this.clientId = clientId; } + public String getClientId() { return clientId; } + + public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } + public String getClientSecret() { return clientSecret; } + public Objects.ToStringHelper addToStringInfo( Objects.ToStringHelper helper) { return helper @@ -400,6 +430,9 @@ public Objects.ToStringHelper addToStringInfo( .add("importClass", importClass) .add("failingSince", failingSince) .add("lastError", lastError) + .add("oauthToken", oauthToken) + .add("clientId", clientId) + .add("clientSecret", clientSecret) .add("refreshToken", refreshToken) .add("refreshTokenUrl", refreshTokenUrl) .add("attributes", attributes); diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index 627098d9133..f6bd6339e03 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -8944,19 +8944,19 @@ TODO: delete them permanently from here Subject prefix for the spam training messages used to sent to the zimbraSpamIsSpamAccount/zimbraSpamIsNotSpamAccount account.
- + Client Id for OAuth token - + Client Secret for OAuth token - + Refresh token for authentication using OAuth - + Url for refreshing OAuth Token diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index 532cb68ff46..ed5a42ec844 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -65,10 +65,18 @@ public void testCustomDS() throws Exception { attrs.add(stringAttr); attrs.add(jsonAttr); attrs.add(colonAttr); + String clientId = "someClientID"; + String clientSecret = "someSecret"; + String token = "oAuthToken"; String refreshToken = "refresh-token"; String refreshTokenUrl = "https://this.is.where.you/?refresh=the&token"; ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); - ZDataSource zds = new ZDataSource(DSName, importClassName, attrs).setRefreshToken(refreshToken).setRefreshTokenURL(refreshTokenUrl); + ZDataSource zds = new ZDataSource(DSName, importClassName, attrs) + .setRefreshToken(refreshToken) + .setRefreshTokenURL(refreshTokenUrl) + .setClientId(clientId) + .setClientSecret(clientSecret) + .setOAuthToken(token); String dsId = zmbox.createDataSource(zds); assertNotNull("DataSource should have an ID", dsId); assertFalse("DataSource id should not be empty", dsId.isEmpty()); @@ -82,6 +90,12 @@ public void testCustomDS() throws Exception { assertEquals("expecting refresh token: " + refreshToken, refreshToken, ds.getRefreshToken()); assertNotNull("new DataSource should have a refresh token URL", ds.getRefreshTokenUrl()); assertEquals("expecting refresh token URL: " + refreshTokenUrl, refreshTokenUrl, ds.getRefreshTokenUrl()); + assertNotNull("new DataSource should have an OAuth token", ds.getOAuthToken()); + assertEquals("expecting OAuth token : " + token, token, ds.getOAuthToken()); + assertNotNull("new DataSource should have a client ID", ds.getClientId()); + assertEquals("expecting OAuth client ID : " + clientId, clientId, ds.getClientId()); + assertNotNull("new DataSource should have a client secretD", ds.getClientSecret()); + assertEquals("expecting OAuth client secret : " + clientSecret, clientSecret, ds.getClientSecret()); assertNotNull("new DataSource should have attributes", ds.getAttributes()); assertFalse("new DataSource attributes should not be empty", ds.getAttributes().isEmpty()); assertTrue("expecting to find attribute with value " + stringAttr, ds.getAttributes().contains(stringAttr)); From 781d1629442ba526b0a5048966d62252300f5492 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 18 Sep 2017 15:15:39 -0700 Subject: [PATCH 079/142] add support for oauth datasource had to refactor ZDataSource to avoid overriding common methods without a need (get/setName, get/setId) created OAuth-specific JAXB and ZClient classes similar to Pop3 and IMAP removed 'custom' datasource type which I added in previous pull request added a test specific to creating an oauth datasource --- .../com/zimbra/client/ZCalDataSource.java | 16 +-- .../java/com/zimbra/client/ZDataSource.java | 124 ++++-------------- .../com/zimbra/client/ZGetInfoResult.java | 3 + .../com/zimbra/client/ZImapDataSource.java | 14 +- .../src/java/com/zimbra/client/ZMailbox.java | 3 + .../com/zimbra/client/ZOAuthDataSource.java | 104 +++++++++++++++ .../com/zimbra/client/ZPop3DataSource.java | 25 ++-- .../com/zimbra/client/ZRssDataSource.java | 17 --- .../com/zimbra/common/soap/MailConstants.java | 1 + .../soap/account/message/GetInfoResponse.java | 3 +- .../soap/account/type/AccountDataSource.java | 57 +------- .../account/type/AccountOAuthDataSource.java | 40 ++++++ .../soap/admin/type/DataSourceType.java | 2 +- .../mail/message/CreateDataSourceRequest.java | 4 +- .../message/CreateDataSourceResponse.java | 3 + .../mail/message/GetDataSourcesResponse.java | 2 + .../soap/mail/type/CalDataSourceId.java | 1 - .../soap/mail/type/GalDataSourceId.java | 1 - .../soap/mail/type/ImapDataSourceId.java | 1 - .../zimbra/soap/mail/type/MailDataSource.java | 5 +- .../soap/mail/type/MailOAuthDataSource.java | 35 +++++ .../soap/mail/type/OAuthDataSourceId.java | 21 +++ .../mail/type/OAuthDataSourceNameOrId.java | 20 +++ .../soap/type/AccountWithModifications.java | 2 - .../com/zimbra/soap/type/DataSources.java | 9 ++ .../com/zimbra/soap/type/OAuthDataSource.java | 10 ++ .../cs/account/ldap/entry/LdapDataSource.java | 6 +- .../cs/datasource/DataSourceManager.java | 2 +- .../com/zimbra/cs/service/mail/ToXML.java | 13 +- .../unittest/server/TestDataSourceServer.java | 58 +++----- 30 files changed, 330 insertions(+), 272 deletions(-) create mode 100644 client/src/java/com/zimbra/client/ZOAuthDataSource.java create mode 100644 soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java create mode 100644 soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java create mode 100644 soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java create mode 100644 soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceNameOrId.java create mode 100644 soap/src/java/com/zimbra/soap/type/OAuthDataSource.java diff --git a/client/src/java/com/zimbra/client/ZCalDataSource.java b/client/src/java/com/zimbra/client/ZCalDataSource.java index fa08c57f818..8a5404ff0bf 100644 --- a/client/src/java/com/zimbra/client/ZCalDataSource.java +++ b/client/src/java/com/zimbra/client/ZCalDataSource.java @@ -20,7 +20,6 @@ import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; -import com.zimbra.common.util.SystemUtil; import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.soap.mail.type.CalDataSourceNameOrId; import com.zimbra.soap.mail.type.DataSourceNameOrId; @@ -31,8 +30,6 @@ public class ZCalDataSource extends ZDataSource implements ToZJSONObject { - private CalDataSource data; - public ZCalDataSource(String name, String folderId, boolean enabled) { data = DataSources.newCalDataSource(); data.setName(name); @@ -44,14 +41,7 @@ public ZCalDataSource(CalDataSource data) { this.data = DataSources.newCalDataSource(data); } - public String getId() { - return data.getId(); - } - - public String getName() { - return data.getName(); - } - + @Override public DataSourceType getType() { return DataSourceType.cal; } @@ -59,10 +49,6 @@ public DataSourceType getType() { public String getFolderId() { return data.getFolderId(); } - - public boolean isEnabled() { - return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); - } @Deprecated public Element toElement(Element parent) { diff --git a/client/src/java/com/zimbra/client/ZDataSource.java b/client/src/java/com/zimbra/client/ZDataSource.java index b269ade0dea..a8cf07638d7 100644 --- a/client/src/java/com/zimbra/client/ZDataSource.java +++ b/client/src/java/com/zimbra/client/ZDataSource.java @@ -17,54 +17,59 @@ package com.zimbra.client; -import java.util.List; - -import com.zimbra.soap.account.type.AccountDataSource; +import com.zimbra.common.util.SystemUtil; import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.soap.mail.type.DataSourceNameOrId; +import com.zimbra.soap.mail.type.MailDataSource; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSources; public class ZDataSource { - private AccountDataSource data; + protected DataSource data; public ZDataSource() { data = DataSources.newDataSource(); + data.setEnabled(false); } - public ZDataSource(String name) { + public ZDataSource(String name, boolean enabled) { data = DataSources.newDataSource(); data.setName(name); + data.setEnabled(enabled); } - public ZDataSource(String name, String importClass) { + public ZDataSource(String name, boolean enabled, Iterable attributes) { data = DataSources.newDataSource(); - data.setImportClass(importClass); - data.setName(name); - } - - public ZDataSource(String name, String importClass, Iterable attributes) { - data = DataSources.newDataSource(); - data.setImportClass(importClass); data.setAttributes(attributes); data.setName(name); + data.setEnabled(enabled); } public ZDataSource(DataSource data) { this.data = DataSources.newDataSource(data); } - public DataSourceType getType() { - return DataSourceType.custom; + public DataSource toJaxb() { + MailDataSource jaxbObject = new MailDataSource(); + jaxbObject.setId(data.getId()); + jaxbObject.setName(data.getName()); + jaxbObject.setEnabled(data.isEnabled()); + return jaxbObject; + } + + public DataSourceNameOrId toJaxbNameOrId() { + DataSourceNameOrId jaxbObject = DataSourceNameOrId.createForId(data.getId()); + return jaxbObject; } + public String getName() { return data.getName(); } public void setName(String name) { data.setName(name); } - public void setFolderId(String name) { - data.setFolderId(name); + public DataSourceType getType() { + return DataSourceType.unknown; } public String getId() { return data.getId(); @@ -78,87 +83,8 @@ public String getImportClass() { public void setImportClass(String importClass) { data.setImportClass(importClass); } - public List getAttributes() { - return data.getAttributes(); - } - public DataSource toJaxb() { - AccountDataSource jaxbObject = new AccountDataSource(); - jaxbObject.setId(data.getId()); - jaxbObject.setName(data.getName()); - jaxbObject.setHost(data.getHost()); - jaxbObject.setPort(data.getPort()); - jaxbObject.setUsername(data.getUsername()); - jaxbObject.setPassword(data.getPassword()); - jaxbObject.setFolderId(data.getFolderId()); - jaxbObject.setConnectionType(data.getConnectionType()); - jaxbObject.setImportOnly(data.isImportOnly()); - return jaxbObject; - } - - public DataSourceNameOrId toJaxbNameOrId() { - DataSourceNameOrId jaxbObject = DataSourceNameOrId.createForId(data.getId()); - return jaxbObject; - } - - public ZDataSource setAttributes(Iterable attrs) { - if(data != null) { - data.setAttributes(attrs); - } - return this; - } - - public ZDataSource setRefreshToken(String val) { - if(data != null) { - data.setRefreshToken(val); - } - return this; - } - - public ZDataSource setRefreshTokenURL(String val) { - if(data != null) { - data.setRefreshTokenUrl(val); - } - return this; - } - - public ZDataSource setOAuthToken(String val) { - if(data != null) { - data.setOAuthToken(val); - } - return this; - } - - public ZDataSource setClientId(String val) { - if(data != null) { - data.setClientId(val); - } - return this; - } - - public ZDataSource setClientSecret(String val) { - if(data != null) { - data.setClientSecret(val); - } - return this; - } - - public String getRefreshToken() { - return data == null ? null : data.getRefreshToken(); - } - - public String getRefreshTokenUrl() { - return data == null ? null : data.getRefreshTokenUrl(); - } - - public String getOAuthToken() { - return data == null ? null : data.getOAuthToken(); - } - - public String getClientId() { - return data == null ? null : data.getClientId(); - } - - public String getClientSecret() { - return data == null ? null : data.getClientSecret(); + public void setEnabled(boolean enabled) { data.setEnabled(enabled); } + public boolean isEnabled() { + return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); } } diff --git a/client/src/java/com/zimbra/client/ZGetInfoResult.java b/client/src/java/com/zimbra/client/ZGetInfoResult.java index 9d2f71963b7..4da1c35a130 100644 --- a/client/src/java/com/zimbra/client/ZGetInfoResult.java +++ b/client/src/java/com/zimbra/client/ZGetInfoResult.java @@ -41,6 +41,7 @@ import com.zimbra.soap.type.CalDataSource; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.ImapDataSource; +import com.zimbra.soap.type.OAuthDataSource; import com.zimbra.soap.type.Pop3DataSource; import com.zimbra.soap.type.RssDataSource; @@ -106,6 +107,8 @@ public List getDataSources() { newList.add(new ZCalDataSource((CalDataSource) ds)); } else if (ds instanceof RssDataSource) { newList.add(new ZRssDataSource((RssDataSource) ds)); + } else if (ds instanceof OAuthDataSource) { + newList.add(new ZOAuthDataSource((OAuthDataSource) ds)); } else { newList.add(new ZDataSource(ds)); } diff --git a/client/src/java/com/zimbra/client/ZImapDataSource.java b/client/src/java/com/zimbra/client/ZImapDataSource.java index f1fdad75a31..ccd503a163c 100644 --- a/client/src/java/com/zimbra/client/ZImapDataSource.java +++ b/client/src/java/com/zimbra/client/ZImapDataSource.java @@ -33,8 +33,6 @@ public class ZImapDataSource extends ZDataSource implements ToZJSONObject { - private ImapDataSource data; - public ZImapDataSource(ImapDataSource data) { this.data = DataSources.newImapDataSource(data); } @@ -111,17 +109,9 @@ public DataSourceNameOrId toJaxbNameOrId() { return jaxbObject; } + @Override public DataSourceType getType() { return DataSourceType.imap; } - public String getId() { return data.getId(); } - - public String getName() { return data.getName(); } - public void setName(String name) { data.setName(name); } - - public boolean isEnabled() { return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); } - - public void setEnabled(boolean enabled) { data.setEnabled(enabled); } - public String getHost() { return data.getHost(); } public void setHost(String host) { data.setHost(host); } @@ -130,7 +120,7 @@ public DataSourceNameOrId toJaxbNameOrId() { public String getUsername() { return data.getUsername(); } public void setUsername(String username) { data.setUsername(username); } - + public String getFolderId() { return data.getFolderId(); } public void setFolderId(String folderid) { data.setFolderId(folderid); } diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index 68c5e045626..bb3f670b60f 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -222,6 +222,7 @@ import com.zimbra.soap.type.CalDataSource; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.ImapDataSource; +import com.zimbra.soap.type.OAuthDataSource; import com.zimbra.soap.type.Pop3DataSource; import com.zimbra.soap.type.RssDataSource; import com.zimbra.soap.type.SearchSortBy; @@ -4709,6 +4710,8 @@ public List getAllDataSources() throws ServiceException { result.add(new ZCalDataSource((CalDataSource) ds)); } else if (ds instanceof RssDataSource) { result.add(new ZRssDataSource((RssDataSource) ds)); + } else if (ds instanceof OAuthDataSource) { + result.add(new ZOAuthDataSource((OAuthDataSource) ds)); } else { result.add(new ZDataSource(ds)); } diff --git a/client/src/java/com/zimbra/client/ZOAuthDataSource.java b/client/src/java/com/zimbra/client/ZOAuthDataSource.java new file mode 100644 index 00000000000..09844996ce3 --- /dev/null +++ b/client/src/java/com/zimbra/client/ZOAuthDataSource.java @@ -0,0 +1,104 @@ +package com.zimbra.client; + +import org.json.JSONException; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.soap.admin.type.DataSourceType; +import com.zimbra.soap.mail.type.DataSourceNameOrId; +import com.zimbra.soap.mail.type.MailOAuthDataSource; +import com.zimbra.soap.mail.type.OAuthDataSourceNameOrId; +import com.zimbra.soap.type.DataSource; +import com.zimbra.soap.type.DataSources; +import com.zimbra.soap.type.OAuthDataSource; + +public class ZOAuthDataSource extends ZDataSource implements ToZJSONObject { + public ZOAuthDataSource(OAuthDataSource data) { + this.data = DataSources.newOAuthDataSource(data); + } + + public ZOAuthDataSource(String name, boolean enabled, String refreshToken, String refreshTokenURL, String folderId, String importClass, boolean isImportOnly) + throws ServiceException { + data = DataSources.newOAuthDataSource(); + data.setName(name); + data.setEnabled(enabled); + ((OAuthDataSource)data).setRefreshToken(refreshToken); + ((OAuthDataSource)data).setRefreshTokenUrl(refreshTokenURL); + data.setImportClass(importClass); + try { + data.setFolderId(folderId); + } catch (NumberFormatException e) { + throw ServiceException.INVALID_REQUEST("Invalid folder id", e); + } + data.setImportOnly(isImportOnly); + } + + private OAuthDataSource getData() { + return ((OAuthDataSource)data); + } + + @Override + public DataSource toJaxb() { + MailOAuthDataSource jaxbObject = new MailOAuthDataSource(); + jaxbObject.setId(data.getId()); + jaxbObject.setName(data.getName()); + jaxbObject.setRefreshToken(getData().getRefreshToken()); + jaxbObject.setRefreshTokenUrl(getData().getRefreshTokenUrl()); + jaxbObject.setFolderId(data.getFolderId()); + jaxbObject.setImportOnly(data.isImportOnly()); + jaxbObject.setImportClass(data.getImportClass()); + jaxbObject.setEnabled(data.isEnabled()); + return jaxbObject; + } + + @Override + public DataSourceNameOrId toJaxbNameOrId() { + OAuthDataSourceNameOrId jaxbObject = OAuthDataSourceNameOrId.createForId(data.getId()); + return jaxbObject; + } + + @Override + public DataSourceType getType() { return DataSourceType.oauth; } + + @Override + public ZJSONObject toZJSONObject() throws JSONException { + ZJSONObject zjo = new ZJSONObject(); + zjo.put("id", data.getId()); + zjo.put("name", data.getName()); + zjo.put("enabled", data.isEnabled()); + zjo.put("refreshToken", getData().getRefreshToken()); + zjo.put("refreshTokenUrl", getData().getRefreshTokenUrl()); + zjo.put("folderId", data.getFolderId()); + zjo.put("importOnly", data.isImportOnly()); + return zjo; + } + public String getFolderId() { return data.getFolderId(); } + public ZOAuthDataSource setFolderId(String folderid) { + data.setFolderId(folderid); + return this; + } + + public ZOAuthDataSource setRefreshToken(String val) { + getData().setRefreshToken(val); + return this; + } + + public ZOAuthDataSource setRefreshTokenURL(String val) { + getData().setRefreshTokenUrl(val); + return this; + } + + public String getRefreshToken() { + return getData().getRefreshToken(); + } + + public String getRefreshTokenUrl() { + return getData().getRefreshTokenUrl(); + } + + public String getImportClass() { + return data.getImportClass(); + } + public void setImportClass(String importClass) { + data.setImportClass(importClass); + } +} diff --git a/client/src/java/com/zimbra/client/ZPop3DataSource.java b/client/src/java/com/zimbra/client/ZPop3DataSource.java index 7c82f946f85..795d8e981a3 100644 --- a/client/src/java/com/zimbra/client/ZPop3DataSource.java +++ b/client/src/java/com/zimbra/client/ZPop3DataSource.java @@ -35,8 +35,6 @@ public class ZPop3DataSource extends ZDataSource implements ToZJSONObject { - private Pop3DataSource data; - public ZPop3DataSource(Pop3DataSource data) { this.data = DataSources.newPop3DataSource(data); } @@ -68,7 +66,7 @@ public Element toElement(Element parent) { src.addAttribute(MailConstants.A_DS_PASSWORD, data.getPassword()); src.addAttribute(MailConstants.A_FOLDER, data.getFolderId()); src.addAttribute(MailConstants.A_DS_CONNECTION_TYPE, data.getConnectionType().name()); - src.addAttribute(MailConstants.A_DS_LEAVE_ON_SERVER, data.isLeaveOnServer()); + src.addAttribute(MailConstants.A_DS_LEAVE_ON_SERVER, getData().isLeaveOnServer()); ZimbraLog.test.info("XXX bburtin: " + src.prettyPrint()); return src; } @@ -91,7 +89,7 @@ public DataSource toJaxb() { jaxbObject.setPassword(data.getPassword()); jaxbObject.setFolderId(data.getFolderId()); jaxbObject.setConnectionType(data.getConnectionType()); - jaxbObject.setLeaveOnServer(data.isLeaveOnServer()); + jaxbObject.setLeaveOnServer(getData().isLeaveOnServer()); jaxbObject.setEnabled(data.isEnabled()); return jaxbObject; } @@ -101,17 +99,12 @@ public DataSourceNameOrId toJaxbNameOrId() { Pop3DataSourceNameOrId jaxbObject = Pop3DataSourceNameOrId.createForId(data.getId()); return jaxbObject; } - + private Pop3DataSource getData() { + return ((Pop3DataSource)data); + } + @Override public DataSourceType getType() { return DataSourceType.pop3; } - public String getId() { return data.getId(); } - - public String getName() { return data.getName(); } - public void setName(String name) { data.setName(name); } - - public boolean isEnabled() { return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); } - public void setEnabled(boolean enabled) { data.setEnabled(enabled); } - public String getHost() { return data.getHost(); } public void setHost(String host) { data.setHost(host); } @@ -134,11 +127,11 @@ public void setConnectionType(ConnectionType connectionType) { } public boolean leaveOnServer() { - Boolean val = data.isLeaveOnServer(); + Boolean val = getData().isLeaveOnServer(); return (val == null ? true : val); } - public void setLeaveOnServer(boolean leaveOnServer) { data.setLeaveOnServer(leaveOnServer); } + public void setLeaveOnServer(boolean leaveOnServer) { getData().setLeaveOnServer(leaveOnServer); } public ZJSONObject toZJSONObject() throws JSONException { ZJSONObject zjo = new ZJSONObject(); @@ -150,7 +143,7 @@ public ZJSONObject toZJSONObject() throws JSONException { zjo.put("username", data.getUsername()); zjo.put("folderId", data.getFolderId()); zjo.put("connectionType", data.getConnectionType().toString()); - zjo.put("leaveOnServer", data.isLeaveOnServer()); + zjo.put("leaveOnServer", getData().isLeaveOnServer()); return zjo; } diff --git a/client/src/java/com/zimbra/client/ZRssDataSource.java b/client/src/java/com/zimbra/client/ZRssDataSource.java index 27bcfa8ab55..d54c18ede36 100644 --- a/client/src/java/com/zimbra/client/ZRssDataSource.java +++ b/client/src/java/com/zimbra/client/ZRssDataSource.java @@ -20,7 +20,6 @@ import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; -import com.zimbra.common.util.SystemUtil; import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.soap.mail.type.DataSourceNameOrId; import com.zimbra.soap.mail.type.MailRssDataSource; @@ -32,8 +31,6 @@ public class ZRssDataSource extends ZDataSource implements ToZJSONObject { - private RssDataSource data; - public ZRssDataSource(String name, String folderId, boolean enabled) { data = DataSources.newRssDataSource(); data.setName(name); @@ -45,16 +42,6 @@ public ZRssDataSource(RssDataSource data) { this.data = DataSources.newRssDataSource(data); } - @Override - public String getId() { - return data.getId(); - } - - @Override - public String getName() { - return data.getName(); - } - @Override public DataSourceType getType() { return DataSourceType.rss; @@ -64,10 +51,6 @@ public String getFolderId() { return data.getFolderId(); } - public boolean isEnabled() { - return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); - } - @Deprecated public Element toElement(Element parent) { Element src = parent.addElement(MailConstants.E_DS_RSS); diff --git a/common/src/java/com/zimbra/common/soap/MailConstants.java b/common/src/java/com/zimbra/common/soap/MailConstants.java index 82f6bd6379b..37697544672 100644 --- a/common/src/java/com/zimbra/common/soap/MailConstants.java +++ b/common/src/java/com/zimbra/common/soap/MailConstants.java @@ -1174,6 +1174,7 @@ private MailConstants() { public static final String E_DS_RSS = "rss"; public static final String E_DS_GAL = "gal"; public static final String E_DS_CAL = "cal"; + public static final String E_DS_OAUTH = "oauth"; public static final String E_DS_UNKNOWN = "unknown"; public static final String E_DS_LAST_ERROR = "lastError"; public static final String A_DS_IS_ENABLED = "isEnabled"; diff --git a/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java b/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java index ea9100be129..3560093b685 100644 --- a/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java +++ b/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java @@ -42,6 +42,7 @@ import com.zimbra.soap.account.type.AccountDataSource; import com.zimbra.soap.account.type.AccountGalDataSource; import com.zimbra.soap.account.type.AccountImapDataSource; +import com.zimbra.soap.account.type.AccountOAuthDataSource; import com.zimbra.soap.account.type.AccountPop3DataSource; import com.zimbra.soap.account.type.AccountRssDataSource; import com.zimbra.soap.account.type.AccountUnknownDataSource; @@ -249,7 +250,7 @@ public final class GetInfoResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=AccountRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=AccountGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=AccountCalDataSource.class), - @XmlElement(name=MailConstants.E_DS /* dsrc */, type=AccountDataSource.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=AccountOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=AccountUnknownDataSource.class) }) private List dataSources = Lists.newArrayList(); diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java index 382e4a988b8..daa67946ef6 100644 --- a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java +++ b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java @@ -38,8 +38,7 @@ @XmlAccessorType(XmlAccessType.NONE) @XmlType(propOrder = {"lastError", "attributes"}) @XmlRootElement -public class AccountDataSource -implements DataSource { +public class AccountDataSource implements DataSource { /** * @zm-api-field-tag data-source-id @@ -209,41 +208,6 @@ public class AccountDataSource @XmlElement(name=MailConstants.E_ATTRIBUTE /* a */, required=false) private List attributes = Lists.newArrayList(); - /** - * @zm-api-field-tag data-source-oauthToken - * @zm-api-field-description oauthToken for data source - */ - @XmlAttribute(name=MailConstants.A_DS_OAUTH_TOKEN /* oauthToken */, required=false) - private String oauthToken; - - /** - * @zm-api-field-tag data-source-refreshToken - * @zm-api-field-description refresh token for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) - private String refreshToken; - - /** - * @zm-api-field-tag data-source-refreshTokenUrl - * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) - private String refreshTokenUrl; - - /** - * @zm-api-field-tag data-source-clientId - * @zm-api-field-description client Id for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_CLIENT_ID /* clientId */, required = false) - private String clientId; - - /** - * @zm-api-field-tag data-source-clientSecret - * @zm-api-field-description client secret for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_CLIENT_SECRET /* clientSecret */, required = false) - private String clientSecret; - public AccountDataSource() { } @@ -391,20 +355,6 @@ public ConnectionType getConnectionType() { public void setConnectionType(ConnectionType connectionType) { this.adsConnectionType = AdsConnectionType.CT_TO_ACT.apply(connectionType); } - public void setOAuthToken(String oauthToken) { this.oauthToken = oauthToken; } - public String getOAuthToken() { return oauthToken; } - - public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } - public String getRefreshToken() { return refreshToken; } - - public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } - public String getRefreshTokenUrl() { return refreshTokenUrl; } - - public void setClientId(String clientId) { this.clientId = clientId; } - public String getClientId() { return clientId; } - - public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } - public String getClientSecret() { return clientSecret; } public Objects.ToStringHelper addToStringInfo( Objects.ToStringHelper helper) { @@ -430,11 +380,6 @@ public Objects.ToStringHelper addToStringInfo( .add("importClass", importClass) .add("failingSince", failingSince) .add("lastError", lastError) - .add("oauthToken", oauthToken) - .add("clientId", clientId) - .add("clientSecret", clientSecret) - .add("refreshToken", refreshToken) - .add("refreshTokenUrl", refreshTokenUrl) .add("attributes", attributes); } diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java new file mode 100644 index 00000000000..43b9eb08d2f --- /dev/null +++ b/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java @@ -0,0 +1,40 @@ +package com.zimbra.soap.account.type; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlType; + +import com.zimbra.common.soap.MailConstants; +import com.zimbra.soap.type.OAuthDataSource; +@XmlType(propOrder = {}) +public class AccountOAuthDataSource extends AccountDataSource implements OAuthDataSource { + public AccountOAuthDataSource() { + } + + public AccountOAuthDataSource(OAuthDataSource data) { + super(data); + refreshToken = data.getRefreshToken(); + refreshTokenUrl = data.getRefreshTokenUrl(); + } + /** + * @zm-api-field-tag data-source-refreshToken + * @zm-api-field-description refresh token for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) + private String refreshToken; + + /** + * @zm-api-field-tag data-source-refreshTokenUrl + * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) + private String refreshTokenUrl; + + + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } + public String getRefreshToken() { return refreshToken; } + + public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } + public String getRefreshTokenUrl() { return refreshTokenUrl; } + + +} diff --git a/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java b/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java index 8bf5b08a300..7134c58ef13 100644 --- a/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java +++ b/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java @@ -26,7 +26,7 @@ @XmlEnum public enum DataSourceType { // case must match protocol - pop3, imap, caldav, contacts, yab, rss, cal, gal, xsync, tagmap, custom; + pop3, imap, caldav, contacts, yab, rss, cal, gal, xsync, tagmap, oauth, unknown; public static DataSourceType fromString(String s) throws ServiceException { try { diff --git a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java index a3b40fbc9dc..866c59031f5 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java @@ -17,18 +17,19 @@ package com.zimbra.soap.mail.message; -import com.google.common.base.Objects; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; +import com.google.common.base.Objects; import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.mail.type.MailCalDataSource; import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; +import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -56,6 +57,7 @@ public class CreateDataSourceRequest { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private DataSource dataSource; diff --git a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java index ca84c3cf187..e824090e177 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java @@ -18,6 +18,7 @@ package com.zimbra.soap.mail.message; import com.google.common.base.Objects; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; @@ -30,6 +31,7 @@ import com.zimbra.soap.mail.type.CaldavDataSourceId; import com.zimbra.soap.mail.type.GalDataSourceId; import com.zimbra.soap.mail.type.ImapDataSourceId; +import com.zimbra.soap.mail.type.OAuthDataSourceId; import com.zimbra.soap.mail.type.Pop3DataSourceId; import com.zimbra.soap.mail.type.RssDataSourceId; import com.zimbra.soap.mail.type.UnknownDataSourceId; @@ -52,6 +54,7 @@ public class CreateDataSourceResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=RssDataSourceId.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=GalDataSourceId.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=CalDataSourceId.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=OAuthDataSourceId.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=UnknownDataSourceId.class) }) private Id dataSource; diff --git a/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java b/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java index 1d69ae015d7..62a000d9177 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java @@ -35,6 +35,7 @@ import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; +import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -56,6 +57,7 @@ public class GetDataSourcesResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* custom */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private List dataSources = Lists.newArrayList(); diff --git a/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceId.java b/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceId.java index adff1519b25..6d84f62eb72 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceId.java +++ b/soap/src/java/com/zimbra/soap/mail/type/CalDataSourceId.java @@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; -import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.type.Id; @XmlAccessorType(XmlAccessType.NONE) diff --git a/soap/src/java/com/zimbra/soap/mail/type/GalDataSourceId.java b/soap/src/java/com/zimbra/soap/mail/type/GalDataSourceId.java index 63cfd37216b..e60366f8661 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/GalDataSourceId.java +++ b/soap/src/java/com/zimbra/soap/mail/type/GalDataSourceId.java @@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; -import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.type.Id; @XmlAccessorType(XmlAccessType.NONE) diff --git a/soap/src/java/com/zimbra/soap/mail/type/ImapDataSourceId.java b/soap/src/java/com/zimbra/soap/mail/type/ImapDataSourceId.java index bb1a9d67135..6081cf079a9 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/ImapDataSourceId.java +++ b/soap/src/java/com/zimbra/soap/mail/type/ImapDataSourceId.java @@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; -import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.type.Id; @XmlAccessorType(XmlAccessType.NONE) diff --git a/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java b/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java index 1d4377d7198..42b81866cc0 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java +++ b/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java @@ -36,10 +36,7 @@ @XmlAccessorType(XmlAccessType.NONE) @XmlType(propOrder = {"lastError", "attributes"}) -abstract public class MailDataSource -implements DataSource { - - +public class MailDataSource implements DataSource { /** * @zm-api-field-tag data-source-id * @zm-api-field-description Unique ID for data source diff --git a/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java b/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java new file mode 100644 index 00000000000..fe5cae56771 --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java @@ -0,0 +1,35 @@ +package com.zimbra.soap.mail.type; + +import javax.xml.bind.annotation.XmlAttribute; + +import com.zimbra.common.soap.MailConstants; +import com.zimbra.soap.type.OAuthDataSource; + +public class MailOAuthDataSource extends MailDataSource implements OAuthDataSource { + public MailOAuthDataSource() { + } + + public MailOAuthDataSource(OAuthDataSource data) { + super(data); + } + + /** + * @zm-api-field-tag data-source-refreshToken + * @zm-api-field-description refresh token for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) + private String refreshToken; + + /** + * @zm-api-field-tag data-source-refreshTokenUrl + * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) + private String refreshTokenUrl; + + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } + public String getRefreshToken() { return refreshToken; } + + public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } + public String getRefreshTokenUrl() { return refreshTokenUrl; } +} diff --git a/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java b/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java new file mode 100644 index 00000000000..0b2fed2b034 --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java @@ -0,0 +1,21 @@ +package com.zimbra.soap.mail.type; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; + +import com.zimbra.soap.type.Id; + +@XmlAccessorType(XmlAccessType.NONE) +public class OAuthDataSourceId extends Id { + /** + * no-argument constructor wanted by JAXB + */ + @SuppressWarnings("unused") + protected OAuthDataSourceId() { + this((String) null); + } + + OAuthDataSourceId(String id) { + super(id); + } +} diff --git a/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceNameOrId.java b/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceNameOrId.java new file mode 100644 index 00000000000..e91d10dd159 --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceNameOrId.java @@ -0,0 +1,20 @@ +package com.zimbra.soap.mail.type; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; + +@XmlAccessorType(XmlAccessType.NONE) +public class OAuthDataSourceNameOrId extends DataSourceNameOrId { + + public static OAuthDataSourceNameOrId createForName(String name) { + OAuthDataSourceNameOrId obj = new OAuthDataSourceNameOrId(); + obj.setName(name); + return obj; + } + + public static OAuthDataSourceNameOrId createForId(String id) { + OAuthDataSourceNameOrId obj = new OAuthDataSourceNameOrId(); + obj.setId(id); + return obj; + } +} diff --git a/soap/src/java/com/zimbra/soap/type/AccountWithModifications.java b/soap/src/java/com/zimbra/soap/type/AccountWithModifications.java index c0d17d9e979..e1034708ea0 100644 --- a/soap/src/java/com/zimbra/soap/type/AccountWithModifications.java +++ b/soap/src/java/com/zimbra/soap/type/AccountWithModifications.java @@ -18,7 +18,6 @@ package com.zimbra.soap.type; import java.util.Collection; -import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -26,7 +25,6 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import com.google.common.collect.Lists; import com.zimbra.common.soap.AdminConstants; import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.mail.type.PendingFolderModifications; diff --git a/soap/src/java/com/zimbra/soap/type/DataSources.java b/soap/src/java/com/zimbra/soap/type/DataSources.java index 34578f7d5e3..9638a9bc2bb 100644 --- a/soap/src/java/com/zimbra/soap/type/DataSources.java +++ b/soap/src/java/com/zimbra/soap/type/DataSources.java @@ -20,6 +20,7 @@ import com.zimbra.soap.account.type.AccountCalDataSource; import com.zimbra.soap.account.type.AccountDataSource; import com.zimbra.soap.account.type.AccountImapDataSource; +import com.zimbra.soap.account.type.AccountOAuthDataSource; import com.zimbra.soap.account.type.AccountPop3DataSource; import com.zimbra.soap.account.type.AccountRssDataSource; @@ -49,6 +50,14 @@ public static ImapDataSource newImapDataSource(ImapDataSource data) { return new AccountImapDataSource(data); } + public static OAuthDataSource newOAuthDataSource() { + return new AccountOAuthDataSource(); + } + + public static OAuthDataSource newOAuthDataSource(OAuthDataSource data) { + return new AccountOAuthDataSource(data); + } + public static RssDataSource newRssDataSource() { return new AccountRssDataSource(); } diff --git a/soap/src/java/com/zimbra/soap/type/OAuthDataSource.java b/soap/src/java/com/zimbra/soap/type/OAuthDataSource.java new file mode 100644 index 00000000000..3c81e8ec95b --- /dev/null +++ b/soap/src/java/com/zimbra/soap/type/OAuthDataSource.java @@ -0,0 +1,10 @@ +package com.zimbra.soap.type; + +public interface OAuthDataSource extends DataSource { + public void setRefreshToken(String refreshToken); + public String getRefreshToken(); + + public void setRefreshTokenUrl(String refreshTokenUrl); + public String getRefreshTokenUrl(); + +} diff --git a/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java b/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java index 6b74f49bd3e..f7be1a6b1f9 100644 --- a/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java +++ b/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java @@ -62,10 +62,8 @@ public static String getObjectClass(DataSourceType type) { return AttributeClass.OC_zimbraRssDataSource; case gal: return AttributeClass.OC_zimbraGalDataSource; - case custom: - return AttributeClass.OC_zimbraDataSource; default: - return null; + return AttributeClass.OC_zimbraDataSource; } } @@ -88,7 +86,7 @@ else if (attr.contains(AttributeClass.OC_zimbraRssDataSource)) else if (attr.contains(AttributeClass.OC_zimbraGalDataSource)) return DataSourceType.gal; else if (attr.contains(AttributeClass.OC_zimbraDataSource)) - return DataSourceType.custom; + return DataSourceType.unknown; else throw ServiceException.FAILURE("unable to determine data source type from object class", null); } diff --git a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java index 91e9240d4a5..d85f236de04 100644 --- a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java +++ b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java @@ -220,7 +220,7 @@ public DataImport getDataImport(DataSource ds, boolean test) throws ServiceExcep } catch (Exception x) { ZimbraLog.datasource.warn("Failed instantiating xsync class: %s", ds, x); } - case custom: + case oauth: try { String className = ds.getDataSourceImportClassName(); if (className != null && className.length() > 0) { diff --git a/store/src/java/com/zimbra/cs/service/mail/ToXML.java b/store/src/java/com/zimbra/cs/service/mail/ToXML.java index e4fd476fe5c..b91c1680023 100644 --- a/store/src/java/com/zimbra/cs/service/mail/ToXML.java +++ b/store/src/java/com/zimbra/cs/service/mail/ToXML.java @@ -70,6 +70,7 @@ import com.zimbra.common.mime.MimeDetect; import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.Element.ContainerException; import com.zimbra.common.soap.HeaderConstants; import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.ArrayUtil; @@ -3126,7 +3127,15 @@ public static Element encodeDataSource(Element parent, DataSource ds) { if (ds.getSmtpUsername() != null) { m.addAttribute(MailConstants.A_DS_SMTP_USERNAME, ds.getSmtpUsername()); } - + if(ds.getDataSourceImportClassName() != null) { + m.addAttribute(MailConstants.A_DS_IMPORT_CLASS, ds.getDataSourceImportClassName()); + } + if(ds.getOauthRefreshToken() != null) { + m.addAttribute(MailConstants.A_DS_REFRESH_TOKEN, ds.getOauthRefreshToken()); + } + if(ds.getOauthRefreshTokenUrl() != null) { + m.addAttribute(MailConstants.A_DS_REFRESH_TOKEN_URL, ds.getOauthRefreshTokenUrl()); + } m.addAttribute(MailConstants.A_DS_EMAIL_ADDRESS, ds.getEmailAddress()); m.addAttribute(MailConstants.A_DS_USE_ADDRESS_FOR_FORWARD_REPLY, ds.useAddressForForwardReply()); m.addAttribute(MailConstants.A_DS_DEFAULT_SIGNATURE, ds.getDefaultSignature()); @@ -3163,6 +3172,8 @@ private static String getDsType(DataSource ds) { return MailConstants.E_DS_GAL; case cal: return MailConstants.E_DS_CAL; + case oauth: + return MailConstants.E_DS_OAUTH; default: return MailConstants.E_DS_UNKNOWN; } diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index ed5a42ec844..cd95419cf63 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -16,9 +16,11 @@ */ package com.zimbra.qa.unittest.server; -import static org.junit.Assert.*; - -import java.util.ArrayList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import org.junit.After; import org.junit.Before; @@ -30,6 +32,7 @@ import com.zimbra.client.ZFolder; import com.zimbra.client.ZImapDataSource; import com.zimbra.client.ZMailbox; +import com.zimbra.client.ZOAuthDataSource; import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.account.Server; import com.zimbra.cs.datasource.DataSourceManager; @@ -55,52 +58,29 @@ public void setUp() throws Exception { } @Test - public void testCustomDS() throws Exception { + public void testOAuthDS() throws Exception { String DSName = "testCustomDS"; String importClassName = "some.data.source.ClassName"; - ArrayList attrs = new ArrayList(); - String stringAttr = "somestringattr"; - String jsonAttr = "{\"someVar\":\"someValue\"}"; - String colonAttr = "someProp:someVal"; - attrs.add(stringAttr); - attrs.add(jsonAttr); - attrs.add(colonAttr); - String clientId = "someClientID"; - String clientSecret = "someSecret"; - String token = "oAuthToken"; String refreshToken = "refresh-token"; String refreshTokenUrl = "https://this.is.where.you/?refresh=the&token"; ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); - ZDataSource zds = new ZDataSource(DSName, importClassName, attrs) - .setRefreshToken(refreshToken) - .setRefreshTokenURL(refreshTokenUrl) - .setClientId(clientId) - .setClientSecret(clientSecret) - .setOAuthToken(token); + ZFolder folder = TestUtil.createFolder(zmbox, "/testCustomDS"); + ZOAuthDataSource zds = new ZOAuthDataSource(DSName, true, refreshToken, refreshTokenUrl, folder.getId(), importClassName, true); String dsId = zmbox.createDataSource(zds); assertNotNull("DataSource should have an ID", dsId); assertFalse("DataSource id should not be empty", dsId.isEmpty()); ZDataSource ds = TestUtil.getDataSource(zmbox, DSName); assertNotNull("should retrieve a non-null DataSource", ds); - assertNotNull("DataSource should have a name", ds.getName()); - assertEquals("Data source name should be " + DSName, ds.getName(), DSName); - assertNotNull("new DataSource should have an import class", ds.getImportClass()); - assertEquals("expecting import class: " + importClassName, importClassName, ds.getImportClass()); - assertNotNull("new DataSource should have a refresh token", ds.getRefreshToken()); - assertEquals("expecting refresh token: " + refreshToken, refreshToken, ds.getRefreshToken()); - assertNotNull("new DataSource should have a refresh token URL", ds.getRefreshTokenUrl()); - assertEquals("expecting refresh token URL: " + refreshTokenUrl, refreshTokenUrl, ds.getRefreshTokenUrl()); - assertNotNull("new DataSource should have an OAuth token", ds.getOAuthToken()); - assertEquals("expecting OAuth token : " + token, token, ds.getOAuthToken()); - assertNotNull("new DataSource should have a client ID", ds.getClientId()); - assertEquals("expecting OAuth client ID : " + clientId, clientId, ds.getClientId()); - assertNotNull("new DataSource should have a client secretD", ds.getClientSecret()); - assertEquals("expecting OAuth client secret : " + clientSecret, clientSecret, ds.getClientSecret()); - assertNotNull("new DataSource should have attributes", ds.getAttributes()); - assertFalse("new DataSource attributes should not be empty", ds.getAttributes().isEmpty()); - assertTrue("expecting to find attribute with value " + stringAttr, ds.getAttributes().contains(stringAttr)); - assertTrue("expecting to find attribute with value " + jsonAttr, ds.getAttributes().contains(jsonAttr)); - assertTrue("expecting to find attribute with value " + colonAttr, ds.getAttributes().contains(colonAttr)); + assertTrue("expecting ZOAuthDataSource", ds instanceof ZOAuthDataSource); + ZOAuthDataSource oads = (ZOAuthDataSource)ds; + assertNotNull("DataSource should have a name", oads.getName()); + assertEquals("Data source name should be " + DSName, oads.getName(), DSName); + assertNotNull("new DataSource should have an import class", oads.getImportClass()); + assertEquals("expecting import class: " + importClassName, importClassName, oads.getImportClass()); + assertNotNull("new DataSource should have a refresh token", oads.getRefreshToken()); + assertEquals("expecting refresh token: " + refreshToken, refreshToken, oads.getRefreshToken()); + assertNotNull("new DataSource should have a refresh token URL", oads.getRefreshTokenUrl()); + assertEquals("expecting refresh token URL: " + refreshTokenUrl, refreshTokenUrl, oads.getRefreshTokenUrl()); } @Test From 7881b16a559612bcaa39cf4be47b5980379b4f20 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 18 Sep 2017 15:34:56 -0700 Subject: [PATCH 080/142] add default values for optional datasource attributes --- .../java/com/zimbra/cs/service/mail/CreateDataSource.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/store/src/java/com/zimbra/cs/service/mail/CreateDataSource.java b/store/src/java/com/zimbra/cs/service/mail/CreateDataSource.java index 3ba059e20a4..20503ad92b4 100644 --- a/store/src/java/com/zimbra/cs/service/mail/CreateDataSource.java +++ b/store/src/java/com/zimbra/cs/service/mail/CreateDataSource.java @@ -87,10 +87,10 @@ public Element handle(Element request, Map context) LdapUtil.getLdapBooleanString(eDataSource.getAttributeBool(MailConstants.A_DS_IS_ENABLED))); dsAttrs.put(Provisioning.A_zimbraDataSourceImportOnly, LdapUtil.getLdapBooleanString(eDataSource.getAttributeBool(MailConstants.A_DS_IS_IMPORTONLY, false))); - dsAttrs.put(Provisioning.A_zimbraDataSourceHost, eDataSource.getAttribute(MailConstants.A_DS_HOST)); - dsAttrs.put(Provisioning.A_zimbraDataSourcePort, eDataSource.getAttribute(MailConstants.A_DS_PORT)); - dsAttrs.put(Provisioning.A_zimbraDataSourceConnectionType, eDataSource.getAttribute(MailConstants.A_DS_CONNECTION_TYPE)); - dsAttrs.put(Provisioning.A_zimbraDataSourceUsername, eDataSource.getAttribute(MailConstants.A_DS_USERNAME)); + dsAttrs.put(Provisioning.A_zimbraDataSourceHost, eDataSource.getAttribute(MailConstants.A_DS_HOST, null)); + dsAttrs.put(Provisioning.A_zimbraDataSourcePort, eDataSource.getAttribute(MailConstants.A_DS_PORT, null)); + dsAttrs.put(Provisioning.A_zimbraDataSourceConnectionType, eDataSource.getAttribute(MailConstants.A_DS_CONNECTION_TYPE, prov.getConfig().getDataSourceConnectionTypeAsString())); + dsAttrs.put(Provisioning.A_zimbraDataSourceUsername, eDataSource.getAttribute(MailConstants.A_DS_USERNAME, null)); String value = eDataSource.getAttribute(MailConstants.A_DS_PASSWORD, null); if (value != null) { dsAttrs.put(Provisioning.A_zimbraDataSourcePassword, value); From 2a34d4132f0ad88121833feb9b9df177df38051e Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 18 Sep 2017 16:23:16 -0700 Subject: [PATCH 081/142] move attributes up --- .../account/type/AccountOAuthDataSource.java | 16 ++++++++-------- .../soap/mail/type/MailOAuthDataSource.java | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java index 43b9eb08d2f..b61de75647a 100644 --- a/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java +++ b/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java @@ -7,14 +7,6 @@ import com.zimbra.soap.type.OAuthDataSource; @XmlType(propOrder = {}) public class AccountOAuthDataSource extends AccountDataSource implements OAuthDataSource { - public AccountOAuthDataSource() { - } - - public AccountOAuthDataSource(OAuthDataSource data) { - super(data); - refreshToken = data.getRefreshToken(); - refreshTokenUrl = data.getRefreshTokenUrl(); - } /** * @zm-api-field-tag data-source-refreshToken * @zm-api-field-description refresh token for refreshing data source oauth token @@ -29,6 +21,14 @@ public AccountOAuthDataSource(OAuthDataSource data) { @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) private String refreshTokenUrl; + public AccountOAuthDataSource() { + } + + public AccountOAuthDataSource(OAuthDataSource data) { + super(data); + refreshToken = data.getRefreshToken(); + refreshTokenUrl = data.getRefreshTokenUrl(); + } public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } public String getRefreshToken() { return refreshToken; } diff --git a/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java b/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java index fe5cae56771..6251c8c55eb 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java +++ b/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java @@ -6,13 +6,6 @@ import com.zimbra.soap.type.OAuthDataSource; public class MailOAuthDataSource extends MailDataSource implements OAuthDataSource { - public MailOAuthDataSource() { - } - - public MailOAuthDataSource(OAuthDataSource data) { - super(data); - } - /** * @zm-api-field-tag data-source-refreshToken * @zm-api-field-description refresh token for refreshing data source oauth token @@ -27,6 +20,13 @@ public MailOAuthDataSource(OAuthDataSource data) { @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) private String refreshTokenUrl; + public MailOAuthDataSource() { + } + + public MailOAuthDataSource(OAuthDataSource data) { + super(data); + } + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } public String getRefreshToken() { return refreshToken; } From bbdd353d1eb473735cf8e33adbe9ca74a02eb3cd Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Mon, 18 Sep 2017 16:23:36 -0700 Subject: [PATCH 082/142] replace unit test for 'custom' with 'oauth' --- .../zimbra/cs/datasource/DataSourceManagerTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java index d5591ee0b36..d813091c2ca 100644 --- a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java +++ b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java @@ -41,7 +41,7 @@ public class DataSourceManagerTest { private Account testAccount = null; - private String CUSTOM_DS_ID = "testCustomDS"; + private String OAUTH_DS_ID = "testOAuthDS"; private String POP3_DS_ID = "testPop3DS"; private String IMAP_DS_ID = "testImap3DS"; private String CALDAV_DS_ID = "CalDavDS"; @@ -49,7 +49,7 @@ public class DataSourceManagerTest { private String CAL_DS_ID = "CalDataSource"; private String GAL_DS_ID = "GALDataSource"; - private String CUSTOM_DS_NAME = "TestCustomDataSource"; + private String OAUTH_DS_NAME = "TestOAuthDataSource"; private String POP3_DS_NAME = "TestPop3DataSource"; private String IMAP_DS_NAME = "TestImapDataSource"; private String CALDAV_DS_NAME = "TestCalDavDataSource"; @@ -115,20 +115,20 @@ public void testGetDataImportWithDefaultClass() throws ServiceException { } @Test - public void testGetDataImportCustomClass() throws ServiceException { + public void testGetDataImportOAuthClass() throws ServiceException { Map testAttrs = new HashMap(); testAttrs.put(Provisioning.A_zimbraDataSourceDomain, "zimbra.com"); testAttrs.put(Provisioning.A_zimbraDataSourceImportClassName, "com.zimbra.cs.datasource.DataSourceManagerTest.TestDSImport"); - DataSource ds = new DataSource(testAccount, DataSourceType.custom, CUSTOM_DS_NAME, CUSTOM_DS_ID, testAttrs, null); + DataSource ds = new DataSource(testAccount, DataSourceType.oauth, OAUTH_DS_NAME, OAUTH_DS_ID, testAttrs, null); assertNotNull("DataSource should not be NULL", ds); DataImport di = DataSourceManager.getInstance().getDataImport(ds); assertNull("should not be able to instantiate non existent DataImport class", di); testAttrs.put(Provisioning.A_zimbraDataSourceImportClassName, "com.zimbra.cs.gal.GalImport"); - ds = new DataSource(testAccount, DataSourceType.custom, CUSTOM_DS_NAME, CUSTOM_DS_ID, testAttrs, null); + ds = new DataSource(testAccount, DataSourceType.oauth, OAUTH_DS_NAME, OAUTH_DS_ID, testAttrs, null); assertNotNull("DataSource should not be NULL", ds); di = DataSourceManager.getInstance().getDataImport(ds); assertNotNull("DataImport should not be NULL", di); - assertTrue("DataImport for 'custom' should be GalImport", di instanceof GalImport); + assertTrue("DataImport for 'oauth' should be GalImport", di instanceof GalImport); } } From 32e39ef1114232d9567c3afdd57fa84a89860939 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:06:41 -0700 Subject: [PATCH 083/142] avoid null values for leaveOnServer --- client/src/java/com/zimbra/client/ZPop3DataSource.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZPop3DataSource.java b/client/src/java/com/zimbra/client/ZPop3DataSource.java index 795d8e981a3..188ed9682c3 100644 --- a/client/src/java/com/zimbra/client/ZPop3DataSource.java +++ b/client/src/java/com/zimbra/client/ZPop3DataSource.java @@ -66,7 +66,7 @@ public Element toElement(Element parent) { src.addAttribute(MailConstants.A_DS_PASSWORD, data.getPassword()); src.addAttribute(MailConstants.A_FOLDER, data.getFolderId()); src.addAttribute(MailConstants.A_DS_CONNECTION_TYPE, data.getConnectionType().name()); - src.addAttribute(MailConstants.A_DS_LEAVE_ON_SERVER, getData().isLeaveOnServer()); + src.addAttribute(MailConstants.A_DS_LEAVE_ON_SERVER, leaveOnServer()); ZimbraLog.test.info("XXX bburtin: " + src.prettyPrint()); return src; } @@ -89,7 +89,7 @@ public DataSource toJaxb() { jaxbObject.setPassword(data.getPassword()); jaxbObject.setFolderId(data.getFolderId()); jaxbObject.setConnectionType(data.getConnectionType()); - jaxbObject.setLeaveOnServer(getData().isLeaveOnServer()); + jaxbObject.setLeaveOnServer(leaveOnServer()); jaxbObject.setEnabled(data.isEnabled()); return jaxbObject; } From 2041f4f24158a084f88471149d9f67275fc4d1a6 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:06:54 -0700 Subject: [PATCH 084/142] fix comment --- .../com/zimbra/soap/mail/message/GetDataSourcesResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java b/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java index 62a000d9177..5481325e3de 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java @@ -57,7 +57,7 @@ public class GetDataSourcesResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* custom */, type=MailOAuthDataSource.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private List dataSources = Lists.newArrayList(); From b62e47aa8af2ff475608c9aae8d83b80b3054488 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:07:16 -0700 Subject: [PATCH 085/142] fix formatting and add a comment about datasource object class in LDAP --- .../cs/account/ldap/entry/LdapDataSource.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java b/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java index f7be1a6b1f9..d020eb3625f 100644 --- a/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java +++ b/store/src/java/com/zimbra/cs/account/ldap/entry/LdapDataSource.java @@ -63,6 +63,13 @@ public static String getObjectClass(DataSourceType type) { case gal: return AttributeClass.OC_zimbraGalDataSource; default: + /* + * All DataSource objects that are not pop3, imap, rss or gal are considered 'generic' + * and are represented by 'dataSource' objectClass in LDAP. + * WARNING: avoid adding more LDAP object classes for new implementations of data sources. Use dataSource object class + * instead and keep all specifics of implementation in DataImport. + * Any configuration that is not covered by existing attributes can be stored in zimbraDataSourceAttribute or outside of LDAP. + */ return AttributeClass.OC_zimbraDataSource; } } @@ -77,17 +84,18 @@ static DataSourceType getObjectType(ZAttributes attrs) throws ServiceException { } List attr = attrs.getMultiAttrStringAsList(Provisioning.A_objectClass, CheckBinary.NOCHECK); - if (attr.contains(AttributeClass.OC_zimbraPop3DataSource)) + if (attr.contains(AttributeClass.OC_zimbraPop3DataSource)) { return DataSourceType.pop3; - else if (attr.contains(AttributeClass.OC_zimbraImapDataSource)) + } else if (attr.contains(AttributeClass.OC_zimbraImapDataSource)) { return DataSourceType.imap; - else if (attr.contains(AttributeClass.OC_zimbraRssDataSource)) + } else if (attr.contains(AttributeClass.OC_zimbraRssDataSource)) { return DataSourceType.rss; - else if (attr.contains(AttributeClass.OC_zimbraGalDataSource)) + } else if (attr.contains(AttributeClass.OC_zimbraGalDataSource)) { return DataSourceType.gal; - else if (attr.contains(AttributeClass.OC_zimbraDataSource)) + } else if (attr.contains(AttributeClass.OC_zimbraDataSource)) { return DataSourceType.unknown; - else + } else { throw ServiceException.FAILURE("unable to determine data source type from object class", null); + } } } From d43f052c076610432fcecb6da60c0c800e8227f8 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:08:29 -0700 Subject: [PATCH 086/142] add importClass to JSON representation --- client/src/java/com/zimbra/client/ZOAuthDataSource.java | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/java/com/zimbra/client/ZOAuthDataSource.java b/client/src/java/com/zimbra/client/ZOAuthDataSource.java index 09844996ce3..a2822255920 100644 --- a/client/src/java/com/zimbra/client/ZOAuthDataSource.java +++ b/client/src/java/com/zimbra/client/ZOAuthDataSource.java @@ -67,6 +67,7 @@ public ZJSONObject toZJSONObject() throws JSONException { zjo.put("enabled", data.isEnabled()); zjo.put("refreshToken", getData().getRefreshToken()); zjo.put("refreshTokenUrl", getData().getRefreshTokenUrl()); + zjo.put("importClass", getData().getImportClass()); zjo.put("folderId", data.getFolderId()); zjo.put("importOnly", data.isImportOnly()); return zjo; From c7172de857ac129409ae8df270e75370fe06bdc2 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:15:14 -0700 Subject: [PATCH 087/142] log error when provided with invalid folder ID --- client/src/java/com/zimbra/client/ZOAuthDataSource.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/java/com/zimbra/client/ZOAuthDataSource.java b/client/src/java/com/zimbra/client/ZOAuthDataSource.java index a2822255920..654543e99d2 100644 --- a/client/src/java/com/zimbra/client/ZOAuthDataSource.java +++ b/client/src/java/com/zimbra/client/ZOAuthDataSource.java @@ -3,6 +3,7 @@ import org.json.JSONException; import com.zimbra.common.service.ServiceException; +import com.zimbra.common.util.ZimbraLog; import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.soap.mail.type.DataSourceNameOrId; import com.zimbra.soap.mail.type.MailOAuthDataSource; @@ -27,6 +28,7 @@ public ZOAuthDataSource(String name, boolean enabled, String refreshToken, Strin try { data.setFolderId(folderId); } catch (NumberFormatException e) { + ZimbraLog.datasource.error("Cannot create ZOAuthDataSource with name %s and import class %s, because folder ID is invalid: %s", name, importClass, folderId); throw ServiceException.INVALID_REQUEST("Invalid folder id", e); } data.setImportOnly(isImportOnly); From 1b57f89a81d3f045b5e5582f0e69d80e50795505 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:19:59 -0700 Subject: [PATCH 088/142] add ***dataSource object classes to documentation --- store/conf/attrs/zimbra-attrs.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index f6bd6339e03..6e591634a88 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -121,7 +121,8 @@ TODO - add support for multi-line values in globalConfigValue and defaultCOSValu mailRecipient, account, alias, distributionList, cos, globalConfig, domain, securityGroup, server, mimeEntry, objectEntry, zimletEntry, calendarResource; - attribute, alwaysOnCluster + attribute, alwaysOnCluster, dataSource, pop3DataSource, + rssDataSource, imapDataSource, galDataSource flags: accountInfo............returned as part of the GetInfo call From a190f35904fdf075ea676ec61d29005bcb540a96 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:40:34 -0700 Subject: [PATCH 089/142] remove special case for oauth datasource, since it is essentially generic --- .../cs/datasource/DataSourceManager.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java index d85f236de04..ba91ae1e4f9 100644 --- a/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java +++ b/store/src/java/com/zimbra/cs/datasource/DataSourceManager.java @@ -214,16 +214,16 @@ public DataImport getDataImport(DataSource ds, boolean test) throws ServiceExcep Constructor constructor = cmdClass.getConstructor(new Class[] {DataSource.class}); return (DataImport) constructor.newInstance(ds); } - ZimbraLog.datasource.warn("Could not find custom DataImport class: %s. Check your classpath.", className); + ZimbraLog.datasource.warn("Could not find DataImport class: %s for xsync dataSource %s Check your classpath.", className, ds.getName()); return null; } } catch (Exception x) { ZimbraLog.datasource.warn("Failed instantiating xsync class: %s", ds, x); } - case oauth: - try { - String className = ds.getDataSourceImportClassName(); - if (className != null && className.length() > 0) { + default: + String className = ds.getDataSourceImportClassName(); + if (className != null && className.length() > 0) { + try { Class cmdClass; try { cmdClass = Class.forName(className); @@ -234,16 +234,15 @@ public DataImport getDataImport(DataSource ds, boolean test) throws ServiceExcep Constructor constructor = cmdClass.getConstructor(new Class[] {DataSource.class}); return (DataImport) constructor.newInstance(ds); } - ZimbraLog.datasource.warn("Could not find custom DataImport class: %s. Check your classpath.", className); + ZimbraLog.datasource.warn("Could not find DataImport class: %s for dataSource %s Check your classpath.", className, ds.getName()); + return null; + } catch (Exception x) { + ZimbraLog.datasource.warn("Caught an exception while instantiating DataImport class: %s", ds, x); return null; } - } catch (Exception x) { - ZimbraLog.datasource.warn("Caught an exception while instantiating custom class: %s", ds, x); + } else { + throw new IllegalArgumentException(String.format("Cannot create datasource %s with unknown data import type: %s and undefined zimbraDataSourceImportClassName", ds.getName(), ds.getType())); } - return null; - default: - // yab is handled by OfflineDataSourceManager - throw new IllegalArgumentException("Unknown data import type: " + ds.getType()); } } From 41447eec5884d2e466c5c3869a975e92a5befaf7 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 19 Sep 2017 11:50:04 -0700 Subject: [PATCH 090/142] missed another call to leaveOnServer --- client/src/java/com/zimbra/client/ZPop3DataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/java/com/zimbra/client/ZPop3DataSource.java b/client/src/java/com/zimbra/client/ZPop3DataSource.java index 188ed9682c3..4ea0e2e70be 100644 --- a/client/src/java/com/zimbra/client/ZPop3DataSource.java +++ b/client/src/java/com/zimbra/client/ZPop3DataSource.java @@ -143,7 +143,7 @@ public ZJSONObject toZJSONObject() throws JSONException { zjo.put("username", data.getUsername()); zjo.put("folderId", data.getFolderId()); zjo.put("connectionType", data.getConnectionType().toString()); - zjo.put("leaveOnServer", getData().isLeaveOnServer()); + zjo.put("leaveOnServer", leaveOnServer()); return zjo; } From 9d466dc804aa8571a7bcd6e77d2ea867722aa972 Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Thu, 21 Sep 2017 16:13:59 +0900 Subject: [PATCH 091/142] zcs-2212:Inconsistent handling of "\" in editheader Sieve:ReplaceHeader:Match pattern containing more than four backslashes leads to incorrect behaviour [Problem] When the match pattern contains four or more than four backslashes in a row, replaceheader matches does not match correctly. [Root cause] The replaceheader and deleteheader call the com.zimbra.cs.filter.jsieve.EditHeaderExtension.matchValue() which makes a matching pattern using jsieve's org.apache.jsieve.comparators.ComparatorUtils.sieveToJavaRegex() method, but this method had a bug. Other tests, such as header or address, have already used the fixed version of com.zimbra.cs.filter.FilterUtil.sieveToJavaRegex(), but replaceheader and deleteheader did not yet. [Fix] Call the fixed version of sieveToJavaRegex() method from replaceheader and deleteheader. --- .../zimbra/cs/filter/DeleteHeaderTest.java | 85 ++++++++++++++++++ .../zimbra/cs/filter/ReplaceHeaderTest.java | 86 +++++++++++++++++++ .../cs/filter/jsieve/EditHeaderExtension.java | 18 +--- 3 files changed, 174 insertions(+), 15 deletions(-) diff --git a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java index 3e942f8bf34..01b4a667c72 100644 --- a/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/DeleteHeaderTest.java @@ -1347,4 +1347,89 @@ mbox, new ParsedMessage("X-Header: example".getBytes(), false), 0, fail("No exception should be thrown" + e); } } + + @Test + public void testBackslashAsciiCasemap4bs() throws Exception { + // Matches four backslashes + String script = "require [\"editheader\"];\n" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-Header\" \"Sample\\\\\\\\\\\\\\\\Pattern\";" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-HeaderA\" \"Sample\\\\\\\\Pattern\";" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-HeaderB\" \"Sample\\\\Pattern\";" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-HeaderC\" \"Sample\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Pattern\";"; + String pattern = "Sample\\\\\\\\Pattern"; + String msg = "X-Header: " + pattern + "\n" + + "X-HeaderA: " + pattern + "\n" + + "X-HeaderB: " + pattern + "\n" + + "X-HeaderC: " + pattern + "\n"; + boolean result = testBackslash(script, pattern, msg); + Assert.assertTrue(result); + } + + @Test + public void testBackslashAsciiCasemap5bs() throws Exception { + // Matches five backslashes + String script = "require [\"editheader\"];\n" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-Header\" \"Sample\\\\\\\\\\\\\\\\\\\\Pattern\";" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-HeaderA\" \"Sample\\\\\\\\\\Pattern\";" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-HeaderB\" \"Sample\\\\\\Pattern\";" + + "deleteheader :comparator \"i;ascii-casemap\" \"X-HeaderC\" \"Sample\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Pattern\";"; + String pattern = "Sample\\\\\\\\\\Pattern"; + String msg = "X-Header: " + pattern + "\n" + + "X-HeaderA: " + pattern + "\n" + + "X-HeaderB: " + pattern + "\n" + + "X-HeaderC: " + pattern + "\n"; + boolean result = testBackslash(script, pattern, msg); + Assert.assertTrue(result); + } + + @Test + public void testBackslashOctet() throws Exception { + String script = "require [\"editheader\"];\n" + + "deleteheader :comparator \"i;octet\" \"X-Header\" \"Sample\\\\\\\\\\\\\\\\Pattern\";" + + "deleteheader :comparator \"i;octet\" \"X-HeaderA\" \"Sample\\\\\\\\Pattern\";" + + "deleteheader :comparator \"i;octet\" \"X-HeaderB\" \"Sample\\\\Pattern\";" + + "deleteheader :comparator \"i;octet\" \"X-HeaderC\" \"Sample\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Pattern\";"; + String pattern = "Sample\\\\\\\\Pattern"; + String msg = "X-Header: " + pattern + "\n" + + "X-HeaderA: " + pattern + "\n" + + "X-HeaderB: " + pattern + "\n" + + "X-HeaderC: " + pattern + "\n"; + boolean result = testBackslash(script, pattern, msg); + Assert.assertTrue(result); + } + + private boolean testBackslash(String script, String pattern, String msg) { + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + RuleManager.clearCachedRules(account); + account.unsetAdminSieveScriptBefore(); + account.unsetMailSieveScript(); + account.unsetAdminSieveScriptAfter(); + account.setSieveEditHeaderEnabled(true); + account.setAdminSieveScriptBefore(script); + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(msg.getBytes(), false), 0, + account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Message message = mbox.getMessageById(null, ids.get(0).getId()); + String[] headers = message.getMimeMessage().getHeader("X-Header"); + Assert.assertNull(headers); + headers = message.getMimeMessage().getHeader("X-HeaderA"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals(pattern, headers[0]); + headers = message.getMimeMessage().getHeader("X-HeaderB"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals(pattern, headers[0]); + headers = message.getMimeMessage().getHeader("X-HeaderC"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals(pattern, headers[0]); + return true; + } catch (Exception e) { + fail("No exception should be thrown" + e); + return false; + } + } } \ No newline at end of file diff --git a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java index 81fb41f856f..6a2306d31c8 100644 --- a/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/ReplaceHeaderTest.java @@ -1730,4 +1730,90 @@ mbox, new ParsedMessage(sampleBaseMsg.getBytes(), false), 0, fail("No exception should be thrown" + e); } } + + @Test + public void testBackslashAsciiCasemap4bs() throws Exception { + // Matches four backslashes + String script = "require [\"editheader\"];\n" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-Header\" \"Sample\\\\\\\\\\\\\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-HeaderA\" \"Sample\\\\\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-HeaderB\" \"Sample\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-HeaderC\" \"Sample\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Pattern\";"; + String pattern = "Sample\\\\\\\\Pattern"; + String msg = "X-Header: " + pattern + "\n" + + "X-HeaderA: " + pattern + "\n" + + "X-HeaderB: " + pattern + "\n" + + "X-HeaderC: " + pattern + "\n"; + boolean result = testBackslash(script, pattern, msg); + Assert.assertTrue(result); + } + + @Test + public void testBackslashAsciiCasemap5bs() throws Exception { + // Matches five backslashes + String script = "require [\"editheader\"];\n" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-Header\" \"Sample\\\\\\\\\\\\\\\\\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-HeaderA\" \"Sample\\\\\\\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-HeaderB\" \"Sample\\\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;ascii-casemap\" \"X-HeaderC\" \"Sample\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Pattern\";"; + String pattern = "Sample\\\\\\\\\\Pattern"; + String msg = "X-Header: " + pattern + "\n" + + "X-HeaderA: " + pattern + "\n" + + "X-HeaderB: " + pattern + "\n" + + "X-HeaderC: " + pattern + "\n"; + boolean result = testBackslash(script, pattern, msg); + Assert.assertTrue(result); + } + @Test + public void testBackslashOctet() throws Exception { + String script = "require [\"editheader\"];\n" + + "replaceheader :newvalue \"replaced\" :comparator \"i;octet\" \"X-Header\" \"Sample\\\\\\\\\\\\\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;octet\" \"X-HeaderA\" \"Sample\\\\\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;octet\" \"X-HeaderB\" \"Sample\\\\Pattern\";" + + "replaceheader :newvalue \"replaced\" :comparator \"i;octet\" \"X-HeaderC\" \"Sample\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Pattern\";"; + String pattern = "Sample\\\\\\\\Pattern"; + String msg = "X-Header: " + pattern + "\n" + + "X-HeaderA: " + pattern + "\n" + + "X-HeaderB: " + pattern + "\n" + + "X-HeaderC: " + pattern + "\n"; + boolean result = testBackslash(script, pattern, msg); + Assert.assertTrue(result); + } + + private boolean testBackslash(String script, String pattern, String msg) { + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + RuleManager.clearCachedRules(account); + account.unsetAdminSieveScriptBefore(); + account.unsetMailSieveScript(); + account.unsetAdminSieveScriptAfter(); + account.setSieveEditHeaderEnabled(true); + account.setAdminSieveScriptBefore(script); + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(msg.getBytes(), false), 0, + account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Message message = mbox.getMessageById(null, ids.get(0).getId()); + String[] headers = message.getMimeMessage().getHeader("X-Header"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals("replaced", headers[0]); + headers = message.getMimeMessage().getHeader("X-HeaderA"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals(pattern, headers[0]); + headers = message.getMimeMessage().getHeader("X-HeaderB"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals(pattern, headers[0]); + headers = message.getMimeMessage().getHeader("X-HeaderC"); + Assert.assertNotNull(headers); + Assert.assertNotSame(0, headers.length); + Assert.assertEquals(pattern, headers[0]); + return true; + } catch (Exception e) { + fail("No exception should be thrown" + e); + return false; + } + } } \ No newline at end of file diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java b/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java index 324c8887780..c385e5a9a8c 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/EditHeaderExtension.java @@ -418,11 +418,11 @@ public boolean matchCondition(ZimbraMailAdapter mailAdapter, Header header, List matchFound = ZimbraComparatorUtils.values(mailAdapter, comparator, relationalComparator, unfoldedAndDecodedHeaderValue, value, context); } else if (this.countTag) { matchFound = ZimbraComparatorUtils.counts(mailAdapter, comparator, relationalComparator, headerList, value, context); - } else if (this.is && ComparatorUtils.is(this.comparator, unfoldedAndDecodedHeaderValue, value, context)) { + } else if (this.is && ComparatorUtils.is(comparator, unfoldedAndDecodedHeaderValue, value, context)) { matchFound = true; - } else if (this.contains && ComparatorUtils.contains(this.comparator, unfoldedAndDecodedHeaderValue, value, context)) { + } else if (this.contains && ComparatorUtils.contains(comparator, unfoldedAndDecodedHeaderValue, value, context)) { matchFound = true; - } else if (this.matches && matchValue(value, unfoldedAndDecodedHeaderValue)) { + } else if (this.matches && ComparatorUtils.matches(comparator, unfoldedAndDecodedHeaderValue, value, context)) { matchFound = true; } else { ZimbraLog.filter.debug("Key: %s and Value: %s pair not matching requested criteria.", this.key, value); @@ -549,18 +549,6 @@ static public boolean isImmutableHeaderKey(String key, ZimbraMailAdapter mailAda return immutableHeaders.stream().map(String::trim).anyMatch(x -> x.equalsIgnoreCase(key)); } - /** - * @param regex - * @param value - * @return - */ - private boolean matchValue(String regex, String value) { - regex = ComparatorUtils.sieveToJavaRegex(regex); - Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); - Matcher matcher = pattern.matcher(value); - return matcher.matches(); - } - static public boolean saveChanges(ZimbraMailAdapter zma, String actionName, MimeMessage mm) { if (zma.getEditHeaderParseStatus() == PARSESTATUS.UNKNOWN) { try { From 387474a26c763ea2bcb04f7cab7f5ce507c76e55 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Wed, 20 Sep 2017 11:25:31 -0700 Subject: [PATCH 092/142] add getDataSourceByName to ZMailbox --- client/src/java/com/zimbra/client/ZMailbox.java | 14 ++++++++++++++ .../qa/unittest/server/TestDataSourceServer.java | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index bb3f670b60f..dcbb80df47a 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -4733,6 +4733,20 @@ public ZDataSource getDataSourceById(String id) throws ServiceException { return null; } + /** + * Gets a data source by name. + * @return the data source, or null if no data source with the + * given name exists + */ + public ZDataSource getDataSourceByName(String name) throws ServiceException { + for (ZDataSource ds : getAllDataSources()) { + if (ds.getName() != null && ds.getName().equals(name)) { + return ds; + } + } + return null; + } + public void modifyDataSource(ZDataSource source) throws ServiceException { ModifyDataSourceRequest req = new ModifyDataSourceRequest(); req.setDataSource(source.toJaxb()); diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index cd95419cf63..118463bb8d4 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -69,7 +69,7 @@ public void testOAuthDS() throws Exception { String dsId = zmbox.createDataSource(zds); assertNotNull("DataSource should have an ID", dsId); assertFalse("DataSource id should not be empty", dsId.isEmpty()); - ZDataSource ds = TestUtil.getDataSource(zmbox, DSName); + ZDataSource ds = zmbox.getDataSourceByName(DSName); assertNotNull("should retrieve a non-null DataSource", ds); assertTrue("expecting ZOAuthDataSource", ds instanceof ZOAuthDataSource); ZOAuthDataSource oads = (ZOAuthDataSource)ds; From dc4a8129eed2d0e49826a50af881f0a218107df9 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 19 Sep 2017 14:33:13 +0100 Subject: [PATCH 093/142] ZCS-2287:delete unused ImapMailboxStore methods * Remove `getListeners(int folderId)` methods * Remove unused `RemoteImapMailboxStore.store( String folderId, Blob content, Date date, int msgFlags)` --- .../com/zimbra/cs/imap/ImapMailboxStore.java | 1 - .../zimbra/cs/imap/LocalImapMailboxStore.java | 16 ---------- .../cs/imap/RemoteImapMailboxStore.java | 32 ------------------- 3 files changed, 49 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java b/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java index a41dd26171c..45d5387b26b 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java +++ b/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java @@ -109,7 +109,6 @@ public abstract List openImapFolder(OperationContext octxt, ItemIde public abstract void registerWithImapServerListener(ImapListener listener); public abstract void unregisterWithImapServerListener(ImapListener listener); - public abstract List getListeners(int folderId); public List getListeners(ItemIdentifier ident) { String acctId = ident.accountId != null ? ident.accountId : getAccountId(); try { diff --git a/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java b/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java index 734c1e44e36..53e5239f198 100644 --- a/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java +++ b/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java @@ -40,7 +40,6 @@ import com.zimbra.cs.mailbox.Metadata; import com.zimbra.cs.mailbox.MetadataList; import com.zimbra.cs.mailbox.OperationContext; -import com.zimbra.cs.session.Session; import com.zimbra.cs.util.AccountUtil; public class LocalImapMailboxStore extends ImapMailboxStore { @@ -178,21 +177,6 @@ public Collection getVisibleFolders(OperationContext octxt, ImapCre return fStores; } - @Override - public List getListeners(int folderId) { - List sessions = mailbox.getListeners(Session.Type.IMAP); - List listeners = Lists.newArrayListWithCapacity(sessions.size()); - for (Session sess : sessions) { - if (sess instanceof ImapSession) { - ImapSession imapSess = (ImapSession) sess; - if (folderId == imapSess.getFolderId()) { - listeners.add((ImapSession)sess); - } - } - } - return listeners; - } - public boolean attachmentsIndexingEnabled() throws ServiceException { return mailbox.attachmentsIndexingEnabled(); } diff --git a/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java b/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java index c36b55747a2..ebb0e3ca694 100644 --- a/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java +++ b/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java @@ -17,11 +17,8 @@ package com.zimbra.cs.imap; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Set; @@ -45,11 +42,8 @@ import com.zimbra.cs.account.AuthTokenException; import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.imap.ImapFlagCache.ImapFlag; -import com.zimbra.cs.mailbox.Flag; import com.zimbra.cs.mailbox.OperationContext; import com.zimbra.cs.service.UserServlet; -import com.zimbra.cs.service.util.ItemId; -import com.zimbra.cs.store.Blob; import com.zimbra.cs.util.AccountUtil; import com.zimbra.soap.mail.type.ImapMessageInfo; @@ -172,22 +166,6 @@ public Collection getVisibleFolders(OperationContext octxt, ImapCre return fStores; } - @Override - public List getListeners(int folderId) { - try { - ImapServerListener listener = ImapServerListenerPool.getInstance().get(zMailbox); - List listeners = new ArrayList(); - for (ImapRemoteSession sess: listener.getListeners(zMailbox.getAccountId(), folderId)) { - listeners.add(sess); - } - return listeners; - } catch (ServiceException e) { - ZimbraLog.imap.debug("Problem getting listeners for account %s from ImapServerListener (folderId=%s)", - accountId, folderId, e); - return Collections.emptyList(); - } - } - @Override public boolean addressMatchesAccountOrSendAs(String givenAddress) throws ServiceException { return (AccountUtil.addressMatchesAccountOrSendAs(getAccount(), givenAddress)); @@ -232,16 +210,6 @@ public int getImapRECENT(OperationContext octxt, FolderStore folder) throws Serv return ((ZFolder) folder).getImapRECENT(); } - public int store(String folderId, Blob content, Date date, int msgFlags) - throws ImapSessionClosedException, ServiceException, IOException { - String id; - try (InputStream is = content.getInputStream()) { - id = zMailbox.addMessage(folderId, Flag.toString(msgFlags), (String) null, date.getTime(), is, - content.getRawSize(), true); - } - return new ItemId(id, accountId).getId(); - } - @Override public MailboxStore getMailboxStore() { return zMailbox; From 93f8a4f407b06390e2f509ed233b4bb0ef00d970 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Mon, 18 Sep 2017 10:53:05 +0100 Subject: [PATCH 094/142] ZCS-2287:Reduce loglevel of adding folder/message These messages clutter up the log without adding much value. If needed, same info could be obtained from redolog. --- store/src/java/com/zimbra/cs/mailbox/Folder.java | 2 +- store/src/java/com/zimbra/cs/mailbox/Message.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/store/src/java/com/zimbra/cs/mailbox/Folder.java b/store/src/java/com/zimbra/cs/mailbox/Folder.java index b65af748612..ae6f8c2ab15 100644 --- a/store/src/java/com/zimbra/cs/mailbox/Folder.java +++ b/store/src/java/com/zimbra/cs/mailbox/Folder.java @@ -874,7 +874,7 @@ static Folder create(int id, String uuid, Mailbox mbox, Folder parent, String na data.metadata = encodeMetadata(color, 1, 1, custom, attributes, view, null, new SyncData(url), id + 1, 0, mbox.getOperationChangeID(), -1, 0, 0, 0, null, false, -1); data.contentChanged(mbox); - ZimbraLog.mailop.info("adding folder %s: id=%d, parentId=%d.", name, data.id, data.parentId); + ZimbraLog.mailop.debug("adding folder %s: id=%d, parentId=%d.", name, data.id, data.parentId); new DbMailItem(mbox).create(data); Folder folder = new Folder(mbox, data); diff --git a/store/src/java/com/zimbra/cs/mailbox/Message.java b/store/src/java/com/zimbra/cs/mailbox/Message.java index b007445e5b0..4445a3dd44d 100644 --- a/store/src/java/com/zimbra/cs/mailbox/Message.java +++ b/store/src/java/com/zimbra/cs/mailbox/Message.java @@ -596,8 +596,10 @@ static Message createInternal(int id, Folder folder, Conversation conv, ParsedMe data.unreadCount = unread ? 1 : 0; data.contentChanged(mbox); - ZimbraLog.mailop.info("Adding Message: id=%d, Message-ID=%s, parentId=%d, folderId=%d, folderName=%s.", - data.id, pm.getMessageID(), data.parentId, folder.getId(), folder.getName()); + ZimbraLog.mailop.debug( + "Adding Message: id=%d, Message-ID=%s, parentId=%d, folderId=%d, folderName=%s acct=%s.", + data.id, pm.getMessageID(), data.parentId, folder.getId(), folder.getName(), + mbox.getAccountId()); new DbMailItem(mbox) .setSender(pm.getParsedSender().getSortString()) .setRecipients(ParsedAddress.getSortString(pm.getParsedRecipients())) From 0522522551cc78e0f7e8996427561a0b7d9a38ee Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 30 Aug 2017 19:00:20 +0100 Subject: [PATCH 095/142] ImapPath - methods made visible for testing --- store/src/java/com/zimbra/cs/imap/ImapPath.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapPath.java b/store/src/java/com/zimbra/cs/imap/ImapPath.java index f14889aec5d..ba434af4368 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapPath.java +++ b/store/src/java/com/zimbra/cs/imap/ImapPath.java @@ -19,6 +19,7 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.zimbra.client.ZFolder; import com.zimbra.client.ZMailbox; @@ -180,7 +181,8 @@ public boolean isEquivalent(ImapPath other) { return (mOwner == null ? 0 : mOwner.toUpperCase().hashCode()) ^ mPath.toUpperCase().hashCode() ^ (mCredentials == null ? 0 : mCredentials.hashCode()); } - protected ImapPath canonicalize() throws ServiceException { + @VisibleForTesting + public ImapPath canonicalize() throws ServiceException { getFolder(); String path = folder.getPath(); @@ -201,7 +203,6 @@ protected ImapPath canonicalize() throws ServiceException { return this; } - protected String getOwner() { return mOwner; } @@ -347,7 +348,8 @@ private OperationContext getContext() throws ServiceException { return (mCredentials == null ? null : mCredentials.getContext()); } - protected FolderStore getFolder() throws ServiceException { + @VisibleForTesting + public FolderStore getFolder() throws ServiceException { if (useReferent()) { return getReferent().getFolder(); } @@ -422,7 +424,8 @@ protected boolean useReferent() throws ServiceException { * @return If the folder is a mountpoint (i.e. an accepted share), may return an ImapPath representing * that, otherwise, the value is this. */ - protected ImapPath getReferent() throws ServiceException { + @VisibleForTesting + public ImapPath getReferent() throws ServiceException { if (mReferent != null) { return mReferent; } From cb516254718f919e06aa5180622989df5fb6d49d Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 30 Aug 2017 19:01:09 +0100 Subject: [PATCH 096/142] ZCS-2287:SharedImapTests.imapPath imapPath test used to explore the `ImapPath` and `FolderStore` objects used for shared (and non-shared) folders. --- .../zimbra/qa/unittest/SharedImapTests.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index 2a50489c1d1..14eadc96af5 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -4,7 +4,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -32,11 +34,15 @@ import com.zimbra.client.ZTag; import com.zimbra.client.ZTag.Color; import com.zimbra.common.localconfig.LC; +import com.zimbra.common.mailbox.FolderStore; +import com.zimbra.common.mailbox.MailboxStore; import com.zimbra.common.mime.MimeConstants; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.imap.ImapCredentials; +import com.zimbra.cs.imap.ImapPath; import com.zimbra.cs.mailbox.Mailbox; import com.zimbra.cs.mailclient.CommandFailedException; import com.zimbra.cs.mailclient.imap.AppendMessage; @@ -65,6 +71,85 @@ @SuppressWarnings("PMD.ExcessiveClassLength") public abstract class SharedImapTests extends ImapTestBase { + @Test(timeout=100000) + public void imapPath() throws IOException, ServiceException, MessagingException { + Account userAcct = TestUtil.getAccount(USER); + Account shareeAcct = TestUtil.createAccount(SHAREE); + ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); + ZMailbox zmbox = TestUtil.getZMailbox(USER); + /* create a few folders to ensure that the sharee account won't have the same folder IDs + * present as are used in the shared folders. + */ + for (int cnt = 0;cnt < 10;cnt++) { + TestUtil.createFolder(zmbox, "/toplevel-" + cnt); + } + String remFolder = String.format("/INBOX/%s-shared", testInfo.getMethodName()); + String underRemFolder = String.format("%s/subFolder", remFolder); + String otherUserFolder = String.format("/home/%s%s", USER, remFolder); + String otherUserSubFolder = String.format("/home/%s%s", USER, underRemFolder); + ZFolder zfolder = TestUtil.createFolder(zmbox, remFolder); + ZFolder underZfolder = TestUtil.createFolder(zmbox, underRemFolder); + String mp = String.format("%s's %s-shared", USER, testInfo.getMethodName()); + String subMp = String.format("%s/subFolder", mp); + TestUtil.createMountpoint(zmbox, remFolder, shareeZmbox, mp); + ImapCredentials creds = new ImapCredentials(shareeAcct); + + checkImapPath("inbox", creds, "INBOX", false /* usingReferent */, + Integer.parseInt(ZFolder.ID_INBOX), shareeAcct.getId()); + checkImapPath(mp, creds, mp, true /* usingReferent */, + zfolder.getFolderItemIdentifier().id, userAcct.getId()); + checkImapPath(subMp, creds, subMp, true /* usingReferent */, + underZfolder.getFolderItemIdentifier().id, userAcct.getId()); + checkImapPath(otherUserFolder, creds, otherUserFolder, false /* usingReferent */, + zfolder.getFolderItemIdentifier().id, userAcct.getId()); + checkImapPath(otherUserSubFolder, creds, otherUserSubFolder, false /* usingReferent */, + underZfolder.getFolderItemIdentifier().id, userAcct.getId()); + } + + private void checkImapPath(String mboxName, ImapCredentials creds, String expectedPathToString, + boolean usingReferent, int expectedReferentFolderId, String expectedReferentFolderAcct) + throws ServiceException { + ImapPath path = new ImapPath(mboxName, creds); + path.canonicalize(); + ImapPath referent = path.getReferent(); + assertEquals(String.format("toString() for ImapPath for mailbox '%s'", mboxName), + expectedPathToString, path.toString()); + if (usingReferent) { + assertNotSame( + String.format("ImapPath=%s and it's getReferent() for mailbox '%s'", path, mboxName), + path, referent); + } else { + assertSame( + String.format("ImapPath=%s and it's getReferent() for mailbox '%s'", path, mboxName), + path, referent); + } + FolderStore folderForPath = path.getFolder(); + assertEquals(String.format( + "Folder ID for path.getReferent().getFolder() for mailbox '%s'", mboxName), + expectedReferentFolderId, folderIdForFolder(folderForPath)); + assertEquals(String.format( + "Account ID for path.getReferent().getFolder() for mailbox '%s'", mboxName), + expectedReferentFolderAcct, + acctIdForFolder(folderForPath)); + } + + private String acctIdForFolder(FolderStore folder) { + MailboxStore mbox = folder.getMailboxStore(); + String acctId; + try { + acctId = mbox.getAccountId(); + } catch (ServiceException e) { + acctId = ""; + } + ZimbraLog.test.debug("Account ID = %s for folder %s", acctId, folder); + return acctId; + } + + private int folderIdForFolder(FolderStore folder) { + ZimbraLog.test.debug("Folder ID = %s for folder %s", folder.getFolderIdInOwnerMailbox(), folder); + return folder.getFolderIdInOwnerMailbox(); + } + @Test(timeout=100000) public void testListFolderContents() throws IOException, ServiceException, MessagingException { String folderName = "SharedImapTests-testOpenFolder"; From 5f7845ad242706479dc7cc475554eed3a5d66e65 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 19 Sep 2017 16:34:17 +0100 Subject: [PATCH 097/142] ZCS-2287:Comment on imapCopy method --- store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java | 5 ++++- store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java | 5 ++++- .../src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java b/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java index 45d5387b26b..5d9f33b81e2 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java +++ b/store/src/java/com/zimbra/cs/imap/ImapMailboxStore.java @@ -84,7 +84,10 @@ public List getFlagList(boolean permanentOnly) { public abstract void resetImapUid(List renumber) throws ServiceException; public abstract void beginTrackingImap() throws ServiceException; public abstract void deleteMessages(OperationContext octxt, List ids); - /** @return List of IMAP UIDs */ + /** + * MUST only be called when the source items and target folder are in the same mailbox + * @return List of IMAP UIDs + */ public abstract List imapCopy(OperationContext octxt, int[] itemIds, MailItemType type, int folderId) throws IOException, ServiceException; public abstract InputStreamWithSize getByImapId(OperationContext octxt, int imapId, String folderId, String resolvedPath) diff --git a/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java b/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java index 53e5239f198..f9ad8c21ed7 100644 --- a/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java +++ b/store/src/java/com/zimbra/cs/imap/LocalImapMailboxStore.java @@ -107,7 +107,10 @@ public void deleteMessages(OperationContext octxt, List ids) { } } - /** @return List of IMAP UIDs */ + /** + * MUST only be called when the source items and target folder are in the same mailbox + * @return List of IMAP UIDs + */ @Override public List imapCopy(OperationContext octxt, int[] itemIds, MailItemType type, int folderId) throws IOException, ServiceException { diff --git a/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java b/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java index ebb0e3ca694..6d9f637c112 100644 --- a/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java +++ b/store/src/java/com/zimbra/cs/imap/RemoteImapMailboxStore.java @@ -101,7 +101,10 @@ public void deleteMessages(OperationContext octxt, List ids) { } } - /** @return List of IMAP UIDs */ + /** + * MUST only be called when the source items and target folder are in the same mailbox + * @return List of IMAP UIDs + */ @Override public List imapCopy(OperationContext octxt, int[] itemIds, MailItemType type, int folderId) throws IOException, ServiceException { From d70d1a5cae625d305259d77f7c383127aa0b187f Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 20 Sep 2017 15:42:44 +0100 Subject: [PATCH 098/142] ImapPath PMD fix - simplify getReferent --- .../src/java/com/zimbra/cs/imap/ImapPath.java | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapPath.java b/store/src/java/com/zimbra/cs/imap/ImapPath.java index ba434af4368..d984bbe13e2 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapPath.java +++ b/store/src/java/com/zimbra/cs/imap/ImapPath.java @@ -480,8 +480,36 @@ public ImapPath getReferent() throws ServiceException { return mReferent; } - String owner = mCredentials != null && mCredentials.getAccountId().equalsIgnoreCase(target.getId()) ? null + ImapMailboxStore imapMailboxStore = setupMailboxStoreForTarget(target, iidRemote); + if (null == imapMailboxStore) { + return mReferent; + } + FolderStore fldr = imapMailboxStore.getMailboxStore().getFolderById( + getContext(), Integer.toString(iidRemote.getId())); + if (fldr == null) { + return mReferent; + } + String owner = getOwner(target); + if (Strings.isNullOrEmpty(subpathRemote)) { + mReferent = new ImapPath(owner, fldr, mCredentials); + } else { + mReferent = ImapPath.get(owner, fldr.getPath() + + (fldr.getPath().equals("/") ? "" : "/") + subpathRemote, mCredentials, imapMailboxStore); + } + + if (mReferent != this) { + mReferent.mScope = Scope.REFERENCE; + } + return mReferent; + } + + private String getOwner(Account target) { + return mCredentials != null && mCredentials.getAccountId().equalsIgnoreCase(target.getId()) ? null : target.getName(); + } + + private ImapMailboxStore setupMailboxStoreForTarget(Account target, ItemId iidRemote) + throws ServiceException { ImapMailboxStore imapMailboxStore = null; // if both target and owner are on local server and using local imap if (Provisioning.onLocalServer(target) && onLocalServer()) { @@ -495,38 +523,20 @@ public ImapPath getReferent() throws ServiceException { Account acct = mCredentials == null ? null : Provisioning.getInstance().get(AccountBy.id, mCredentials.getAccountId()); if (acct == null) { - return mReferent; + return null; } try { ZMailbox zmbx = getZMailboxForAccount(target); ZFolder zfolder = zmbx.getFolderById(iidRemote.toString(mCredentials.getAccountId())); if (zfolder == null) { - return mReferent; + return null; } imapMailboxStore = ImapMailboxStore.get(zmbx); } catch (ServiceException e) { ZimbraLog.imap.debug("Unexpected exception", e); } } - if (null == imapMailboxStore) { - return mReferent; - } - FolderStore fldr = imapMailboxStore.getMailboxStore().getFolderById( - getContext(), Integer.toString(iidRemote.getId())); - if (fldr == null) { - return mReferent; - } - if (Strings.isNullOrEmpty(subpathRemote)) { - mReferent = new ImapPath(owner, fldr, mCredentials); - } else { - mReferent = ImapPath.get(owner, fldr.getPath() + - (fldr.getPath().equals("/") ? "" : "/") + subpathRemote, mCredentials, imapMailboxStore); - } - - if (mReferent != this) { - mReferent.mScope = Scope.REFERENCE; - } - return mReferent; + return imapMailboxStore; } protected short getFolderRights() throws ServiceException { @@ -540,7 +550,6 @@ protected short getFolderRights() throws ServiceException { } } - protected boolean isCreatable() { String path = mPath.toLowerCase(); return !path.matches("\\s*notebook\\s*(/.*)?") && From 7d65032867a20bbada00eab4e2d1d1c2c65b4d48 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 20 Sep 2017 15:56:59 +0100 Subject: [PATCH 099/142] SharedImapTests PMD fixes --- .../com/zimbra/qa/unittest/SharedImapTests.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index 14eadc96af5..04ab622fcb1 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -74,6 +74,7 @@ public abstract class SharedImapTests extends ImapTestBase { @Test(timeout=100000) public void imapPath() throws IOException, ServiceException, MessagingException { Account userAcct = TestUtil.getAccount(USER); + assertNotNull("Account object for user", userAcct); // Shuts up PMD complaint about missing asserts Account shareeAcct = TestUtil.createAccount(SHAREE); ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); ZMailbox zmbox = TestUtil.getZMailbox(USER); @@ -304,6 +305,7 @@ public void idleOnInboxNotification() throws IOException, ServiceException, Mess otherConnection = connectAndLogin(USER); String subject = "SharedImapTest-testIdleNotification"; ZMailbox zmbox = TestUtil.getZMailbox(USER); + assertNotNull("ZMailbox for USER", zmbox); TestUtil.addMessage(zmbox, subject, "1", null); doIdleNotificationCheck(connection, otherConnection, "INBOX"); } @@ -313,6 +315,7 @@ public void idleOnMountpoint() throws ServiceException, IOException, MessagingEx TestUtil.createAccount(SHAREE); ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); ZMailbox zmbox = TestUtil.getZMailbox(USER); + assertNotNull("ZMailbox for USER", zmbox); String sharedFolderName = String.format("INBOX/%s-shared", testId); String remoteFolderPath = "/" + sharedFolderName; TestUtil.createFolder(zmbox, remoteFolderPath); @@ -326,7 +329,8 @@ public void idleOnMountpoint() throws ServiceException, IOException, MessagingEx @Test(timeout=100000) public void idleOnFolderViaHome() throws ServiceException, IOException, MessagingException { - TestUtil.createAccount(SHAREE); + Account shareeAcct = TestUtil.createAccount(SHAREE); + assertNotNull("Account for SHAREE", shareeAcct); connection = connectAndSelectInbox(USER); String sharedFolderName = String.format("INBOX/%s-shared", testId); connection.create(sharedFolderName); @@ -359,6 +363,7 @@ public void statusOnInbox() throws ServiceException, IOException, MessagingExcep otherConnection.close(); otherConnection = null; ZMailbox zmbox = TestUtil.getZMailbox(USER); + assertNotNull("ZMailbox for USER", zmbox); new StatusExecutor(connection).setExists(2).setRecent(0) .execShouldSucceed("INBOX", "UIDNEXT", "MESSAGES", "RECENT"); /* Add a message so that the RECENT count will be > 0 */ @@ -372,6 +377,7 @@ public void statusOnMountpoint() throws ServiceException, IOException, Messaging TestUtil.createAccount(SHAREE); ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); ZMailbox zmbox = TestUtil.getZMailbox(USER); + assertNotNull("ZMailbox for USER", zmbox); String sharedFolderName = String.format("INBOX/%s", testInfo.getMethodName()); String remoteFolderPath = "/" + sharedFolderName; ZFolder zfolder = TestUtil.createFolder(zmbox, remoteFolderPath); @@ -928,7 +934,6 @@ public void testStoreTags() throws Exception { assertTrue(tags != null && tags.size() == 1); assertEquals("T1", tags.get(0).getName()); - connection.store(seq+"", "-FLAGS", tagName3); data = connection.fetch(seq+"", "FLAGS"); assertEquals(1, data.size()); @@ -1889,7 +1894,8 @@ private String url(String mbox, AppendResult res) { @Test(timeout=100000) public void listSharedFolderViaHome() throws ServiceException, IOException { - TestUtil.createAccount(SHAREE); + Account shareeAcct = TestUtil.createAccount(SHAREE); + assertNotNull("Account for SHAREE", shareeAcct); connection = connectAndSelectInbox(); String sharedFolderName = String.format("INBOX/%s-shared", testId); connection.create(sharedFolderName); @@ -2016,6 +2022,7 @@ public void mountpointWithSubFolder() throws ServiceException, IOException, Mess SubFolderEnv subFolderEnv = new SubFolderEnv(sharedFolderName, subFolder); ZMailbox userZmbox = TestUtil.getZMailbox(USER); + assertNotNull("ZMailbox for USER", userZmbox); ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); String mountpointName = String.format("%s's %s-shared", USER, testId); @@ -2058,12 +2065,12 @@ public void mountpointWithSubFolder() throws ServiceException, IOException, Mess otherConnection = null; } - @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") // checking done in called methods @Test(timeout=100000) public void homeNameSpaceWithSubFolder() throws ServiceException, IOException, MessagingException { String sharedFolderName = String.format("INBOX/%s-shared", testId); String subFolder = sharedFolderName + "/subFolder"; - TestUtil.createAccount(SHAREE); + Account shareeAcct = TestUtil.createAccount(SHAREE); + assertNotNull("Account for SHAREE", shareeAcct); SubFolderEnv subFolderEnv = new SubFolderEnv(sharedFolderName, subFolder); connection = connectAndLogin(USER); connection.setacl(sharedFolderName, SHAREE, "lrswickxteda"); From 2f1df123dd0f4d5852b759ea72be15036dc3439e Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Wed, 20 Sep 2017 14:22:54 -0700 Subject: [PATCH 100/142] add external client instance to ZimbraHttpClientManager --- .../httpclient/ZimbraHttpClientManager.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java b/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java index 6aabf20684f..15ba34ef3fe 100644 --- a/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java +++ b/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java @@ -32,9 +32,12 @@ public class ZimbraHttpClientManager { protected static ZimbraHttpClientManager instance; final CloseableHttpAsyncClient internalAsyncClient; final CloseableHttpClient internalClient; + final CloseableHttpClient externalClient; final PoolingHttpClientConnectionManager internalConnectionMgr; + final PoolingHttpClientConnectionManager externallConnectionMgr; final RequestConfig internalRequestConfig; - + final RequestConfig externalRequestConfig; + public ZimbraHttpClientManager() { SSLContext sslcontext = null; try { @@ -68,6 +71,21 @@ public ZimbraHttpClientManager() { .setTcpNoDelay(LC.httpclient_internal_connmgr_tcp_nodelay.booleanValue()) .build()) .build(); + externallConnectionMgr = new PoolingHttpClientConnectionManager(); + externallConnectionMgr.setDefaultMaxPerRoute(LC.httpclient_external_connmgr_max_host_connections.intValue()); + externallConnectionMgr.setMaxTotal(LC.httpclient_external_connmgr_max_total_connections.intValue()); + externalRequestConfig = RequestConfig.custom(). + setConnectTimeout(LC.httpclient_external_connmgr_connection_timeout.intValue()) + .setSocketTimeout(LC.httpclient_external_connmgr_so_timeout.intValue()) + .setStaleConnectionCheckEnabled(LC.httpclient_external_connmgr_stale_connection_check.booleanValue()) + .build(); + externalClient = HttpClientBuilder.create() + .setConnectionManager(externallConnectionMgr) + .setDefaultRequestConfig(externalRequestConfig) + .setDefaultSocketConfig(SocketConfig.custom() + .setTcpNoDelay(LC.httpclient_external_connmgr_tcp_nodelay.booleanValue()) + .build()) + .build(); } public static synchronized ZimbraHttpClientManager getInstance() { @@ -91,6 +109,10 @@ public CloseableHttpClient getInternalHttpClient() { return internalClient; } + public CloseableHttpClient getExternalHttpClient() { + return externalClient; + } + /** * orderly shutdown the client */ @@ -98,5 +120,6 @@ public CloseableHttpClient getInternalHttpClient() { public void shutDown() throws IOException { internalAsyncClient.close(); internalClient.close(); + externalClient.close(); } } From cdb2dacd8fae06aaabf7a7a327311702cbf50fce Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Wed, 20 Sep 2017 14:32:27 -0700 Subject: [PATCH 101/142] set scope on members --- .../common/httpclient/ZimbraHttpClientManager.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java b/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java index 15ba34ef3fe..d151b798a7f 100644 --- a/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java +++ b/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java @@ -30,13 +30,13 @@ public class ZimbraHttpClientManager { protected static ZimbraHttpClientManager instance; - final CloseableHttpAsyncClient internalAsyncClient; - final CloseableHttpClient internalClient; - final CloseableHttpClient externalClient; - final PoolingHttpClientConnectionManager internalConnectionMgr; - final PoolingHttpClientConnectionManager externallConnectionMgr; - final RequestConfig internalRequestConfig; - final RequestConfig externalRequestConfig; + private final CloseableHttpAsyncClient internalAsyncClient; + private final CloseableHttpClient internalClient; + private final CloseableHttpClient externalClient; + private final PoolingHttpClientConnectionManager internalConnectionMgr; + private final PoolingHttpClientConnectionManager externallConnectionMgr; + private final RequestConfig internalRequestConfig; + private final RequestConfig externalRequestConfig; public ZimbraHttpClientManager() { SSLContext sslcontext = null; From 9e4bd8f36a3ee3d99762d505a4c151c7fd58a8c7 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Wed, 20 Sep 2017 19:33:30 -0700 Subject: [PATCH 102/142] move connection manager and request config to local scope --- .../common/httpclient/ZimbraHttpClientManager.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java b/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java index d151b798a7f..b55a48634b3 100644 --- a/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java +++ b/common/src/java/com/zimbra/common/httpclient/ZimbraHttpClientManager.java @@ -33,12 +33,11 @@ public class ZimbraHttpClientManager { private final CloseableHttpAsyncClient internalAsyncClient; private final CloseableHttpClient internalClient; private final CloseableHttpClient externalClient; - private final PoolingHttpClientConnectionManager internalConnectionMgr; - private final PoolingHttpClientConnectionManager externallConnectionMgr; - private final RequestConfig internalRequestConfig; - private final RequestConfig externalRequestConfig; - public ZimbraHttpClientManager() { + PoolingHttpClientConnectionManager internalConnectionMgr; + PoolingHttpClientConnectionManager externallConnectionMgr; + RequestConfig internalRequestConfig; + RequestConfig externalRequestConfig; SSLContext sslcontext = null; try { sslcontext = SSLContexts.custom().loadTrustMaterial(CustomTrustManager.loadKeyStore(), new TrustSelfSignedStrategy()).build(); From ec6301c3ed61cf9acf2df23b4ec5a2e896da9b0a Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Sat, 23 Sep 2017 23:54:19 +0000 Subject: [PATCH 103/142] add a SOAP test for copying to shared folder via IMAP --- .../zimbra/qa/unittest/SharedImapTests.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java index 04ab622fcb1..b1beb0783e1 100644 --- a/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java +++ b/store/src/java/com/zimbra/qa/unittest/SharedImapTests.java @@ -2389,6 +2389,37 @@ public void searchBodyMountpoint() throws ServiceException, IOException { otherConnection = null; } + @Test + public void copyToMountpoint() throws Exception { + TestUtil.createAccount(SHAREE); + ZMailbox userZmbox = TestUtil.getZMailbox(USER); + ZMailbox shareeZmbox = TestUtil.getZMailbox(SHAREE); + String sharedFolder = "INBOX/share"; + String mountpoint = String.format("shared-", testInfo.getMethodName()); + String subject = "SharedImapTests-testMessage"; + TestUtil.createMountpoint(userZmbox, "/" + sharedFolder, shareeZmbox, mountpoint); + TestUtil.addMessage(shareeZmbox, subject, Integer.toString(Mailbox.ID_FOLDER_INBOX), null); + connection = connectAndSelectInbox(SHAREE); + CopyResult copyResult = connection.copy("1", mountpoint); + assertNotNull("copyResult.getFromUids()", copyResult.getFromUids()); + assertNotNull("copyResult.getToUids()", copyResult.getToUids()); + assertEquals("Number of fromUIDs", 1, copyResult.getFromUids().length); + assertEquals("Number of toUIDs", 1, copyResult.getToUids().length); + MailboxInfo selectMboxInfo = connection.select(mountpoint); + assertNotNull(String.format("Select result for folder=%s", mountpoint), selectMboxInfo); + assertEquals("Select result Folder Name folder", mountpoint, selectMboxInfo.getName()); + assertEquals(String.format("Number of exists for folder=%s after copy", mountpoint), + 1, selectMboxInfo.getExists()); + Map mdMap = this.doFetchShouldSucceed(connection, "1:*", "(ENVELOPE)", + Lists.newArrayList(subject)); + MessageData md = mdMap.values().iterator().next(); + assertNull("Internal date was NOT requested and should be NULL", md.getInternalDate()); + BodyStructure bs = md.getBodyStructure(); + assertNull("Body Structure was not requested and should be NULL", bs); + Body[] body = md.getBodySections(); + assertNull("body sections were not requested and should be null", body); + } + protected void flushCacheIfNecessary() throws Exception { // overridden by tests running against imapd } From a55813c6f0a9a7fef62cbbe970fe5946d4929ca4 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Sat, 23 Sep 2017 23:54:55 +0000 Subject: [PATCH 104/142] return correct imap mail store --- store/src/java/com/zimbra/cs/imap/ImapPath.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/store/src/java/com/zimbra/cs/imap/ImapPath.java b/store/src/java/com/zimbra/cs/imap/ImapPath.java index d984bbe13e2..e4e9a458e97 100644 --- a/store/src/java/com/zimbra/cs/imap/ImapPath.java +++ b/store/src/java/com/zimbra/cs/imap/ImapPath.java @@ -256,8 +256,8 @@ protected boolean onLocalServer() throws ServiceException { } protected MailboxStore getOwnerMailbox() throws ServiceException { - getOwnerImapMailboxStore(!onLocalServer()); - return (null == imapMboxStore) ? null : imapMboxStore.getMailboxStore(); + ImapMailboxStore store = getOwnerImapMailboxStore(); + return (null == store) ? null : store.getMailboxStore(); } protected ImapMailboxStore getOwnerImapMailboxStore() throws ServiceException { From 53a4d39fe2b5d720a1de2af26a076cc02b6f6bed Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Sun, 24 Sep 2017 17:49:52 +0530 Subject: [PATCH 105/142] ZCS-3017 Add separate attributes for NG modules initialisation --- .../common/account/ZAttrProvisioning.java | 20 ++- store/conf/attrs/zimbra-attrs.xml | 16 +- .../com/zimbra/cs/account/ZAttrConfig.java | 164 +++++++++++++++++- .../com/zimbra/cs/account/ZAttrServer.java | 164 +++++++++++++++++- .../admin/GetAdminExtensionZimlets.java | 48 +++-- 5 files changed, 383 insertions(+), 29 deletions(-) diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index e3b5f2670be..f25bb31275d 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -11524,6 +11524,22 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc @ZAttr(id=2119) public static final String A_zimbraNetworkAdminEnabled = "zimbraNetworkAdminEnabled"; + /** + * Whether to enable zimbra network new generation backup module. + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public static final String A_zimbraNetworkBackupNGEnabled = "zimbraNetworkBackupNGEnabled"; + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public static final String A_zimbraNetworkHSMNGEnabled = "zimbraNetworkHSMNGEnabled"; + /** * Contents of a signed Zimbra license key - an XML string. */ @@ -11539,7 +11555,9 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkMobileNGEnabled = "zimbraNetworkMobileNGEnabled"; /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @since ZCS 8.8.0 */ diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index 6e591634a88..139423d01da 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9372,12 +9372,13 @@ TODO: delete them permanently from here outgoing sieve script defined by admin (not able to edit and view from the end user) applied after the end user filter rule - + TRUE Whether to enable zimbra network new generation modules. + Separate attributes have bee introduced for each module, hence this has been deprecated. - + TRUE Whether to enable zimbra network new generation mobile sync module. @@ -9585,4 +9586,15 @@ TODO: delete them permanently from here + + TRUE + Whether to enable zimbra network new generation HSM module. + + + + + TRUE + Whether to enable zimbra network new generation backup module. + + diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index 333391fe5d1..467b1a14adf 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -47504,6 +47504,150 @@ public Map unsetNetworkAdminEnabled(Map attrs) { return attrs; } + /** + * Whether to enable zimbra network new generation backup module. + * + * @return zimbraNetworkBackupNGEnabled, or true if unset + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public boolean isNetworkBackupNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, true, true); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public Map unsetNetworkBackupNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @return zimbraNetworkHSMNGEnabled, or true if unset + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public boolean isNetworkHSMNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public Map unsetNetworkHSMNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + return attrs; + } + /** * Contents of a signed Zimbra license key - an XML string. * @@ -47639,7 +47783,9 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -47651,7 +47797,9 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47666,7 +47814,9 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47682,7 +47832,9 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47696,7 +47848,9 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index 595861f5de4..ea63fb7bbf2 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -35533,6 +35533,150 @@ public Map unsetNetworkAdminEnabled(Map attrs) { return attrs; } + /** + * Whether to enable zimbra network new generation backup module. + * + * @return zimbraNetworkBackupNGEnabled, or true if unset + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public boolean isNetworkBackupNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, true, true); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2127) + public Map unsetNetworkBackupNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @return zimbraNetworkHSMNGEnabled, or true if unset + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public boolean isNetworkHSMNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.3 + */ + @ZAttr(id=2126) + public Map unsetNetworkHSMNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + return attrs; + } + /** * Whether to enable zimbra network new generation mobile sync module. * @@ -35606,7 +35750,9 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -35618,7 +35764,9 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35633,7 +35781,9 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35649,7 +35799,9 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35663,7 +35815,9 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.3. Separate attributes have bee introduced for + * each module, hence this has been deprecated.. Orig desc: Whether to + * enable zimbra network new generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java index a6241bc91b3..c774e58a301 100644 --- a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java +++ b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java @@ -52,13 +52,18 @@ public Element handle(Element request, Map context) throws Servi } private void doExtensionZimlets(ZimbraSoapContext zsc, Map context, Element response) throws ServiceException { - boolean isNGEnabled = true; - boolean isMobileNGEnabled = true; - boolean isNetworkAdminEnabled = true; + + boolean mobileNGEnabled = true; + boolean networkAdminEnabled = true; + boolean hsmNGEnabled = true; + boolean backupRestoreNGEnabled = true; + try { - isNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkModulesNGEnabled(); - isMobileNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkMobileNGEnabled(); - isNetworkAdminEnabled = Provisioning.getInstance().getLocalServer().isNetworkAdminEnabled(); + mobileNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkMobileNGEnabled(); + networkAdminEnabled = Provisioning.getInstance().getLocalServer().isNetworkAdminEnabled(); + hsmNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkHSMNGEnabled(); + backupRestoreNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkBackupNGEnabled(); + } catch (ServiceException e) { ZimbraLog.mailbox.warn("Exception while getting zimbraNetworkModulesNGEnabled.", e); } @@ -72,23 +77,34 @@ private void doExtensionZimlets(ZimbraSoapContext zsc, Map conte if (z.isExtension()) { boolean include = true; - if ("com_zimbra_hsm".equals(z.getName()) || "com_zimbra_backuprestore".equals(z.getName()) - || "com_zimbra_delegatedadmin".equals(z.getName())) { - include = !isNGEnabled; + if ("com_zimbra_mobilesync".equals(z.getName()) && mobileNGEnabled) { + include = !mobileNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkModulesNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkMobileNGEnabled is true.", z.getName()); } } - if ("com_zimbra_mobilesync".equals(z.getName()) && isNGEnabled) { - include = !isMobileNGEnabled; + + if ("com_zimbra_hsm".equals(z.getName()) && hsmNGEnabled) { + include = !hsmNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkMobileNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworHSMNGEnabled is true.", z.getName()); + } + } + + if ("com_zimbra_backuprestore".equals(z.getName()) && backupRestoreNGEnabled) { + include = !backupRestoreNGEnabled; + if (!include) { + ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkBackupNGEnabled is true.", z.getName()); } } - if ("com_zimbra_delegatedadmin".equals(z.getName()) && isNetworkAdminEnabled) - include = include && (AccessManager.getInstance() instanceof ACLAccessManager); - if (include) + if ("com_zimbra_delegatedadmin".equals(z.getName()) && networkAdminEnabled) { + include = !networkAdminEnabled; + include = include && (AccessManager.getInstance() instanceof ACLAccessManager); + } + + if (include) { ZimletUtil.listZimlet(response, z, -1, Presence.enabled); // admin zimlets are all enabled + } } } } From b3a6ab9a7cc786818b1b1402a2e606d5571bbf73 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Sun, 24 Sep 2017 11:59:20 +0100 Subject: [PATCH 106/142] ZCS-3016:TestZClient new test copyMsgToMountpoint Also changed users etc to be test specific --- .../com/zimbra/qa/unittest/TestZClient.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/TestZClient.java b/store/src/java/com/zimbra/qa/unittest/TestZClient.java index 5b6b99dfb04..5160d141f8f 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestZClient.java +++ b/store/src/java/com/zimbra/qa/unittest/TestZClient.java @@ -39,6 +39,8 @@ import java.util.Map; import java.util.Set; +import javax.mail.MessagingException; + import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.Before; @@ -60,11 +62,13 @@ import com.zimbra.client.ZMailbox.GalEntryType; import com.zimbra.client.ZMailbox.OpenIMAPFolderParams; import com.zimbra.client.ZMailbox.Options; +import com.zimbra.client.ZMailbox.ZActionResult; import com.zimbra.client.ZMailbox.ZAppointmentResult; import com.zimbra.client.ZMailbox.ZOutgoingMessage; import com.zimbra.client.ZMailbox.ZSearchGalResult; import com.zimbra.client.ZMessage; import com.zimbra.client.ZMessageHit; +import com.zimbra.client.ZMountpoint; import com.zimbra.client.ZPrefs; import com.zimbra.client.ZSearchFolder; import com.zimbra.client.ZSearchHit; @@ -119,14 +123,18 @@ public class TestZClient { @Rule public TestName testInfo = new TestName(); - private static String NAME_PREFIX = "TestZClient"; - private static String RECIPIENT_USER_NAME = NAME_PREFIX + "_user2"; - private static final String USER_NAME = NAME_PREFIX + "_user1"; - private static final String FOLDER_NAME = "testfolder"; + private static String NAME_PREFIX; + private static String RECIPIENT_USER_NAME; + private static String USER_NAME; + private static String FOLDER_NAME; @Before public void setUp() throws Exception { + NAME_PREFIX = String.format("%s-%d", testInfo.getMethodName(), (int)Math.abs(Math.random()*100)); + RECIPIENT_USER_NAME = NAME_PREFIX + "_user2"; + USER_NAME = NAME_PREFIX + "_user1"; + FOLDER_NAME = String.format("%s-Folder", this.getClass().getSimpleName()); if (!TestUtil.fromRunUnitTests) { TestUtil.cliSetup(); } @@ -1375,6 +1383,21 @@ public void createSearchFolder() throws ServiceException { "is:read", (String)null, SearchSortBy.nameAsc, ZFolder.Color.GREEN); } + @Test(timeout=100000) + public void copyMsgToMountpoint() throws ServiceException, IOException, MessagingException { + String sharedFolder = "shared"; + String mountpoint = String.format("shared-", testInfo.getMethodName()); + ZMailbox sharerZmbox = TestUtil.getZMailbox(RECIPIENT_USER_NAME); + ZMailbox shareeZmbox = TestUtil.getZMailbox(USER_NAME); + ZMountpoint mp = TestUtil.createMountpoint(sharerZmbox, "/" + sharedFolder, shareeZmbox, mountpoint); + String msgId = TestUtil.addMessage(shareeZmbox, String.format("test message for %s", + testInfo.getMethodName())); + ZActionResult result = shareeZmbox.moveMessage(msgId, mp.getFolderIdAsString()); + assertNotNull("ZActionResult for move message", result); + assertNotNull("ZActionResult Ids array for move message", result.getIdsAsArray()); + assertEquals("ZActionResult Ids array length for move message", 1, result.getIdsAsArray().length); + } + public static void main(String[] args) throws Exception { TestUtil.cliSetup(); TestUtil.runTest(TestZClient.class); From 2cc5e32fbd3e3c092d796e5f6b5166278a0ae7b1 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Sun, 24 Sep 2017 12:25:03 +0100 Subject: [PATCH 107/142] ZCS-3016:ZMailbox setup accountId/name if known `initTargetAccount` will populate fields `accountId` or `name` if they are known to reduce the likelyhood of calls to `GetInfoRequest` to get their values - which is not allowed in the 'on-behalf-of' case --- client/src/java/com/zimbra/client/ZMailbox.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index dcbb80df47a..dc69870c1be 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -242,11 +242,10 @@ public class ZMailbox implements ToZJSONObject, MailboxStore { private static final int CALENDAR_FOLDER_ALL = -1; /* Generally set "accountId" explicitly when using another user's auth token, as don't have GetAccountInfo - * capability which is what is normally used to get the account ID. Choosing not to populate accountId - * for other use cases to avoid increasing memory footprint. + * capability which is what is normally used to get the account ID. Note that not always set. */ private String accountId = null; - /* As above, generally set "name" explicitly only when using another user's auth token */ + /* As above, generally set "name" explicitly when using another user's auth token */ private String name = null; private String authName = null; private static final Pattern sAttachmentId = Pattern.compile("\\d+,'.*','(.*)'"); @@ -750,8 +749,10 @@ private void initPreAuth(Options options) { private void initTargetAccount(String key, AccountBy by) { if (AccountBy.id.equals(by)) { mTransport.setTargetAcctId(key); + accountId = key; } else if (AccountBy.name.equals(by)) { mTransport.setTargetAcctName(key); + name = key; } } From 806ac58a86dfe80fb2e3a6e3a220772594e36cf4 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Sun, 24 Sep 2017 12:27:39 +0100 Subject: [PATCH 108/142] ZCS-3016:onBehalfOf - set ZMailbox name/accountId In call locations where we're creating an onBehalfOf `ZMailbox` (or not sure whether we are or not) setup the `ZMailbox` fields `name` and `accountId`. Note that the ZMailbox constructor will setup the one associated with the TargetAccount in `ZOptions`. After this change, when runnint the `TestZClient` SOAP tests, no longer get any of these lines in mailbox.log: Code:service.PERM_DENIED Arg:(NOT_EFFECTIVE_DELEGATED_ADMIN_ACCOUNT, STR, "VIOLATED") With a complete RunUnitTests run - the only occurrences of the string are related to not having Admin auth caps. --- .../src/java/com/zimbra/cs/dav/DavContext.java | 6 +++++- .../cs/dav/resource/MailItemResource.java | 6 +++++- .../cs/dav/resource/RemoteCollection.java | 12 ++++++++---- .../java/com/zimbra/cs/filter/FilterUtil.java | 17 +++++++++++------ .../java/com/zimbra/cs/mailbox/MailSender.java | 6 +++++- .../java/com/zimbra/cs/mailbox/Mailbox.java | 18 ++++++++++-------- .../mailbox/calendar/cache/CtagInfoCache.java | 2 +- .../com/zimbra/cs/service/mail/GetMiniCal.java | 15 ++++++++------- .../com/zimbra/cs/service/mail/ItemAction.java | 1 + .../cs/service/mail/ItemActionHelper.java | 1 + .../com/zimbra/cs/service/mail/Search.java | 1 + .../cs/service/mail/SendInviteReply.java | 6 +++++- 12 files changed, 61 insertions(+), 30 deletions(-) diff --git a/store/src/java/com/zimbra/cs/dav/DavContext.java b/store/src/java/com/zimbra/cs/dav/DavContext.java index 631bf2e5bbb..f7c46bb2591 100644 --- a/store/src/java/com/zimbra/cs/dav/DavContext.java +++ b/store/src/java/com/zimbra/cs/dav/DavContext.java @@ -677,7 +677,11 @@ public ZMailbox getZMailbox(Account acct) throws ServiceException { zoptions.setNoSession(true); zoptions.setTargetAccount(acct.getId()); zoptions.setTargetAccountBy(Key.AccountBy.id); - return ZMailbox.getMailbox(zoptions); + ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + if (zmbx != null) { + zmbx.setName(acct.getName()); /* need this when logging in using another user's auth */ + } + return zmbx; } public String getNewName() throws DavException { diff --git a/store/src/java/com/zimbra/cs/dav/resource/MailItemResource.java b/store/src/java/com/zimbra/cs/dav/resource/MailItemResource.java index cd82f676e70..938e4cbf5c9 100644 --- a/store/src/java/com/zimbra/cs/dav/resource/MailItemResource.java +++ b/store/src/java/com/zimbra/cs/dav/resource/MailItemResource.java @@ -254,7 +254,11 @@ private static ZMailbox getZMailbox(DavContext ctxt, Collection col) throws Serv zoptions.setNoSession(true); zoptions.setTargetAccount(acct.getId()); zoptions.setTargetAccountBy(Key.AccountBy.id); - return ZMailbox.getMailbox(zoptions); + ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + if (zmbx != null) { + zmbx.setName(acct.getName()); /* need this when logging in using another user's auth */ + } + return zmbx; } private void deleteDestinationItem(DavContext ctxt, Collection dest, int id) throws ServiceException, DavException { Mailbox mbox = getMailbox(ctxt); diff --git a/store/src/java/com/zimbra/cs/dav/resource/RemoteCollection.java b/store/src/java/com/zimbra/cs/dav/resource/RemoteCollection.java index c928a45b1d0..0774ad2c301 100644 --- a/store/src/java/com/zimbra/cs/dav/resource/RemoteCollection.java +++ b/store/src/java/com/zimbra/cs/dav/resource/RemoteCollection.java @@ -21,6 +21,8 @@ import javax.servlet.http.HttpServletResponse; +import com.zimbra.client.ZFolder; +import com.zimbra.client.ZMailbox; import com.zimbra.common.account.Key; import com.zimbra.common.auth.ZAuthToken; import com.zimbra.common.service.ServiceException; @@ -40,8 +42,6 @@ import com.zimbra.cs.service.AuthProvider; import com.zimbra.cs.service.util.ItemId; import com.zimbra.cs.util.AccountUtil; -import com.zimbra.client.ZFolder; -import com.zimbra.client.ZMailbox; public class RemoteCollection extends Collection { @@ -78,7 +78,7 @@ public RemoteCollection(DavContext ctxt, String path, Account user) throws DavEx if (zview != null) view = MailItem.Type.of(zview.name()); } - + @Override public void delete(DavContext ctxt) throws DavException { throw new DavException("cannot delete this resource", HttpServletResponse.SC_FORBIDDEN, null); @@ -101,7 +101,11 @@ static ZMailbox getRemoteMailbox(ZAuthToken zat, String ownerId) throws ServiceE zoptions.setNoSession(true); zoptions.setTargetAccount(ownerId); zoptions.setTargetAccountBy(Key.AccountBy.id); - return ZMailbox.getMailbox(zoptions); + ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + if (zmbx != null) { + zmbx.setName(target.getName()); /* need this when logging in using another user's auth */ + } + return zmbx; } protected void getMountpointTarget(DavContext ctxt) throws ServiceException { ZAuthToken zat = AuthProvider.getAuthToken(ctxt.getAuthAccount()).toZAuthToken(); diff --git a/store/src/java/com/zimbra/cs/filter/FilterUtil.java b/store/src/java/com/zimbra/cs/filter/FilterUtil.java index 6149988e0b2..e7a2e2bbefe 100644 --- a/store/src/java/com/zimbra/cs/filter/FilterUtil.java +++ b/store/src/java/com/zimbra/cs/filter/FilterUtil.java @@ -31,7 +31,7 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang.StringEscapeUtils; + import javax.mail.Address; import javax.mail.Header; import javax.mail.MessagingException; @@ -40,6 +40,7 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.apache.jsieve.exception.SyntaxException; @@ -257,7 +258,11 @@ public static ZMailbox getRemoteZMailbox(Mailbox localMbox, Mountpoint mountpoin zoptions.setNoSession(true); zoptions.setTargetAccount(account.getId()); zoptions.setTargetAccountBy(AccountBy.id); - return ZMailbox.getMailbox(zoptions); + ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + if (zmbx != null) { + zmbx.setName(account.getName()); /* need this when logging in using another user's auth */ + } + return zmbx; } public static final String HEADER_FORWARDED = "X-Zimbra-Forwarded"; @@ -850,7 +855,7 @@ public static String[] getTagsUnion(String[] tags1, String[] tags2) { * @param matchedVariables a list of Matched Variables * @param sourceStr text string that may contain "variable-ref" (RFC 5229 Section 3.) * @return Replaced text string - * @throws SyntaxException + * @throws SyntaxException */ public static String replaceVariables(ZimbraMailAdapter mailAdapter, String sourceStr) throws SyntaxException { if (null == mailAdapter) { @@ -860,7 +865,7 @@ public static String replaceVariables(ZimbraMailAdapter mailAdapter, String sour return sourceStr; } validateVariableIndex(sourceStr); - + try { Require.checkCapability(mailAdapter, CAPABILITY_VARIABLES); } catch (SyntaxException e) { @@ -989,7 +994,7 @@ public static String handleQuotedAndEncodedVar(String varName) { } } processedStr = sb.toString(); - + return processedStr; } @@ -1035,7 +1040,7 @@ else if (isSieveMatcherSpecialChar(pattern.charAt(ch + 1))) } return buffer.toString(); } - + /** * Returns true if the char is a special char for regex */ diff --git a/store/src/java/com/zimbra/cs/mailbox/MailSender.java b/store/src/java/com/zimbra/cs/mailbox/MailSender.java index 5720c51dfe0..1701cfecff8 100644 --- a/store/src/java/com/zimbra/cs/mailbox/MailSender.java +++ b/store/src/java/com/zimbra/cs/mailbox/MailSender.java @@ -805,7 +805,11 @@ private Object getTargetMailbox(OperationContext octxt, Account authuser, boolea options.setTargetAccount(targetUser.getId()); options.setTargetAccountBy(AccountBy.id); } - return ZMailbox.getMailbox(options); + ZMailbox zmbx = ZMailbox.getMailbox(options); + if (zmbx != null) { + zmbx.setName(targetUser.getName()); + } + return zmbx; } } catch (Exception e) { ZimbraLog.smtp.info("could not fetch home mailbox for delegated send", e); diff --git a/store/src/java/com/zimbra/cs/mailbox/Mailbox.java b/store/src/java/com/zimbra/cs/mailbox/Mailbox.java index 8fdcbc822a4..5275bef2337 100644 --- a/store/src/java/com/zimbra/cs/mailbox/Mailbox.java +++ b/store/src/java/com/zimbra/cs/mailbox/Mailbox.java @@ -763,7 +763,7 @@ protected Mailbox(MailboxData data) { // index init done in open() lock = new MailboxLock(data.accountId, this); } - + public void setGalSyncMailbox(boolean galSyncMailbox) { this.galSyncMailbox = galSyncMailbox; } @@ -1878,7 +1878,7 @@ public String getConfig(OperationContext octxt, Pattern pattern) throws ServiceE SortedSet clientIds= new TreeSet(mData.configKeys); for (String key : clientIds) { if (pattern.matcher(key).matches()) { - + previousDeviceId = key; if (previousDeviceId.indexOf(":") != -1) { int index = previousDeviceId.indexOf(":"); @@ -1888,7 +1888,7 @@ public String getConfig(OperationContext octxt, Pattern pattern) throws ServiceE if (!tmp.contains("build")) { break; } - + } } } @@ -5899,6 +5899,7 @@ private void processICalReplies(OperationContext octxt, ZVCalendar cal, String s options.setUri(uri); options.setNoSession(true); ZMailbox zmbox = ZMailbox.getMailbox(options); + zmbox.setAccountId(orgAccount.getId()); zmbox.iCalReply(ical, sender); } catch (IOException e) { throw ServiceException.FAILURE("Error while posting REPLY to organizer mailbox host", e); @@ -6055,16 +6056,16 @@ private Message addMessage(OperationContext octxt, ParsedMessage pm, int folderI } StagedBlob staged = sm.stage(blob, this); - + Account account = this.getAccount(); boolean localMsgMarkedRead = false; - if (account.getPrefMailForwardingAddress() != null && account.isFeatureMailForwardingEnabled() + if (account.getPrefMailForwardingAddress() != null && account.isFeatureMailForwardingEnabled() && account.isFeatureMarkMailForwardedAsRead()) { ZimbraLog.mailbox.debug("Marking forwarded message as read."); flags = flags & ~Flag.BITMASK_UNREAD; localMsgMarkedRead = true; - } - + } + lock.lock(); try { @@ -6073,7 +6074,7 @@ private Message addMessage(OperationContext octxt, ParsedMessage pm, int folderI rcptEmail, dinfo, customData, dctxt, staged); if (localMsgMarkedRead && account.getPrefMailSendReadReceipts().isAlways()) { SendDeliveryReport.sendReport(account, message, true, null, null); - } + } return message; } finally { if (deleteIncoming) { @@ -8760,6 +8761,7 @@ public Mountpoint refreshMountpoint(OperationContext octxt, int mountpointId) th zoptions.setTargetAccount(shareOwner.getId()); zoptions.setTargetAccountBy(Key.AccountBy.id); ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + zmbx.setName(shareOwner.getName()); /* need this when logging in using another user's auth */ ZFolder zfolder = zmbx.getFolderByUuid(shloc.getUuid()); if (zfolder != null) { diff --git a/store/src/java/com/zimbra/cs/mailbox/calendar/cache/CtagInfoCache.java b/store/src/java/com/zimbra/cs/mailbox/calendar/cache/CtagInfoCache.java index be214bce56e..5ded0853002 100644 --- a/store/src/java/com/zimbra/cs/mailbox/calendar/cache/CtagInfoCache.java +++ b/store/src/java/com/zimbra/cs/mailbox/calendar/cache/CtagInfoCache.java @@ -56,7 +56,7 @@ public class CtagInfoCache { - private MemcachedMap mMemcachedLookup; + private final MemcachedMap mMemcachedLookup; CtagInfoCache() { ZimbraMemcachedClient memcachedClient = MemcachedConnector.getClient(); diff --git a/store/src/java/com/zimbra/cs/service/mail/GetMiniCal.java b/store/src/java/com/zimbra/cs/service/mail/GetMiniCal.java index 5e2c1fa7ff8..b5755e76ac6 100644 --- a/store/src/java/com/zimbra/cs/service/mail/GetMiniCal.java +++ b/store/src/java/com/zimbra/cs/service/mail/GetMiniCal.java @@ -27,6 +27,11 @@ import java.util.Set; import java.util.TreeSet; +import com.zimbra.client.ZMailbox; +import com.zimbra.client.ZMailbox.ZGetMiniCalResult; +import com.zimbra.client.ZMailbox.ZMiniCalError; +import com.zimbra.common.account.Key; +import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.calendar.ICalTimeZone; import com.zimbra.common.calendar.WellKnownTimeZones; import com.zimbra.common.localconfig.LC; @@ -39,8 +44,6 @@ import com.zimbra.cs.account.AuthToken; import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.account.Server; -import com.zimbra.common.account.Key; -import com.zimbra.common.account.Key.AccountBy; import com.zimbra.cs.mailbox.Folder; import com.zimbra.cs.mailbox.MailItem; import com.zimbra.cs.mailbox.MailServiceException; @@ -51,17 +54,14 @@ import com.zimbra.cs.mailbox.calendar.IcalXmlStrMap; import com.zimbra.cs.mailbox.calendar.Util; import com.zimbra.cs.mailbox.calendar.cache.CalSummaryCache; +import com.zimbra.cs.mailbox.calendar.cache.CalSummaryCache.CalendarDataResult; import com.zimbra.cs.mailbox.calendar.cache.CalendarCacheManager; import com.zimbra.cs.mailbox.calendar.cache.CalendarData; import com.zimbra.cs.mailbox.calendar.cache.CalendarItemData; import com.zimbra.cs.mailbox.calendar.cache.InstanceData; -import com.zimbra.cs.mailbox.calendar.cache.CalSummaryCache.CalendarDataResult; import com.zimbra.cs.service.util.ItemId; import com.zimbra.cs.service.util.ItemIdFormatter; import com.zimbra.cs.util.AccountUtil; -import com.zimbra.client.ZMailbox; -import com.zimbra.client.ZMailbox.ZGetMiniCalResult; -import com.zimbra.client.ZMailbox.ZMiniCalError; import com.zimbra.soap.ZimbraSoapContext; /* @@ -233,7 +233,7 @@ private static void addBusyDates(Calendar cal, CalendarData calData, long rangeS if (partStat == null) partStat = item.getDefaultData().getPartStat(); if (IcalXmlStrMap.PARTSTAT_DECLINED.equals(partStat)) - continue; + continue; Long start = inst.getDtStart(); if (start != null) { String datestampStart = getDatestamp(cal, start); @@ -272,6 +272,7 @@ private static void doRemoteFolders( zoptions.setTargetAccountBy(AccountBy.id); zoptions.setNoSession(true); ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + zmbx.setName(target.getName()); /* need this when logging in using another user's auth */ String remoteIds[] = new String[remoteFolders.size()]; for (int i=0; i < remoteIds.length; i++) remoteIds[i] = remoteFolders.get(i).toString(); ZGetMiniCalResult result = zmbx.getMiniCal(rangeStart, rangeEnd, remoteIds); diff --git a/store/src/java/com/zimbra/cs/service/mail/ItemAction.java b/store/src/java/com/zimbra/cs/service/mail/ItemAction.java index 46f94174866..b7a20fc60a5 100644 --- a/store/src/java/com/zimbra/cs/service/mail/ItemAction.java +++ b/store/src/java/com/zimbra/cs/service/mail/ItemAction.java @@ -503,6 +503,7 @@ private Account forceRemoteSession(ZimbraSoapContext zsc, Map co zoptions.setTargetAccount(owner.getId()); zoptions.setTargetAccountBy(Key.AccountBy.id); ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + zmbx.setName(owner.getName()); /* need this when logging in using another user's auth */ ZFolder zfolder = zmbx.getFolderById(iidFolder.toString(zsc.getAuthtokenAccountId())); if (!(zfolder instanceof ZMountpoint)) break; diff --git a/store/src/java/com/zimbra/cs/service/mail/ItemActionHelper.java b/store/src/java/com/zimbra/cs/service/mail/ItemActionHelper.java index a77692aed83..5e27683e39d 100644 --- a/store/src/java/com/zimbra/cs/service/mail/ItemActionHelper.java +++ b/store/src/java/com/zimbra/cs/service/mail/ItemActionHelper.java @@ -616,6 +616,7 @@ private ItemActionResult executeRemote() throws ServiceException, IOException { zoptions.setTargetAccount(target.getId()); zoptions.setTargetAccountBy(Key.AccountBy.id); ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + zmbx.setName(target.getName()); /* need this when logging in using another user's auth */ // check for mountpoints before going any further... ZFolder zfolder = zmbx.getFolderById(mIidFolder.toString(mAuthenticatedAccount)); diff --git a/store/src/java/com/zimbra/cs/service/mail/Search.java b/store/src/java/com/zimbra/cs/service/mail/Search.java index afe950ff200..80f7efae634 100644 --- a/store/src/java/com/zimbra/cs/service/mail/Search.java +++ b/store/src/java/com/zimbra/cs/service/mail/Search.java @@ -451,6 +451,7 @@ private static void searchRemoteAccountCalendars( zoptions.setTargetAccountBy(AccountBy.id); zoptions.setNoSession(true); ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + zmbx.setName(target.getName()); /* need this when logging in using another user's auth */ Element resp = zmbx.invoke(req); for (Element hit : resp.listElements()) { diff --git a/store/src/java/com/zimbra/cs/service/mail/SendInviteReply.java b/store/src/java/com/zimbra/cs/service/mail/SendInviteReply.java index 5a9c1b2c49c..41c08cc9092 100644 --- a/store/src/java/com/zimbra/cs/service/mail/SendInviteReply.java +++ b/store/src/java/com/zimbra/cs/service/mail/SendInviteReply.java @@ -476,7 +476,11 @@ private static ZMailbox getRemoteZMailbox(OperationContext octxt, Account authAc zoptions.setNoSession(true); zoptions.setTargetAccount(targetAcct.getId()); zoptions.setTargetAccountBy(Key.AccountBy.id); - return ZMailbox.getMailbox(zoptions); + ZMailbox zmbx = ZMailbox.getMailbox(zoptions); + if (zmbx != null) { + zmbx.setName(targetAcct.getName()); /* need this when logging in using another user's auth */ + } + return zmbx; } private static AddInviteResult sendAddInvite(ZMailbox zmbx, OperationContext octxt, Message msg) From ad1d2f76865cdf0134fbaf5c08208c2d8e38ed30 Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Mon, 25 Sep 2017 16:46:25 +0900 Subject: [PATCH 109/142] zcs-2915:Few mimes are discarded on LMTP inject [Bug] Five test scripts are failed because of a bug introduced by the fix of zcs-168. Any spammy message delivered to the user with empty filter rules was discarded. [Root cause] Originally when the triggering message was spammy, the Sieve filter is neither evaluated nor executed. After the fix of zcs-168, the Sieve filter was indeed not evaluated and an empty action list was generated. ZCS, however, mistakenly executed such empty action list; the empty action list meant that the message should be discarded. [Fix] When the message is spammy and the attribute 'zimbraSpamApplyUserFilters' is FALSE (default), ZCS will not evaluate and execute the filter rule. --- store/src/java/com/zimbra/cs/filter/RuleManager.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/store/src/java/com/zimbra/cs/filter/RuleManager.java b/store/src/java/com/zimbra/cs/filter/RuleManager.java index 95d8e92d546..46dec9ffb2d 100644 --- a/store/src/java/com/zimbra/cs/filter/RuleManager.java +++ b/store/src/java/com/zimbra/cs/filter/RuleManager.java @@ -406,10 +406,10 @@ public static List applyRulesToIncomingMessage( }; try { + boolean applyRules = true; Account account = mailbox.getAccount(); for (String filter : filters) { // Determine whether to apply rules - boolean applyRules = true; Node node = getRulesNode(account, filter); if (null == node) { @@ -419,6 +419,7 @@ public static List applyRulesToIncomingMessage( !account.getBooleanAttr(Provisioning.A_zimbraSpamApplyUserFilters, false)) { // Don't apply user filters to spam by default applyRules = false; + break; } if (applyRules) { if (filter.equals(FILTER_RULES_CACHE_KEY)) { @@ -435,8 +436,10 @@ public static List applyRulesToIncomingMessage( mailAdapter.resetCapabilities(); } } - mailAdapter.executeAllActions(); - addedMessageIds = mailAdapter.getAddedMessageIds(); + if (applyRules) { + mailAdapter.executeAllActions(); + addedMessageIds = mailAdapter.getAddedMessageIds(); + } } catch (ErejectException ex) { throw DeliveryServiceException.DELIVERY_REJECTED(ex.getMessage(), ex); } catch (Exception e) { From be886b002eb88f98fff2d26142109c33cfd7a279 Mon Sep 17 00:00:00 2001 From: Fulvio Scapin Date: Wed, 2 Aug 2017 12:38:05 +0200 Subject: [PATCH 110/142] Fixed unescaped newline in the value of the key zimbra_index_lucene_io_impl Fixed an unescaped newline half-way through the value for the zimbra_index_lucene_io_impl key. Missing in the english base file and in all the other localized versions. --- store-conf/conf/msgs/ZsMsg.properties | 2 +- store-conf/conf/msgs/ZsMsg_ar.properties | 2 +- store-conf/conf/msgs/ZsMsg_ca.properties | 2 +- store-conf/conf/msgs/ZsMsg_da.properties | 2 +- store-conf/conf/msgs/ZsMsg_de.properties | 2 +- store-conf/conf/msgs/ZsMsg_en_AU.properties | 2 +- store-conf/conf/msgs/ZsMsg_en_GB.properties | 2 +- store-conf/conf/msgs/ZsMsg_es.properties | 2 +- store-conf/conf/msgs/ZsMsg_eu.properties | 2 +- store-conf/conf/msgs/ZsMsg_fr.properties | 2 +- store-conf/conf/msgs/ZsMsg_fr_CA.properties | 2 +- store-conf/conf/msgs/ZsMsg_hi.properties | 2 +- store-conf/conf/msgs/ZsMsg_hu.properties | 2 +- store-conf/conf/msgs/ZsMsg_in.properties | 2 +- store-conf/conf/msgs/ZsMsg_it.properties | 2 +- store-conf/conf/msgs/ZsMsg_iw.properties | 2 +- store-conf/conf/msgs/ZsMsg_ja.properties | 2 +- store-conf/conf/msgs/ZsMsg_ko.properties | 2 +- store-conf/conf/msgs/ZsMsg_lo.properties | 2 +- store-conf/conf/msgs/ZsMsg_ms.properties | 2 +- store-conf/conf/msgs/ZsMsg_nl.properties | 2 +- store-conf/conf/msgs/ZsMsg_no.properties | 2 +- store-conf/conf/msgs/ZsMsg_pl.properties | 2 +- store-conf/conf/msgs/ZsMsg_pt.properties | 2 +- store-conf/conf/msgs/ZsMsg_pt_BR.properties | 2 +- store-conf/conf/msgs/ZsMsg_ro.properties | 2 +- store-conf/conf/msgs/ZsMsg_ru.properties | 2 +- store-conf/conf/msgs/ZsMsg_sl.properties | 2 +- store-conf/conf/msgs/ZsMsg_sv.properties | 2 +- store-conf/conf/msgs/ZsMsg_th.properties | 2 +- store-conf/conf/msgs/ZsMsg_tr.properties | 2 +- store-conf/conf/msgs/ZsMsg_uk.properties | 2 +- store-conf/conf/msgs/ZsMsg_zh_CN.properties | 2 +- store-conf/conf/msgs/ZsMsg_zh_HK.properties | 2 +- store-conf/conf/msgs/ZsMsg_zh_TW.properties | 2 +- 35 files changed, 35 insertions(+), 35 deletions(-) diff --git a/store-conf/conf/msgs/ZsMsg.properties b/store-conf/conf/msgs/ZsMsg.properties index 0d15176e7b8..f3e89fd01a0 100644 --- a/store-conf/conf/msgs/ZsMsg.properties +++ b/store-conf/conf/msgs/ZsMsg.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = The minimal number of documents required documents are flushed as a new segment. Large values generally give faster indexing. zimbra_index_lucene_ram_buffer_size_kb = Lucene Max Buffered RAM in KB zimbra_index_lucene_io_impl = Lucene FSDirectory implementation used for indexing IO. \ - Possible values + Possible values \ nio - Use NIOFSDirectory. Uses java.nio's FileChannel's positional io when reading to avoid synchronization when reading from the same file. \ mmap - Use MMapDirectory. Uses memory-mapped IO when reading. A good choice if there is plenty of virtual memory relative to index size. \ simple - Use SimpleFSDirectory. Uses java.io.RandomAccessFile. It has poor concurrent performance as it synchronizes when multiple threads read the same file. \ diff --git a/store-conf/conf/msgs/ZsMsg_ar.properties b/store-conf/conf/msgs/ZsMsg_ar.properties index 3167e472d55..03a8c603110 100644 --- a/store-conf/conf/msgs/ZsMsg_ar.properties +++ b/store-conf/conf/msgs/ZsMsg_ar.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = \u0627\u0644\u062d\u062f \u0627\u0644\u0 \u0627\u0644\u0645\u062e\u0632\u0646\u0629 \u0645\u0624\u0642\u062a\u064b\u0627 \u0641\u064a \u0627\u0644\u0630\u0627\u0643\u0631\u0629 \u0643\u0645\u0642\u0637\u0639 \u062c\u062f\u064a\u062f. \u0639\u0627\u062f\u0629 \u0645\u0646 \u062a\u0648\u0641\u0631 \u0627\u0644\u0642\u064a\u0645 \u0627\u0644\u0643\u0628\u064a\u0631\u0629 \u0641\u0647\u0631\u0633\u0629 \u0623\u0633\u0631\u0639.\u200f zimbra_index_lucene_ram_buffer_size_kb = \u0623\u0642\u0635\u0649 \u062d\u062f \u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u0639\u0634\u0648\u0627\u0626\u064a \u0630\u0627\u062a \u0627\u0644\u0645\u062e\u0632\u0646 \u0627\u0644\u0645\u0624\u0642\u062a Lucene \u0628\u0627\u0644\u0643\u064a\u0644\u0648\u0628\u0627\u064a\u062a zimbra_index_lucene_io_impl = \u062a\u0646\u0641\u064a\u0630 Lucene FSDirectory \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 \u0644\u0641\u0647\u0631\u0633\u0629 \u0627\u0644\u0625\u062f\u062e\u0627\u0644/\u0627\u0644\u0625\u062e\u0631\u0627\u062c. \ - \u0627\u0644\u0642\u064a\u0645 \u0627\u0644\u0645\u062d\u062a\u0645\u0644\u0629 + \u0627\u0644\u0642\u064a\u0645 \u0627\u0644\u0645\u062d\u062a\u0645\u0644\u0629 \ nio - \u0627\u0633\u062a\u062e\u062f\u0645 NIOFSDirectory. \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0627\u0644\u0625\u062f\u062e\u0627\u0644/\u0627\u0644\u0625\u062e\u0631\u0627\u062c \u0627\u0644\u0645\u0648\u0636\u0639\u064a \u0644\u0640 java.nio's FileChannel \u0639\u0646\u062f \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0644\u062a\u062c\u0646\u0628 \u0627\u0644\u0645\u0632\u0627\u0645\u0646\u0629 \u0639\u0646\u062f \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0645\u0646 \u0646\u0641\u0633 \u0627\u0644\u0645\u0644\u0641. \ mmap \u2013 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 MMapDirectory \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0627\u0644\u0625\u062f\u062e\u0627\u0644/\u0627\u0644\u0625\u062e\u0631\u0627\u062c \u0627\u0644\u0645\u062e\u0637\u0637 \u0627\u0644\u0630\u0627\u0643\u0631\u0629 \u0639\u0646\u062f \u0627\u0644\u0642\u0631\u0627\u0621\u0629. \u0627\u062e\u062a\u064a\u0627\u0631 \u062c\u064a\u062f \u0641\u064a \u062d\u0627\u0644\u0629 \u0648\u062c\u0648\u062f \u0645\u0633\u0627\u062d\u0629 \u0643\u0628\u064a\u0631\u0629 \u0645\u0646 \u0627\u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0638\u0627\u0647\u0631\u064a\u0629 \u0630\u0627\u062a \u0627\u0644\u0635\u0644\u0629 \u0628\u062d\u062c\u0645 \u0627\u0644\u0641\u0647\u0631\u0633. \ \u0628\u0633\u064a\u0637 \u2013 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 SimpleFSDirectory \u0627\u0633\u062a\u062e\u062f\u0627\u0645 java.io.RandomAccessFile. \u0644\u0647 \u0623\u062f\u0627\u0621 \u0645\u062a\u0632\u0627\u0645\u0646 \u0631\u062f\u064a\u0621 \u062d\u064a\u062b \u064a\u0642\u0648\u0645 \u0628\u0627\u0644\u0645\u0632\u0627\u0645\u0646\u0629 \u0639\u0646\u062f\u0645\u0627 \u062a\u0642\u0648\u0645 \u062e\u064a\u0648\u0637 \u0645\u062a\u0639\u062f\u062f\u0629 \u0628\u0642\u0631\u0627\u0621\u0629 \u0646\u0641\u0633 \u0627\u0644\u0645\u0644\u0641. \ diff --git a/store-conf/conf/msgs/ZsMsg_ca.properties b/store-conf/conf/msgs/ZsMsg_ca.properties index aa949fc34f9..da3be235126 100644 --- a/store-conf/conf/msgs/ZsMsg_ca.properties +++ b/store-conf/conf/msgs/ZsMsg_ca.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = Nombre m\u00ednim de documents necessari desats a la mem\u00f2ria interm\u00e8dia es bolquin com a nou segment. Amb valors grans, la indexaci\u00f3 acostuma a ser m\u00e9s r\u00e0pida. zimbra_index_lucene_ram_buffer_size_kb = RAM interm\u00e8dia m\u00e0xima en KB per a Lucene zimbra_index_lucene_io_impl = Implementaci\u00f3 de FSDirectory de Lucene emprada per l\u2019E/S d\u2019indexaci\u00f3. \ - Valors possibles + Valors possibles \ nio - Fer servir el NIOFSDirectory. Fa servir l\u2019E/S posicional de FileChannel de java.nio durant la lectura per evitar la sincronitzaci\u00f3 quan es llegeix del mateix fitxer. \ mmap - Fer servir el MMapDirectory. Fa servir E/S assignada a mem\u00f2ria durant la lectura. Bona opci\u00f3 si es disposa de molta mem\u00f2ria virtual respecte de la mida de l\u2019\u00edndex. \ simple - Fer servir SimpleFSDirectory. Fa servir java.io.RandomAccessFile. T\u00e9 un rendiment concurrent feble, perqu\u00e8 sincronitza quan hi ha m\u00e9s d\u2019un fil llegint el mateix fitxer. \ diff --git a/store-conf/conf/msgs/ZsMsg_da.properties b/store-conf/conf/msgs/ZsMsg_da.properties index ad5b85d9d41..2706b19dbed 100644 --- a/store-conf/conf/msgs/ZsMsg_da.properties +++ b/store-conf/conf/msgs/ZsMsg_da.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = Det mindste antal dokumenter, som er n\u t\u00f8mmes som et nyt segment. St\u00f8rre v\u00e6rdier giver generelt hurtigere indeksering. zimbra_index_lucene_ram_buffer_size_kb = Lucene \u2013 Maks. buffer-RAM i KB zimbra_index_lucene_io_impl = Lucene FSDirectory implementering brugt til indeksering af IO. \ - Mulige v\u00e6rdier + Mulige v\u00e6rdier \ nio - Brug NIOFSDirectory. Bruger java.nio's FileChannels stillings-io under l\u00e6sning for at undg\u00e5 synkronisering, n\u00e5r der l\u00e6ses fra den samme fil. \ mmap - Brug MMapDirectory. Bruger hukommelseskortlagt IO under l\u00e6sning. Et godt valg, hvis der er nok virtuel hukommelse i forhold til indeksst\u00f8rrelsen. \ simpel - Brug SimpleFSDirectory. Bruger java.io.RandomAccessFile. Det har d\u00e5rlig sidel\u00f8bende ydeevne under synkronisering, n\u00e5r flere tr\u00e5de l\u00e6ser den samme fil. \ diff --git a/store-conf/conf/msgs/ZsMsg_de.properties b/store-conf/conf/msgs/ZsMsg_de.properties index 1641d19fb82..9e64490df2a 100644 --- a/store-conf/conf/msgs/ZsMsg_de.properties +++ b/store-conf/conf/msgs/ZsMsg_de.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = Die Mindestanzahl von Dokumenten, die n\ Dokumente als neues Segment geleert werden. Gr\u00f6\u00dfere Werte ergeben in der Regel schnellere Indizierung. zimbra_index_lucene_ram_buffer_size_kb = H\u00f6chstwert des gepufferten RAM in KB f\u00fcr Lucene zimbra_index_lucene_io_impl = Implementierung des Lucene-FSDirectory f\u00fcr die Indizierung von E/A. \ - M\u00f6gliche Werte + M\u00f6gliche Werte \ nio - NIOFSDirectory verwenden. Verwendet beim Lesen java.nio's FileChannel's positional IO, um beim Lesen aus der gleichen Datei eine Synchronisierung zu vermeiden. \ mmap - MMapDirectory verwenden. Verwendet beim Lesen Memory-Mapped IO. Eine gute Wahl, wenn in Bezug auf die Indexgr\u00f6\u00dfe viel virtueller Speicher vorhanden ist. \ simple - SimpleFSDirectory verwenden. Verwendet java.io.RandomAccessFile. Zeigt bei der Synchronisierung eine schlechte gleichzeitige Leistung, wenn mehrere Threads die gleiche Datei lesen. \ diff --git a/store-conf/conf/msgs/ZsMsg_en_AU.properties b/store-conf/conf/msgs/ZsMsg_en_AU.properties index cda28bdc0f3..b571f74296c 100644 --- a/store-conf/conf/msgs/ZsMsg_en_AU.properties +++ b/store-conf/conf/msgs/ZsMsg_en_AU.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = The minimal number of documents required documents are flushed as a new segment. Large values generally give faster indexing. zimbra_index_lucene_ram_buffer_size_kb = Lucene Max Buffered RAM in KB zimbra_index_lucene_io_impl = Lucene FSDirectory implementation used for indexing IO. \ - Possible values + Possible values \ nio - Use NIOFSDirectory. Uses java.nio's FileChannel's positional io when reading to avoid synchronisation when reading from the same file. \ mmap - Use MMapDirectory. Uses memory-mapped IO when reading. A good choice if there is plenty of virtual memory relative to index size. \ simple - Use SimpleFSDirectory. Uses java.io.RandomAccessFile. It has poor concurrent performance as it synchronises when multiple threads read the same file. \ diff --git a/store-conf/conf/msgs/ZsMsg_en_GB.properties b/store-conf/conf/msgs/ZsMsg_en_GB.properties index c66c3c6e884..3ceb07ef443 100644 --- a/store-conf/conf/msgs/ZsMsg_en_GB.properties +++ b/store-conf/conf/msgs/ZsMsg_en_GB.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = The minimal number of documents required documents are flushed as a new segment. Large values generally give faster indexing. zimbra_index_lucene_ram_buffer_size_kb = Lucene Max Buffered RAM in KB zimbra_index_lucene_io_impl = Lucene FSDirectory implementation used for indexing IO. \ - Possible values + Possible values \ nio - Use NIOFSDirectory. Uses java.nio's FileChannel's positional io when reading to avoid synchronisation when reading from the same file. \ mmap - Use MMapDirectory. Uses memory-mapped IO when reading. A good choice if there is plenty of virtual memory relative to index size. \ simple - Use SimpleFSDirectory. Uses java.io.RandomAccessFile. It has poor concurrent performance as it synchronises when multiple threads read the same file. \ diff --git a/store-conf/conf/msgs/ZsMsg_es.properties b/store-conf/conf/msgs/ZsMsg_es.properties index 4002ac34624..634453371e3 100644 --- a/store-conf/conf/msgs/ZsMsg_es.properties +++ b/store-conf/conf/msgs/ZsMsg_es.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = El n\u00famero m\u00ednimo de documentos en la memoria sean liberados como un segmento nuevo. Los valores grandes proporcionan generalmente un indizado m\u00e1s r\u00e1pido. zimbra_index_lucene_ram_buffer_size_kb = RAM m\u00e1ximo en KB guardado en el b\u00fafer de Lucene zimbra_index_lucene_io_impl = La implementaci\u00f3n de FSDirectory de Lucene usado para el indizado de IO. \ - Posibles valores + Posibles valores \ nio - Usa NIOFSDirectory. Usa el io posicional de FileChannel de java.nio al leer para evitar la sincronizaci\u00f3n cuando leas el mismo archivo. \ mmap \u2013 Usa MMapDirectory. Usa el IO mapeado en la memoria para leer. Una buena elecci\u00f3n en caso que se disponga de mucha memoria virtual en relaci\u00f3n al tama\u00f1o del indizado. \ simple \u2013 Usa SimpleFSDirectory. Usa java.io.RandomAccessFile. Tiene un rendimiento pobre ya que realiza la sincronizaci\u00f3n cuando varios subprocesos leen el mismo archivo. \ diff --git a/store-conf/conf/msgs/ZsMsg_eu.properties b/store-conf/conf/msgs/ZsMsg_eu.properties index 03517c1147d..887482a8fdd 100644 --- a/store-conf/conf/msgs/ZsMsg_eu.properties +++ b/store-conf/conf/msgs/ZsMsg_eu.properties @@ -463,7 +463,7 @@ zimbra_index_lucene_max_buffered_docs = Gutxienez zenbat dokumentu behar diren, dokumentuak segmentu berri gisa hustu baino lehen. Balio handiek, oro har, indexazio azkarra sortzen dute. zimbra_index_lucene_ram_buffer_size_kb = Gehienezko RAM Lucene-ko buferrean gordetako KB-n zimbra_index_lucene_io_impl = Lucene FSDirectory inplementatu da, IO indexatzeko. \ - Balio posibleak: + Balio posibleak: \ nio - Erabili NIOFSDirectory. Fitxategi beretik irakurtzen denean, irakurketa egiterakoan, java.nio's FileChannel-en posizio-IO erabiltzen du, sinkronizazioa saihesteko. \ mmap - Erabili MMapDirectory. Memoria-mapatutako IO erabiltzen du, irakurketa bitartean. Aukera ona da, baldin eta, indizearen tamaina aintzat hartuta, memoria birtual handia badago. \ sinplea - Erabili SimpleFSDirectory. java.io.RandomAccessFile erabiltzen du. Errendimendua ez da oso ona, azpiprozesu anitzek fitxategi bera irakurtzen dutenean, sinkronizatu egin delako. \ diff --git a/store-conf/conf/msgs/ZsMsg_fr.properties b/store-conf/conf/msgs/ZsMsg_fr.properties index 2f96b14bfe9..dac05a08688 100644 --- a/store-conf/conf/msgs/ZsMsg_fr.properties +++ b/store-conf/conf/msgs/ZsMsg_fr.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = Nombre minimum de documents \u00e0 attei documents stock\u00e9s dans la m\u00e9moire tampon soient vid\u00e9s sous la forme d\u2019un nouveau segment. En g\u00e9n\u00e9ral, les valeurs \u00e9lev\u00e9es garantissent une indexation plus rapide. zimbra_index_lucene_ram_buffer_size_kb = Taille maximale de la RAM avec m\u00e9moire tampon Lucene en Ko zimbra_index_lucene_io_impl = Impl\u00e9mentation Lucene FSDirectory utilis\u00e9e pour l\u2019indexation des E/S. \ - Valeurs possibles + Valeurs possibles \ nio - Utiliser NIOFSDirectory. Utilise les E/S positionnelles FileChannel du package java.nio pendant la lecture pour \u00e9viter la synchronisation si la lecture s\u2019effectue dans le m\u00eame fichier. \ mmap - Utiliser MMapDirectory. Utilise des E/S mapp\u00e9es sur la m\u00e9moire pendant la lecture (choix int\u00e9ressant si la taille de la m\u00e9moire virtuelle est beaucoup plus importante que la taille de l\u2019index). \ simple - Utiliser SimpleFSDirectory. Utilise RandomAccessFile du package java.io. Performances concurrentes m\u00e9diocres dans la mesure o\u00f9 la synchronisation s\u2019effectue chaque fois que plusieurs fils lisent le m\u00eame fichier. \ diff --git a/store-conf/conf/msgs/ZsMsg_fr_CA.properties b/store-conf/conf/msgs/ZsMsg_fr_CA.properties index a563c6d7b22..723192c067f 100644 --- a/store-conf/conf/msgs/ZsMsg_fr_CA.properties +++ b/store-conf/conf/msgs/ZsMsg_fr_CA.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = Le nombre minimal de documents requis av soient transpos\u00e9s dans un nouveau segment. Les valeurs plus \u00e9lev\u00e9es permettent g\u00e9n\u00e9ralement une indexation plus rapide. zimbra_index_lucene_ram_buffer_size_kb = Taille maximale de la RAM avec m\u00e9moire tampon Lucene en Ko zimbra_index_lucene_io_impl = Impl\u00e9mentation de Lucene FSDirectory pour l\u2019indexation des E/S. \ - Valeurs possibles + Valeurs possibles \ nio - Utilisez NIOFSDirectory. Utilise l\u2019E/S de position FileChannel de java.nio lors de la lecture pour \u00e9viter la synchronisation pendant la lecture d\u2019un m\u00eame fichier. \ mmap - Utilisez MMapDirectory. Utilise les E/S mapp\u00e9s en m\u00e9moire pendant la lecture. C\u2019est un bon choix si la m\u00e9moire virtuelle est importante comparativement \u00e0 la taille de l\u2019index. \ simple - Utilisez SimpleFSDirectory. Utilise java.io.RandomAccessFile. Sa performance concurrente est faible pendant la synchronisation puisque plusieurs threads lisent le m\u00eame fichier. \ diff --git a/store-conf/conf/msgs/ZsMsg_hi.properties b/store-conf/conf/msgs/ZsMsg_hi.properties index 61ce04edeea..0067b6bc8d8 100644 --- a/store-conf/conf/msgs/ZsMsg_hi.properties +++ b/store-conf/conf/msgs/ZsMsg_hi.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = \u092e\u0947\u092e\u094b\u0930\u0940- \u \u0926\u0938\u094d\u0924\u093e\u0935\u0947\u091c\u093c \u0928\u090f \u0905\u0928\u0941\u092d\u093e\u0917 \u0915\u0947 \u0930\u0942\u092a \u092e\u0947\u0902 \u0928\u093f\u0915\u093e\u0932\u0947 \u091c\u093e\u0924\u0947 \u0939\u0948\u0902. \u092c\u0921\u093c\u093e \u092e\u093e\u0928 \u0938\u093e\u092e\u093e\u0928\u094d\u092f\u0924\u092f\u093e \u0924\u0940\u0935\u094d\u0930\u0924\u0930 \u0907\u0902\u0921\u0947\u0915\u094d\u0938\u093f\u0902\u0917 \u0926\u0947\u0924\u093e \u0939\u0948. zimbra_index_lucene_ram_buffer_size_kb = \u0932\u094d\u092f\u0942\u0938\u093f\u0928 \u0905\u0927\u093f\u0915\u0924\u092e \u092c\u092b\u093c\u0930 \u0915\u0940 \u0917\u0908 RAM \u0915\u0947\u092c\u0940 \u092e\u0947\u0902 zimbra_index_lucene_io_impl = IO \u0907\u0902\u0921\u0947\u0915\u094d\u0938\u093f\u0902\u0917 \u0915\u0947 \u0932\u093f\u090f Lucene FSDirectory \u0915\u093e\u0930\u094d\u092f\u093e\u0928\u094d\u0935\u092f\u0928 \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u093f\u092f\u093e \u091c\u093e\u0924\u093e \u0939\u0948. \ - \u0938\u0902\u092d\u093e\u0935\u093f\u0924 \u092e\u093e\u0928 + \u0938\u0902\u092d\u093e\u0935\u093f\u0924 \u092e\u093e\u0928 \ nio \u2013 NIOFSDirectory \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0947\u0902. \u0909\u0938\u0940 \u092b\u093c\u093e\u0907\u0932 \u0938\u0947 \u092a\u0922\u093c\u0928\u0947 \u0915\u0947 \u0926\u094c\u0930\u093e\u0928 \u092a\u0922\u093c\u0924\u0947 \u0938\u092e\u092f \u0938\u093f\u0902\u0915\u094d\u0930\u0928\u093e\u0907\u091c\u093c\u0947\u0936\u0928 \u0938\u0947 \u092c\u091a\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f java.nio \u0915\u0947 FileChannel \u0915\u0947 \u0938\u094d\u0925\u093f\u0924\u093f io \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0924\u093e \u0939\u0948. \ mmap \u2013 MmapDirectory \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0947\u0902. \u092a\u0922\u093c\u0924\u0947 \u0938\u092e\u092f \u092e\u0947\u092e\u094b\u0930\u0940-mapped IO \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0924\u093e \u0939\u0948. A good choice \u092f\u0926\u093f \u0907\u0902\u0921\u0947\u0915\u094d\u0938 \u0906\u0915\u093e\u0930 \u0938\u0947 \u0938\u0902\u092c\u0902\u0927\u093f\u0924 \u0935\u0930\u094d\u091a\u0941\u0905\u0932 \u0915\u0940 \u0905\u0927\u093f\u0915\u0924\u093e \u0939\u094b \u0924\u094b \u0905\u091a\u094d\u091b\u0940 \u092a\u0938\u0902\u0926 \u0939\u0948. \ \u0938\u093e\u092e\u093e\u0928\u094d\u092f \u2013 SimpleFSDirectory \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0947\u0902. java.io.RandomAccessFile \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0924\u093e \u0939\u0948. \u0907\u0938\u0915\u093e \u092a\u094d\u0930\u0926\u0930\u094d\u0936\u0928 \u0938\u0902\u092f\u0941\u0915\u094d\u0924 \u0930\u0942\u092a \u0938\u0947 \u0915\u092e\u091c\u094b\u0930 \u0939\u094b\u0924\u093e \u0939\u0948 \u0915\u094d\u092f\u094b\u0902\u0915\u093f \u090f\u0915\u093e\u0927\u093f\u0915 \u0925\u094d\u0930\u0947\u0921 \u0926\u094d\u0935\u093e\u0930\u093e \u0909\u0938\u0940 \u092b\u093c\u093e\u0907\u0932 \u0915\u094b \u092a\u0922\u093c\u0924\u0947 \u0938\u092e\u092f \u092f\u0939 \u0938\u093f\u0902\u0915\u094d\u0930\u0928\u093e\u0907\u091c\u093c \u0915\u0930\u0924\u093e \u0939\u0948. \ diff --git a/store-conf/conf/msgs/ZsMsg_hu.properties b/store-conf/conf/msgs/ZsMsg_hu.properties index 57d472eb106..10643a78f86 100644 --- a/store-conf/conf/msgs/ZsMsg_hu.properties +++ b/store-conf/conf/msgs/ZsMsg_hu.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = A mem\u00f3ri\u00e1ba pufferel\u00e9s el \u00faj szegmensk\u00e9nt van ki\u00fcr\u00edtve. A nagyobb \u00e9rt\u00e9kek \u00e1ltal\u00e1ban gyorsabb indexel\u00e9st biztos\u00edtanak. zimbra_index_lucene_ram_buffer_size_kb = Lucene max. pufferelt RAM KB-ban zimbra_index_lucene_io_impl = Lucene FSDirectory alkalmaz\u00e1sa haszn\u00e1lva az IO indexel\u00e9shez. \ -Lehets\u00e9ges \u00e9rt\u00e9kek +Lehets\u00e9ges \u00e9rt\u00e9kek \ nio \u2013 NIOFSDirectory haszn\u00e1lata. Olvas\u00e1skor a java.nio FileChannel helyzetbe\u00e1ll\u00edt\u00f3 io-j\u00e1t haszn\u00e1lja, hogy elker\u00fclje a szinkroniz\u00e1l\u00e1st, amikor ugyanabb\u00f3l a f\u00e1jlb\u00f3l olvas. \ mmap \u2013 MMapDirectory haszn\u00e1lata. Olvas\u00e1skor a mem\u00f3ri\u00e1ba \u00e1gyazott IO-t haszn\u00e1lja. J\u00f3 v\u00e1laszt\u00e1s, ha az index m\u00e9ret\u00e9hez k\u00e9pest sok a virtu\u00e1lis mem\u00f3ria. \ egyszer\u0171 \u2013 SimpleFSDirectory haszn\u00e1lata. java.io.RandomAccessFile haszn\u00e1lata. A p\u00e1rhuzamos teljes\u00edtm\u00e9nye gyenge, mivel akkor szinkroniz\u00e1l, amikor t\u00f6bb sz\u00e1l olvassa ugyanazt a f\u00e1jlt. \ diff --git a/store-conf/conf/msgs/ZsMsg_in.properties b/store-conf/conf/msgs/ZsMsg_in.properties index 6512b8cc5e0..b41d85ebda2 100644 --- a/store-conf/conf/msgs/ZsMsg_in.properties +++ b/store-conf/conf/msgs/ZsMsg_in.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = Jumlah minimal dokumen yang dibutuhkan s dokumen dibersihkan sebagai segmen baru. Nilai yang lebih besar biasanya memberi pengindeksan yang lebih cepat. zimbra_index_lucene_ram_buffer_size_kb = RAM Buffer Maks Lucene dalam KB zimbra_index_lucene_io_impl = Implementasi FSDirectory Lucene yang digunakan untuk IO pengindeksan. \ - Nilai yang mungkin + Nilai yang mungkin \ nio - Gunakan NIOFSDirectory. Menggunakan io posisi FileChannel java.nio saat membaca untuk menghindari sinkronisasi ketika membaca dari file yang sama. \ mmap - Gunakan MMapDirectory. Menggunakan IO yang dipetakan-memori saat membaca. Pilihan yang tepat jika ada banyak memori virtual yang relatif terhadap ukuran indeks. \ simple - Gunakan SimpleFSDirectory. Menggunakan java.io.RandomAccessFile. Kinerja bersamanya buruk karena ini melakukan sinkronisasi ketika beberapa thread membaca file yang sama. \ diff --git a/store-conf/conf/msgs/ZsMsg_it.properties b/store-conf/conf/msgs/ZsMsg_it.properties index 82a6281ef3a..ce1eeda07bc 100644 --- a/store-conf/conf/msgs/ZsMsg_it.properties +++ b/store-conf/conf/msgs/ZsMsg_it.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = Il numero minimo di documenti richiesto come un nuovo segmento. Valori pi\u00f9 elevati di norma determinano un'indicizzazione pi\u00f9 rapida. zimbra_index_lucene_ram_buffer_size_kb = Quantit\u00e0 massima di RAM in buffer Lucene in KB zimbra_index_lucene_io_impl = Per l'indicizzazione dell'IO si usa l'implementazione Lucene FSDirectory. \ - Valori possibili + Valori possibili \ nio - Uso di NIOFSDirectory. Utilizza l'io posizionale del FileChannel di java.nio durante la lettura per evitare la sincronizzazione con lettura dallo stesso file. \ mmap - Uso di MMapDirectory. Durante la lettura utilizza l'IO mappato in memoria. Una buona scelta se si dispone di molta memoria virtuale relativa alle dimensioni dell'indice. \ semplice - Uso di SimpleFSDirectory. Utilizza java.io.RandomAccessFile. Le prestazioni concorrenti sono scarse in quanto sincronizza quando pi\u00f9 thread leggono lo stesso file. \ diff --git a/store-conf/conf/msgs/ZsMsg_iw.properties b/store-conf/conf/msgs/ZsMsg_iw.properties index 7cf56d1f0d1..5517085f6a8 100644 --- a/store-conf/conf/msgs/ZsMsg_iw.properties +++ b/store-conf/conf/msgs/ZsMsg_iw.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = \u05de\u05e1\u05e4\u05e8 \u05d4\u05de\u0 \u05e2\u05d5\u05d1\u05e8\u05d9\u05dd flush \u05db\u05de\u05e7\u05d8\u05e2 \u05d7\u05d3\u05e9. \u05e2\u05e8\u05db\u05d9\u05dd \u05d2\u05d1\u05d5\u05d4\u05d9\u05dd \u05d9\u05d5\u05ea\u05e8 \u05de\u05e1\u05e4\u05e7\u05d9\u05dd \u05d1\u05d3"\u05db \u05e8\u05d9\u05e9\u05d5\u05dd \u05de\u05d4\u05d9\u05e8 \u05d9\u05d5\u05ea\u05e8 \u05d1\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1. zimbra_index_lucene_ram_buffer_size_kb = \u05d4-RAM \u05d4\u05de\u05e8\u05d1\u05d9 \u05d1\u05de\u05d0\u05d2\u05e8 \u05e9\u05dc Lucene \u05d1-KB zimbra_index_lucene_io_impl = \u05d9\u05d9\u05e9\u05d5\u05dd Lucene FSDirectory \u05dc\u05e6\u05d5\u05e8\u05da \u05e8\u05d9\u05e9\u05d5\u05dd IO \u05d1\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1. \ - \u05e2\u05e8\u05db\u05d9\u05dd \u05d0\u05e4\u05e9\u05e8\u05d9\u05d9\u05dd + \u05e2\u05e8\u05db\u05d9\u05dd \u05d0\u05e4\u05e9\u05e8\u05d9\u05d9\u05dd \ nio - \u05de\u05e9\u05ea\u05de\u05e9 \u05d1-NIOFSDirectory. \u05de\u05e9\u05ea\u05de\u05e9 \u05d1-java.nio's FileChannel's positional io \u05d1\u05e2\u05ea \u05d4\u05e7\u05e8\u05d9\u05d0\u05d4 \u05db\u05d3\u05d9 \u05dc\u05d4\u05d9\u05de\u05e0\u05e2 \u05de\u05e1\u05e0\u05db\u05e8\u05d5\u05df \u05d1\u05e2\u05ea \u05e7\u05e8\u05d9\u05d0\u05d4 \u05de\u05d0\u05d5\u05ea\u05d5 \u05e7\u05d5\u05d1\u05e5. \ mmap - \u05de\u05e9\u05ea\u05de\u05e9 \u05d1-MMapDirectory. \u05de\u05e9\u05ea\u05de\u05e9 \u05d1-memory-mapped IO \u05d1\u05e2\u05ea \u05d4\u05e7\u05e8\u05d9\u05d0\u05d4. \u05d1\u05d7\u05d9\u05e8\u05d4 \u05d8\u05d5\u05d1\u05d4 \u05d0\u05dd \u05d9\u05e9 \u05d4\u05e8\u05d1\u05d4 \u05d6\u05d9\u05db\u05e8\u05d5\u05df \u05d5\u05d9\u05e8\u05d8\u05d5\u05d0\u05dc\u05d9 \u05d1\u05d9\u05d7\u05e1 \u05dc\u05d2\u05d5\u05d3\u05dc \u05d4\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1. \ simple - \u05de\u05e9\u05ea\u05de\u05e9 \u05d1-SimpleFSDirectory. \u05de\u05e9\u05ea\u05de\u05e9 \u05d1-java.io.RandomAccessFile. \u05d9\u05e9 \u05dc\u05d5 \u05d1\u05d9\u05e6\u05d5\u05e2\u05d9\u05dd \u05d1\u05d5-\u05d6\u05de\u05e0\u05d9\u05d9\u05dd \u05d2\u05e8\u05d5\u05e2\u05d9\u05dd \u05d1\u05de\u05d4\u05dc\u05da \u05d4\u05e1\u05e0\u05db\u05e8\u05d5\u05df \u05d1\u05e2\u05ea \u05e9\u05ea\u05d4\u05dc\u05d9\u05db\u05d9 \u05de\u05e9\u05e0\u05d4 \u05e8\u05d1\u05d9\u05dd \u05e7\u05d5\u05e8\u05d0\u05d9\u05dd \u05d0\u05ea \u05d0\u05d5\u05ea\u05d5 \u05e7\u05d5\u05d1\u05e5. \ diff --git a/store-conf/conf/msgs/ZsMsg_ja.properties b/store-conf/conf/msgs/ZsMsg_ja.properties index 1109d6e5e38..88b92708c44 100644 --- a/store-conf/conf/msgs/ZsMsg_ja.properties +++ b/store-conf/conf/msgs/ZsMsg_ja.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = \u30d0\u30c3\u30d5\u30a1\u3055\u308c\u30 \u5fc5\u8981\u306a\u6587\u66f8\u306e\u6700\u4f4e\u6570\u3002\u4e00\u822c\u306b\u3001\u5024\u3092\u5927\u304d\u304f\u3059\u308b\u3068\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4f5c\u6210\u304c\u901f\u304f\u306a\u308a\u307e\u3059\u3002 zimbra_index_lucene_ram_buffer_size_kb = Lucene\u6700\u5927\u30d0\u30c3\u30d5\u30a1RAM\uff08KB\u5358\u4f4d\uff09 zimbra_index_lucene_io_impl = IO\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4f5c\u6210\u306b\u4f7f\u7528\u3055\u308c\u308bLucene FSDirectory\u5b9f\u88c5\u3002 \ - \u53ef\u80fd\u306a\u5024 + \u53ef\u80fd\u306a\u5024 \ nio \u2013 NIOFSDirectory\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u8aad\u307f\u53d6\u308a\u6642\u306bjava.nio\u306eFileChannel\u306e\u4f4d\u7f6e\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u8aad\u307f\u53d6\u308b\u3068\u304d\u306e\u540c\u671f\u3092\u56de\u907f\u3057\u307e\u3059\u3002 \ mmap \u2013 MmapDirectory\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u8aad\u307f\u53d6\u308a\u6642\u306b\u30e1\u30e2\u30ea\u30de\u30c3\u30d7\u3055\u308c\u305fIO\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30b5\u30a4\u30ba\u306b\u5bfe\u3057\u3066\u5341\u5206\u306a\u91cf\u306e\u4eee\u60f3\u30e1\u30e2\u30ea\u304c\u3042\u308b\u5834\u5408\u306b\u9069\u3057\u3066\u3044\u307e\u3059\u3002 \ simple \u2013 SimpleFSDirectory\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002java.io.RandomAccessFile\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u8907\u6570\u306e\u30b9\u30ec\u30c3\u30c9\u304c\u540c\u4e00\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u53d6\u308b\u3068\u304d\u306b\u540c\u671f\u3092\u5b9f\u884c\u3059\u308b\u305f\u3081\u3001\u540c\u6642\u5b9f\u884c\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u306f\u3088\u304f\u3042\u308a\u307e\u305b\u3093\u3002 \ diff --git a/store-conf/conf/msgs/ZsMsg_ko.properties b/store-conf/conf/msgs/ZsMsg_ko.properties index 5cf2d7fc898..058e75e1118 100644 --- a/store-conf/conf/msgs/ZsMsg_ko.properties +++ b/store-conf/conf/msgs/ZsMsg_ko.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = \ubc84\ud37c\ub9c1\ub41c \uba54\ubaa8\ub \ucd5c\uc18c \ubb38\uc11c \uc218. \ubcf4\ud1b5 \uac12\uc774 \ud074\uc218\ub85d \uc0c9\uc778\ud654 \uc18d\ub3c4\uac00 \ub354 \ube60\ub985\ub2c8\ub2e4. zimbra_index_lucene_ram_buffer_size_kb = Lucene \ubc84\ud37c\ub41c \ucd5c\ub300 RAM \ud06c\uae30(KB) zimbra_index_lucene_io_impl = IO \uc0c9\uc778\ud654\uc5d0 \uc0ac\uc6a9\ub41c Lucene FSDirectory \uad6c\ud604. \ - \uac00\ub2a5\ud55c \uac12 + \uac00\ub2a5\ud55c \uac12 \ nio - NIOFSDirectory\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. \ub3d9\uc77c\ud55c \ud30c\uc77c\ub85c\ubd80\ud130 \uc77d\uc744 \ub54c \ub3d9\uae30\ud654\ub97c \ud53c\ud558\uae30 \uc704\ud574 java.nio\uc758 FileChannel \uc704\uce58 io\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. \ mmap \u2013 MmapDirectory\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. \uc77d\uc744 \ub54c \uba54\ubaa8\ub9ac \ub9e4\ud551\ub41c IO\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. \uc0c9\uc778\ud654 \ud06c\uae30\uc5d0 \ube44\ud574 \uac00\uc0c1 \uba54\ubaa8\ub9ac\uac00 \ucda9\ubd84\ud55c \uacbd\uc6b0\uc5d0 \uc88b\uc740 \uc120\ud0dd\uc785\ub2c8\ub2e4. \ simple \u2013 SimpleFSDirectory\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. java.io.RandomAccessFile\uc744 \uc0ac\uc6a9\ud569\ub2c8\ub2e4. \uc5ec\ub7ec \uc2a4\ub808\ub4dc\uac00 \ub3d9\uc77c\ud55c \ud30c\uc77c\uc744 \uc77d\uc744 \ub54c \ub3d9\uae30\ud654\ud558\ubbc0\ub85c \ub3d9\uc2dc \uc131\ub2a5\uc774 \ub098\uc069\ub2c8\ub2e4. \ diff --git a/store-conf/conf/msgs/ZsMsg_lo.properties b/store-conf/conf/msgs/ZsMsg_lo.properties index b75e9b1da9d..1dc3a4f3a77 100644 --- a/store-conf/conf/msgs/ZsMsg_lo.properties +++ b/store-conf/conf/msgs/ZsMsg_lo.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = \u0e88\u0eb3\u200b\u0e99\u0ea7\u0e99\u20 \u0e96\u0eb7\u0e81\u0e95\u0eb1\u0e99\u200b\u0ec0\u0e9b\u0eb1\u0e99\u200b\u0eaa\u0ec8\u0ea7\u0e99\u200b\u0ec3\u0edd\u0ec8. \u0ec2\u0e94\u0e8d\u200b\u0e97\u0ebb\u0ec8\u0ea7\u200b\u0ec4\u0e9b\u200b\u0e84\u0ec8\u0eb2\u200b\u0ec3\u0eab\u0e8d\u0ec8\u200b\u0ec3\u0eab\u0ec9\u200b\u0e81\u0eb2\u0e99\u200b\u0ec0\u0eae\u0eb1\u0e94\u200b\u0e94\u0eb1\u0e94\u200b\u0e8a\u0eb0\u200b\u0e99\u0eb5\u200b\u0ec4\u0e94\u0ec9\u200b\u0ec4\u0ea7\u200b\u0e81\u0ea7\u0ec8\u0eb2. zimbra_index_lucene_ram_buffer_size_kb = RAM \u0e81\u0eb3\u200b\u0e99\u0ebb\u0e94\u200b\u0ead\u0eb1\u0e94\u200b\u0e95\u0eb2\u200b\u0ec1\u0ea5\u0ec9\u0ea7\u200b\u0eaa\u0eb9\u0e87\u200b\u0eaa\u0eb8\u0e94\u200b\u0ec0\u0e9b\u0eb1\u0e99 KB zimbra_index_lucene_io_impl = \u0e81\u0eb2\u0e99\u200b\u0e88\u0eb1\u0e94\u200b\u0e95\u0eb1\u0ec9\u0e87\u200b\u0e9b\u0eb0\u200b\u0e95\u0eb4\u200b\u0e9a\u0eb1\u0e94Lucene FSDirectory\u200b\u0ec3\u0e8a\u0ec9\u200b\u0eaa\u0eb3\u200b\u0ea5\u0eb1\u0e9a\u200b\u0e81\u0eb2\u0e99\u200b\u0ec0\u0eae\u0eb1\u0e94\u200b\u0e94\u0eb1\u0e94\u200b\u0e8a\u0eb0\u200b\u0e99\u0eb5 IO. \ - \u0e84\u0ec8\u0eb2\u200b\u0e97\u0eb5\u0ec8\u200b\u0ec0\u0e9b\u0eb1\u0e99\u200b\u0ec4\u0e9b\u200b\u0ec4\u0e94\u0ec9 + \u0e84\u0ec8\u0eb2\u200b\u0e97\u0eb5\u0ec8\u200b\u0ec0\u0e9b\u0eb1\u0e99\u200b\u0ec4\u0e9b\u200b\u0ec4\u0e94\u0ec9 \ nio - \u0ec3\u0e8a\u0ec9 NIOFSDirectory. \u0ec3\u0e8a\u0ec9 io \u0e95\u0eb3\u200b\u0ec1\u0edc\u0ec8\u0e87\u200b\u0e82\u0ead\u0e87 FileChannel \u0e82\u0ead\u0e87 java.nio \u0ec0\u0ea1\u0eb7\u0ec8\u0ead\u200b\u0e81\u0eb3\u200b\u0ea5\u0eb1\u0e87\u200b\u0ead\u0ec8\u0eb2\u0e99\u0ec0\u0e9e\u0eb7\u0ec8\u0ead\u200b\u0eab\u0ebc\u0eb5\u0e81\u200b\u0ec0\u0ea7\u0eb1\u0ec9\u0e99\u200b\u0e81\u0eb2\u0e99\u200b\u0e8a\u0eb4\u0e87\u0e84\u0ecc\u0e82\u0ecd\u0ec9\u0ea1\u0eb9\u0e99\u0ec0\u0ea1\u0eb7\u0ec8\u0ead\u200b\u0e81\u0eb3\u200b\u0ea5\u0eb1\u0e87\u200b\u0ead\u0ec8\u0eb2\u0e99\u200b\u0e88\u0eb2\u0e81\u200b\u0ec4\u0e9f\u200b\u0ea5\u0ecc\u200b\u0e94\u0ebd\u0ea7\u200b\u0e81\u0eb1\u0e99. \ mmap - .-h MMapDirectory. \u0ec3\u0e8a\u0ec9 IO \u0e84\u0ea7\u0eb2\u0ea1\u200b\u0e88\u0eb3-\u0ec0\u0eae\u0eb1\u0e94\u200b\u0ec1\u0e9c\u0e99\u200b\u0e97\u0eb5\u0ec8\u200b\u0ec1\u0ea5\u0ec9\u0ea7\u0ec0\u0ea1\u0eb7\u0ec8\u0ead\u200b\u0e81\u0eb3\u200b\u0ea5\u0eb1\u0e87\u200b\u0ead\u0ec8\u0eb2\u0e99. \u0e97\u0eb2\u0e87\u200b\u0ec0\u0ea5\u0eb7\u0ead\u0e81\u200b\u0e97\u0eb5\u0ec8\u200b\u0e94\u0eb5\u200b\u0ead\u0eb1\u0e99\u200b\u0edc\u0eb6\u0ec8\u0e87\u0e96\u0ec9\u0eb2\u200b\u0ea1\u0eb5\u200b\u0eab\u0ebc\u0eb2\u0e8d\u0e84\u0ea7\u0eb2\u0ea1\u200b\u0e88\u0eb3\u0eaa\u0eb0\u200b\u0ec0\u0edd\u0eb7\u0ead\u0e99\u200b\u0e81\u0ec8\u0ebd\u0ea7\u200b\u0e82\u0ec9\u0ead\u0e87\u0e81\u0eb1\u0e9a\u200b\u0e82\u0eb0\u200b\u0edc\u0eb2\u0e94\u200b\u0e94\u0eb1\u0e94\u200b\u0e8a\u0eb0\u200b\u0e99\u0eb5. \ \u0e87\u0ec8\u0eb2\u0e8d - \u0ec3\u0e8a\u0ec9 SimpleFSDirectory. \u0ec3\u0e8a\u0ec9 java.io.RandomAccessFile. \u0ea1\u0eb1\u0e99\u200b\u0ea1\u0eb5\u200b\u0e81\u0eb2\u0e99\u200b\u0e94\u0eb3\u200b\u0ec0\u0e99\u0eb5\u0e99\u200b\u0e81\u0eb2\u0e99\u200b\u0e9e\u0ec9\u0ead\u0ea1\u200b\u0e81\u0eb1\u0e99\u200b\u0e97\u0eb5\u0ec8\u200b\u0e9a\u0ecd\u0ec8\u200b\u0e94\u0eb5\u0ec0\u0e99\u0eb7\u0ec8\u0ead\u0e87\u200b\u0e88\u0eb2\u0e81\u200b\u0ea1\u0eb1\u0e99\u200b\u0e8a\u0eb4\u0e87\u200b\u0e84\u0ecc\u0e82\u0ecd\u0ec9\u0ea1\u0eb9\u0e99\u0ec0\u0ea1\u0eb7\u0ec8\u0ead\u200b\u0eab\u0ebc\u0eb2\u0e8d\u200b\u0e81\u0eb2\u0e99\u200b\u0eaa\u0ebb\u0e99\u200b\u0e97\u0eb0\u200b\u0e99\u0eb2\u200b\u0ead\u0ec8\u0eb2\u0e99\u200b\u0ec4\u0e9f\u200b\u0ea5\u0ecc\u200b\u0e94\u0ebd\u0ea7\u200b\u0e81\u0eb1\u0e99. \ diff --git a/store-conf/conf/msgs/ZsMsg_ms.properties b/store-conf/conf/msgs/ZsMsg_ms.properties index ba8c468a572..73712fa8e58 100644 --- a/store-conf/conf/msgs/ZsMsg_ms.properties +++ b/store-conf/conf/msgs/ZsMsg_ms.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = Bilangan minimum dokumen diperlukan sebe penimbal dikosongkan sebagai segmen baharu. Nilai yang lebih besar biasanya memberi pengindeksan yang lebih pantas. zimbra_index_lucene_ram_buffer_size_kb = RAM Bertimbal Maks Lucene dalam KB zimbra_index_lucene_io_impl = Pelaksanaan FSDirectory Lucene digunakan untuk pengindeksan IO. \ -Nilai kemungkinan +Nilai kemungkinan \ nio - Guna NIOFSDirectory. Gunakan io posisi FileChannel java.nio semasa membaca untuk mengelakkan penyegerakkan apabila membaca fail yang sama. \ mmap - Guna MMapDirectory. Guna IO pemetaan ingatan semasa membaca. Pilihan yang bijak jika terdapat banyak ingatan maya relatif dengan saiz indeks. \ ringkas - Guna SimpleFSDirectory. Gunakan java.io.RandomAccessFile. Ia mempunyai prestasi serentak yang buruk disebabkan ia segerakkan dengan berbilang jaluran pada masa yang sama. \ diff --git a/store-conf/conf/msgs/ZsMsg_nl.properties b/store-conf/conf/msgs/ZsMsg_nl.properties index 2d92ff2ddf3..35677430564 100644 --- a/store-conf/conf/msgs/ZsMsg_nl.properties +++ b/store-conf/conf/msgs/ZsMsg_nl.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = Het minimale aantal documenten dat is ve geplaatste documenten als een een nieuw segment worden verwijderd. Grote waarden zorgen doorgaans voor een snellere indexering. zimbra_index_lucene_ram_buffer_size_kb = Lucene Max. gebufferde RAM, in KB (Max Buffered RAM in kB) zimbra_index_lucene_io_impl = Lucene FSDirectory-implementatie die wordt gebruikt voor indexering van IO. \ - Mogelijke waarden + Mogelijke waarden \ nio \u2013 NIOFSDirectory gebruiken. Maakt gebruik van java.nio's FileChannel's positionele IO bij het lezen om synchronisatie te voorkomen bij het lezen van hetzelfde bestand. \ mmap \u2013 MmapDirectory gebruiken. Gebruikt geheugentoegewezen IO tijdens het lezen. Een goede keuze als er voldoende virtueel geheugen is in verhouding tot de indexgrootte. \ simple \u2013 SimpleFSDirectory gebruiken. Gebruikt java.io.RandomAccessFile. Dit heeft slechte gelijktijdige prestaties wanneer wordt gesynchroniseerd terwijl meerdere threads hetzelfde bestand lezen. \ diff --git a/store-conf/conf/msgs/ZsMsg_no.properties b/store-conf/conf/msgs/ZsMsg_no.properties index 5993e37c40c..445686f5232 100644 --- a/store-conf/conf/msgs/ZsMsg_no.properties +++ b/store-conf/conf/msgs/ZsMsg_no.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = Minimumsantallet dokumenter som kreves f i minnet blir t\u00f8mt som et nytt segment. Store verdier gir generelt raskere indeksering. zimbra_index_lucene_ram_buffer_size_kb = Maksimal buffer-RAM i kB for Lucene zimbra_index_lucene_io_impl = Lucene FSDirectory-implementering brukt til IU-indeksering. \ - Mulige verdier + Mulige verdier \ nio \u2013 Bruk NIOFSDirectory. Bruker FileChannels posisjon-IU i java.nio ved lesing for \u00e5 unng\u00e5 synkronisering n\u00e5r det leses fra samme fil. \ mmap \u2013 Bruk MMapDirectory. Bruker minnetilordnet IU ved lesing. Et godt valg hvis det er nok virtuelt minne i forhold til indeksst\u00f8rrelsen. \ simple \u2013 Bruk SimpleFSDirectory. Bruker java.io.RandomAccessFile. Den har d\u00e5rlig samtidig ytelse fordi den synkroniserer n\u00e5r flere tr\u00e5der leser samme fil. \ diff --git a/store-conf/conf/msgs/ZsMsg_pl.properties b/store-conf/conf/msgs/ZsMsg_pl.properties index 33fc311b8a0..9b2a2d3861f 100644 --- a/store-conf/conf/msgs/ZsMsg_pl.properties +++ b/store-conf/conf/msgs/ZsMsg_pl.properties @@ -468,7 +468,7 @@ zimbra_index_lucene_max_buffered_docs = Minimalna liczba dokument\u00f3w wymagan dokumenty zostan\u0105 zapisane jako nowy segment. Du\u017ce warto\u015bci zazwyczaj zwi\u0119kszaj\u0105 szybko\u015b\u0107 indeksowania. zimbra_index_lucene_ram_buffer_size_kb = Lucene \u2013 maksymalna wielko\u015b\u0107 bufora pami\u0119ci RAM w kB zimbra_index_lucene_io_impl = Implementacja FSDirectory u\u017cywana przez Lucene do indeksowania we/wy. \ - Mo\u017cliwe warto\u015bci + Mo\u017cliwe warto\u015bci \ nio \u2013 u\u017cywana jest implementacja NIOFSDirectory. W\u00a0celu unikni\u0119cia synchronizacji podczas odczytu z\u00a0tego samego pliku wykorzystuje pozycyjne we/wy klasy FileChannel z\u00a0interfejsu java.nio. \ mmap \u2013 u\u017cywana jest implementacja MMapDirectory. Do odczytu wykorzystuje mapowane na pami\u0119\u0107 we/wy. Dobry wyb\u00f3r, je\u015bli do dyspozycji jest relatywnie du\u017co pami\u0119ci wirtualnej wzgl\u0119dem rozmiaru indeksu. \ simple \u2013 u\u017cywana jest implementacja SimpleFSDirectory. Wykorzystuje klas\u0119 java.io.RandomAccessFile. Ma niewielk\u0105 wydajno\u015b\u0107 przy pracy wsp\u00f3\u0142bie\u017cnej, poniewa\u017c przeprowadza synchronizacj\u0119, gdy kilka w\u0105tk\u00f3w odczytuje ten sam plik. \ diff --git a/store-conf/conf/msgs/ZsMsg_pt.properties b/store-conf/conf/msgs/ZsMsg_pt.properties index 5a3bb6f0a29..b5267d6630b 100644 --- a/store-conf/conf/msgs/ZsMsg_pt.properties +++ b/store-conf/conf/msgs/ZsMsg_pt.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = O n\u00famero m\u00ednimo de documentos mem\u00f3ria interm\u00e9dia serem esvaziados como um novo segmento. Os valores mais altos fornecem geralmente uma indexa\u00e7\u00e3o mais r\u00e1pida. zimbra_index_lucene_ram_buffer_size_kb = RAM de mem\u00f3ria interm\u00e9dia m\u00e1xima do Lucene em kB zimbra_index_lucene_io_impl = Implementa\u00e7\u00e3o do FSDirectory do Lucene utilizada para a indexa\u00e7\u00e3o de E/S. \ - Valores poss\u00edveis + Valores poss\u00edveis \ nio - Utilize o NIOFSDirectory. Utiliza a E/S posicional do FileChannel do java.nio ao efetuar leituras para evitar a sincroniza\u00e7\u00e3o ao ler a partir do mesmo ficheiro. \ mmap - Utilize o MMapDirectory. Utiliza uma E/S mapeada na mem\u00f3ria ao efetuar leituras. Uma boa escolha se existir bastante mem\u00f3ria virtual relativamente ao tamanho do \u00edndice. \ simple \u2013 Utilize o SimpleFSDirectory. Utiliza o java.io.RandomAccessFile. Tem um desempenho simult\u00e2neo fraco, uma vez que efetua a sincroniza\u00e7\u00e3o sempre que v\u00e1rios encadeamentos leem o mesmo ficheiro. \ diff --git a/store-conf/conf/msgs/ZsMsg_pt_BR.properties b/store-conf/conf/msgs/ZsMsg_pt_BR.properties index 1caf7d610a3..9132c5a472f 100644 --- a/store-conf/conf/msgs/ZsMsg_pt_BR.properties +++ b/store-conf/conf/msgs/ZsMsg_pt_BR.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = O n\u00famero m\u00ednimo de documentos em buffer sejam esvaziados como um novo segmento. Grandes valores geralmente proporcionam indexa\u00e7\u00e3o mais r\u00e1pida. zimbra_index_lucene_ram_buffer_size_kb = RAM em buffer m\u00e1xima do Lucene em KB zimbra_index_lucene_io_impl = A implementa\u00e7\u00e3o do Lucene FSDirectory utilizada para indexa\u00e7\u00e3o de E/S. \ - Valores poss\u00edveis + Valores poss\u00edveis \ nio - Utiliza NIOFSDirectory. Utiliza E/S posicional java.nio's FileChannel's durante a leitura para evitar sincroniza\u00e7\u00e3o quando est\u00e1 lendo a partir do mesmo arquivo. \ mmap - Utiliza MMapDirectory. Utiliza E/S mapeada por mem\u00f3ria durante a leitura. Uma boa escolha caso haja grande quantidade de mem\u00f3ria virtual relacionada ao tamanho do \u00edndice. \ simples - Utiliza SimpleFSDirectory. Utiliza java.io.RandomAccessFile. Tem desempenho concomitante fraco pois sincroniza quando encadeamentos m\u00faltiplos fazem a leitura do mesmo arquivo. \ diff --git a/store-conf/conf/msgs/ZsMsg_ro.properties b/store-conf/conf/msgs/ZsMsg_ro.properties index 445532905f0..12003030a09 100644 --- a/store-conf/conf/msgs/ZsMsg_ro.properties +++ b/store-conf/conf/msgs/ZsMsg_ro.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = Num\u0103rul minim de documente necesare tampon s\u0103 fie golite ca segment nou. Valori mai mari ofer\u0103 \u00een general o indexare mai rapid\u0103. zimbra_index_lucene_ram_buffer_size_kb = RAM maxim\u0103 tamponat\u0103 pentru Lucene, \u00een KB zimbra_index_lucene_io_impl = Implementarea Lucene FSDirectory utilizat\u0103 pentru indexarea IO. \ - Valori posibile + Valori posibile \ nio - Utilizeaz\u0103 NIOFSDirectory. Utilizeaz\u0103 IO pozi\u0163ional\u0103 a FileChannel din java.nio la citire pentru a evita sincronizarea la citirea din acela\u015fi fi\u015fier. \ mmap - Utilizeaz\u0103 MMapDirectory. Utilizeaz\u0103 IO mapate \u00een memorie \u00een momentul citirii. Este o alegere bun\u0103 dac\u0103 exist\u0103 destul\u0103 memorie virtual\u0103 fa\u0163\u0103 de dimensiunea indec\u015filor. \ simple - Utilizeaz\u0103 SimpleFSDirectory. Utilizeaz\u0103 java.io.RandomAccessFile. Are o performan\u0163\u0103 slab\u0103 la opera\u0163ii concurente deoarece sincronizeaz\u0103 c\u00e2nd mai multe fire de execu\u0163ie citesc acela\u015fi fi\u015fier. \ diff --git a/store-conf/conf/msgs/ZsMsg_ru.properties b/store-conf/conf/msgs/ZsMsg_ru.properties index 69b3f49527d..73505a2060a 100644 --- a/store-conf/conf/msgs/ZsMsg_ru.properties +++ b/store-conf/conf/msgs/ZsMsg_ru.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = \u041c\u0438\u043d\u0438\u043c\u0430\u04 \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0430\u043c\u044f\u0442\u0438 \u0432 \u043d\u043e\u0432\u044b\u0439 \u0441\u0435\u0433\u043c\u0435\u043d\u0442. \u041f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u0445 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f \u043e\u0431\u044b\u0447\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442\u0441\u044f. zimbra_index_lucene_ram_buffer_size_kb = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 (\u041a\u0411) \u041e\u0417\u0423 Lucene zimbra_index_lucene_io_impl = \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Lucene FSDirectory, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0434\u043b\u044f \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u0438 \u0432\u0432\u043e\u0434\u0430-\u0432\u044b\u0432\u043e\u0434\u0430. \ - \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f + \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \ nio - \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c NIOFSDirectory. \u0414\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0432\u0432\u043e\u0434-\u0432\u044b\u0432\u043e\u0434 FileChannel \u0432 java.nio \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0438\u0437 \u0442\u043e\u0433\u043e \u0436\u0435 \u0444\u0430\u0439\u043b\u0430. \ mmap - \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c MMapDirectory. \u041f\u0440\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u0432\u043e\u0434-\u0432\u044b\u0432\u043e\u0434 \u0441 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u043f\u0430\u043c\u044f\u0442\u044c. \u041f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043e\u0431\u044a\u0435\u043c\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0438\u043d\u0434\u0435\u043a\u0441\u0430. \ simple - \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c SimpleFSDirectory. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f java.io.RandomAccessFile. \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0438\u043c\u0435\u0435\u0442 \u043d\u0438\u0437\u043a\u043e\u0435 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0440\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438. \ diff --git a/store-conf/conf/msgs/ZsMsg_sl.properties b/store-conf/conf/msgs/ZsMsg_sl.properties index 06d0f2c1c68..0a249634895 100644 --- a/store-conf/conf/msgs/ZsMsg_sl.properties +++ b/store-conf/conf/msgs/ZsMsg_sl.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = Najmanj\u0161e \u0161tevilo potrebnih do predpomnilniku strnejo kot nov segment. Velike vrednosti obi\u010dajno pomenijo hitrej\u0161e indeksiranje. zimbra_index_lucene_ram_buffer_size_kb = Lucene najv. medpomn. RAM v KB zimbra_index_lucene_io_impl = Uvedba Lucene FSDirectory uporabljena za V/I indeksiranja. \ - Mo\u017ene vrednosti + Mo\u017ene vrednosti \ nio - Uporabite NIOFSDirectory. Pri branju uporablja pozicijski V/I datote\u010dnega kanala java.nio, da prepre\u010di sinhronizacijo pri branju iz iste datoteke. \ mmap - Uporabite MMapDirectory. Pri branju uporablja V/I s preslikavo pomnilnika. Dober izbor, \u010de je glede na velikost kazala na voljo veliko navideznega pomnilnika. \ simple - Uporabite SimpleFSDirectory. Uporablja java.io.RandomAccessFile. Ima slabo so\u010dasno zmogljivost, ker se sinhronizira, ko ve\u010d niti bere isto datoteko. \ diff --git a/store-conf/conf/msgs/ZsMsg_sv.properties b/store-conf/conf/msgs/ZsMsg_sv.properties index 04ed4bc317c..027a4e68592 100644 --- a/store-conf/conf/msgs/ZsMsg_sv.properties +++ b/store-conf/conf/msgs/ZsMsg_sv.properties @@ -416,7 +416,7 @@ zimbra_index_lucene_max_buffered_docs = Det minsta antal dokument som kr\u00e4vs i minnet t\u00f6ms som ett nytt segment. Stora v\u00e4rden ger generellt snabbare indexering. zimbra_index_lucene_ram_buffer_size_kb = Maximalt buffrat RAM i kB f\u00f6r Lucene zimbra_index_lucene_io_impl = Lucene FSDirectory-implementering som anv\u00e4nds f\u00f6r IO-indexering. \ - M\u00f6jliga v\u00e4rden + M\u00f6jliga v\u00e4rden \ nio - Anv\u00e4nd NIOFSDirectory. Anv\u00e4nder java.nios FileChannels positions-IO vid l\u00e4sning f\u00f6r att undvika synkronisering vid l\u00e4sning fr\u00e5n samma fil. \ mmap - Anv\u00e4nd MMapDirectory. Anv\u00e4nder minnesmappade IO vid l\u00e4sning. Ett bra val om det finns gott om virtuellt minne i relation till indexstorleken. \ simple - Anv\u00e4nd SimpleFSDirectory. Anv\u00e4nder java.io.RandomAccessFile. Den har d\u00e5lig samtidig prestanda eftersom den synkroniserar n\u00e4r flera tr\u00e5da l\u00e4ser samma fil. \ diff --git a/store-conf/conf/msgs/ZsMsg_th.properties b/store-conf/conf/msgs/ZsMsg_th.properties index 7f20aaa18a0..a6e099abb2b 100644 --- a/store-conf/conf/msgs/ZsMsg_th.properties +++ b/store-conf/conf/msgs/ZsMsg_th.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = \u0e08\u0e33\u0e19\u0e27\u0e19\u0e40\u0e \u0e02\u0e2d\u0e07\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23\u0e08\u0e30\u0e16\u0e39\u0e01\u0e25\u0e49\u0e32\u0e07\u0e43\u0e2b\u0e49\u0e40\u0e1b\u0e47\u0e19\u0e2a\u0e48\u0e27\u0e19\u0e43\u0e2b\u0e21\u0e48 \u0e1b\u0e01\u0e15\u0e34\u0e41\u0e25\u0e49\u0e27\u0e04\u0e48\u0e32\u0e17\u0e35\u0e48\u0e2a\u0e39\u0e07\u0e08\u0e30\u0e17\u0e33\u0e14\u0e31\u0e0a\u0e19\u0e35\u0e44\u0e14\u0e49\u0e40\u0e23\u0e47\u0e27\u0e01\u0e27\u0e48\u0e32 zimbra_index_lucene_ram_buffer_size_kb = \u0e1a\u0e31\u0e1f\u0e40\u0e1f\u0e2d\u0e23\u0e4c RAM \u0e2a\u0e39\u0e07\u0e2a\u0e38\u0e14\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a Lucene \u0e40\u0e1b\u0e47\u0e19 KB zimbra_index_lucene_io_impl = \u0e01\u0e32\u0e23\u0e19\u0e33 Lucene FSDirectory \u0e44\u0e1b\u0e43\u0e0a\u0e49\u0e07\u0e32\u0e19\u0e42\u0e14\u0e22\u0e43\u0e0a\u0e49\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e01\u0e32\u0e23\u0e17\u0e33\u0e14\u0e31\u0e0a\u0e19\u0e35 IO \ - \u0e04\u0e48\u0e32\u0e17\u0e35\u0e48\u0e40\u0e1b\u0e47\u0e19\u0e44\u0e1b\u0e44\u0e14\u0e49 + \u0e04\u0e48\u0e32\u0e17\u0e35\u0e48\u0e40\u0e1b\u0e47\u0e19\u0e44\u0e1b\u0e44\u0e14\u0e49 \ nio \u2013 \u0e43\u0e0a\u0e49 NIOFSDirectory \u0e43\u0e0a\u0e49 IO \u0e15\u0e32\u0e21\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e02\u0e2d\u0e07 FileChannel \u0e02\u0e2d\u0e07 java.nio \u0e40\u0e21\u0e37\u0e48\u0e2d\u0e2d\u0e48\u0e32\u0e19 \u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e44\u0e21\u0e48\u0e43\u0e2b\u0e49\u0e40\u0e01\u0e34\u0e14\u0e01\u0e32\u0e23\u0e1b\u0e23\u0e31\u0e1a\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e43\u0e2b\u0e49\u0e15\u0e23\u0e07\u0e01\u0e31\u0e19\u0e40\u0e21\u0e37\u0e48\u0e2d\u0e2d\u0e48\u0e32\u0e19\u0e08\u0e32\u0e01\u0e44\u0e1f\u0e25\u0e4c\u0e40\u0e14\u0e35\u0e22\u0e27\u0e01\u0e31\u0e19 \ mmap \u2013 \u0e43\u0e0a\u0e49 MMapDirectory \u0e43\u0e0a\u0e49 IO \u0e17\u0e35\u0e48\u0e41\u0e21\u0e1b\u0e2b\u0e19\u0e48\u0e27\u0e22\u0e04\u0e27\u0e32\u0e21\u0e08\u0e33\u0e40\u0e21\u0e37\u0e48\u0e2d\u0e2d\u0e48\u0e32\u0e19 \u0e17\u0e32\u0e07\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e17\u0e35\u0e48\u0e40\u0e2b\u0e21\u0e32\u0e30\u0e2a\u0e21\u0e16\u0e49\u0e32\u0e21\u0e35\u0e2b\u0e19\u0e48\u0e27\u0e22\u0e04\u0e27\u0e32\u0e21\u0e08\u0e33\u0e40\u0e2a\u0e21\u0e37\u0e2d\u0e19\u0e08\u0e33\u0e19\u0e27\u0e19\u0e21\u0e32\u0e01\u0e40\u0e21\u0e37\u0e48\u0e2d\u0e40\u0e17\u0e35\u0e22\u0e1a\u0e01\u0e31\u0e1a\u0e02\u0e19\u0e32\u0e14\u0e02\u0e2d\u0e07\u0e14\u0e31\u0e0a\u0e19\u0e35 \ \u0e07\u0e48\u0e32\u0e22 \u2013 \u0e43\u0e0a\u0e49 SimpleFSDirectory \u0e43\u0e0a\u0e49 java.io.RandomAccessFile \u0e0b\u0e36\u0e48\u0e07\u0e17\u0e33\u0e07\u0e32\u0e19\u0e1e\u0e23\u0e49\u0e2d\u0e21\u0e01\u0e31\u0e19\u0e44\u0e14\u0e49\u0e44\u0e21\u0e48\u0e14\u0e35\u0e19\u0e31\u0e01\u0e02\u0e13\u0e30\u0e17\u0e35\u0e48\u0e1b\u0e23\u0e31\u0e1a\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e43\u0e2b\u0e49\u0e15\u0e23\u0e07\u0e01\u0e31\u0e19\u0e40\u0e21\u0e37\u0e48\u0e2d\u0e21\u0e35\u0e2b\u0e25\u0e32\u0e22\u0e40\u0e18\u0e23\u0e14\u0e2d\u0e48\u0e32\u0e19\u0e44\u0e1f\u0e25\u0e4c\u0e40\u0e14\u0e35\u0e22\u0e27\u0e01\u0e31\u0e19 \ diff --git a/store-conf/conf/msgs/ZsMsg_tr.properties b/store-conf/conf/msgs/ZsMsg_tr.properties index 31f1469a87f..81213d3eada 100644 --- a/store-conf/conf/msgs/ZsMsg_tr.properties +++ b/store-conf/conf/msgs/ZsMsg_tr.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = Ara belle\u011fe al\u0131nm\u0131\u015f gereken minimum belge say\u0131s\u0131. B\u00fcy\u00fck de\u011ferler genellikle daha h\u0131zl\u0131 dizinleme i\u015flemi sa\u011flar. zimbra_index_lucene_ram_buffer_size_kb = Lucene Arabelle\u011fe Al\u0131nm\u0131\u015f RAM \u00dcst S\u0131n\u0131r\u0131 (KB) zimbra_index_lucene_io_impl = G\u00c7 dizinleme i\u015flemi i\u00e7in kullan\u0131lan Lcene FSDirectory uygulamas\u0131. \ - Olas\u0131 de\u011ferler + Olas\u0131 de\u011ferler \ nio - Use NIOFSDirectory. Ayn\u0131 dosya \u00fczerinden okurken e\u015fzamanlama i\u015flemini \u00f6nlemek i\u00e7in okurken java.nio FileChannel\u2019a ait konumsal g\u00e7\u2019yi kullan\u0131r. \ mmap - MMapDirectory Kullan. Okuma i\u015flemi s\u0131ras\u0131nda bellek e\u015flemeli G\u00c7 kullan\u0131r. Dizin boyutuna g\u00f6re y\u00fcksek miktarda sanal bellek varsa iyi bir se\u00e7im. \ basit - SimpleFSDirectory Kullan. java.io.RandomAccessFile kullan\u0131r. \u00c7ok i\u015f par\u00e7ac\u0131klar\u0131 ayn\u0131 dosyay\u0131 okudu\u011funda e\u015fzamanlad\u0131\u011f\u0131 i\u00e7in e\u015fzamanl\u0131 performans\u0131 d\u00fc\u015f\u00fckt\u00fcr. \ diff --git a/store-conf/conf/msgs/ZsMsg_uk.properties b/store-conf/conf/msgs/ZsMsg_uk.properties index 32b597c701d..f09ac9b28ac 100644 --- a/store-conf/conf/msgs/ZsMsg_uk.properties +++ b/store-conf/conf/msgs/ZsMsg_uk.properties @@ -475,7 +475,7 @@ zimbra_index_lucene_max_buffered_docs = \u041c\u0456\u043d\u0456\u043c\u0430\u04 \u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0430\u043c'\u044f\u0442\u0456 \u0434\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430. \u0417 \u0431\u0456\u043b\u044c\u0448\u0438\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f\u043c\u0438 \u0456\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0456\u044f \u0437\u0430\u0437\u0432\u0438\u0447\u0430\u0439 \u043f\u0440\u0438\u0441\u043a\u043e\u0440\u044e\u0454\u0442\u044c\u0441\u044f. zimbra_index_lucene_ram_buffer_size_kb = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0438\u0439 \u043e\u0431\u0441\u044f\u0433 \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043e\u0457 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0457 \u043f\u0430\u043c'\u044f\u0442\u0456 (\u0443 \u041a\u0431\u0430\u0439\u0442) \u0443 Lucene zimbra_index_lucene_io_impl = \u0420\u0435\u0430\u043b\u0456\u0437\u0430\u0446\u0456\u044f Lucene FSDirectory, \u044f\u043a\u0430 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0454\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0443-\u0432\u0438\u0432\u043e\u0434\u0443 \u0456\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0456\u0457. \ - \u041c\u043e\u0436\u043b\u0438\u0432\u0456 \u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f + \u041c\u043e\u0436\u043b\u0438\u0432\u0456 \u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f \ nio - \u0412\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438 NIOFSDirectory. \u0414\u043b\u044f \u0447\u0438\u0442\u0430\u043d\u043d\u044f \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0454\u0442\u044c\u0441\u044f \u043f\u043e\u0437\u0438\u0446\u0456\u0439\u043d\u0438\u0439 \u0432\u0432\u0456\u0434-\u0432\u0438\u0432\u0456\u0434 FileChannel \u0432 java.nio, \u0449\u043e\u0431 \u0437\u0430\u043f\u043e\u0431\u0456\u0433\u0442\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0456\u0437\u0430\u0446\u0456\u0457 \u043f\u0456\u0434 \u0447\u0430\u0441 \u0447\u0438\u0442\u0430\u043d\u043d\u044f \u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u0439 \u0442\u043e\u0433\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0443. \ mmap - \u0412\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438 MMapDirectory. \u0414\u043b\u044f \u0447\u0438\u0442\u0430\u043d\u043d\u044f \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0454\u0442\u044c\u0441\u044f \u0432\u0432\u0456\u0434-\u0432\u0438\u0432\u0456\u0434 \u0437 \u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f\u043c \u043d\u0430 \u043f\u0430\u043c'\u044f\u0442\u044c. \u0414\u043e\u0446\u0456\u043b\u044c\u043d\u043e \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438, \u043a\u043e\u043b\u0438 \u043e\u0431\u0441\u044f\u0433 \u0432\u0456\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0457 \u043f\u0430\u043c'\u044f\u0442\u0456 \u0432\u0435\u043b\u0438\u043a\u0438\u0439 \u043f\u043e\u0440\u0456\u0432\u043d\u044f\u043d\u043e \u0437 \u0440\u043e\u0437\u043c\u0456\u0440\u043e\u043c \u0456\u043d\u0434\u0435\u043a\u0441\u0443. \ simple - \u0412\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438 SimpleFSDirectory. \u0412\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0454\u0442\u044c\u0441\u044f java.io.RandomAccessFile. \u0426\u0435\u0439 \u043c\u0435\u0442\u043e\u0434 \u043c\u0430\u0454 \u043d\u0438\u0437\u044c\u043a\u0443 \u043f\u0430\u0440\u0430\u043b\u0435\u043b\u044c\u043d\u0443 \u0448\u0432\u0438\u0434\u043a\u043e\u0434\u0456\u044e, \u043e\u0441\u043a\u0456\u043b\u044c\u043a\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0456\u0437\u0430\u0446\u0456\u044f \u0432\u0438\u043a\u043e\u043d\u0443\u0454\u0442\u044c\u0441\u044f \u043f\u0456\u0434 \u0447\u0430\u0441 \u0447\u0438\u0442\u0430\u043d\u043d\u044f \u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0443 \u043a\u0456\u043b\u044c\u043a\u043e\u043c\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438. \ diff --git a/store-conf/conf/msgs/ZsMsg_zh_CN.properties b/store-conf/conf/msgs/ZsMsg_zh_CN.properties index fa05ce8192d..c013a5ee8ce 100644 --- a/store-conf/conf/msgs/ZsMsg_zh_CN.properties +++ b/store-conf/conf/msgs/ZsMsg_zh_CN.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = \u7f13\u51b2\u5185\u5b58\u6587\u6863\u52 \u5c06\u6e05\u9664\u4e3a\u65b0\u6bb5\u3002\u8f83\u5927\u503c\u65f6\uff0c\u7d22\u5f15\u7684\u5efa\u7acb\u901a\u5e38\u8f83\u5feb\u3002 zimbra_index_lucene_ram_buffer_size_kb = Lucene \u6700\u5927\u7f13\u51b2 RAM (KB) zimbra_index_lucene_io_impl = Lucene FSDirectory \u5b9e\u65bd\u7528\u4e8e\u5efa\u7acb IO \u7d22\u5f15\u3002 \ - \u53ef\u80fd\u503c + \u53ef\u80fd\u503c \ nio \u2013 \u4f7f\u7528 NIOFSDirectory\u3002\u4ece\u76f8\u540c\u6587\u4ef6\u8bfb\u53d6\u4ee5\u907f\u514d\u540c\u6b65\u65f6\uff0c\u8bf7\u4f7f\u7528 java.nio FileChannel \u7684\u4f4d\u7f6e io\u3002 \ mmap \u2013 \u4f7f\u7528 MmapDirectory\u3002\u5728\u8bfb\u53d6\u65f6\uff0c\u4f7f\u7528\u5185\u5b58\u6620\u5c04\u7684 IO\u3002\u5982\u679c\u76f8\u5bf9\u4e8e\u7d22\u5f15\u5927\u5c0f\u6709\u5927\u91cf\u865a\u62df\u5185\u5b58\uff0c\u5219\u4e0d\u5931\u4e3a\u4e00\u4e2a\u597d\u7684\u9009\u62e9\u3002 \ simple \u2013 \u4f7f\u7528 SimpleFSDirectory\u3002\u4f7f\u7528 java.io.RandomAccessFile\u3002\u5f53\u6709\u591a\u4e2a\u7ebf\u7a0b\u8bfb\u53d6\u76f8\u540c\u6587\u4ef6\u65f6\uff0c\u5982\u679c\u8fdb\u884c\u540c\u6b65\uff0c\u5c31\u4f1a\u9020\u6210\u5e76\u53d1\u6027\u80fd\u5dee\u3002 \ diff --git a/store-conf/conf/msgs/ZsMsg_zh_HK.properties b/store-conf/conf/msgs/ZsMsg_zh_HK.properties index 79baa13ab90..f8b7d06361e 100644 --- a/store-conf/conf/msgs/ZsMsg_zh_HK.properties +++ b/store-conf/conf/msgs/ZsMsg_zh_HK.properties @@ -430,7 +430,7 @@ zimbra_index_lucene_max_buffered_docs = \u5728\u8a18\u61b6\u9ad4\u5167\u7de9\u88 \u6700\u5c11\u6587\u4ef6\u6578\u91cf\u3002\u5927\u6578\u503c\u901a\u5e38\u6703\u52a0\u5feb\u7d22\u5f15\u5efa\u7acb\u904e\u7a0b\u3002 zimbra_index_lucene_ram_buffer_size_kb = Lucene \u7de9\u885d RAM \u6578\u4e0a\u9650 (KB) zimbra_index_lucene_io_impl = \u7d22\u5f15 IO \u4f7f\u7528\u7684 Lucene FSDirectory \u5de5\u5177\u3002 \ - \u53ef\u7528\u6578\u503c + \u53ef\u7528\u6578\u503c \ nio \u2013 \u4f7f\u7528 NIOFSDirectory\u3002\u8b80\u53d6\u6642\u4f7f\u7528 java.nio \u7684 FileChannel \u5b9a\u4f4d io\uff0c\u4ee5\u907f\u514d\u8b80\u53d6\u540c\u4e00\u6a94\u6848\u6642\u7684\u540c\u6b65\u52d5\u4f5c\u3002 \ mmap \u2013 \u4f7f\u7528 MmapDirectory\u3002\u8b80\u53d6\u6642\u4f7f\u7528\u8a18\u61b6\u5c0d\u61c9 IO\u3002\u76f8\u5c0d\u65bc\u7d22\u5f15\u5927\u5c0f\uff0c\u82e5\u6709\u8a31\u591a\u865b\u64ec\u5167\u5b58\uff0c\u5247\u4e0d\u5931\u70ba\u4e00\u9805\u8f03\u597d\u7684\u9078\u64c7\u3002 \ simple \u2013 \u4f7f\u7528 SimpleFSDirectory\u3002\u4f7f\u7528 java.io.RandomAccessFile\u3002\u7576\u591a\u500b\u57f7\u884c\u7dd2\u8b80\u53d6\u540c\u4e00\u6a94\u6848\u6642\uff0c\u9019\u4e00\u5de5\u5177\u7684\u4e26\u884c\u6548\u80fd\u5728\u540c\u6b65\u6642\u8f03\u5dee\u3002 \ diff --git a/store-conf/conf/msgs/ZsMsg_zh_TW.properties b/store-conf/conf/msgs/ZsMsg_zh_TW.properties index 43d56ab7877..0aad75e48ec 100644 --- a/store-conf/conf/msgs/ZsMsg_zh_TW.properties +++ b/store-conf/conf/msgs/ZsMsg_zh_TW.properties @@ -474,7 +474,7 @@ zimbra_index_lucene_max_buffered_docs = \u7de9\u885d\u8a18\u61b6\u9ad4\u6587\u4e \u5c07\u6e05\u9664\u70ba\u65b0\u6bb5\u3002\u8f03\u5927\u503c\u6642\uff0c\u7d22\u5f15\u7684\u5efa\u7acb\u901a\u5e38\u8f03\u5feb\u3002 zimbra_index_lucene_ram_buffer_size_kb = Lucene \u6700\u5927\u7de9\u885d RAM (\u4ee5 KB \u70ba\u55ae\u4f4d) zimbra_index_lucene_io_impl = Lucene FSDirectory \u5be6\u65bd\u7528\u65bc\u5efa\u7acb IO \u7d22\u5f15\u3002 \ - \u53ef\u80fd\u503c + \u53ef\u80fd\u503c \ nio \u2013 \u4f7f\u7528 NIOFSDirectory\u3002\u5f9e\u76f8\u540c\u6a94\u6848\u8b80\u53d6\u4ee5\u907f\u514d\u540c\u6b65\u6642\uff0c\u8acb\u4f7f\u7528 java.nio FileChannel \u7684\u4f4d\u7f6e io\u3002 \ mmap \u2013 \u4f7f\u7528 MmapDirectory\u3002\u5728\u8b80\u53d6\u6642\uff0c\u4f7f\u7528\u8a18\u61b6\u9ad4\u5c0d\u61c9\u7684 IO\u3002\u5982\u679c\u76f8\u5c0d\u65bc\u7d22\u5f15\u5927\u5c0f\u6709\u5927\u91cf\u865b\u64ec\u8a18\u61b6\u9ad4\uff0c\u5247\u4e0d\u5931\u70ba\u4e00\u500b\u597d\u7684\u9078\u64c7\u3002 \ simple \u2013 \u4f7f\u7528 SimpleFSDirectory\u3002\u4f7f\u7528 java.io.RandomAccessFile\u3002\u7576\u6709\u591a\u500b\u57f7\u884c\u7dd2\u8b80\u53d6\u76f8\u540c\u6a94\u6848\u6642\uff0c\u5982\u679c\u9032\u884c\u540c\u6b65\uff0c\u5c31\u6703\u9020\u6210\u4f75\u767c\u6548\u80fd\u5dee\u3002 \ From 49cdb0d6d0cfeaea24b1799fee673dd9a9937b53 Mon Sep 17 00:00:00 2001 From: Fulvio Scapin Date: Wed, 2 Aug 2017 12:44:35 +0200 Subject: [PATCH 111/142] Fixed keys not aligned to the beginning of the line --- store-conf/conf/msgs/ZsMsg_ca.properties | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/store-conf/conf/msgs/ZsMsg_ca.properties b/store-conf/conf/msgs/ZsMsg_ca.properties index da3be235126..cb84fa3aed2 100644 --- a/store-conf/conf/msgs/ZsMsg_ca.properties +++ b/store-conf/conf/msgs/ZsMsg_ca.properties @@ -366,7 +366,7 @@ passwordViolation = Vulneraci\u00f3 de la contrasenya: account={0}, violation={1 # local config settings - zimbra_home = \ +zimbra_home = \ Directori arrel d\u2019instal\u00b7laci\u00f3 del Zimbra i directori d\u2019inici \ de l\u2019usuari \u2019zimbra\u2019 d\u2019UNIX. No podeu traslladar el directori arrel d\u2019instal\u00b7laci\u00f3. \ No canvieu aquesta configuraci\u00f3. @@ -380,7 +380,7 @@ zimbra_extensions_directory = Directori amb els subdirectoris que contenen les e zimbra_extensions_common_directory = Directori amb fitxers jar comuns a totes les extensions. zimbra_mysql_shutdown_timeout = Temps d\u2019espera per donar per acabat el proc\u00e9s MySQL/MariaDB de la b\u00fastia de correu. \ Augmenteu el temps d\u2019espera si mysql.server triga massa a tancar el proc\u00e9s. - zimbra_mysql_user = \ +zimbra_mysql_user = \ Nom d\u2019usuari de MySQL per crear/accedir a les bases de dades i taules \ del zimbra. Aquest \u00e9s el valor que indicar\u00edeu a \ l\u2019opci\u00f3 \u2019-u\u2019 del programa de l\u00ednia d\u2019ordres \u2019mysql\u2019. @@ -398,7 +398,7 @@ zimbra_ldap_password = \ es puguin autenticar. Per canviar la contrasenya, \ feu servir el programa zmmypasswd, que canviar\u00e0 la \ contrasenya tant a LDAP com a la configuraci\u00f3 local. - zimbra_server_hostname = \ +zimbra_server_hostname = \ Nom aprovisionat d\u2019aquest servidor. Cal que hi hagi \ una entrada \u2019server\u2019 corresponent a LDAP. Consulteu \ la documentaci\u00f3 de l\u2019ordre CreateServer del programa zmprov. @@ -577,7 +577,7 @@ mysql_pidfile = Fitxer on s\u2019emmagatzema l\u2019identificador de proc\u00e9s mysql_mycnf = Ruta de my.cnf, el fitxer de configuraci\u00f3 del MySQL. mysql_bind_address = Interf\u00edcie de l\u2019amfitri\u00f3 al qual s\u2019enlla\u00e7ar\u00e0 el MySQL. mysql_port = N\u00famero de port que ha d\u2019escoltar el servidor MySQL. - mysql_root_password = \ +mysql_root_password = \ Contrasenya de l\u2019usuari \u2019root\u2019 integrat de MySQL, que no s\u2019ha \ de confondre amb l\u2019usuari root d\u2019UNIX. Per comoditat, durant la inicialitzaci\u00f3 \ de la base de dades es genera una contrasenya aleat\u00f2ria \ @@ -772,7 +772,7 @@ zimbra_zmjava_java_ext_dirs = Propietat java.ext.dirs de Java per a l\u2019scrip debug_update_config_use_old_scheme = \ Si \u00e9s TRUE, DbMailbox.updateConfig() far\u00e0 DELETE/INSERT enlloc d\u2019UPDATE. debug_xmpp_disable_client_tls = inhabilita TLS per al protocol XMPP C2S - im_dnsutil_dnsoverride = \ +im_dnsutil_dnsoverride = \ Configuraci\u00f3 de l\u2019anul\u00b7laci\u00f3 del DNS per a la federaci\u00f3 de missatges instantanis, en el format \u2019{domain,host:port}, {domain,host:port},...\u2019 javamail_pop3_debug = Si cal permetre la depuraci\u00f3 de JavaMail per POP3. javamail_zparser = Si cal fer servir l\u2019analitzador MIME del Zimbra enlloc del de JavaMail. From 79c63fd10474a3f9224c1a1228e3592ee28f7eba Mon Sep 17 00:00:00 2001 From: Fulvio Scapin Date: Wed, 2 Aug 2017 12:52:48 +0200 Subject: [PATCH 112/142] Fixed unescaped newline in the Arabic localization Fixed unescaped newline half-way through the value of the key ldap_cache_custom_dynamic_group_membership_maxage_ms --- store-conf/conf/msgs/ZsMsg_ar.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store-conf/conf/msgs/ZsMsg_ar.properties b/store-conf/conf/msgs/ZsMsg_ar.properties index 03a8c603110..c043ffa8d80 100644 --- a/store-conf/conf/msgs/ZsMsg_ar.properties +++ b/store-conf/conf/msgs/ZsMsg_ar.properties @@ -567,7 +567,7 @@ ldap_cache_share_locator_maxage = \u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0 ldap_cache_timezone_maxsize = \u0623\u0642\u0635\u0649 \u0639\u062f\u062f \u0645\u0646 \u0643\u0627\u0626\u0646\u0627\u062a \u0627\u0644\u0645\u0646\u0637\u0642\u0629 \u0627\u0644\u0632\u0645\u0646\u064a\u0629 \u062a\u064f\u062e\u0632\u0651\u0646 \u0645\u0624\u0642\u062a\u064b\u0627. ldap_cache_zimlet_maxsize = \u0623\u0642\u0635\u0649 \u0639\u062f\u062f \u0645\u0646 \u0643\u0627\u0626\u0646\u0627\u062a zimlet \u062a\u064f\u062e\u0632\u0651\u0646 \u0645\u0624\u0642\u062a\u064b\u0627. ldap_cache_zimlet_maxage = \u0623\u0642\u0635\u0649 \u0639\u0645\u0631 (\u0628\u0627\u0644\u062f\u0642\u0627\u0626\u0642) \u0644\u0643\u0627\u0626\u0646\u0627\u062a zimlet \u0641\u064a \u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u062a\u062e\u0632\u064a\u0646 \u0627\u0644\u0645\u0624\u0642\u062a. -ldap_cache_custom_dynamic_group_membership_maxage_ms = \u0623\u0642\u0635\u0649 \u0639\u0645\u0631 (\u0628\u0627\u0644\u0645\u0644\u0644\u064a \u062b\u0627\u0646\u064a\u0629) \u0644\u0644\u062a\u062e\u0632\u064a\u0646 \u0627\u0644\u0645\u0624\u0642\u062a \u0644\u0623\u064a \u0645\u062c\u0645\u0648\u0639\u0627\u062a \u062f\u064a\u0646\u0627\u0645\u064a\u0643\u064a\u0629. +ldap_cache_custom_dynamic_group_membership_maxage_ms = \u0623\u0642\u0635\u0649 \u0639\u0645\u0631 (\u0628\u0627\u0644\u0645\u0644\u0644\u064a \u062b\u0627\u0646\u064a\u0629) \u0644\u0644\u062a\u062e\u0632\u064a\u0646 \u0627\u0644\u0645\u0624\u0642\u062a \u0644\u0623\u064a \u0645\u062c\u0645\u0648\u0639\u0627\u062a \u062f\u064a\u0646\u0627\u0645\u064a\u0643\u064a\u0629.\ \u0627\u0644\u062d\u0633\u0627\u0628 \u0647\u0648 \u0639\u0636\u0648 \u0644\u0647\u0630\u0647 \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0627\u062a \u0627\u0644\u062a\u064a \u064a\u062a\u0645 \u062a\u062d\u062f\u064a\u062f \u0639\u0636\u0648\u064a\u062a\u0647\u0627 \u0628\u0627\u0633\u062a\u062e\u062f\u0627\u0645 MemberURL \u0645\u062e\u0635\u0635. mysql_directory = \u0645\u0648\u0642\u0639 \u062a\u062b\u0628\u064a\u062a MySQL. mysql_data_directory = \u0627\u0644\u062f\u0644\u064a\u0644 \u0627\u0644\u0630\u064a \u064a\u062c\u0628 \u0623\u0646 \u064a\u0648\u062c\u062f \u0641\u064a\u0647 \u0628\u064a\u0627\u0646\u0627\u062a MySQL\u200f. From 82cfb4dfb3789a1abcaa8a1764d10c3c37ebae14 Mon Sep 17 00:00:00 2001 From: Fulvio Scapin Date: Wed, 2 Aug 2017 12:54:05 +0200 Subject: [PATCH 113/142] Fixed wrong value for key ldap_cache_custom_dynamic_group_membership_maxage_ms The value for the key ldap_cache_custom_dynamic_group_membership_maxage_ms in the English-Australian file was wrong, containing "Maximum age (in minutes) of group objects in cache." instead of the correct "Maximum age (in milliseconds) to cache which dynamic groups" present in every other English localization. Probably a Copy&Paste error. --- store-conf/conf/msgs/ZsMsg_en_AU.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store-conf/conf/msgs/ZsMsg_en_AU.properties b/store-conf/conf/msgs/ZsMsg_en_AU.properties index b571f74296c..64a0cf91aab 100644 --- a/store-conf/conf/msgs/ZsMsg_en_AU.properties +++ b/store-conf/conf/msgs/ZsMsg_en_AU.properties @@ -567,7 +567,7 @@ ldap_cache_share_locator_maxage = Named entry cache TTL in minutes. ldap_cache_timezone_maxsize = Maximum number of timezone objects to cache. ldap_cache_zimlet_maxsize = Maximum number of zimlet objects to cache. ldap_cache_zimlet_maxage = Maximum age (in minutes) of zimlet objects in cache. -ldap_cache_custom_dynamic_group_membership_maxage_ms = Maximum age (in minutes) of group objects in cache. +ldap_cache_custom_dynamic_group_membership_maxage_ms = Maximum age (in milliseconds) to cache which dynamic groups \ an account is a member of for those groups whose membership is determind using a custom MemberURL. mysql_directory = Location of MySQL installation. mysql_data_directory = Directory in which MySQL data should reside. From 04d4d6730f3b2adecd3fdb47663175fc7c27b1fe Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Wed, 27 Sep 2017 11:43:42 +0900 Subject: [PATCH 114/142] zcs-282:SIEVE:notify:Capitalize the header name Headers specified by mailto: URI should capitalize the first letter [Problem] The name of the URL headers specified in the "mailto:" parameter was always lower-cased; RFC says the the first letter of the added header name should be capitalized though. [Fix] * The name of the URL headers will be capitalized. Although the MIME header name is defined as only ASCII character's string, if the header name should consisted of non-ascii characters, the first letter of the header name will not changed. * Fixed an unit test case "testNotifyMethodCapability_OnlineYes": It was failed because the filter string was not grammatically correct, and it threw an exception. --- .../zimbra/cs/filter/NotifyMailtoTest.java | 34 ++++++++++++++++--- .../java/com/zimbra/cs/filter/FilterUtil.java | 2 +- .../zimbra/cs/filter/jsieve/NotifyMailto.java | 8 +++-- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java b/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java index 2809a5072a1..cb442f7b19f 100644 --- a/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java +++ b/store/src/java-test/com/zimbra/cs/filter/NotifyMailtoTest.java @@ -18,11 +18,13 @@ import static org.junit.Assert.fail; +import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import javax.mail.Header; import javax.mail.internet.MimeMessage; import org.junit.Assert; @@ -107,7 +109,7 @@ public void setUp() throws Exception { + " notify :message \"${subject}\"\n" + " :from \"test1@zimbra.com\"\n" + " :importance \"3\"\n" - + " \"mailto:test2@zimbra.com?to=test3@zimbra.com&Importance=High&X-Priority=1&From=notifyfrom@example.com&body=${contents}\";" + + " \"mailto:test2@zimbra.com?to=test3@zimbra.com&Importance=High&X-Priority=1&X-HEADER1=value1&x-header2=value2&x-HeAdEr3=value3&x-hEader4=value4A&x-heAder4=value4B&From=notifyfrom@example.com&body=${contents}\";" + " keep;\n" + "}\n"; @@ -287,6 +289,30 @@ public void test() { Assert.assertFalse(notifyMsg.getSender() == null); Assert.assertEquals("test1@zimbra.com", notifyMsg.getSender()); + boolean header1 = false; + boolean header2 = false; + boolean header3 = false; + boolean header4 = false; + for (Enumeration
e = notifyMsg.getMimeMessage().getAllHeaders(); e.hasMoreElements();) { + Header temp = e.nextElement(); + if ("X-HEADER1".equals(temp.getName())) { + header1 = true; + } + if ("X-header2".equals(temp.getName())) { + header2 = true; + } + if ("X-HeAdEr3".equals(temp.getName())) { + header3 = true; + } + if ("X-hEader4".equals(temp.getName())) { + header4 = true; + } + } + Assert.assertTrue(header1); + Assert.assertTrue(header2); + Assert.assertTrue(header3); + Assert.assertTrue(header4); + notifyMsg = mbox3.getMessageById(null, item); Assert.assertEquals("おしらせ", notifyMsg.getSubject()); } catch (Exception e) { @@ -942,10 +968,10 @@ public void testNotifyMethodCapability_OnlineMaybe() { public void testNotifyMethodCapability_OnlineYes() { String filterScript = "require [\"enotify\", \"tag\"];\n" - + "if not notify_method_capability\n" + + "if notify_method_capability\n" + " \"mailto:test2@zimbra.com\"\n" + " \"Online\"\n" - + " \"YES\"] { \n" + + " [\"YES\"] { \n" + " tag \"notify_method_capability\";\n" + "}"; @@ -962,7 +988,7 @@ public void testNotifyMethodCapability_OnlineYes() { Mailbox.ID_FOLDER_INBOX, true); // ZCS implements the RFC 5436 so that it returns true when 'notify_method_capability' - // checkes whether the "Online" status is "maybe". Otherwise it returns false. + // checks whether the "Online" status is "maybe". Otherwise it returns false. Assert.assertEquals(1, ids.size()); Message msg = mbox1.getMessageById(null, ids.get(0).getId()); Assert.assertEquals(null, ArrayUtil.getFirstElement(msg.getTags())); diff --git a/store/src/java/com/zimbra/cs/filter/FilterUtil.java b/store/src/java/com/zimbra/cs/filter/FilterUtil.java index e7a2e2bbefe..2af0e26245e 100644 --- a/store/src/java/com/zimbra/cs/filter/FilterUtil.java +++ b/store/src/java/com/zimbra/cs/filter/FilterUtil.java @@ -709,7 +709,7 @@ public static void notifyMailto(LmtpEnvelope envelope, OperationContext octxt, M "body".equalsIgnoreCase(headerName))) { List values = mailtoParams.get(headerName); for (String value : values) { - notification.addHeader(headerName, value); + notification.addHeaderLine(headerName + ": " + value); } } } diff --git a/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMailto.java b/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMailto.java index c7e19a35cc2..3b4b4d5ecd0 100644 --- a/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMailto.java +++ b/store/src/java/com/zimbra/cs/filter/jsieve/NotifyMailto.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.TreeMap; import javax.mail.internet.InternetAddress; import javax.mail.internet.AddressException; @@ -251,7 +252,7 @@ private Object execute(MailAdapter mail, Arguments arguments, SieveContext conte method = FilterUtil.replaceVariables(mailAdapter, method); } - mailtoParams = new HashMap>(); + mailtoParams = new TreeMap>(String.CASE_INSENSITIVE_ORDER); try { URL url = new URL(method); mailto = FilterUtil.replaceVariables(mailAdapter, url.getPath()); @@ -275,12 +276,13 @@ private Object execute(MailAdapter mail, Arguments arguments, SieveContext conte String headerName = null; String headerValue = null; try { - headerName = URLDecoder.decode(token[0].toLowerCase(), "UTF-8"); + headerName = URLDecoder.decode(token[0], "UTF-8"); } catch (UnsupportedEncodingException e) { // No exception should be thrown because the charset is always "UTF-8" } catch (IllegalArgumentException e) { - headerName = token[0].toLowerCase(); + headerName = token[0]; } + headerName = Character.toUpperCase(headerName.charAt(0)) + headerName.substring(1); if (token.length == 1) { // The value must be empty headerValue = ""; From 0c97c4cedd1f2a62b44bf74f8e21ef3b9da62a2c Mon Sep 17 00:00:00 2001 From: Sneha Patil Date: Thu, 21 Sep 2017 11:45:14 +0530 Subject: [PATCH 115/142] ZCS-2670:API to verify ownership of forwarding email address --- .../common/account/ZAttrProvisioning.java | 56 +++ .../zimbra/common/soap/AccountConstants.java | 7 + .../java/com/zimbra/common/util/L10nUtil.java | 6 +- store-conf/conf/msgs/ZsMsg.properties | 16 + store/conf/attrs/zimbra-attrs.xml | 17 + .../zimbra/cs/account/ExtShareInfoTest.java | 3 +- .../zimbra/cs/service/ModifyPrefsTest.java | 137 +++++++ .../mail/SendShareNotificationTest.java | 2 +- .../java/com/zimbra/cs/account/ShareInfo.java | 149 ++----- .../com/zimbra/cs/account/ZAttrAccount.java | 387 ++++++++++++++++++ .../java/com/zimbra/cs/account/ZAttrCos.java | 184 +++++++++ .../cs/service/account/ModifyPrefs.java | 104 ++++- .../service/mail/SendShareNotification.java | 114 ++---- .../java/com/zimbra/cs/util/AccountUtil.java | 195 +++++++++ 14 files changed, 1190 insertions(+), 187 deletions(-) create mode 100644 store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index e3b5f2670be..b47ea23c43d 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -440,6 +440,26 @@ public static DomainType fromString(String s) throws ServiceException { public boolean isAlias() { return this == alias;} } + public static enum FeatureAddressVerificationStatus { + verified("verified"), + pending("pending"), + failed("failed"), + expired("expired"); + private String mValue; + private FeatureAddressVerificationStatus(String value) { mValue = value; } + public String toString() { return mValue; } + public static FeatureAddressVerificationStatus fromString(String s) throws ServiceException { + for (FeatureAddressVerificationStatus value : values()) { + if (value.mValue.equals(s)) return value; + } + throw ServiceException.INVALID_REQUEST("invalid value: "+s+", valid values: "+ Arrays.asList(values()), null); + } + public boolean isVerified() { return this == verified;} + public boolean isPending() { return this == pending;} + public boolean isFailed() { return this == failed;} + public boolean isExpired() { return this == expired;} + } + public static enum FeatureSocialFiltersEnabled { SocialCast("SocialCast"), LinkedIn("LinkedIn"), @@ -6092,6 +6112,42 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc @ZAttr(id=1244) public static final String A_zimbraExternalUserMailAddress = "zimbraExternalUserMailAddress"; + /** + * RFC822 email address under verification for an account + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2128) + public static final String A_zimbraFeatureAddressUnderVerification = "zimbraFeatureAddressUnderVerification"; + + /** + * Enable end-user email address verification + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public static final String A_zimbraFeatureAddressVerificationEnabled = "zimbraFeatureAddressVerificationEnabled"; + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public static final String A_zimbraFeatureAddressVerificationExpiry = "zimbraFeatureAddressVerificationExpiry"; + + /** + * End-user email address verification status + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public static final String A_zimbraFeatureAddressVerificationStatus = "zimbraFeatureAddressVerificationStatus"; + /** * whether email features and tabs are enabled in the web client if * accessed from the admin console diff --git a/common/src/java/com/zimbra/common/soap/AccountConstants.java b/common/src/java/com/zimbra/common/soap/AccountConstants.java index f37415d3278..74260381da4 100644 --- a/common/src/java/com/zimbra/common/soap/AccountConstants.java +++ b/common/src/java/com/zimbra/common/soap/AccountConstants.java @@ -558,4 +558,11 @@ public class AccountConstants { public static final String A_CONSUMER_APP_NAME = "appName"; public static final String A_APPROVED_ON = "approvedOn"; public static final String A_CONSUMER_DEVICE = "device"; + + //ext user prov URL metadata constants + public static final String P_ACCOUNT_ID = "aid"; + public static final String P_FOLDER_ID = "fid"; + public static final String P_LINK_EXPIRY = "exp"; + public static final String P_EMAIL = "email"; + public static final String P_ADDRESS_VERIFICATION = "address-verification"; } diff --git a/common/src/java/com/zimbra/common/util/L10nUtil.java b/common/src/java/com/zimbra/common/util/L10nUtil.java index a05b79bebde..25d4684e88f 100644 --- a/common/src/java/com/zimbra/common/util/L10nUtil.java +++ b/common/src/java/com/zimbra/common/util/L10nUtil.java @@ -274,8 +274,12 @@ public static enum MsgKey { //sieve seiveRejectMDNSubject, - seiveRejectMDNErrorMsg + seiveRejectMDNErrorMsg, + //forwarding email address verification + verifyEmailSubject, + verifyEmailBodyText, + verifyEmailBodyHtml // add other messages in the future... } diff --git a/store-conf/conf/msgs/ZsMsg.properties b/store-conf/conf/msgs/ZsMsg.properties index f3e89fd01a0..22751aa8e79 100644 --- a/store-conf/conf/msgs/ZsMsg.properties +++ b/store-conf/conf/msgs/ZsMsg.properties @@ -906,3 +906,19 @@ zipFile = Zip File seiveRejectMDNSubject = Disposition notification seiveRejectMDNErrorMsg = The message was refused by the recipient's mail filtering program. The reason given was as follows: + +# email address verification +verifyEmailSubject = Request for email address verification by {0} +verifyEmailBodyText =\ + {0} has requested verification of your email address\n\ + \n\ + Click on the link below to verify your email address: {1}\n\ + The link expires by: {2}\n\ + *~*~*~*~*~*~*~*~*~*\n +verifyEmailBodyHtml =\ +
\ +

{0} has requested verification of your email address

\ +
\ + Click on this link to verify your email address
\ + The link expires by {2}\ +
diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index 6e591634a88..3fd492cd1b4 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9585,4 +9585,21 @@ TODO: delete them permanently from here + + FALSE + Enable end-user email address verification + + + + 1d + Expiry time for end-user email address verification + + + + RFC822 email address under verification for an account + + + + End-user email address verification status + diff --git a/store/src/java-test/com/zimbra/cs/account/ExtShareInfoTest.java b/store/src/java-test/com/zimbra/cs/account/ExtShareInfoTest.java index c812ac9ebb6..ef8bff0ce79 100644 --- a/store/src/java-test/com/zimbra/cs/account/ExtShareInfoTest.java +++ b/store/src/java-test/com/zimbra/cs/account/ExtShareInfoTest.java @@ -33,6 +33,7 @@ import com.google.common.collect.Maps; import com.zimbra.common.service.ServiceException; +import com.zimbra.common.util.L10nUtil; import com.zimbra.cs.mailbox.ACL; import com.zimbra.cs.mailbox.MailItem; import com.zimbra.cs.mailbox.MailboxManager; @@ -66,6 +67,7 @@ public void setUp() throws Exception { // this MailboxManager does everything except use SMTP to deliver mail MailboxManager.setInstance(new DirectInsertionMailboxManager()); + L10nUtil.setMsgClassLoader("../store-conf/conf/msgs"); } @Test @@ -90,7 +92,6 @@ public void testGenNotifyBody() { sid.setOwnerAcctDisplayName("Demo User Two"); try { - sid.setRights(ACL.stringToRights("rwidxap")); MimeMultipart mmp = ShareInfo.NotificationSender.genNotifBody(sid, notes, locale, null, null); diff --git a/store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java b/store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java new file mode 100644 index 00000000000..f351a7d998c --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java @@ -0,0 +1,137 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.cs.service; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import javax.mail.Address; +import javax.mail.internet.MimeMessage; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.Maps; +import com.zimbra.common.account.Key; +import com.zimbra.common.soap.Element; +import com.zimbra.common.util.L10nUtil; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailItem; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.MailboxManager; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.cs.mailbox.Message; +import com.zimbra.cs.mailbox.Mailbox.MailboxData; +import com.zimbra.cs.service.account.ModifyPrefs; +import com.zimbra.cs.service.mail.ServiceTestUtil; +import com.zimbra.soap.JaxbUtil; +import com.zimbra.soap.account.message.ModifyPrefsRequest; +import com.zimbra.soap.account.type.Pref; + +import junit.framework.Assert; + +public class ModifyPrefsTest { + + public static String zimbraServerDir = ""; + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + Provisioning prov = Provisioning.getInstance(); + + Map attrs = Maps.newHashMap(); + prov.createDomain("zimbra.com", attrs); + + attrs = Maps.newHashMap(); + prov.createAccount("test@zimbra.com", "secret", attrs); + + MailboxManager.setInstance(new MailboxManager() { + + @Override + protected Mailbox instantiateMailbox(MailboxData data) { + return new Mailbox(data) { + + @Override + public MailSender getMailSender() { + return new MailSender() { + + @Override + protected Collection
sendMessage(Mailbox mbox, MimeMessage mm, + Collection rollbacks) + throws SafeMessagingException, IOException { + try { + return Arrays.asList(getRecipients(mm)); + } catch (Exception e) { + return Collections.emptyList(); + } + } + }; + } + }; + } + }); + + L10nUtil.setMsgClassLoader("../store-conf/conf/msgs"); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + } + + @Test + public void testMsgMaxAttr() throws Exception { + Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct1); + acct1.setFeatureMailForwardingEnabled(true); + acct1.setFeatureAddressVerificationEnabled(true); + Assert.assertNull(acct1.getPrefMailForwardingAddress()); + Assert.assertNull(acct1.getFeatureAddressUnderVerification()); + ModifyPrefsRequest request = new ModifyPrefsRequest(); + Pref pref = new Pref(Provisioning.A_zimbraPrefMailForwardingAddress, + "test1@somedomain.com"); + request.addPref(pref); + Element req = JaxbUtil.jaxbToElement(request); + new ModifyPrefs().handle(req, ServiceTestUtil.getRequestContext(mbox.getAccount())); + /* + * Verify that the forwarding address is not directly stored into + * 'zimbraPrefMailForwardingAddress' Instead, it is stored in + * 'zimbraFeatureAddressUnderVerification' till the time it + * gets verification + */ + Assert.assertNull(acct1.getPrefMailForwardingAddress()); + Assert.assertEquals("test1@somedomain.com", + acct1.getFeatureAddressUnderVerification()); + /* + * disable the verification feature and check that the forwarding + * address is directly stored into 'zimbraPrefMailForwardingAddress' + */ + acct1.setPrefMailForwardingAddress(null); + acct1.setFeatureAddressUnderVerification(null); + acct1.setFeatureAddressVerificationEnabled(false); + new ModifyPrefs().handle(req, ServiceTestUtil.getRequestContext(mbox.getAccount())); + Assert.assertNull(acct1.getFeatureAddressUnderVerification()); + Assert.assertEquals("test1@somedomain.com", acct1.getPrefMailForwardingAddress()); + } +} \ No newline at end of file diff --git a/store/src/java-test/com/zimbra/cs/service/mail/SendShareNotificationTest.java b/store/src/java-test/com/zimbra/cs/service/mail/SendShareNotificationTest.java index 055c89f8daa..148ee2e822a 100644 --- a/store/src/java-test/com/zimbra/cs/service/mail/SendShareNotificationTest.java +++ b/store/src/java-test/com/zimbra/cs/service/mail/SendShareNotificationTest.java @@ -128,7 +128,7 @@ protected Collection
sendMessage(Mailbox mbox, MimeMessage mm, Collecti } }); - L10nUtil.setMsgClassLoader("conf/msgs"); + L10nUtil.setMsgClassLoader("../store-conf/conf/msgs"); } @Before diff --git a/store/src/java/com/zimbra/cs/account/ShareInfo.java b/store/src/java/com/zimbra/cs/account/ShareInfo.java index e3c1390987b..20b67fd6c34 100644 --- a/store/src/java/com/zimbra/cs/account/ShareInfo.java +++ b/store/src/java/com/zimbra/cs/account/ShareInfo.java @@ -16,12 +16,6 @@ */ package com.zimbra.cs.account; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -33,7 +27,6 @@ import java.util.Set; import javax.activation.DataHandler; -import javax.activation.DataSource; import javax.mail.Address; import javax.mail.MessagingException; import javax.mail.Transport; @@ -42,7 +35,6 @@ import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; -import org.apache.commons.codec.binary.Hex; import com.google.common.base.Strings; import com.sun.mail.smtp.SMTPMessage; @@ -55,7 +47,6 @@ import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants.ShareConstants; import com.zimbra.common.soap.SoapProtocol; -import com.zimbra.common.util.BlobMetaData; import com.zimbra.common.util.L10nUtil; import com.zimbra.common.util.L10nUtil.MsgKey; import com.zimbra.common.util.Pair; @@ -76,10 +67,11 @@ import com.zimbra.cs.mailbox.Mountpoint; import com.zimbra.cs.mailbox.OperationContext; import com.zimbra.cs.mailbox.acl.AclPushSerializer; -import com.zimbra.cs.servlet.ZimbraServlet; import com.zimbra.cs.util.AccountUtil; import com.zimbra.cs.util.JMSession; import com.zimbra.soap.mail.message.SendShareNotificationRequest.Action; +import com.zimbra.cs.util.AccountUtil.HtmlPartDataSource; +import com.zimbra.cs.util.AccountUtil.XmlPartDataSource; public class ShareInfo { @@ -555,10 +547,9 @@ public static class NotificationSender { private static final String HTML_LINE_BREAK = "
"; private static final String NEWLINE = "\n"; - - + public static MimeMultipart genNotifBody(ShareInfoData sid, String notes, - Locale locale, Action action, String externalGroupMember) + Locale locale, Action action, String externalGroupMember) throws MessagingException, ServiceException { // Body @@ -576,8 +567,8 @@ public static MimeMultipart genNotifBody(ShareInfoData sid, String notes, boolean goesToExternalAddr = (externalGranteeName != null); if (action == null && goesToExternalAddr) { Account owner = Provisioning.getInstance().getAccountById(sid.getOwnerAcctId()); - extUserShareAcceptUrl = getShareAcceptURL(owner, sid.getItemId(), externalGranteeName); - extUserLoginUrl = getExtUserLoginURL(owner); + extUserShareAcceptUrl = AccountUtil.getShareAcceptURL(owner, sid.getItemId(), externalGranteeName); + extUserLoginUrl = AccountUtil.getExtUserLoginURL(owner); } // TEXT part (add me first!) @@ -618,35 +609,37 @@ public static MimeMultipart genNotifBody(ShareInfoData sid, String notes, return mmp; } - private static String getExtUserLoginURL(Account owner) throws ServiceException { - return ZimbraServlet.getServiceUrl( - owner.getServer(), - Provisioning.getInstance().getDomain(owner), - "?virtualacctdomain=" + owner.getDomainName()); - } + public static String getMimePartHtml(ShareInfoData sid, String notes, Locale locale, + Action action, String extUserShareAcceptUrl, String extUserLoginUrl) throws MessagingException, ServiceException { - private static String getShareAcceptURL(Account account, int folderId, String externalUserEmail) - throws ServiceException { - StringBuilder encodedBuff = new StringBuilder(); - BlobMetaData.encodeMetaData("aid", account.getId(), encodedBuff); - BlobMetaData.encodeMetaData("fid", folderId, encodedBuff); - BlobMetaData.encodeMetaData("email", externalUserEmail, encodedBuff); - Domain domain = Provisioning.getInstance().getDomain(account); - if (domain != null) { - long urlExpiration = domain.getExternalShareInvitationUrlExpiration(); - if (urlExpiration != 0) { - BlobMetaData.encodeMetaData("exp", System.currentTimeMillis() + urlExpiration, encodedBuff); - } + String mimePartHtml; + if (action == Action.revoke) { + mimePartHtml = genRevokePart(sid, locale, true); + } else if (action == Action.expire) { + mimePartHtml = genExpirePart(sid, locale, true); + } else { + mimePartHtml = genPart(sid, action == Action.edit, notes, extUserShareAcceptUrl, + extUserLoginUrl, locale, null, true); } - String data = new String(Hex.encodeHex(encodedBuff.toString().getBytes())); - ExtAuthTokenKey key = ExtAuthTokenKey.getCurrentKey(); - String hmac = TokenUtil.getHmac(data, key.getKey()); - String encoded = key.getVersion() + "_" + hmac + "_" + data; - String path = "/service/extuserprov/?p=" + encoded; - return ZimbraServlet.getServiceUrl( - account.getServer(), Provisioning.getInstance().getDomain(account), path); - } + return mimePartHtml; + } + + + + public static String getMimePartText(ShareInfoData sid, String notes, Locale locale, + Action action, String extUserShareAcceptUrl, String extUserLoginUrl) throws MessagingException, ServiceException { + String mimePartText; + if (action == Action.revoke) { + mimePartText = genRevokePart(sid, locale, false); + } else if (action == Action.expire) { + mimePartText = genExpirePart(sid, locale, false); + } else { + mimePartText = genPart(sid, action == Action.edit, notes, extUserShareAcceptUrl, + extUserLoginUrl, locale, null, false); + } + return mimePartText; + } private static String genPart(ShareInfoData sid, boolean shareModified, String senderNotes, String extUserShareAcceptUrl, String extUserLoginUrl, Locale locale, StringBuilder sb, boolean html) { @@ -703,7 +696,7 @@ private static String genExpirePart(ShareInfoData sid, Locale locale, boolean ht sid.getOwnerNotifName()); } - private static String genXmlPart(ShareInfoData sid, String senderNotes, StringBuilder sb, Action action) + public static String genXmlPart(ShareInfoData sid, String senderNotes, StringBuilder sb, Action action) throws ServiceException { if (sb == null) { sb = new StringBuilder(); @@ -1063,78 +1056,6 @@ private static void sendMessage(Provisioning prov, buildContentAndSend(out, dl, visitor, locale, null); } } - - private static abstract class MimePartDataSource implements DataSource { - - private final String mText; - private byte[] mBuf = null; - - public MimePartDataSource(String text) { - mText = text; - } - - @Override - public InputStream getInputStream() throws IOException { - synchronized(this) { - if (mBuf == null) { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - OutputStreamWriter wout = - new OutputStreamWriter(buf, MimeConstants.P_CHARSET_UTF8); - String text = mText; - wout.write(text); - wout.flush(); - mBuf = buf.toByteArray(); - } - } - return new ByteArrayInputStream(mBuf); - } - - @Override - public OutputStream getOutputStream() { - throw new UnsupportedOperationException(); - } - } - - private static class HtmlPartDataSource extends MimePartDataSource { - private static final String CONTENT_TYPE = - MimeConstants.CT_TEXT_HTML + "; " + MimeConstants.P_CHARSET + "=" + MimeConstants.P_CHARSET_UTF8; - private static final String NAME = "HtmlDataSource"; - - HtmlPartDataSource(String text) { - super(text); - } - - @Override - public String getContentType() { - return CONTENT_TYPE; - } - - @Override - public String getName() { - return NAME; - } - } - - private static class XmlPartDataSource extends MimePartDataSource { - private static final String CONTENT_TYPE = - MimeConstants.CT_XML_ZIMBRA_SHARE + "; " + MimeConstants.P_CHARSET + "=" + MimeConstants.P_CHARSET_UTF8; - private static final String NAME = "XmlDataSource"; - - XmlPartDataSource(String text) { - super(text); - } - - @Override - public String getContentType() { - return CONTENT_TYPE; - } - - @Override - public String getName() { - return NAME; - } - } - } } diff --git a/store/src/java/com/zimbra/cs/account/ZAttrAccount.java b/store/src/java/com/zimbra/cs/account/ZAttrAccount.java index 61c01cb99cd..10de72146b1 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrAccount.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrAccount.java @@ -12088,6 +12088,393 @@ public Map unsetExternalUserMailAddress(Map attrs) return attrs; } + /** + * RFC822 email address under verification for an account + * + * @return zimbraFeatureAddressUnderVerification, or null if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2128) + public String getFeatureAddressUnderVerification() { + return getAttr(Provisioning.A_zimbraFeatureAddressUnderVerification, null, true); + } + + /** + * RFC822 email address under verification for an account + * + * @param zimbraFeatureAddressUnderVerification new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2128) + public void setFeatureAddressUnderVerification(String zimbraFeatureAddressUnderVerification) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressUnderVerification, zimbraFeatureAddressUnderVerification); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * RFC822 email address under verification for an account + * + * @param zimbraFeatureAddressUnderVerification new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2128) + public Map setFeatureAddressUnderVerification(String zimbraFeatureAddressUnderVerification, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressUnderVerification, zimbraFeatureAddressUnderVerification); + return attrs; + } + + /** + * RFC822 email address under verification for an account + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2128) + public void unsetFeatureAddressUnderVerification() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressUnderVerification, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * RFC822 email address under verification for an account + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2128) + public Map unsetFeatureAddressUnderVerification(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressUnderVerification, ""); + return attrs; + } + + /** + * Enable end-user email address verification + * + * @return zimbraFeatureAddressVerificationEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public boolean isFeatureAddressVerificationEnabled() { + return getBooleanAttr(Provisioning.A_zimbraFeatureAddressVerificationEnabled, false, true); + } + + /** + * Enable end-user email address verification + * + * @param zimbraFeatureAddressVerificationEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public void setFeatureAddressVerificationEnabled(boolean zimbraFeatureAddressVerificationEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, zimbraFeatureAddressVerificationEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Enable end-user email address verification + * + * @param zimbraFeatureAddressVerificationEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public Map setFeatureAddressVerificationEnabled(boolean zimbraFeatureAddressVerificationEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, zimbraFeatureAddressVerificationEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Enable end-user email address verification + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public void unsetFeatureAddressVerificationEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Enable end-user email address verification + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public Map unsetFeatureAddressVerificationEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, ""); + return attrs; + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + *

Use getFeatureAddressVerificationExpiryAsString to access value as a string. + * + * @see #getFeatureAddressVerificationExpiryAsString() + * + * @return zimbraFeatureAddressVerificationExpiry in millseconds, or 86400000 (1d) if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public long getFeatureAddressVerificationExpiry() { + return getTimeInterval(Provisioning.A_zimbraFeatureAddressVerificationExpiry, 86400000L, true); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @return zimbraFeatureAddressVerificationExpiry, or "1d" if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public String getFeatureAddressVerificationExpiryAsString() { + return getAttr(Provisioning.A_zimbraFeatureAddressVerificationExpiry, "1d", true); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureAddressVerificationExpiry new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public void setFeatureAddressVerificationExpiry(String zimbraFeatureAddressVerificationExpiry) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, zimbraFeatureAddressVerificationExpiry); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureAddressVerificationExpiry new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public Map setFeatureAddressVerificationExpiry(String zimbraFeatureAddressVerificationExpiry, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, zimbraFeatureAddressVerificationExpiry); + return attrs; + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public void unsetFeatureAddressVerificationExpiry() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public Map unsetFeatureAddressVerificationExpiry(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, ""); + return attrs; + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @return zimbraFeatureAddressVerificationStatus, or null if unset and/or has invalid value + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public ZAttrProvisioning.FeatureAddressVerificationStatus getFeatureAddressVerificationStatus() { + try { String v = getAttr(Provisioning.A_zimbraFeatureAddressVerificationStatus, true, true); return v == null ? null : ZAttrProvisioning.FeatureAddressVerificationStatus.fromString(v); } catch(com.zimbra.common.service.ServiceException e) { return null; } + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @return zimbraFeatureAddressVerificationStatus, or null if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public String getFeatureAddressVerificationStatusAsString() { + return getAttr(Provisioning.A_zimbraFeatureAddressVerificationStatus, null, true); + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @param zimbraFeatureAddressVerificationStatus new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public void setFeatureAddressVerificationStatus(ZAttrProvisioning.FeatureAddressVerificationStatus zimbraFeatureAddressVerificationStatus) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, zimbraFeatureAddressVerificationStatus.toString()); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @param zimbraFeatureAddressVerificationStatus new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public Map setFeatureAddressVerificationStatus(ZAttrProvisioning.FeatureAddressVerificationStatus zimbraFeatureAddressVerificationStatus, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, zimbraFeatureAddressVerificationStatus.toString()); + return attrs; + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @param zimbraFeatureAddressVerificationStatus new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public void setFeatureAddressVerificationStatusAsString(String zimbraFeatureAddressVerificationStatus) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, zimbraFeatureAddressVerificationStatus); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @param zimbraFeatureAddressVerificationStatus new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public Map setFeatureAddressVerificationStatusAsString(String zimbraFeatureAddressVerificationStatus, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, zimbraFeatureAddressVerificationStatus); + return attrs; + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public void unsetFeatureAddressVerificationStatus() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * End-user email address verification status + * + *

Valid values: [verified, pending, failed, expired] + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2129) + public Map unsetFeatureAddressVerificationStatus(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, ""); + return attrs; + } + /** * whether email features and tabs are enabled in the web client if * accessed from the admin console diff --git a/store/src/java/com/zimbra/cs/account/ZAttrCos.java b/store/src/java/com/zimbra/cs/account/ZAttrCos.java index 732c2c29515..5f95e0fee9a 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrCos.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrCos.java @@ -7036,6 +7036,190 @@ public Map unsetExternalSharingEnabled(Map attrs) return attrs; } + /** + * Enable end-user email address verification + * + * @return zimbraFeatureAddressVerificationEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public boolean isFeatureAddressVerificationEnabled() { + return getBooleanAttr(Provisioning.A_zimbraFeatureAddressVerificationEnabled, false, true); + } + + /** + * Enable end-user email address verification + * + * @param zimbraFeatureAddressVerificationEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public void setFeatureAddressVerificationEnabled(boolean zimbraFeatureAddressVerificationEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, zimbraFeatureAddressVerificationEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Enable end-user email address verification + * + * @param zimbraFeatureAddressVerificationEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public Map setFeatureAddressVerificationEnabled(boolean zimbraFeatureAddressVerificationEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, zimbraFeatureAddressVerificationEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Enable end-user email address verification + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public void unsetFeatureAddressVerificationEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Enable end-user email address verification + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2126) + public Map unsetFeatureAddressVerificationEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationEnabled, ""); + return attrs; + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + *

Use getFeatureAddressVerificationExpiryAsString to access value as a string. + * + * @see #getFeatureAddressVerificationExpiryAsString() + * + * @return zimbraFeatureAddressVerificationExpiry in millseconds, or 86400000 (1d) if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public long getFeatureAddressVerificationExpiry() { + return getTimeInterval(Provisioning.A_zimbraFeatureAddressVerificationExpiry, 86400000L, true); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @return zimbraFeatureAddressVerificationExpiry, or "1d" if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public String getFeatureAddressVerificationExpiryAsString() { + return getAttr(Provisioning.A_zimbraFeatureAddressVerificationExpiry, "1d", true); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureAddressVerificationExpiry new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public void setFeatureAddressVerificationExpiry(String zimbraFeatureAddressVerificationExpiry) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, zimbraFeatureAddressVerificationExpiry); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param zimbraFeatureAddressVerificationExpiry new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public Map setFeatureAddressVerificationExpiry(String zimbraFeatureAddressVerificationExpiry, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, zimbraFeatureAddressVerificationExpiry); + return attrs; + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public void unsetFeatureAddressVerificationExpiry() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Expiry time for end-user email address verification. Must be in valid + * duration format: {digits}{time-unit}. digits: 0-9, time-unit: + * [hmsd]|ms. h - hours, m - minutes, s - seconds, d - days, ms - + * milliseconds. If time unit is not specified, the default is + * s(seconds). + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2127) + public Map unsetFeatureAddressVerificationExpiry(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraFeatureAddressVerificationExpiry, ""); + return attrs; + } + /** * whether email features and tabs are enabled in the web client if * accessed from the admin console diff --git a/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java b/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java index 5d161ab913e..648962caa05 100644 --- a/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java +++ b/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java @@ -20,21 +20,42 @@ */ package com.zimbra.cs.service.account; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.TimeZone; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + +import org.apache.commons.codec.binary.Hex; import com.google.common.base.Strings; +import com.zimbra.common.account.ZAttrProvisioning.FeatureAddressVerificationStatus; +import com.zimbra.common.mime.MimeConstants; import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.AccountConstants; import com.zimbra.common.soap.Element; import com.zimbra.common.soap.Element.KeyValuePair; +import com.zimbra.common.util.BlobMetaData; +import com.zimbra.common.util.L10nUtil; import com.zimbra.common.util.StringUtil; +import com.zimbra.common.util.ZimbraLog; +import com.zimbra.common.util.L10nUtil.MsgKey; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.AttributeInfo; import com.zimbra.cs.account.AttributeManager; import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.MailboxManager; +import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.util.AccountUtil; import com.zimbra.soap.ZimbraSoapContext; /** @@ -48,6 +69,8 @@ public Element handle(Element request, Map context) throws Servi ZimbraSoapContext zsc = getZimbraSoapContext(context); Account account = getRequestedAccount(zsc); + OperationContext octxt = getOperationContext(zsc, context); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account, false); if (!canModifyOptions(zsc, account)) throw ServiceException.PERM_DENIED("can not modify options"); @@ -83,8 +106,33 @@ public Element handle(Element request, Map context) throws Servi } if (prefs.containsKey(Provisioning.A_zimbraPrefMailForwardingAddress)) { - if (!account.getBooleanAttr(Provisioning.A_zimbraFeatureMailForwardingEnabled, false)) + if (!account.getBooleanAttr(Provisioning.A_zimbraFeatureMailForwardingEnabled, false)) { throw ServiceException.PERM_DENIED("forwarding not enabled"); + } else { + if (account.getBooleanAttr( + Provisioning.A_zimbraFeatureAddressVerificationEnabled, false)) { + /* + * forwarding address verification enabled, store the email + * ID in 'zimbraFeatureAddressUnderVerification' + * till the time it's verified + */ + String emailIdToVerify = (String) prefs + .get(Provisioning.A_zimbraPrefMailForwardingAddress); + if (!Strings.isNullOrEmpty(emailIdToVerify)) { + prefs.remove(Provisioning.A_zimbraPrefMailForwardingAddress); + prefs.put(Provisioning.A_zimbraFeatureAddressUnderVerification, + emailIdToVerify); + Account authAccount = getAuthenticatedAccount(zsc); + sendEmailVerificationLink(authAccount, account, emailIdToVerify, octxt, + mbox); + prefs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, + FeatureAddressVerificationStatus.pending); + } else { + account.unsetFeatureAddressUnderVerification(); + account.unsetFeatureAddressVerificationStatus(); + } + } + } } // call modifyAttrs and pass true to checkImmutable @@ -93,4 +141,58 @@ public Element handle(Element request, Map context) throws Servi Element response = zsc.createElement(AccountConstants.MODIFY_PREFS_RESPONSE); return response; } + + public static void sendEmailVerificationLink(Account authAccount, Account ownerAccount, + String emailIdToVerify, OperationContext octxt, Mailbox mbox) throws ServiceException { + Locale locale = authAccount.getLocale(); + String ownerAcctDisplayName = ownerAccount.getDisplayName(); + if (ownerAcctDisplayName == null) { + ownerAcctDisplayName = ownerAccount.getName(); + } + String subject = L10nUtil.getMessage(MsgKey.verifyEmailSubject, locale, + ownerAcctDisplayName); + String charset = authAccount.getAttr(Provisioning.A_zimbraPrefMailDefaultCharset, + MimeConstants.P_CHARSET_UTF8); + try { + long expiry = ownerAccount.getFeatureAddressVerificationExpiry(); + Date now = new Date(); + long expiryTime = now.getTime() + expiry; + DateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z"); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + String gmtDate = format.format(expiryTime); + String url = generateAddressVerificationURL(ownerAccount, expiryTime, emailIdToVerify); + if (ZimbraLog.account.isDebugEnabled()) { + ZimbraLog.account.debug( + "Expiry of Forwarding address verification link sent to %s is %s", + emailIdToVerify, gmtDate); + ZimbraLog.account.debug("Forwarding address verification URL sent to %s is %s", + emailIdToVerify, url); + } + String mimePartText = L10nUtil.getMessage(MsgKey.verifyEmailBodyText, locale, + ownerAcctDisplayName, url, gmtDate); + String mimePartHtml = L10nUtil.getMessage(MsgKey.verifyEmailBodyHtml, locale, + ownerAcctDisplayName, url, gmtDate); + MimeMultipart mmp = AccountUtil.generateMimeMultipart(mimePartText, mimePartHtml, null); + MimeMessage mm = AccountUtil.generateMimeMessage(authAccount, ownerAccount, subject, + charset, null, null, emailIdToVerify, mmp); + mbox.getMailSender().sendMimeMessage(octxt, mbox, false, mm, null, null, null, null, + false); + } catch (MessagingException e) { + ZimbraLog.account + .warn("Failed to send verification link to email ID: '" + emailIdToVerify + "'", e); + throw ServiceException + .FAILURE("Failed to send verification link to email ID: " + emailIdToVerify, e); + } + } + + private static String generateAddressVerificationURL(Account account, long expiry, + String externalUserEmail) throws ServiceException { + StringBuilder encodedBuff = new StringBuilder(); + BlobMetaData.encodeMetaData(AccountConstants.P_ACCOUNT_ID, account.getId(), encodedBuff); + BlobMetaData.encodeMetaData(AccountConstants.P_LINK_EXPIRY, expiry, encodedBuff); + BlobMetaData.encodeMetaData(AccountConstants.P_EMAIL, externalUserEmail, encodedBuff); + BlobMetaData.encodeMetaData(AccountConstants.P_ADDRESS_VERIFICATION, true, encodedBuff); + String data = new String(Hex.encodeHex(encodedBuff.toString().getBytes())); + return AccountUtil.generateExtUserProvURL(account, data); + } } diff --git a/store/src/java/com/zimbra/cs/service/mail/SendShareNotification.java b/store/src/java/com/zimbra/cs/service/mail/SendShareNotification.java index e8e580c5654..7dd520fc29b 100644 --- a/store/src/java/com/zimbra/cs/service/mail/SendShareNotification.java +++ b/store/src/java/com/zimbra/cs/service/mail/SendShareNotification.java @@ -16,17 +16,13 @@ */ package com.zimbra.cs.service.mail; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Date; import java.util.Locale; import java.util.Map; import javax.mail.MessagingException; -import javax.mail.internet.AddressException; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; @@ -36,11 +32,9 @@ import com.zimbra.common.account.Key.DistributionListBy; import com.zimbra.common.localconfig.DebugConfig; import com.zimbra.common.mime.MimeConstants; -import com.zimbra.common.mime.shim.JavaMailInternetAddress; import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.Element; import com.zimbra.common.soap.MailConstants; -import com.zimbra.common.util.CharsetUtil; import com.zimbra.common.util.L10nUtil; import com.zimbra.common.util.L10nUtil.MsgKey; import com.zimbra.common.util.Log; @@ -63,13 +57,10 @@ import com.zimbra.cs.mailbox.MailboxManager; import com.zimbra.cs.mailbox.Mountpoint; import com.zimbra.cs.mailbox.OperationContext; -import com.zimbra.cs.mime.Mime; import com.zimbra.cs.service.UserServlet; import com.zimbra.cs.service.util.ItemId; import com.zimbra.cs.util.AccountUtil; -import com.zimbra.cs.util.JMSession; import com.zimbra.cs.util.Zimbra; -import com.zimbra.soap.JaxbUtil; import com.zimbra.soap.ZimbraSoapContext; import com.zimbra.soap.mail.message.SendShareNotificationRequest; import com.zimbra.soap.mail.message.SendShareNotificationRequest.Action; @@ -550,31 +541,28 @@ private Folder getFolder(OperationContext octxt, Account authAccount, Mailbox mb } protected MimeMessage generateShareNotification(Account authAccount, Account ownerAccount, - ShareInfoData sid, String notes, Action action, - Collection internlaRecipients, String externalRecipient) - throws ServiceException, MessagingException { + ShareInfoData sid, String notes, Action action, Collection internalRecipients, + String externalRecipient) throws ServiceException, MessagingException { Locale locale = authAccount.getLocale(); - String charset = authAccount.getAttr( - Provisioning.A_zimbraPrefMailDefaultCharset, MimeConstants.P_CHARSET_UTF8); - - MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSmtpSession(authAccount)); + String charset = authAccount.getAttr(Provisioning.A_zimbraPrefMailDefaultCharset, + MimeConstants.P_CHARSET_UTF8); MsgKey subjectKey; if (action == null) { subjectKey = MsgKey.shareNotifSubject; } else { switch (action) { - case edit: - subjectKey = MsgKey.shareModifySubject; - break; - case revoke: - subjectKey = MsgKey.shareRevokeSubject; - break; - case expire: - subjectKey = MsgKey.shareExpireSubject; - break; - default: - subjectKey = MsgKey.shareNotifSubject; + case edit: + subjectKey = MsgKey.shareModifySubject; + break; + case revoke: + subjectKey = MsgKey.shareRevokeSubject; + break; + case expire: + subjectKey = MsgKey.shareExpireSubject; + break; + default: + subjectKey = MsgKey.shareNotifSubject; } } String subject = L10nUtil.getMessage(subjectKey, locale); @@ -582,50 +570,38 @@ protected MimeMessage generateShareNotification(Account authAccount, Account own if (ownerAcctDisplayName == null) { ownerAcctDisplayName = ownerAccount.getName(); } - subject += L10nUtil.getMessage(MsgKey.sharedBySubject, locale, sid.getName(), ownerAcctDisplayName); - mm.setSubject(subject, CharsetUtil.checkCharset(subject, charset)); - mm.setSentDate(new Date()); - - // from the owner - mm.setFrom(AccountUtil.getFriendlyEmailAddress(ownerAccount)); - - // sent by auth account - mm.setSender(AccountUtil.getFriendlyEmailAddress(authAccount)); - - // to the grantee - if (internlaRecipients != null) { - assert(externalRecipient == null); - for (String recipient : internlaRecipients) { - try { - mm.addRecipient(javax.mail.Message.RecipientType.TO, new JavaMailInternetAddress(recipient)); - } catch (AddressException e) { - sLog.warn("Ignoring error while sending share notification to " + recipient, e); - } - } - } else if (externalRecipient != null) { - mm.setRecipient(javax.mail.Message.RecipientType.TO, new JavaMailInternetAddress(externalRecipient)); - } else { - String recipient = sid.getGranteeName(); - mm.setRecipient(javax.mail.Message.RecipientType.TO, new JavaMailInternetAddress(recipient)); + subject += L10nUtil.getMessage(MsgKey.sharedBySubject, locale, sid.getName(), + ownerAcctDisplayName); + String recipient = sid.getGranteeName(); + String extUserShareAcceptUrl = null; + String extUserLoginUrl = null; + String externalGranteeName = null; + if (sid.getGranteeTypeCode() == ACL.GRANTEE_GUEST) { + externalGranteeName = sid.getGranteeName(); + } else if (sid.getGranteeTypeCode() == ACL.GRANTEE_GROUP && externalRecipient != null) { + externalGranteeName = externalRecipient; } - - MimeMultipart mmp = ShareInfo.NotificationSender.genNotifBody(sid, notes, locale, action, externalRecipient); - mm.setContent(mmp); - mm.saveChanges(); - - if (sLog.isDebugEnabled()) { - // log4j.logger.com.zimbra.cs.service.mail=DEBUG - try { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - mm.writeTo(buf); - String mmDump = new String(buf.toByteArray()); - sLog.debug("********\n" + mmDump); - } catch (MessagingException e) { - sLog.debug("failed log debug share notification message", e); - } catch (IOException e) { - sLog.debug("failed log debug share notification message", e); - } + // this mail will go to external email address + boolean goesToExternalAddr = (externalGranteeName != null); + if (action == null && goesToExternalAddr) { + Account owner = Provisioning.getInstance().getAccountById(sid.getOwnerAcctId()); + extUserShareAcceptUrl = AccountUtil.getShareAcceptURL(owner, sid.getItemId(), externalGranteeName); + extUserLoginUrl = AccountUtil.getExtUserLoginURL(owner); } + String mimePartText = ShareInfo.NotificationSender.getMimePartText(sid, notes, locale, + action, extUserShareAcceptUrl, extUserLoginUrl); + String mimePartHtml = ShareInfo.NotificationSender.getMimePartHtml(sid, notes, locale, + action, extUserShareAcceptUrl, extUserLoginUrl); + + String mimePartXml = null; + if (!goesToExternalAddr) { + mimePartXml = ShareInfo.NotificationSender.genXmlPart(sid, notes, null, action); + } + + MimeMultipart mmp = AccountUtil.generateMimeMultipart(mimePartText, mimePartHtml, + mimePartXml); + MimeMessage mm = AccountUtil.generateMimeMessage(authAccount, ownerAccount, subject, + charset, internalRecipients, externalRecipient, recipient, mmp); return mm; } diff --git a/store/src/java/com/zimbra/cs/util/AccountUtil.java b/store/src/java/com/zimbra/cs/util/AccountUtil.java index edf96225f9c..7dc0ff53918 100644 --- a/store/src/java/com/zimbra/cs/util/AccountUtil.java +++ b/store/src/java/com/zimbra/cs/util/AccountUtil.java @@ -17,15 +17,29 @@ package com.zimbra.cs.util; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; +import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.activation.DataHandler; import javax.mail.Address; import javax.mail.MessagingException; +import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + +import org.apache.commons.codec.binary.Hex; import com.zimbra.common.account.Key; import com.zimbra.common.account.Key.DomainBy; @@ -34,23 +48,31 @@ import com.zimbra.common.mime.shim.JavaMailInternetAddress; import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.AccountConstants; +import com.zimbra.common.util.BlobMetaData; +import com.zimbra.common.util.CharsetUtil; import com.zimbra.common.util.EmailUtil; import com.zimbra.common.util.StringUtil; import com.zimbra.common.util.SystemUtil; import com.zimbra.common.util.ZimbraLog; +import com.zimbra.common.zmime.ZMimeBodyPart; +import com.zimbra.common.zmime.ZMimeMultipart; import com.zimbra.cs.account.AccessManager; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.AuthToken; import com.zimbra.cs.account.DataSource; import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.ExtAuthTokenKey; import com.zimbra.cs.account.NamedEntry; import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.account.Server; +import com.zimbra.cs.account.TokenUtil; import com.zimbra.cs.mailbox.MailItem; import com.zimbra.cs.mailbox.MailServiceException; import com.zimbra.cs.mailbox.Mailbox; import com.zimbra.cs.mailbox.Metadata; import com.zimbra.cs.mailbox.MetadataList; +import com.zimbra.cs.mime.Mime; +import com.zimbra.cs.servlet.ZimbraServlet; import com.zimbra.soap.admin.type.DataSourceType; public class AccountUtil { @@ -636,4 +658,177 @@ public static Set parseConfig(Metadata config) throws ServiceException { } return subscriptions; } + + public static MimeMessage generateMimeMessage(Account authAccount, Account ownerAccount, + String subject, String charset, Collection internalRecipients, + String externalRecipient, String recipient, MimeMultipart mmp) throws MessagingException { + MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSmtpSession(authAccount)); + mm.setSubject(subject, CharsetUtil.checkCharset(subject, charset)); + mm.setSentDate(new Date()); + // from the owner + mm.setFrom(AccountUtil.getFriendlyEmailAddress(ownerAccount)); + // sent by auth account + mm.setSender(AccountUtil.getFriendlyEmailAddress(authAccount)); + if (internalRecipients != null) { + assert (externalRecipient == null); + for (String iRecipient : internalRecipients) { + try { + mm.addRecipient(javax.mail.Message.RecipientType.TO, + new JavaMailInternetAddress(iRecipient)); + } catch (AddressException e) { + ZimbraLog.account.warn( + "Ignoring error while sending notification to " + iRecipient, e); + } + } + } else if (externalRecipient != null) { + mm.setRecipient(javax.mail.Message.RecipientType.TO, + new JavaMailInternetAddress(externalRecipient)); + } else { + mm.setRecipient(javax.mail.Message.RecipientType.TO, + new JavaMailInternetAddress(recipient)); + } + mm.setContent(mmp); + mm.saveChanges(); + + if (ZimbraLog.account.isDebugEnabled()) { + try { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + mm.writeTo(buf); + String mmDump = new String(buf.toByteArray()); + ZimbraLog.account.debug("********\n" + mmDump); + } catch (MessagingException e) { + ZimbraLog.account.debug("failed log debug share notification message", e); + } catch (IOException e) { + ZimbraLog.account.debug("failed log debug share notification message", e); + } + } + return mm; + } + + public static MimeMultipart generateMimeMultipart(String mimePartText, String mimePartHtml, + String mimePartXml) throws MessagingException { + MimeMultipart mmp = new ZMimeMultipart("alternative"); + + if (mimePartText != null) { + MimeBodyPart textPart = new ZMimeBodyPart(); + textPart.setText(mimePartText, MimeConstants.P_CHARSET_UTF8); + mmp.addBodyPart(textPart); + } + if (mimePartHtml != null) { + MimeBodyPart htmlPart = new ZMimeBodyPart(); + htmlPart.setDataHandler(new DataHandler(new HtmlPartDataSource(mimePartHtml))); + mmp.addBodyPart(htmlPart); + } + if (mimePartXml != null) { + MimeBodyPart xmlPart = new ZMimeBodyPart(); + xmlPart.setDataHandler(new DataHandler(new XmlPartDataSource(mimePartXml))); + mmp.addBodyPart(xmlPart); + } + return mmp; + } + + private static abstract class MimePartDataSource implements javax.activation.DataSource { + + private final String mText; + private byte[] mBuf = null; + + public MimePartDataSource(String text) { + mText = text; + } + + @Override + public InputStream getInputStream() throws IOException { + synchronized(this) { + if (mBuf == null) { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + OutputStreamWriter wout = + new OutputStreamWriter(buf, MimeConstants.P_CHARSET_UTF8); + String text = mText; + wout.write(text); + wout.flush(); + mBuf = buf.toByteArray(); + } + } + return new ByteArrayInputStream(mBuf); + } + + @Override + public OutputStream getOutputStream() { + throw new UnsupportedOperationException(); + } + } + + public static class HtmlPartDataSource extends MimePartDataSource { + private static final String CONTENT_TYPE = + MimeConstants.CT_TEXT_HTML + "; " + MimeConstants.P_CHARSET + "=" + MimeConstants.P_CHARSET_UTF8; + private static final String NAME = "HtmlDataSource"; + + public HtmlPartDataSource(String text) { + super(text); + } + + @Override + public String getContentType() { + return CONTENT_TYPE; + } + + @Override + public String getName() { + return NAME; + } + } + + public static class XmlPartDataSource extends MimePartDataSource { + private static final String CONTENT_TYPE = + MimeConstants.CT_XML_ZIMBRA_SHARE + "; " + MimeConstants.P_CHARSET + "=" + MimeConstants.P_CHARSET_UTF8; + private static final String NAME = "XmlDataSource"; + + public XmlPartDataSource(String text) { + super(text); + } + + @Override + public String getContentType() { + return CONTENT_TYPE; + } + + @Override + public String getName() { + return NAME; + } + } + + public static String getExtUserLoginURL(Account owner) throws ServiceException { + return ZimbraServlet.getServiceUrl(owner.getServer(), + Provisioning.getInstance().getDomain(owner), + "?virtualacctdomain=" + owner.getDomainName()); + } + + public static String getShareAcceptURL(Account account, int folderId, String externalUserEmail) + throws ServiceException { + StringBuilder encodedBuff = new StringBuilder(); + BlobMetaData.encodeMetaData(AccountConstants.P_ACCOUNT_ID, account.getId(), encodedBuff); + BlobMetaData.encodeMetaData(AccountConstants.P_FOLDER_ID, folderId, encodedBuff); + BlobMetaData.encodeMetaData(AccountConstants.P_EMAIL, externalUserEmail, encodedBuff); + Domain domain = Provisioning.getInstance().getDomain(account); + if (domain != null) { + long urlExpiration = domain.getExternalShareInvitationUrlExpiration(); + if (urlExpiration != 0) { + BlobMetaData.encodeMetaData(AccountConstants.P_LINK_EXPIRY, System.currentTimeMillis() + urlExpiration, + encodedBuff); + } + } + String data = new String(Hex.encodeHex(encodedBuff.toString().getBytes())); + return AccountUtil.generateExtUserProvURL(account, data); + } + + public static String generateExtUserProvURL(Account account, String data) + throws ServiceException { + ExtAuthTokenKey key = ExtAuthTokenKey.getCurrentKey(); + String hmac = TokenUtil.getHmac(data, key.getKey()); + String encoded = key.getVersion() + "_" + hmac + "_" + data; + String path = "/service/extuserprov/?p=" + encoded; + return ZimbraServlet.getServiceUrl(account.getServer(), + Provisioning.getInstance().getDomain(account), path); + } } \ No newline at end of file From 0d6bc5c02a1fc0d9dcd96bb59aaaf08be2e52c35 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Wed, 27 Sep 2017 13:32:44 +0530 Subject: [PATCH 116/142] ZCS-3017 Creating separate attributes for NG modules --- .../common/account/ZAttrProvisioning.java | 20 ++- .../common/service/ServiceException.java | 4 +- store/conf/attrs/zimbra-attrs.xml | 18 ++- .../com/zimbra/cs/account/ZAttrConfig.java | 144 ++++++++++++++---- .../com/zimbra/cs/account/ZAttrServer.java | 144 ++++++++++++++---- .../admin/GetAdminExtensionZimlets.java | 34 +++-- 6 files changed, 274 insertions(+), 90 deletions(-) diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index f25bb31275d..fa08477d583 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -11517,27 +11517,37 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkActivation = "zimbraNetworkActivation"; /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @since ZCS 8.8.2 */ @ZAttr(id=2119) public static final String A_zimbraNetworkAdminEnabled = "zimbraNetworkAdminEnabled"; + /** + * Whether to enable old zimbra network admin module. + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public static final String A_zimbraNetworkAdminNGEnabled = "zimbraNetworkAdminNGEnabled"; + /** * Whether to enable zimbra network new generation backup module. * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public static final String A_zimbraNetworkBackupNGEnabled = "zimbraNetworkBackupNGEnabled"; /** * Whether to enable zimbra network new generation HSM module. * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public static final String A_zimbraNetworkHSMNGEnabled = "zimbraNetworkHSMNGEnabled"; /** diff --git a/common/src/java/com/zimbra/common/service/ServiceException.java b/common/src/java/com/zimbra/common/service/ServiceException.java index 9c56cdd0846..e95574e50e9 100644 --- a/common/src/java/com/zimbra/common/service/ServiceException.java +++ b/common/src/java/com/zimbra/common/service/ServiceException.java @@ -432,7 +432,7 @@ public static ServiceException OPERATION_DENIED(String message) { return new ServiceException("operation denied: "+message, OPERATION_DENIED, SENDERS_FAULT); } - public static ServiceException NETWORK_MODULES_NG_ENABLED() { - return new ServiceException("ZimbraNetworkModulesNGEnabled is true", ZIMBRA_NETWORK_MODULES_NG_ENABLED, RECEIVERS_FAULT); + public static ServiceException NETWORK_MODULES_NG_ENABLED(String str) { + return new ServiceException("ZimbraNetworkModulesNG: "+ str + " is not enabled.", ZIMBRA_NETWORK_MODULES_NG_ENABLED, RECEIVERS_FAULT); } } diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index 139423d01da..c8e5e2f759e 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9379,13 +9379,14 @@ TODO: delete them permanently from here - TRUE + FALSE Whether to enable zimbra network new generation mobile sync module. - - TRUE + + FALSE Whether to enable old zimbra network admin module. + This attribute has been renamed to zimbraNetworkAdminNGEnabled @@ -9586,15 +9587,20 @@ TODO: delete them permanently from here - + TRUE Whether to enable zimbra network new generation HSM module. - - TRUE + + FALSE Whether to enable zimbra network new generation backup module. + + + FALSE + Whether to enable old zimbra network admin module. + diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index 467b1a14adf..e166cf2bf6b 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -47433,19 +47433,23 @@ public Map unsetNetworkActivation(Map attrs) { } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * - * @return zimbraNetworkAdminEnabled, or true if unset + * @return zimbraNetworkAdminEnabled, or false if unset * * @since ZCS 8.8.2 */ @ZAttr(id=2119) public boolean isNetworkAdminEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, false, true); } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47460,7 +47464,9 @@ public void setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabled) throws com } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47476,7 +47482,9 @@ public Map setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabl } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47490,7 +47498,9 @@ public void unsetNetworkAdminEnabled() throws com.zimbra.common.service.ServiceE } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs @@ -47504,16 +47514,88 @@ public Map unsetNetworkAdminEnabled(Map attrs) { return attrs; } + /** + * Whether to enable old zimbra network admin module. + * + * @return zimbraNetworkAdminNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public boolean isNetworkAdminNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable old zimbra network admin module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map unsetNetworkAdminNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + return attrs; + } + /** * Whether to enable zimbra network new generation backup module. * - * @return zimbraNetworkBackupNGEnabled, or true if unset + * @return zimbraNetworkBackupNGEnabled, or false if unset * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public boolean isNetworkBackupNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); } /** @@ -47522,9 +47604,9 @@ public boolean isNetworkBackupNGEnabled() { * @param zimbraNetworkBackupNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47538,9 +47620,9 @@ public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) thro * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47552,9 +47634,9 @@ public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupN * * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -47567,9 +47649,9 @@ public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.Servi * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public Map unsetNetworkBackupNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -47581,9 +47663,9 @@ public Map unsetNetworkBackupNGEnabled(Map attrs) * * @return zimbraNetworkHSMNGEnabled, or true if unset * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public boolean isNetworkHSMNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); } @@ -47594,9 +47676,9 @@ public boolean isNetworkHSMNGEnabled() { * @param zimbraNetworkHSMNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47610,9 +47692,9 @@ public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47624,9 +47706,9 @@ public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabl * * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -47639,9 +47721,9 @@ public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceE * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public Map unsetNetworkHSMNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -47713,13 +47795,13 @@ public Map unsetNetworkLicense(Map attrs) { /** * Whether to enable zimbra network new generation mobile sync module. * - * @return zimbraNetworkMobileNGEnabled, or true if unset + * @return zimbraNetworkMobileNGEnabled, or false if unset * * @since ZCS 8.8.0 */ @ZAttr(id=2118) public boolean isNetworkMobileNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, false, true); } /** diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index ea63fb7bbf2..6edd71ee42e 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -35462,19 +35462,23 @@ public Map unsetMtaVirtualMailboxMaps(Map attrs) { } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * - * @return zimbraNetworkAdminEnabled, or true if unset + * @return zimbraNetworkAdminEnabled, or false if unset * * @since ZCS 8.8.2 */ @ZAttr(id=2119) public boolean isNetworkAdminEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, false, true); } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35489,7 +35493,9 @@ public void setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabled) throws com } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35505,7 +35511,9 @@ public Map setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabl } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35519,7 +35527,9 @@ public void unsetNetworkAdminEnabled() throws com.zimbra.common.service.ServiceE } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs @@ -35533,16 +35543,88 @@ public Map unsetNetworkAdminEnabled(Map attrs) { return attrs; } + /** + * Whether to enable old zimbra network admin module. + * + * @return zimbraNetworkAdminNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public boolean isNetworkAdminNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable old zimbra network admin module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map unsetNetworkAdminNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + return attrs; + } + /** * Whether to enable zimbra network new generation backup module. * - * @return zimbraNetworkBackupNGEnabled, or true if unset + * @return zimbraNetworkBackupNGEnabled, or false if unset * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public boolean isNetworkBackupNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); } /** @@ -35551,9 +35633,9 @@ public boolean isNetworkBackupNGEnabled() { * @param zimbraNetworkBackupNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35567,9 +35649,9 @@ public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) thro * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35581,9 +35663,9 @@ public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupN * * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -35596,9 +35678,9 @@ public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.Servi * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2127) + @ZAttr(id=2130) public Map unsetNetworkBackupNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -35610,9 +35692,9 @@ public Map unsetNetworkBackupNGEnabled(Map attrs) * * @return zimbraNetworkHSMNGEnabled, or true if unset * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public boolean isNetworkHSMNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); } @@ -35623,9 +35705,9 @@ public boolean isNetworkHSMNGEnabled() { * @param zimbraNetworkHSMNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35639,9 +35721,9 @@ public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35653,9 +35735,9 @@ public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabl * * @throws com.zimbra.common.service.ServiceException if error during update * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -35668,9 +35750,9 @@ public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceE * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs * - * @since ZCS 8.8.3 + * @since ZCS 8.8.5 */ - @ZAttr(id=2126) + @ZAttr(id=2129) public Map unsetNetworkHSMNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -35680,13 +35762,13 @@ public Map unsetNetworkHSMNGEnabled(Map attrs) { /** * Whether to enable zimbra network new generation mobile sync module. * - * @return zimbraNetworkMobileNGEnabled, or true if unset + * @return zimbraNetworkMobileNGEnabled, or false if unset * * @since ZCS 8.8.0 */ @ZAttr(id=2118) public boolean isNetworkMobileNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, false, true); } /** diff --git a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java index c774e58a301..36b3986800f 100644 --- a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java +++ b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java @@ -60,12 +60,12 @@ private void doExtensionZimlets(ZimbraSoapContext zsc, Map conte try { mobileNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkMobileNGEnabled(); - networkAdminEnabled = Provisioning.getInstance().getLocalServer().isNetworkAdminEnabled(); + networkAdminEnabled = Provisioning.getInstance().getLocalServer().isNetworkAdminNGEnabled(); hsmNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkHSMNGEnabled(); backupRestoreNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkBackupNGEnabled(); } catch (ServiceException e) { - ZimbraLog.mailbox.warn("Exception while getting zimbraNetworkModulesNGEnabled.", e); + ZimbraLog.mailbox.warn("Exception while getting zimbraNetworkModulesNG related attributes.", e); } Iterator zimlets = Provisioning.getInstance().listAllZimlets().iterator(); while (zimlets.hasNext()) { @@ -80,33 +80,37 @@ private void doExtensionZimlets(ZimbraSoapContext zsc, Map conte if ("com_zimbra_mobilesync".equals(z.getName()) && mobileNGEnabled) { include = !mobileNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkMobileNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkMobileNGEnabled is true.", z.getName()); } } if ("com_zimbra_hsm".equals(z.getName()) && hsmNGEnabled) { include = !hsmNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworHSMNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworHSMNGEnabled is true.", z.getName()); } } if ("com_zimbra_backuprestore".equals(z.getName()) && backupRestoreNGEnabled) { include = !backupRestoreNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkBackupNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkBackupNGEnabled is true.", z.getName()); } } - if ("com_zimbra_delegatedadmin".equals(z.getName()) && networkAdminEnabled) { - include = !networkAdminEnabled; - include = include && (AccessManager.getInstance() instanceof ACLAccessManager); - } - - if (include) { - ZimletUtil.listZimlet(response, z, -1, Presence.enabled); // admin zimlets are all enabled - } - } - } + if ("com_zimbra_delegatedadmin".equals(z.getName()) && networkAdminEnabled) { + include = !networkAdminEnabled; + if (!include) { + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkAdminNGEnabled is true.", z.getName()); + } + include = include && (AccessManager.getInstance() instanceof ACLAccessManager); + } + + if (include) { + ZimletUtil.listZimlet(response, z, -1, Presence.enabled); + // admin zimlets are all enabled + } + } + } } @Override From 36b69165216bcf436b4f454f09a25a21a6074c72 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Thu, 28 Sep 2017 10:10:48 +0530 Subject: [PATCH 117/142] ZCS-3017 Fixing as per review comments --- .../common/account/ZAttrProvisioning.java | 10 ++-- store/conf/attrs/zimbra-attrs.xml | 11 ++-- .../com/zimbra/cs/account/ZAttrConfig.java | 54 ++++++++----------- .../com/zimbra/cs/account/ZAttrServer.java | 54 ++++++++----------- 4 files changed, 53 insertions(+), 76 deletions(-) diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index fa08477d583..1f1732e98cc 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -11531,7 +11531,7 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public static final String A_zimbraNetworkAdminNGEnabled = "zimbraNetworkAdminNGEnabled"; /** @@ -11539,7 +11539,7 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public static final String A_zimbraNetworkBackupNGEnabled = "zimbraNetworkBackupNGEnabled"; /** @@ -11547,7 +11547,7 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public static final String A_zimbraNetworkHSMNGEnabled = "zimbraNetworkHSMNGEnabled"; /** @@ -11565,9 +11565,7 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkMobileNGEnabled = "zimbraNetworkMobileNGEnabled"; /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @since ZCS 8.8.0 */ diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index c8e5e2f759e..cf376ba6d99 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9372,10 +9372,9 @@ TODO: delete them permanently from here outgoing sieve script defined by admin (not able to edit and view from the end user) applied after the end user filter rule - + TRUE Whether to enable zimbra network new generation modules. - Separate attributes have bee introduced for each module, hence this has been deprecated. @@ -9384,7 +9383,7 @@ TODO: delete them permanently from here - FALSE + TRUE Whether to enable old zimbra network admin module. This attribute has been renamed to zimbraNetworkAdminNGEnabled @@ -9587,19 +9586,19 @@ TODO: delete them permanently from here - + TRUE Whether to enable zimbra network new generation HSM module. - + FALSE Whether to enable zimbra network new generation backup module. - + FALSE Whether to enable old zimbra network admin module. diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index e166cf2bf6b..68d1ec54efc 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -47437,13 +47437,13 @@ public Map unsetNetworkActivation(Map attrs) { * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra * network admin module. * - * @return zimbraNetworkAdminEnabled, or false if unset + * @return zimbraNetworkAdminEnabled, or true if unset * * @since ZCS 8.8.2 */ @ZAttr(id=2119) public boolean isNetworkAdminEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, false, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, true, true); } /** @@ -47521,7 +47521,7 @@ public Map unsetNetworkAdminEnabled(Map attrs) { * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public boolean isNetworkAdminNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); } @@ -47534,7 +47534,7 @@ public boolean isNetworkAdminNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47550,7 +47550,7 @@ public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47564,7 +47564,7 @@ public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGE * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); @@ -47579,7 +47579,7 @@ public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.Servic * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public Map unsetNetworkAdminNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); @@ -47593,7 +47593,7 @@ public Map unsetNetworkAdminNGEnabled(Map attrs) { * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public boolean isNetworkBackupNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); } @@ -47606,7 +47606,7 @@ public boolean isNetworkBackupNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47622,7 +47622,7 @@ public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) thro * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47636,7 +47636,7 @@ public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupN * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -47651,7 +47651,7 @@ public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.Servi * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public Map unsetNetworkBackupNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -47665,7 +47665,7 @@ public Map unsetNetworkBackupNGEnabled(Map attrs) * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public boolean isNetworkHSMNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); } @@ -47678,7 +47678,7 @@ public boolean isNetworkHSMNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47694,7 +47694,7 @@ public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47708,7 +47708,7 @@ public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabl * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -47723,7 +47723,7 @@ public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceE * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public Map unsetNetworkHSMNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -47865,9 +47865,7 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -47879,9 +47877,7 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47896,9 +47892,7 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47914,9 +47908,7 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47930,9 +47922,7 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index 6edd71ee42e..bb088fe5465 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -35466,13 +35466,13 @@ public Map unsetMtaVirtualMailboxMaps(Map attrs) { * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra * network admin module. * - * @return zimbraNetworkAdminEnabled, or false if unset + * @return zimbraNetworkAdminEnabled, or true if unset * * @since ZCS 8.8.2 */ @ZAttr(id=2119) public boolean isNetworkAdminEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, false, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminEnabled, true, true); } /** @@ -35550,7 +35550,7 @@ public Map unsetNetworkAdminEnabled(Map attrs) { * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public boolean isNetworkAdminNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); } @@ -35563,7 +35563,7 @@ public boolean isNetworkAdminNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35579,7 +35579,7 @@ public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35593,7 +35593,7 @@ public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGE * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); @@ -35608,7 +35608,7 @@ public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.Servic * * @since ZCS 8.8.5 */ - @ZAttr(id=2131) + @ZAttr(id=2132) public Map unsetNetworkAdminNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); @@ -35622,7 +35622,7 @@ public Map unsetNetworkAdminNGEnabled(Map attrs) { * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public boolean isNetworkBackupNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); } @@ -35635,7 +35635,7 @@ public boolean isNetworkBackupNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35651,7 +35651,7 @@ public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) thro * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35665,7 +35665,7 @@ public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupN * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -35680,7 +35680,7 @@ public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.Servi * * @since ZCS 8.8.5 */ - @ZAttr(id=2130) + @ZAttr(id=2131) public Map unsetNetworkBackupNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); @@ -35694,7 +35694,7 @@ public Map unsetNetworkBackupNGEnabled(Map attrs) * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public boolean isNetworkHSMNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); } @@ -35707,7 +35707,7 @@ public boolean isNetworkHSMNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35723,7 +35723,7 @@ public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35737,7 +35737,7 @@ public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabl * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -35752,7 +35752,7 @@ public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceE * * @since ZCS 8.8.5 */ - @ZAttr(id=2129) + @ZAttr(id=2130) public Map unsetNetworkHSMNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); @@ -35832,9 +35832,7 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -35846,9 +35844,7 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35863,9 +35859,7 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35881,9 +35875,7 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35897,9 +35889,7 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Deprecated since: 8.8.3. Separate attributes have bee introduced for - * each module, hence this has been deprecated.. Orig desc: Whether to - * enable zimbra network new generation modules. + * Whether to enable zimbra network new generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs From 5d8ddee35bc78981f09d35642dd10e5be905e8b9 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Thu, 28 Sep 2017 14:56:31 +0530 Subject: [PATCH 118/142] ZCS-3017 Fixing as per review comments --- .../common/account/ZAttrProvisioning.java | 4 +++- store/conf/attrs/zimbra-attrs.xml | 5 ++-- .../com/zimbra/cs/account/ZAttrConfig.java | 24 +++++++++++++------ .../com/zimbra/cs/account/ZAttrServer.java | 24 +++++++++++++------ 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index 1f1732e98cc..3c192dd8280 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -11565,7 +11565,9 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkMobileNGEnabled = "zimbraNetworkMobileNGEnabled"; /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @since ZCS 8.8.0 */ diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index cf376ba6d99..42bb448fce8 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9372,9 +9372,10 @@ TODO: delete them permanently from here outgoing sieve script defined by admin (not able to edit and view from the end user) applied after the end user filter rule - + TRUE Whether to enable zimbra network new generation modules. + This attribute has been replaced with individual attributes @@ -9587,7 +9588,7 @@ TODO: delete them permanently from here - TRUE + FALSE Whether to enable zimbra network new generation HSM module. diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index 68d1ec54efc..65c42512308 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -47661,13 +47661,13 @@ public Map unsetNetworkBackupNGEnabled(Map attrs) /** * Whether to enable zimbra network new generation HSM module. * - * @return zimbraNetworkHSMNGEnabled, or true if unset + * @return zimbraNetworkHSMNGEnabled, or false if unset * * @since ZCS 8.8.5 */ @ZAttr(id=2130) public boolean isNetworkHSMNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, false, true); } /** @@ -47865,7 +47865,9 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -47877,7 +47879,9 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47892,7 +47896,9 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47908,7 +47914,9 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47922,7 +47930,9 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index bb088fe5465..03b163de641 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -35690,13 +35690,13 @@ public Map unsetNetworkBackupNGEnabled(Map attrs) /** * Whether to enable zimbra network new generation HSM module. * - * @return zimbraNetworkHSMNGEnabled, or true if unset + * @return zimbraNetworkHSMNGEnabled, or false if unset * * @since ZCS 8.8.5 */ @ZAttr(id=2130) public boolean isNetworkHSMNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, false, true); } /** @@ -35832,7 +35832,9 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -35844,7 +35846,9 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35859,7 +35863,9 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35875,7 +35881,9 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35889,7 +35897,9 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs From 8316aec152b9fb16a76d149b06d1ca5309888655 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Sun, 24 Sep 2017 17:49:52 +0530 Subject: [PATCH 119/142] ZCS-3017 Add separate attributes for NG modules initialisation ZCS-3017 Creating separate attributes for NG modules ZCS-3017 Fixing as per review comments ZCS-3017 Fixing as per review comments --- .../common/account/ZAttrProvisioning.java | 32 ++- .../common/service/ServiceException.java | 4 +- store/conf/attrs/zimbra-attrs.xml | 26 +- .../com/zimbra/cs/account/ZAttrConfig.java | 260 +++++++++++++++++- .../com/zimbra/cs/account/ZAttrServer.java | 260 +++++++++++++++++- .../admin/GetAdminExtensionZimlets.java | 58 ++-- 6 files changed, 589 insertions(+), 51 deletions(-) diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index e3b5f2670be..3c192dd8280 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -11517,13 +11517,39 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkActivation = "zimbraNetworkActivation"; /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @since ZCS 8.8.2 */ @ZAttr(id=2119) public static final String A_zimbraNetworkAdminEnabled = "zimbraNetworkAdminEnabled"; + /** + * Whether to enable old zimbra network admin module. + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public static final String A_zimbraNetworkAdminNGEnabled = "zimbraNetworkAdminNGEnabled"; + + /** + * Whether to enable zimbra network new generation backup module. + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public static final String A_zimbraNetworkBackupNGEnabled = "zimbraNetworkBackupNGEnabled"; + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public static final String A_zimbraNetworkHSMNGEnabled = "zimbraNetworkHSMNGEnabled"; + /** * Contents of a signed Zimbra license key - an XML string. */ @@ -11539,7 +11565,9 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkMobileNGEnabled = "zimbraNetworkMobileNGEnabled"; /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @since ZCS 8.8.0 */ diff --git a/common/src/java/com/zimbra/common/service/ServiceException.java b/common/src/java/com/zimbra/common/service/ServiceException.java index 9c56cdd0846..e95574e50e9 100644 --- a/common/src/java/com/zimbra/common/service/ServiceException.java +++ b/common/src/java/com/zimbra/common/service/ServiceException.java @@ -432,7 +432,7 @@ public static ServiceException OPERATION_DENIED(String message) { return new ServiceException("operation denied: "+message, OPERATION_DENIED, SENDERS_FAULT); } - public static ServiceException NETWORK_MODULES_NG_ENABLED() { - return new ServiceException("ZimbraNetworkModulesNGEnabled is true", ZIMBRA_NETWORK_MODULES_NG_ENABLED, RECEIVERS_FAULT); + public static ServiceException NETWORK_MODULES_NG_ENABLED(String str) { + return new ServiceException("ZimbraNetworkModulesNG: "+ str + " is not enabled.", ZIMBRA_NETWORK_MODULES_NG_ENABLED, RECEIVERS_FAULT); } } diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index 6e591634a88..42bb448fce8 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9372,19 +9372,21 @@ TODO: delete them permanently from here outgoing sieve script defined by admin (not able to edit and view from the end user) applied after the end user filter rule - + TRUE Whether to enable zimbra network new generation modules. + This attribute has been replaced with individual attributes - - TRUE + + FALSE Whether to enable zimbra network new generation mobile sync module. - + TRUE Whether to enable old zimbra network admin module. + This attribute has been renamed to zimbraNetworkAdminNGEnabled @@ -9585,4 +9587,20 @@ TODO: delete them permanently from here + + FALSE + Whether to enable zimbra network new generation HSM module. + + + + + FALSE + Whether to enable zimbra network new generation backup module. + + + + + FALSE + Whether to enable old zimbra network admin module. + diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index 333391fe5d1..65c42512308 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -47433,7 +47433,9 @@ public Map unsetNetworkActivation(Map attrs) { } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @return zimbraNetworkAdminEnabled, or true if unset * @@ -47445,7 +47447,9 @@ public boolean isNetworkAdminEnabled() { } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47460,7 +47464,9 @@ public void setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabled) throws com } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47476,7 +47482,9 @@ public Map setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabl } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47490,7 +47498,9 @@ public void unsetNetworkAdminEnabled() throws com.zimbra.common.service.ServiceE } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs @@ -47504,6 +47514,222 @@ public Map unsetNetworkAdminEnabled(Map attrs) { return attrs; } + /** + * Whether to enable old zimbra network admin module. + * + * @return zimbraNetworkAdminNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public boolean isNetworkAdminNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable old zimbra network admin module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public Map unsetNetworkAdminNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + return attrs; + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @return zimbraNetworkBackupNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public boolean isNetworkBackupNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map unsetNetworkBackupNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @return zimbraNetworkHSMNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public boolean isNetworkHSMNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, false, true); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public Map unsetNetworkHSMNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + return attrs; + } + /** * Contents of a signed Zimbra license key - an XML string. * @@ -47569,13 +47795,13 @@ public Map unsetNetworkLicense(Map attrs) { /** * Whether to enable zimbra network new generation mobile sync module. * - * @return zimbraNetworkMobileNGEnabled, or true if unset + * @return zimbraNetworkMobileNGEnabled, or false if unset * * @since ZCS 8.8.0 */ @ZAttr(id=2118) public boolean isNetworkMobileNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, false, true); } /** @@ -47639,7 +47865,9 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -47651,7 +47879,9 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47666,7 +47896,9 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47682,7 +47914,9 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47696,7 +47930,9 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index 595861f5de4..03b163de641 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -35462,7 +35462,9 @@ public Map unsetMtaVirtualMailboxMaps(Map attrs) { } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @return zimbraNetworkAdminEnabled, or true if unset * @@ -35474,7 +35476,9 @@ public boolean isNetworkAdminEnabled() { } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35489,7 +35493,9 @@ public void setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabled) throws com } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param zimbraNetworkAdminEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35505,7 +35511,9 @@ public Map setNetworkAdminEnabled(boolean zimbraNetworkAdminEnabl } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35519,7 +35527,9 @@ public void unsetNetworkAdminEnabled() throws com.zimbra.common.service.ServiceE } /** - * Whether to enable old zimbra network admin module. + * Deprecated since: 8.8.5. This attribute has been renamed to + * zimbraNetworkAdminNGEnabled. Orig desc: Whether to enable old zimbra + * network admin module. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs @@ -35533,16 +35543,232 @@ public Map unsetNetworkAdminEnabled(Map attrs) { return attrs; } + /** + * Whether to enable old zimbra network admin module. + * + * @return zimbraNetworkAdminNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public boolean isNetworkAdminNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param zimbraNetworkAdminNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable old zimbra network admin module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable old zimbra network admin module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2132) + public Map unsetNetworkAdminNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); + return attrs; + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @return zimbraNetworkBackupNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public boolean isNetworkBackupNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param zimbraNetworkBackupNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation backup module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2131) + public Map unsetNetworkBackupNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @return zimbraNetworkHSMNGEnabled, or false if unset + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public boolean isNetworkHSMNGEnabled() { + return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, false, true); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param zimbraNetworkHSMNGEnabled new value + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); + return attrs; + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @throws com.zimbra.common.service.ServiceException if error during update + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { + HashMap attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + getProvisioning().modifyAttrs(this, attrs); + } + + /** + * Whether to enable zimbra network new generation HSM module. + * + * @param attrs existing map to populate, or null to create a new map + * @return populated map to pass into Provisioning.modifyAttrs + * + * @since ZCS 8.8.5 + */ + @ZAttr(id=2130) + public Map unsetNetworkHSMNGEnabled(Map attrs) { + if (attrs == null) attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); + return attrs; + } + /** * Whether to enable zimbra network new generation mobile sync module. * - * @return zimbraNetworkMobileNGEnabled, or true if unset + * @return zimbraNetworkMobileNGEnabled, or false if unset * * @since ZCS 8.8.0 */ @ZAttr(id=2118) public boolean isNetworkMobileNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, true, true); + return getBooleanAttr(Provisioning.A_zimbraNetworkMobileNGEnabled, false, true); } /** @@ -35606,7 +35832,9 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -35618,7 +35846,9 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35633,7 +35863,9 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35649,7 +35881,9 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35663,7 +35897,9 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Whether to enable zimbra network new generation modules. + * Deprecated since: 8.8.5. This attribute has been replaced with + * individual attributes. Orig desc: Whether to enable zimbra network new + * generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java index a6241bc91b3..36b3986800f 100644 --- a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java +++ b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java @@ -52,15 +52,20 @@ public Element handle(Element request, Map context) throws Servi } private void doExtensionZimlets(ZimbraSoapContext zsc, Map context, Element response) throws ServiceException { - boolean isNGEnabled = true; - boolean isMobileNGEnabled = true; - boolean isNetworkAdminEnabled = true; + + boolean mobileNGEnabled = true; + boolean networkAdminEnabled = true; + boolean hsmNGEnabled = true; + boolean backupRestoreNGEnabled = true; + try { - isNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkModulesNGEnabled(); - isMobileNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkMobileNGEnabled(); - isNetworkAdminEnabled = Provisioning.getInstance().getLocalServer().isNetworkAdminEnabled(); + mobileNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkMobileNGEnabled(); + networkAdminEnabled = Provisioning.getInstance().getLocalServer().isNetworkAdminNGEnabled(); + hsmNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkHSMNGEnabled(); + backupRestoreNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkBackupNGEnabled(); + } catch (ServiceException e) { - ZimbraLog.mailbox.warn("Exception while getting zimbraNetworkModulesNGEnabled.", e); + ZimbraLog.mailbox.warn("Exception while getting zimbraNetworkModulesNG related attributes.", e); } Iterator zimlets = Provisioning.getInstance().listAllZimlets().iterator(); while (zimlets.hasNext()) { @@ -72,25 +77,40 @@ private void doExtensionZimlets(ZimbraSoapContext zsc, Map conte if (z.isExtension()) { boolean include = true; - if ("com_zimbra_hsm".equals(z.getName()) || "com_zimbra_backuprestore".equals(z.getName()) - || "com_zimbra_delegatedadmin".equals(z.getName())) { - include = !isNGEnabled; + if ("com_zimbra_mobilesync".equals(z.getName()) && mobileNGEnabled) { + include = !mobileNGEnabled; + if (!include) { + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkMobileNGEnabled is true.", z.getName()); + } + } + + if ("com_zimbra_hsm".equals(z.getName()) && hsmNGEnabled) { + include = !hsmNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkModulesNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworHSMNGEnabled is true.", z.getName()); } } - if ("com_zimbra_mobilesync".equals(z.getName()) && isNGEnabled) { - include = !isMobileNGEnabled; + + if ("com_zimbra_backuprestore".equals(z.getName()) && backupRestoreNGEnabled) { + include = !backupRestoreNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' zimbraNetworkMobileNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkBackupNGEnabled is true.", z.getName()); } } - if ("com_zimbra_delegatedadmin".equals(z.getName()) && isNetworkAdminEnabled) + if ("com_zimbra_delegatedadmin".equals(z.getName()) && networkAdminEnabled) { + include = !networkAdminEnabled; + if (!include) { + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkAdminNGEnabled is true.", z.getName()); + } include = include && (AccessManager.getInstance() instanceof ACLAccessManager); - if (include) - ZimletUtil.listZimlet(response, z, -1, Presence.enabled); // admin zimlets are all enabled - } - } + } + + if (include) { + ZimletUtil.listZimlet(response, z, -1, Presence.enabled); + // admin zimlets are all enabled + } + } + } } @Override From 34ddc592848c718a21f91d5da6ffce410bf1801f Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Fri, 29 Sep 2017 14:10:10 +0530 Subject: [PATCH 120/142] ZCS-3017 Fixing attribute decsription --- .../com/zimbra/common/account/ZAttrProvisioning.java | 2 +- store/conf/attrs/zimbra-attrs.xml | 2 +- store/src/java/com/zimbra/cs/account/ZAttrConfig.java | 10 +++++----- store/src/java/com/zimbra/cs/account/ZAttrServer.java | 10 +++++----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index 041dc8f501c..dd6cddbc019 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -11583,7 +11583,7 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkAdminEnabled = "zimbraNetworkAdminEnabled"; /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @since ZCS 8.8.5 */ diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index a9838a659f0..dd7ee5eca6f 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9617,7 +9617,7 @@ TODO: delete them permanently from here FALSE - Whether to enable old zimbra network admin module. + Whether to enable zimbra network new generation admin module. diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index 65c42512308..98400e59ea7 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -47515,7 +47515,7 @@ public Map unsetNetworkAdminEnabled(Map attrs) { } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @return zimbraNetworkAdminNGEnabled, or false if unset * @@ -47527,7 +47527,7 @@ public boolean isNetworkAdminNGEnabled() { } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @param zimbraNetworkAdminNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47542,7 +47542,7 @@ public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @param zimbraNetworkAdminNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47558,7 +47558,7 @@ public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGE } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47572,7 +47572,7 @@ public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.Servic } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index 03b163de641..c9912bb0bc4 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -35544,7 +35544,7 @@ public Map unsetNetworkAdminEnabled(Map attrs) { } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @return zimbraNetworkAdminNGEnabled, or false if unset * @@ -35556,7 +35556,7 @@ public boolean isNetworkAdminNGEnabled() { } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @param zimbraNetworkAdminNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35571,7 +35571,7 @@ public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @param zimbraNetworkAdminNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35587,7 +35587,7 @@ public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGE } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35601,7 +35601,7 @@ public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.Servic } /** - * Whether to enable old zimbra network admin module. + * Whether to enable zimbra network new generation admin module. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs From f357aa308c3cf4ac70a07807418966d3dac09264 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 29 Sep 2017 09:03:38 +0100 Subject: [PATCH 121/142] build-common.xml - test-results-file init ant test task should ensure that test-result-file var has a value, otherwise file called `${test-results-file}` gets created. Note that you can't re-assign properties in ant, so if had previously been set, it doesn't get a new value. Also some tab to spaces changes --- build-common.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build-common.xml b/build-common.xml index 1c6f5cd4523..2adaf1a3539 100644 --- a/build-common.xml +++ b/build-common.xml @@ -289,6 +289,7 @@ + @@ -327,11 +328,11 @@ Test Report: ${test.dir}/report/index.html - - - - - + + + + + ${test.src.dir} not found. Will not run unit tests From 572ba3fb5f11fa698772ff5f8db6bc68c11539f7 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 29 Sep 2017 09:06:40 +0100 Subject: [PATCH 122/142] common/ivy.xml commons-logging Needed for new `Ical4jTest` --- common/ivy.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/common/ivy.xml b/common/ivy.xml index df9a82c14a5..36236c123ec 100644 --- a/common/ivy.xml +++ b/common/ivy.xml @@ -8,6 +8,7 @@ + From c020187c1dc154ed2a6af950967288cb08a4826b Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Fri, 29 Sep 2017 09:08:02 +0100 Subject: [PATCH 123/142] ZCS-3092:Ical4JTest.java testUrisEncodeDecode Tests handling of mailto URIs - here to confirm that an issue that was present in baseline ical4j-0.9.16 is no longer present. testMultiVCALENDAR currently fails. We need a workaround to allow multi vcalendars. testTabWrappedLine support wrapping with tabs testEmptyCN https://bugzilla.zimbra.com/show_bug.cgi?id=50398 Handling of empty CN parameter An empty CN parameter should not affect the value of the property. With unpatched ical4j-0.9.16 it did. It is acceptable to either drop the CN parameter or leave it as the empty string --- .../zimbra/common/calendar/Ical4JTest.java | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 common/src/java-test/com/zimbra/common/calendar/Ical4JTest.java diff --git a/common/src/java-test/com/zimbra/common/calendar/Ical4JTest.java b/common/src/java-test/com/zimbra/common/calendar/Ical4JTest.java new file mode 100644 index 00000000000..98a62ea191c --- /dev/null +++ b/common/src/java-test/com/zimbra/common/calendar/Ical4JTest.java @@ -0,0 +1,170 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ + +package com.zimbra.common.calendar; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import com.google.common.base.Charsets; +import com.zimbra.common.calendar.ZCalendar.ICalTok; +import com.zimbra.common.calendar.ZCalendar.ZComponent; +import com.zimbra.common.calendar.ZCalendar.ZParameter; +import com.zimbra.common.calendar.ZCalendar.ZProperty; +import com.zimbra.common.calendar.ZCalendar.ZVCalendar; +import com.zimbra.common.service.ServiceException; + +import net.fortuna.ical4j.data.ParserException; +import net.fortuna.ical4j.util.Uris; + +/** + * Intended to test features that Zimbra has chosen to add to ical4j in the past, to ensure that future + * integrations still function correctly. + * + */ +public class Ical4JTest { + + public static final String emptyCN = + "BEGIN:VCALENDAR\r\n" + + "VERSION:2.0\r\n" + + "PRODID:Microsoft Exchange Server 2007\r\n" + + "BEGIN:VEVENT\r\n" + + "ORGANIZER;CN=:MAILTO:test1@invalid.dom\r\n" + + "ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=:MAILTO:te\r\n" + + " st2@invalid.dom\r\n" + + "SUMMARY;LANGUAGE=en-US:Testing Empty CNs\r\n" + + "UID:U4\r\n" + + "DTSTAMP:20070228T183803Z\r\n" + + "DTSTART;VALUE=DATE:20051018\r\n" + + "DTEND;VALUE=DATE:20051019\r\n" + + "END:VEVENT\r\n" + + "END:VCALENDAR\r\n"; + + public static final String multiVcalendar = + "BEGIN:VCALENDAR\r\n" + + "VERSION:2.0\r\n" + + "PRODID:Oracle/Oracle Calendar Server 9.0.4.2.8\r\n" + + "BEGIN:VEVENT\r\n" + + "UID:U1\r\n" + + "DTSTAMP:20070228T183803Z\r\n" + + "DTSTART;VALUE=DATE:20051018\r\n" + + "DTEND;VALUE=DATE:20051019\r\n" + + "SUMMARY:event in cal1\r\n" + + "END:VEVENT\r\n" + + "END:VCALENDAR\r\n" + + "BEGIN:VCALENDAR\r\n" + + "VERSION:2.0\r\n" + + "PRODID:Oracle/Oracle Calendar Server 9.0.4.2.8\r\n" + + "BEGIN:VEVENT\r\n" + + "UID:U2\r\n" + + "DTSTAMP:20070228T183800Z\r\n" + + "DTSTART;VALUE=DATE:20051019\r\n" + + "DTEND;VALUE=DATE:20051020\r\n" + + "SUMMARY:event in cal2\r\n" + + "END:VEVENT\r\n" + + "END:VCALENDAR\r\n"; + + public static final String wrappedWithTab = + "BEGIN:VCALENDAR\r\n" + + "VERSION:2.0\r\n" + + "PRODID:-//Microsoft Corporation//Outlook 12.0 MIMEDIR//EN\r\n" + + "BEGIN:VEVENT\r\n" + + "DESCRIPTION:When: Friday\\, March 30\\, 2007 8:00 AM-8:30 AM (GMT-07:00) Moun\r\n" + + "\ttain Time (US & Canada).\\nWhere: Certified Service\\, Inc. \\n\\n*~*~*~*~*~*~\r\n" + + "\t*~*~*~*\\n\\nGood morning Ray\\, \\n\\nFriday works for me. Just let me know w\r\n" + + "\that time. \\n\\nThanks\\, \\n\\r\\n\r\n" + + "UID:U1\r\n" + + "DTSTAMP:20070228T183803Z\r\n" + + "DTSTART;VALUE=DATE:20051018\r\n" + + "DTEND;VALUE=DATE:20051019\r\n" + + "SUMMARY:mySumm\r\n" + + "END:VEVENT\r\n" + + "END:VCALENDAR\r\n"; + + /** + * Uri-encoding was causing problems with java.net.URL building (specifically we would end up + * with URL's where the SchemeSpecificPart was "MAILTO%3Afoo%40bar.com") + */ + @Test + public void testUrisEncodeDecode() { + String mailtourl = "mailto:foobar@example.net"; + String decoded = Uris.decode(mailtourl); + Assert.assertEquals("Result of Decode", mailtourl, decoded); + String encoded = Uris.encode(mailtourl); + /** + * This was failing on baseline ical4j-0.9.16 with: + * junit.framework.ComparisonFailure: Result of Encode expected: + * but was: + */ + Assert.assertEquals("Result of Encode", mailtourl, encoded); + mailtourl = "rubbishfoobar@example.net"; + decoded = Uris.decode(mailtourl); + Assert.assertEquals("Result of Decode", mailtourl, decoded); + encoded = Uris.encode(mailtourl); + Assert.assertEquals("Result of Encode", mailtourl, encoded); + } + + @Test + public void testMultiVCALENDAR() throws IOException, ParserException, ServiceException { + List zvcals = doParse(multiVcalendar); + Assert.assertNotNull("List of ZVCalendar", zvcals); + Assert.assertEquals("Number of cals", 2, zvcals.size()); + } + + @Test + public void testTabWrappedLine() throws IOException, ParserException, ServiceException { + List zvcals = doParse(wrappedWithTab); + Assert.assertNotNull("List of ZVCalendar", zvcals); + Assert.assertEquals("Number of cals", 1, zvcals.size()); + } + + /** + * Bug 50398 - handling of empty CN parameter + * An empty CN parameter should not affect the value of a property. With unpatched ical4j-0.9.16 it did. + * It is acceptable to either drop the CN parameter or leave it as the empty string + */ + @Test + public void testEmptyCN() throws IOException, ParserException, ServiceException { + List zvcals = doParse(emptyCN); + Assert.assertNotNull("List of ZVCalendar", zvcals); + Assert.assertEquals("Number of cals", 1, zvcals.size()); + ZVCalendar zvcal = zvcals.get(0); + ZComponent vevent = zvcal.getComponent(ICalTok.VEVENT); + Assert.assertNotNull("VEVENT", vevent); + ZProperty orgProp = vevent.getProperty(ICalTok.ORGANIZER); + // With unpatched ical4j-0.9.16 value is ":test1@invalid.dom" + Assert.assertEquals("ORGANIZER value", "MAILTO:test1@invalid.dom", orgProp.getValue()); + ZParameter orgCNparam = orgProp.getParameter(ICalTok.CN); + Assert.assertNotNull("ORGANIZER CN parameter", orgCNparam); + String cnValue = orgCNparam.getValue(); + if (cnValue != null) { + // Note that with ical4j-0.9.16-patched, the value is null + Assert.assertEquals("ORGANIZER CN param value", "", cnValue); + } + } + + public static List doParse(String ical) + throws IOException, ParserException, ServiceException { + ByteArrayInputStream bais = new ByteArrayInputStream (ical.getBytes(Charsets.UTF_8)); + List zvcals = ZCalendar.ZCalendarBuilder.buildMulti(bais, Charsets.UTF_8.name()); + return zvcals; + } +} From 3e92c66bcb88e91be174630f0ac6cd2e5c5eb4d4 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Mon, 2 Oct 2017 19:07:45 +0530 Subject: [PATCH 124/142] ZCS-2937 Fixing failong unit test --- build-common.xml | 3 --- .../com/zimbra/cs/extension/ExtensionTestUtil.java | 2 +- .../java-test/com/zimbra/cs/zimlet/ZimletUtilTest.java | 8 ++++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/build-common.xml b/build-common.xml index 2adaf1a3539..1b9018dd4e8 100644 --- a/build-common.xml +++ b/build-common.xml @@ -313,10 +313,7 @@ - - - diff --git a/store/src/java-test/com/zimbra/cs/extension/ExtensionTestUtil.java b/store/src/java-test/com/zimbra/cs/extension/ExtensionTestUtil.java index 4736a1bfb50..59f1da7ab77 100644 --- a/store/src/java-test/com/zimbra/cs/extension/ExtensionTestUtil.java +++ b/store/src/java-test/com/zimbra/cs/extension/ExtensionTestUtil.java @@ -30,7 +30,7 @@ public class ExtensionTestUtil { private static URL classpath; public static void init() throws Exception { - classpath = new File("build/test/extensions").toURI().toURL(); + classpath = new File("store/build/test/extensions").toURI().toURL(); LC.zimbra_extension_common_directory.setDefault(null); LC.zimbra_extension_directory.setDefault(null); } diff --git a/store/src/java-test/com/zimbra/cs/zimlet/ZimletUtilTest.java b/store/src/java-test/com/zimbra/cs/zimlet/ZimletUtilTest.java index 4f8d0f30ef6..32bf162b2d3 100644 --- a/store/src/java-test/com/zimbra/cs/zimlet/ZimletUtilTest.java +++ b/store/src/java-test/com/zimbra/cs/zimlet/ZimletUtilTest.java @@ -38,21 +38,21 @@ public void testZimletRootDir() { } try { - assertEquals(LC.zimlet_directory.value() + "/org_my_zimlet", ZimletUtil.getZimletRootDir("org_my_zimlet").getAbsolutePath()); + assertEquals(LC.zimlet_directory.value() + "/org_my_zimlet", ZimletUtil.getZimletRootDir("org_my_zimlet").getPath()); } catch (ZimletException e) { fail("Should not throw ZimletException for good zimlet name"); } try { - assertEquals(LC.zimlet_directory.value() + "/myzimlet", ZimletUtil.getZimletRootDir("myzimlet").getAbsolutePath()); + assertEquals(LC.zimlet_directory.value() + "/myzimlet", ZimletUtil.getZimletRootDir("myzimlet").getPath()); } catch (ZimletException e) { fail("Should not throw ZimletException for good zimlet name"); } try { - assertEquals(LC.zimlet_directory.value() + "/my.zimlet", ZimletUtil.getZimletRootDir("my.zimlet").getAbsolutePath()); + assertEquals(LC.zimlet_directory.value() + "/my.zimlet", ZimletUtil.getZimletRootDir("my.zimlet").getPath()); } catch (ZimletException e) { fail("Should not throw ZimletException for good zimlet name"); } } -} \ No newline at end of file +} From 3ec34b917670b5b7a1649b1a5ab036d4820a4f9d Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Fri, 22 Sep 2017 15:12:14 -0700 Subject: [PATCH 125/142] add oauth datasource to Modify*** and Test*** requests --- .../com/zimbra/soap/mail/message/ModifyDataSourceRequest.java | 3 +++ .../com/zimbra/soap/mail/message/TestDataSourceRequest.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java b/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java index db9ef185902..3e0dc5f35c2 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java @@ -18,6 +18,7 @@ package com.zimbra.soap.mail.message; import com.google.common.base.Objects; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; @@ -29,6 +30,7 @@ import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; +import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -58,6 +60,7 @@ public class ModifyDataSourceRequest { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private DataSource dataSource; diff --git a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java index 5d48e62d1fb..d56597b7ab2 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java @@ -18,6 +18,7 @@ package com.zimbra.soap.mail.message; import com.google.common.base.Objects; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; @@ -29,6 +30,7 @@ import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; +import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -57,6 +59,7 @@ public class TestDataSourceRequest { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* cal */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private DataSource dataSource; From 91865e8868ba6b015f4fb7476afbef0b104bae62 Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Tue, 3 Oct 2017 04:03:06 +0000 Subject: [PATCH 126/142] adjust Jaxb and fix ZMailbox::testDataSource Jaxb classes for TestDataSourceResponse do not match what the response looks like and therefore ZMailbox::testDataSource does not properly report errors when DataImport::test method fails --- .../src/java/com/zimbra/client/ZMailbox.java | 17 ++++-- .../mail/message/TestDataSourceResponse.java | 61 +++++++++++-------- .../zimbra/soap/mail/type/TestDataSource.java | 44 +++++++++++++ .../zimbra/qa/unittest/TestDataSource.java | 39 +++++++++--- 4 files changed, 121 insertions(+), 40 deletions(-) create mode 100644 soap/src/java/com/zimbra/soap/mail/type/TestDataSource.java diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index dc69870c1be..6e19fff423f 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -217,6 +217,7 @@ import com.zimbra.soap.mail.type.NewContactAttr; import com.zimbra.soap.mail.type.NewContactGroupMember; import com.zimbra.soap.mail.type.NewSearchFolderSpec; +import com.zimbra.soap.mail.type.TestDataSource; import com.zimbra.soap.type.AccountSelector; import com.zimbra.soap.type.AccountWithModifications; import com.zimbra.soap.type.CalDataSource; @@ -4691,12 +4692,18 @@ public String testDataSource(ZDataSource source) throws ServiceException { DataSource jaxbObj = source.toJaxb(); req.setDataSource(jaxbObj); TestDataSourceResponse resp = (TestDataSourceResponse)invokeJaxb(req); - boolean success = resp.getSuccess(); - if(!success) { - return resp.getError(); - } else { - return null; + List dataSources = resp.getDataSources(); + int success = 0; + if(dataSources.size() > 0 && dataSources.get(0) != null) { + TestDataSource ds = dataSources.get(0); + success = ds.getSuccess(); + if(success < 1) { + return ds.getError(); + } else { + return null; + } } + return null; } public List getAllDataSources() throws ServiceException { diff --git a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java index b18ab91d452..e16b5e5090e 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java @@ -17,53 +17,62 @@ package com.zimbra.soap.mail.message; -import com.google.common.base.Objects; +import java.util.Collections; +import java.util.List; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; +import com.google.common.base.Objects; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.zimbra.common.soap.MailConstants; -import com.zimbra.soap.type.ZmBoolean; +import com.zimbra.soap.mail.type.TestDataSource; @XmlAccessorType(XmlAccessType.NONE) @XmlRootElement(name=MailConstants.E_TEST_DATA_SOURCE_RESPONSE) public class TestDataSourceResponse { - /** - * @zm-api-field-tag success - * @zm-api-field-description Flags whether the test was successful + * @zm-api-field-description Data source information */ - @XmlAttribute(name=MailConstants.A_DS_SUCCESS /* success */, required=true) - private final ZmBoolean success; + @XmlElements({ + @XmlElement(name=MailConstants.E_DS_IMAP /* imap */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_POP3 /* pop3 */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_CALDAV /* caldav */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_YAB /* yab */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=TestDataSource.class), + @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=TestDataSource.class) + }) + private List dataSources = Lists.newArrayList(); - /** - * @zm-api-field-tag error-message - * @zm-api-field-description Error message - */ - @XmlAttribute(name=MailConstants.A_DS_ERROR /* error */, required=false) - private String error; + public void setDataSources(Iterable dataSources) { + this.dataSources.clear(); + if (dataSources != null) { + Iterables.addAll(this.dataSources,dataSources); + } + } - /** - * no-argument constructor wanted by JAXB - */ - @SuppressWarnings("unused") private TestDataSourceResponse() { - this(false); } - public TestDataSourceResponse(boolean success) { - this.success = ZmBoolean.fromBool(success); + public TestDataSourceResponse addDataSource(TestDataSource dataSource) { + this.dataSources.add(dataSource); + return this; } - public void setError(String error) { this.error = error; } - public boolean getSuccess() { return ZmBoolean.toBool(success); } - public String getError() { return error; } + public List getDataSources() { + return Collections.unmodifiableList(dataSources); + } public Objects.ToStringHelper addToStringInfo(Objects.ToStringHelper helper) { return helper - .add("success", success) - .add("error", error); + .add("dataSources", dataSources); } @Override diff --git a/soap/src/java/com/zimbra/soap/mail/type/TestDataSource.java b/soap/src/java/com/zimbra/soap/mail/type/TestDataSource.java new file mode 100644 index 00000000000..2be542d71bd --- /dev/null +++ b/soap/src/java/com/zimbra/soap/mail/type/TestDataSource.java @@ -0,0 +1,44 @@ +package com.zimbra.soap.mail.type; + +import javax.xml.bind.annotation.XmlAttribute; + +import com.zimbra.common.soap.MailConstants; + +public class TestDataSource { + /** + * @zm-api-field-tag data-source-success + * @zm-api-field-description 0 if data source test failed, 1 if test succeeded + */ + @XmlAttribute(name = MailConstants.A_DS_SUCCESS /* success */, required = true) + private int success; + + /** + * @zm-api-field-tag data-source-error + * @zm-api-field-description error message passed by DatImport::test method of the datasource being tested + */ + @XmlAttribute(name = MailConstants.A_DS_ERROR /* error */, required = false) + private String error; + + public TestDataSource() { + this.success = 1; + this.error = null; + } + + public TestDataSource(String error) { + if(error != null && !error.isEmpty()) { + success = 0; + } + this.error = error; + } + + public TestDataSource(int success, String error) { + this.success = success; + this.error = error; + } + + public void setSuccess(int success) { this.success = success; } + public int getSuccess() { return success; } + + public void setError(String error) { this.error = error; } + public String getError() { return this.error; } +} diff --git a/store/src/java/com/zimbra/qa/unittest/TestDataSource.java b/store/src/java/com/zimbra/qa/unittest/TestDataSource.java index 78362afc48f..216c24cd827 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestDataSource.java +++ b/store/src/java/com/zimbra/qa/unittest/TestDataSource.java @@ -16,6 +16,13 @@ */ package com.zimbra.qa.unittest; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -27,13 +34,6 @@ import org.junit.Test; import org.junit.rules.TestName; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - import com.google.common.collect.Lists; import com.zimbra.client.ZCalDataSource; import com.zimbra.client.ZDataSource; @@ -437,13 +437,34 @@ public void testPop3() throws Exception { assertEquals(id, hits.get(0).getId()); } + /** + * Tests {@link ZMailbox#testDataSource}. + */ + @Test + public void testBadDataSource() throws Exception { + ZMailbox mbox = TestUtil.getZMailbox(USER_NAME); + // Create data source + Provisioning prov = Provisioning.getInstance(); + Map attrs = new HashMap(); + attrs.put(Provisioning.A_zimbraDataSourceEnabled, LdapConstants.LDAP_FALSE); + attrs.put(Provisioning.A_zimbraDataSourceHost, "testhost"); + attrs.put(Provisioning.A_zimbraDataSourcePort, "0"); + attrs.put(Provisioning.A_zimbraDataSourceUsername, "testuser"); + attrs.put(Provisioning.A_zimbraDataSourcePassword, "testpass"); + attrs.put(Provisioning.A_zimbraDataSourceFolderId, "1"); + attrs.put(Provisioning.A_zimbraDataSourceConnectionType, ConnectionType.cleartext.toString()); + prov.createDataSource(account, DataSourceType.pop3, NAME_PREFIX + DS_NAME, attrs); + ZDataSource zds = TestUtil.getDataSource(mbox, NAME_PREFIX + DS_NAME); + String testVal = mbox.testDataSource(zds); + assertNotNull("ZMailbox::testDataSource should return an error", testVal); + } + /** * Creates a folder that syncs to another folder via RSS, and verifies that an * RSS data source was implicitly created. */ @Test - public void testRss() - throws Exception { + public void testRss() throws Exception { // Create source folder, make it publicly readable, and add a message to it. ZMailbox mbox = TestUtil.getZMailbox(USER_NAME); String parentId = Integer.toString(Mailbox.ID_FOLDER_USER_ROOT); From d36a0d2de60335c0e0645e989d509326b9366248 Mon Sep 17 00:00:00 2001 From: Yasuko Komiyama Date: Fri, 29 Sep 2017 21:38:04 +0900 Subject: [PATCH 127/142] zcs-2352:Bug108145:Windows-unfriendly files in zip File name with a Japanese diacritic sign generated by Mac is garbled in zip format when "download all attachments" is performed from the Windows. [bug] When an attachment file is created on Mac environment, and the name of the attachment contains some "dakuten (full-phonetic-voiced)" symbols, and the message with such attachment is received and downloaded in zip format from Windows PC, then the file name of the expanded attachment file gets garbled. [root cause] Mac OS represents the file name in Normalization Form D (NFD: Canonical Decomposition), whereas Windows OS in Normalization Form C (NFC: Canonical Decomposition, followed by Canonical Composition). The attachment file name is specified in the MIME header (Content-Disposition and/or Content-Type). When the email is composed on the Mac OS, it is represented in the NFD style. When the recipient user downloads a set of attachment files in zip format, the file name in the zip archive is taken from the MIME header. If the file name is specified in NFD, the file name in the zip format is also composed in NFD. Windows can't display the file name in NFD properly, and the file name in the zip file is displayed garbled on the Windows OS. Note: Because Mac OS can handle the file name in both NFD and NFC, the files created and attached on the Windows OS can be opened on the Mac OS without any garbled file name. [fix] If the file name is represented in NFD, it will be converted to NFC. --- .../com/zimbra/cs/service/formatter/ArchiveFormatter.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/store/src/java/com/zimbra/cs/service/formatter/ArchiveFormatter.java b/store/src/java/com/zimbra/cs/service/formatter/ArchiveFormatter.java index 7fdd151b6ed..34ba6864c52 100644 --- a/store/src/java/com/zimbra/cs/service/formatter/ArchiveFormatter.java +++ b/store/src/java/com/zimbra/cs/service/formatter/ArchiveFormatter.java @@ -26,6 +26,7 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.text.DateFormat; +import java.text.Normalizer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -635,6 +636,9 @@ private ArchiveOutputStream saveItem(UserServletContext context, MailItem mi, throw MailServiceException.NO_SUCH_PART(part); } name = Mime.getFilename(mp); + if (!Normalizer.isNormalized(name, Normalizer.Form.NFC)) { + name = Normalizer.normalize(name, Normalizer.Form.NFC); + } ext = null; sz = mp.getSize(); if (sz == -1) { From a6a130209f8639a68b65ce20d5a503f92ad57129 Mon Sep 17 00:00:00 2001 From: Shrikant Date: Thu, 28 Sep 2017 12:16:14 +0530 Subject: [PATCH 128/142] ZCS-2948:Validation of verification link when clicked --- .../service/ExternalUserProvServletTest.java | 77 ++++++ .../zimbra/cs/service/ModifyPrefsTest.java | 6 +- .../cs/service/ExternalUserProvServlet.java | 255 ++++++++++-------- .../cs/service/account/ModifyPrefs.java | 2 +- 4 files changed, 230 insertions(+), 110 deletions(-) create mode 100644 store/src/java-test/com/zimbra/cs/service/ExternalUserProvServletTest.java diff --git a/store/src/java-test/com/zimbra/cs/service/ExternalUserProvServletTest.java b/store/src/java-test/com/zimbra/cs/service/ExternalUserProvServletTest.java new file mode 100644 index 00000000000..9cc1f62d5d2 --- /dev/null +++ b/store/src/java-test/com/zimbra/cs/service/ExternalUserProvServletTest.java @@ -0,0 +1,77 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.service; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.Maps; +import com.zimbra.common.account.Key; +import com.zimbra.common.account.ZAttrProvisioning.FeatureAddressVerificationStatus; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailboxTestUtil; + +import junit.framework.Assert; + +public class ExternalUserProvServletTest { + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + Provisioning prov = Provisioning.getInstance(); + + Map attrs = Maps.newHashMap(); + attrs = Maps.newHashMap(); + prov.createAccount("test@zimbra.com", "secret", attrs); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + } + + @Test + public void testHandleAddressVerificationExpired() throws Exception { + Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + HashMap headers = new HashMap(); + HttpServletRequest req = new MockHttpServletRequest(null, null, null, 123, "127.0.0.1", headers); + MockHttpServletResponse resp = new MockHttpServletResponse(); + ExternalUserProvServlet servlet = new ExternalUserProvServlet(); + servlet.handleAddressVerification(req, resp, acct1.getId(), "test2@zimbra.com", true); + Assert.assertNull(acct1.getPrefMailForwardingAddress()); + Assert.assertEquals(FeatureAddressVerificationStatus.expired, acct1.getFeatureAddressVerificationStatus()); + } + + @Test + public void testHandleAddressVerificationSuccess() throws Exception { + Account acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + HashMap headers = new HashMap(); + HttpServletRequest req = new MockHttpServletRequest(null, null, null, 123, "127.0.0.1", headers); + MockHttpServletResponse resp = new MockHttpServletResponse(); + ExternalUserProvServlet servlet = new ExternalUserProvServlet(); + servlet.handleAddressVerification(req, resp, acct1.getId(), "test2@zimbra.com", false); + Assert.assertEquals("test2@zimbra.com", acct1.getPrefMailForwardingAddress()); + Assert.assertEquals(FeatureAddressVerificationStatus.verified, acct1.getFeatureAddressVerificationStatus()); + } +} diff --git a/store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java b/store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java index f351a7d998c..e5111e53379 100644 --- a/store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java +++ b/store/src/java-test/com/zimbra/cs/service/ModifyPrefsTest.java @@ -32,17 +32,16 @@ import com.google.common.collect.Maps; import com.zimbra.common.account.Key; +import com.zimbra.common.account.ZAttrProvisioning.FeatureAddressVerificationStatus; import com.zimbra.common.soap.Element; import com.zimbra.common.util.L10nUtil; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.mailbox.MailItem; import com.zimbra.cs.mailbox.MailSender; import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.Mailbox.MailboxData; import com.zimbra.cs.mailbox.MailboxManager; import com.zimbra.cs.mailbox.MailboxTestUtil; -import com.zimbra.cs.mailbox.Message; -import com.zimbra.cs.mailbox.Mailbox.MailboxData; import com.zimbra.cs.service.account.ModifyPrefs; import com.zimbra.cs.service.mail.ServiceTestUtil; import com.zimbra.soap.JaxbUtil; @@ -133,5 +132,6 @@ public void testMsgMaxAttr() throws Exception { new ModifyPrefs().handle(req, ServiceTestUtil.getRequestContext(mbox.getAccount())); Assert.assertNull(acct1.getFeatureAddressUnderVerification()); Assert.assertEquals("test1@somedomain.com", acct1.getPrefMailForwardingAddress()); + Assert.assertEquals(FeatureAddressVerificationStatus.pending, acct1.getFeatureAddressVerificationStatus()); } } \ No newline at end of file diff --git a/store/src/java/com/zimbra/cs/service/ExternalUserProvServlet.java b/store/src/java/com/zimbra/cs/service/ExternalUserProvServlet.java index a86668e87b2..f33c11529ee 100644 --- a/store/src/java/com/zimbra/cs/service/ExternalUserProvServlet.java +++ b/store/src/java/com/zimbra/cs/service/ExternalUserProvServlet.java @@ -38,8 +38,10 @@ import com.zimbra.client.ZMailbox; import com.zimbra.client.ZMountpoint; import com.zimbra.common.account.ProvisioningConstants; +import com.zimbra.common.account.ZAttrProvisioning.FeatureAddressVerificationStatus; import com.zimbra.common.localconfig.DebugConfig; import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.AccountConstants; import com.zimbra.common.util.BlobMetaData; import com.zimbra.common.util.L10nUtil; import com.zimbra.common.util.Log; @@ -78,9 +80,12 @@ public class ExternalUserProvServlet extends ZimbraServlet { private static final String EXT_USER_PROV_ON_UI_NODE = "/fromservice/extuserprov"; private static final String PUBLIC_LOGIN_ON_UI_NODE = "/fromservice/publiclogin"; public static final String PUBLIC_EXTUSERPROV_JSP = "/public/extuserprov.jsp"; + public static final String PUBLIC_ADDRESS_VERIFICATION_JSP = "/public/addressVerification.jsp"; public static final String PUBLIC_LOGIN_JSP = "/public/login.jsp"; public static final String ERROR_CODE = "errorCode"; + public static final String MESSAGE_KEY = "messageKey"; public static final String ERROR_MESSAGE = "errorMessage"; + public static final String EXPIRED = "expired"; @Override public void init() throws ServletException { @@ -104,123 +109,156 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se } Map tokenMap = validatePrelimToken(param); Map reqHeaders = new HashMap(); - String ownerId = (String) tokenMap.get("aid"); - String folderId = (String) tokenMap.get("fid"); - String extUserEmail = (String) tokenMap.get("email"); - - Provisioning prov = Provisioning.getInstance(); - Account grantee; - try { - Account owner = prov.getAccountById(ownerId); - Domain domain = prov.getDomain(owner); - grantee = prov.getAccountByName(mapExtEmailToAcctName(extUserEmail, domain)); - if (grantee == null) { - // external virtual account not created yet - if (prov.isOctopus() && DebugConfig.skipVirtualAccountRegistrationPage) { - // provision using 'null' password and display name - // UI will ask the user to set these post provisioning - provisionVirtualAccountAndRedirect(req, resp, null, null, ownerId, extUserEmail); + String ownerId = (String) tokenMap.get(AccountConstants.P_ACCOUNT_ID); + String folderId = (String) tokenMap.get(AccountConstants.P_FOLDER_ID); + String extUserEmail = (String) tokenMap.get(AccountConstants.P_EMAIL); + String addressVerification = (String) tokenMap.get(AccountConstants.P_ADDRESS_VERIFICATION); + if ("1".equals(addressVerification)) { + Boolean expired = false; + if (tokenMap.get(EXPIRED) != null) { + expired = (Boolean) tokenMap.get(EXPIRED); + } + Map attributes = handleAddressVerification(req, resp, ownerId, extUserEmail, expired); + redirectRequest(req, resp, attributes, EXT_USER_PROV_ON_UI_NODE, PUBLIC_ADDRESS_VERIFICATION_JSP); + } else { + Provisioning prov = Provisioning.getInstance(); + Account grantee; + try { + Account owner = prov.getAccountById(ownerId); + Domain domain = prov.getDomain(owner); + grantee = prov.getAccountByName(mapExtEmailToAcctName(extUserEmail, domain)); + if (grantee == null) { + // external virtual account not created yet + if (prov.isOctopus() && DebugConfig.skipVirtualAccountRegistrationPage) { + // provision using 'null' password and display name + // UI will ask the user to set these post provisioning + provisionVirtualAccountAndRedirect(req, resp, null, null, ownerId, extUserEmail); + } else { + resp.addCookie(new Cookie("ZM_PRELIM_AUTH_TOKEN", param)); + Map attrs = new HashMap(); + attrs.put("extuseremail", extUserEmail); + reqHeaders.put("ZM_PRELIM_AUTH_TOKEN", param); + redirectRequest(req, resp, attrs, reqHeaders, EXT_USER_PROV_ON_UI_NODE, PUBLIC_EXTUSERPROV_JSP); + } } else { - resp.addCookie(new Cookie("ZM_PRELIM_AUTH_TOKEN", param)); - Map attrs = new HashMap(); - attrs.put("extuseremail", extUserEmail); - reqHeaders.put("ZM_PRELIM_AUTH_TOKEN", param); - redirectRequest(req, resp, attrs, reqHeaders, EXT_USER_PROV_ON_UI_NODE, PUBLIC_EXTUSERPROV_JSP); - } - } else { - // create a new mountpoint in the external user's mailbox if not already created - - String[] sharedItems = owner.getSharedItem(); - int sharedFolderId = Integer.valueOf(folderId); - String sharedFolderPath = null; - MailItem.Type sharedFolderView = null; - for (String sharedItem : sharedItems) { - ShareInfoData sid = AclPushSerializer.deserialize(sharedItem); - if (sid.getItemId() == sharedFolderId && extUserEmail.equalsIgnoreCase(sid.getGranteeId())) { - sharedFolderPath = sid.getPath(); - sharedFolderView = sid.getFolderDefaultViewCode(); - break; + // create a new mountpoint in the external user's mailbox if not already created + + String[] sharedItems = owner.getSharedItem(); + int sharedFolderId = Integer.valueOf(folderId); + String sharedFolderPath = null; + MailItem.Type sharedFolderView = null; + for (String sharedItem : sharedItems) { + ShareInfoData sid = AclPushSerializer.deserialize(sharedItem); + if (sid.getItemId() == sharedFolderId && extUserEmail.equalsIgnoreCase(sid.getGranteeId())) { + sharedFolderPath = sid.getPath(); + sharedFolderView = sid.getFolderDefaultViewCode(); + break; + } } - } - if (sharedFolderPath == null) { - throw new ServletException("share not found"); - } - String mountpointName = getMountpointName(owner, grantee, sharedFolderPath); - - ZMailbox.Options options = new ZMailbox.Options(); - options.setNoSession(true); - options.setAuthToken(AuthProvider.getAuthToken(grantee).toZAuthToken()); - options.setUri(AccountUtil.getSoapUri(grantee)); - ZMailbox zMailbox = new ZMailbox(options); - ZMountpoint zMtpt = null; - try { - zMtpt = zMailbox.createMountpoint( - String.valueOf(getMptParentFolderId(sharedFolderView, prov)), mountpointName, - ZFolder.View.fromString(sharedFolderView.toString()), ZFolder.Color.DEFAULTCOLOR, null, - ZMailbox.OwnerBy.BY_ID, ownerId, ZMailbox.SharedItemBy.BY_ID, folderId, false); - } catch (ServiceException e) { - logger.debug("Error in attempting to create mountpoint. Probably it already exists.", e); - } - if (zMtpt != null) { - if (sharedFolderView == MailItem.Type.APPOINTMENT) { - // make sure that the mountpoint is checked in the UI by default - FolderActionSelector actionSelector = new FolderActionSelector(zMtpt.getId(), "check"); - FolderActionRequest actionRequest = new FolderActionRequest(actionSelector); - try { - zMailbox.invokeJaxb(actionRequest); - } catch (ServiceException e) { - logger.warn("Error in invoking check action on calendar mountpoint", e); + if (sharedFolderPath == null) { + throw new ServletException("share not found"); + } + String mountpointName = getMountpointName(owner, grantee, sharedFolderPath); + + ZMailbox.Options options = new ZMailbox.Options(); + options.setNoSession(true); + options.setAuthToken(AuthProvider.getAuthToken(grantee).toZAuthToken()); + options.setUri(AccountUtil.getSoapUri(grantee)); + ZMailbox zMailbox = new ZMailbox(options); + ZMountpoint zMtpt = null; + try { + zMtpt = zMailbox.createMountpoint( + String.valueOf(getMptParentFolderId(sharedFolderView, prov)), mountpointName, + ZFolder.View.fromString(sharedFolderView.toString()), ZFolder.Color.DEFAULTCOLOR, null, + ZMailbox.OwnerBy.BY_ID, ownerId, ZMailbox.SharedItemBy.BY_ID, folderId, false); + } catch (ServiceException e) { + logger.debug("Error in attempting to create mountpoint. Probably it already exists.", e); + } + if (zMtpt != null) { + if (sharedFolderView == MailItem.Type.APPOINTMENT) { + // make sure that the mountpoint is checked in the UI by default + FolderActionSelector actionSelector = new FolderActionSelector(zMtpt.getId(), "check"); + FolderActionRequest actionRequest = new FolderActionRequest(actionSelector); + try { + zMailbox.invokeJaxb(actionRequest); + } catch (ServiceException e) { + logger.warn("Error in invoking check action on calendar mountpoint", e); + } } + HashSet types = new HashSet(); + types.add(sharedFolderView); + enableAppFeatures(grantee, types); } - HashSet types = new HashSet(); - types.add(sharedFolderView); - enableAppFeatures(grantee, types); - } - // check if the external user is already logged-in - String zAuthTokenCookie = null; - javax.servlet.http.Cookie cookies[] = req.getCookies(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals("ZM_AUTH_TOKEN")) { - zAuthTokenCookie = cookie.getValue(); - break; + // check if the external user is already logged-in + String zAuthTokenCookie = null; + javax.servlet.http.Cookie cookies[] = req.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("ZM_AUTH_TOKEN")) { + zAuthTokenCookie = cookie.getValue(); + break; + } } } - } - AuthToken zAuthToken = null; - if (zAuthTokenCookie != null) { - try { - zAuthToken = AuthProvider.getAuthToken(zAuthTokenCookie); - } catch (AuthTokenException ignored) { - // auth token is not valid + AuthToken zAuthToken = null; + if (zAuthTokenCookie != null) { + try { + zAuthToken = AuthProvider.getAuthToken(zAuthTokenCookie); + } catch (AuthTokenException ignored) { + // auth token is not valid + } + } + if (zAuthToken != null && !zAuthToken.isExpired() && zAuthToken.isRegistered() && grantee.getId().equals(zAuthToken.getAccountId())) { + // external virtual account already logged-in + resp.sendRedirect("/"); + } else if (prov.isOctopus() && !grantee.isVirtualAccountInitialPasswordSet() && + DebugConfig.skipVirtualAccountRegistrationPage) { + // seems like the virtual user did not set his password during his last visit, after an account was + // provisioned for him + setCookieAndRedirect(req, resp, grantee); + } else { + Map attrs = new HashMap(); + attrs.put("virtualacctdomain", domain.getName()); + redirectRequest(req, resp, attrs, PUBLIC_LOGIN_ON_UI_NODE, PUBLIC_LOGIN_JSP); } } - if (zAuthToken != null && !zAuthToken.isExpired() && zAuthToken.isRegistered() && grantee.getId().equals(zAuthToken.getAccountId())) { - // external virtual account already logged-in - resp.sendRedirect("/"); - } else if (prov.isOctopus() && !grantee.isVirtualAccountInitialPasswordSet() && - DebugConfig.skipVirtualAccountRegistrationPage) { - // seems like the virtual user did not set his password during his last visit, after an account was - // provisioned for him - setCookieAndRedirect(req, resp, grantee); - } else { - Map attrs = new HashMap(); - attrs.put("virtualacctdomain", domain.getName()); - redirectRequest(req, resp, attrs, PUBLIC_LOGIN_ON_UI_NODE, PUBLIC_LOGIN_JSP); - } + } catch (ServiceException e) { + Map errorAttrs = new HashMap(); + errorAttrs.put(ERROR_CODE, e.getCode()); + errorAttrs.put(ERROR_MESSAGE, e.getMessage()); + redirectRequest(req, resp, errorAttrs, EXT_USER_PROV_ON_UI_NODE, PUBLIC_EXTUSERPROV_JSP); + } catch (Exception e) { + Map errorAttrs = new HashMap(); + errorAttrs.put(ERROR_CODE, ServiceException.FAILURE); + errorAttrs.put(ERROR_MESSAGE, e.getMessage()); + redirectRequest(req, resp, errorAttrs, EXT_USER_PROV_ON_UI_NODE, PUBLIC_EXTUSERPROV_JSP); } + } + } + + public Map handleAddressVerification(HttpServletRequest req, HttpServletResponse resp, String accountId, String emailVerified, Boolean expired) throws ServletException, IOException { + Map attrs = new HashMap(); + HashMap prefs = new HashMap(); + Provisioning prov = Provisioning.getInstance(); + try { + Account acct = prov.getAccountById(accountId); + if (expired) { + prefs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, FeatureAddressVerificationStatus.expired.toString()); + attrs.put(MESSAGE_KEY, "Expired"); + } else { + prefs.put(Provisioning.A_zimbraPrefMailForwardingAddress, emailVerified); + prefs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, FeatureAddressVerificationStatus.verified.toString()); + acct.unsetFeatureAddressUnderVerification(); + attrs.put(MESSAGE_KEY, "Success"); + } + prov.modifyAttrs(acct, prefs, true, null); } catch (ServiceException e) { Map errorAttrs = new HashMap(); - errorAttrs.put(ERROR_CODE, e.getCode()); - errorAttrs.put(ERROR_MESSAGE, e.getMessage()); - redirectRequest(req, resp, errorAttrs, EXT_USER_PROV_ON_UI_NODE, PUBLIC_EXTUSERPROV_JSP); - } catch (Exception e) { - Map errorAttrs = new HashMap(); - errorAttrs.put(ERROR_CODE, ServiceException.FAILURE); - errorAttrs.put(ERROR_MESSAGE, e.getMessage()); - redirectRequest(req, resp, errorAttrs, EXT_USER_PROV_ON_UI_NODE, PUBLIC_EXTUSERPROV_JSP); + errorAttrs.put(MESSAGE_KEY, "Failure"); + redirectRequest(req, resp, errorAttrs, EXT_USER_PROV_ON_UI_NODE, PUBLIC_ADDRESS_VERIFICATION_JSP); } + return attrs; } private static String getMountpointName(Account owner, Account grantee, String sharedFolderPath) @@ -501,11 +539,16 @@ public static Map validatePrelimToken(String param) throws Servl } catch (Exception e) { throw new ServletException(e); } - Object expiry = map.get("exp"); + Object expiry = map.get(AccountConstants.P_LINK_EXPIRY); if (expiry != null) { // check validity if (System.currentTimeMillis() > Long.parseLong((String) expiry)) { - throw new ServletException("url no longer valid"); + String addressVerification = (String) map.get(AccountConstants.P_ADDRESS_VERIFICATION); + if ("1".equals(addressVerification)) { + map.put(EXPIRED, true); + } else { + throw new ServletException("url no longer valid"); + } } } return map; diff --git a/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java b/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java index 648962caa05..86a565d76ba 100644 --- a/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java +++ b/store/src/java/com/zimbra/cs/service/account/ModifyPrefs.java @@ -126,7 +126,7 @@ public Element handle(Element request, Map context) throws Servi sendEmailVerificationLink(authAccount, account, emailIdToVerify, octxt, mbox); prefs.put(Provisioning.A_zimbraFeatureAddressVerificationStatus, - FeatureAddressVerificationStatus.pending); + FeatureAddressVerificationStatus.pending.toString()); } else { account.unsetFeatureAddressUnderVerification(); account.unsetFeatureAddressVerificationStatus(); From f50ff2204c62ff0505a9e08782561941e91e468a Mon Sep 17 00:00:00 2001 From: Sneha Patil Date: Fri, 29 Sep 2017 14:57:57 +0530 Subject: [PATCH 129/142] ZCS-3093:error during tgz import results in endless loop and memory leak --- store/src/java-test/Truncated.tgz | Bin 0 -> 15371 bytes .../com/zimbra/cs/mailbox/ContactTest.java | 27 ++++++++++++++++++ .../service/formatter/ArchiveFormatter.java | 4 ++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 store/src/java-test/Truncated.tgz diff --git a/store/src/java-test/Truncated.tgz b/store/src/java-test/Truncated.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c33b1d85abe8c3e646bde93779ba634a5cf24332 GIT binary patch literal 15371 zcmY*=c_5VE_y03v7X}HDMk#=FYwMoO{k|IYSN=M`r(q^UnBm8NFNikY0GV*4wjl z$9VMmM=clbY~A5AHMFL0yQ1YT#g;q2laA*!p3DORk{Rtms|A8JRk0etX7C1-u==I#wzuK>1CyD#)p^XPk63WAdt*x%EwHX zUNp)+=XRNhzHZYzVak{TdL@l2)+AdAQ*SB4=`CUTB-BV zTa`JdXAMYb16KZyYzmhugr27d^eCCjj{zHQ#+*PkhuB);?|~NduH?=K>WA-eR53fO zT$<;bk{(cHOlo=WT2FuEnaLeb|JLXiden>h!kR<2^AThDDS6g+Ft1X2=~!ieAYp0| zbLA$5ljeK-=`^9M9v@Eqr7pU!Gk0W=V!O0?@kNA$$mlQ z7JrTvxCn20t(J6 zgLK92K(Wp=y(UK`lA7@PZx-wC)I}V(@zLMEC2eK#uJ=Dz#4g#k-6?_mAuaF6(l13u ze$h%y!Yu3{G(YRzZ8FT_&!?NAHRg@twD&`cKPb5$u~b@ z=mZ7HbR**%MqU>eg`RHoCz$)mF?<>G+Hz2=l0O>hnTO(IeK|~&pFUPg&x;(*&1&u_tN^&R$6I z%4pYR_%$*;=+qTODJ-h3WR~5N=s5 z;4BriM(X799(#;9yy^}A2JbBDS8s1pU{F{m*_ul(Q2xjz>%iOU=;7!Eyba!HD0Nx$ z^JCW{(=f@lI?DqK#@!Fb%-ukh%UxSKxWS>0`k>*O)#3(f2na>YX!F?spm(%e2(iShUNz+IWl7^Sz7#{H8c z9lqElX=NGxIhz#@D$10y(Gz$q+|hctBUTTGJW*n_z`3YHJ*IF|imHrkxTsTLw1Ss+ z4)Zww+Iu76&tqzAG3g%5)Xro1Thntde$p{;>Oz-yk!6kXEDd%C{a^%mte2Usb=`|< znrz1%`w&7@mv>K72|VvK@XVjK*I~j12`YW%v921aOZir%A}q=wyJEg8bX((8gu~br z1&r^3d0O=rQPzA0rvlzuQr3hA29Jrn4hSnNUl#{CX&}2VZC)9Ka+W6gHE~N{R*S+QY}rC{2fZl-g|alcPVrW2>Un z(k#nm$DeNkQDNvUH9W1{pJQAAHgJ#539Rq7Q_rA$ww$QV{A?`2=u0&5c=zj9{Gm&~ zBZyedMZJyUI}aDzS>{G$IkbiNXH{0Y5$DrE^mni<$U{(jtLi%HLIXdhOEg9G>lfIm zM{l@dR2i)WLbFYtX$VU#1%@xf`X@k&z2DuBza$E_tv(qB*8|<$@d|#M^E9j>E7E~n zK`X|Xcb^1AIcS<*W}R`hK*)eg`kevH-iNIXGxk*UeC%7~=`roIt+&>F?IMac<gX4lf9x(U%-71g6$X=d?a;#Yq+v?u;R z8EnD!K0$a2MmOihsSII^waNIkt0?&+#=KP(f(l`b3MHqZ_+CJ`kBGmYPm{G;b9UsL zv>0c&{U;?&Z(s?i4mcb@AI^p;FpUyhV#vC(b;Ln>Rq@Sa`nMSk-ZLcO7xc0H14BrSVYd%uxxh;hHO!OoWYo5E=| zXR1w0uIZn?>tcTO6F`gh+|e1$(O8`+tltK7xRj-@@#w$NIYf24?fHNwc4C0skc^9b z)mYZ~Yykl0k*Ou}NfV#YL{`vqt?X!P?G<5j_Tuy}6`ps)BEboqlGIQQ_QO}bx#X7Xqv|6AGS2UUv>>_hspH z4Wbo1iuWXScs6;@1i*sx_lDegWbvn&dDm9c9*t5f2bc&>_PbG$o@>W4YEf0@#~Rdt z*gl~B!~;amyDtr{5O69}DPCPRt`}^&55y*4Z79@UdFSFimmf`}kWl1picv}#A@$

^mgeY;#`;FDOdSSGD|n1o;MmsQA_iQkOv!01-UZowpCCRtpJuYH z^XUEI&T8GVQPY;CLWb({64%zXPwRv`JZL#Vyhrb=QGn+<>EGI2vhO2_mHmDnFfXNu z6jcAI8J;xo9dvIN*Bv_j{7=NuN9D7WshF%eGQT)K!cSGFoFpb{}O2NkE)8=WDpXo zM1zzZkeC+J!-SprMVA2Cv-8(VnPsAQWh2nI@#()O6rq=yVr&b{4Fn|DdSIq}@qqu_ zlTIIShrX*0Z^aXuKUhfN)$oTP1ITwUlhv$lx^+LO?F1e&7Aj8@?J^(-KxLt&HcCSjqF~U8`bc3w*VveqF8O@qOOdtJUDZB z`zU2Eh(vAjlYAW77`tVp=XyCm1UhtJwdw*!ohd}N4PX$4PR!;!a=VIP5xbY*zoJE@ zP_`|VU8F8y?O3lvTw-|mm}i!#@6-5Y$5Ys->)WvOT=Kn0S1;dHI6d+p{`dIQT6la| z6c^nGAuBt8`@0MGV}|p89FKgl8%cfl+zLtE`&d6SOC)=*BNYJMU&r}*w*wisSpvps z0rmIP?BoA)m{9-vV#<=aAj*_g8<}}Rgc0Ch9(poU(9nBf4z2NJtSTv`56u&dwUogG zp_7NI!Lg4xi8bGgleLK5!9>7lcc{C#zAew(pr7O#jjM;5s@>Xm&~3VQr6BQ!>Ul}z z2>0t;7w^k~iErl4-HX?vU}}&AdMUgXW+3O34sd7!tGqcgZ~-os-Z!&YHBxLKBztBx zQY%4NBHuf49ogKquh;uK&UfEfRGcR9=zZ}UlQ(IG2cG#1E@8SwC^K7oxx<=jaT3ROx$o6d4hpXsbY#AmEBqt^ zA1_ZB0be{qs}@WrD}=LwKXVe;&sOYx`OO+_hHO%06(yC*jkMf%?DOj6z``@QH#@5i(AI3_k^%NH!x_~ z*)7Rs6Z@y=Z<3UV5VfTaU#D$beMWpI7xnrS8NLwslw$NMP$Kn-`=|EVj)5S(%mQOu ztjK^xqHe}QJ;|Nvr1*{iis4JQ{vC+@1Et4^zbN>w>4VsoQ3%aF|L%J$JU1wU)#^+= zz?q*Jaly?+x&nXc&9WSXBjrQ~MPX~PmMB=EUgGqjPbF-zTR$QoT4aO#mc8$W90FJz^G8yw=Nn1HWOhfgtjCJ-||0x)W8@-}sblPsd5U zAXG!QQ)iUP)ojzXbrV)e2WdlKDeMVSW zy<9!lTIG?0Q{V%sN}pdkETl1BT#4Q9A%sNcRx zvtS4(kXd>!U6|O|NEV%fFFL_nB40X@3Fd@MM?;{3B)vc_l5jcq0rHYva~{1E7?butSpekTJ52Jxmi~QN-bz9` z;r%8MFVP2>SimoNAsvDWr%$G9%+vf&ZG|@qBfkgSun{cgtwFXn7*1E)p&?+}oZ}hO zW+#cG@2&w##-p#DWajS%P|zF>hRfYJVz9nG*E5O}OLB!95XcESQFZw@T<(#NwLaH; z%Q|lbR(rl4d+Bs|mmpHe^X}J1R2SRRJAnSZR-fOUOvB;G^7oW;62s|k1M!p04xrw} z*y}s^{W^$bbwnxJ4Gu*e_Cv?-wHbvO?1x1>HfG_QgO#0d^#6nd{c7Djql~l z-5<4D*~yn^UBC|cHC+AJr!n5mCnuD&KR?uX>)}?N7Fw}%9^p!zZ>L<7sBlH7qx-m4 z8_(A-h_kuPb8$TvC_w)97p`8)Z!RU&3!5#Ui@Y!;$XetXkyatQz@6`<0E`8Ex=E6y z%?S;>V9|w9#19HQ|MZrJpoKTXAgUGu0bfpotEUXywF zn2RxDxNeY*GD}KcugJnWPPwVTqEmsRy&Uit8AG5AU&ILc?niVloiFzE#3#q&uGm_^ zxQ&3k;BM1IuV7oS!;ha!v3(Ej3l)sRz_qdh`~`M1D2cAD2?Ed8UE;lcB9JDxgf%Ur%TO9PTbo16fpaOI-YQ>?_4(9dQ$^tL) zZGj;>vZ9LevKqT)IPih%61#9}tG^yyNNOke`4#$=<8fMTVqGqLqtCU%sq+}6{WKMG6 zWj9{5D8m~M*?=e4HG&U||8-woo-G^1Re@tXjH2v5?KvPySv|Ml36J0AZ7;#zrG$W3>$eO4xstlG3QuqV4=Zxcs=hdOZb;wfOSlhvyV&dfLw`yMN%gy?R#a zTuDdnkHPuO7b3JLZN^HX*E_i2IHP&x>qYA72~r5)JyA~Z!pSFA&Sp;omvKukb5()i z+^8=$W=SZbA9`IC80#Qo_nn3w1LNlFO6_1R=5+hVSfmXL9H+XqN7~F@v=SS1XGW%j zFFp{eIh9%7_Aqj2`z*`vd&nb80{S|f{+B;P0KLoefkgRnP4#*g;&^dDw9ekYc|QwbV^4c$A+h^#v8UJW*V(un#m%OXuuu)~D=^AM_WyZjuut@(Hc4O= zq-)oA1*?7?i>KH7o_7RqZ~E~4Cu?&}Qkf-|`O9>ID@tg^?s-4V5?RI9c6_~JvH6I; zkyIaG4UYr{NGFn?L}{Eovc~xlM*hen&)}u_PVfbC9%4O4(PV?>5{&Y3xQh#ci-3oo z&?&U5Joed%p#Dtu${Z50v4G;mhus4zAQ$oUKYb?yxnD&*u0#hqSpg7}s6leoK?T>o zKA(s34X&ewF+3pr{}FpR&j(zk@+yW|JXg$mZfZP%4j_BJWQpbtT33iC^*K>C7i+-5m9mHC ze(m3;xkb93#XSUP4AWEZqRY*yaMT`PI|@$xp1;mcBJxd|q8KTE|{wb_mplYUr51{y4v27q<8#(5ia`+^t-SDE2ek zWb%$)yX^LWtyKOHUOwBQ3Ez13O_!eUn-;OJ{JCw{e&;#t|6UE*cH`E~J(k_^L#y(~ z?fW(PN8NF|egKQt$(hbw0ph~|eCDwK5cH#9G)xKlVHVMIv8pyyUc%`T8{OP>lmE$r zoES$@(AMib^q6_bkJ&RPR6v>P!O7V?>P+)^g)zQxJOkc}FkHu}>e29wKheMowO`|v zLj7+`xggq|Nf*u|_*WhGAw^7^;#7q|;?J+StYt09aN(PO>>D4qqCQ0aUa&DO z{~0}f5$d(XjPUS2C_{FQjShexkW2qr4y{vak%a|bsT^apAI0f2;DYX7wrs-&pOO<- z%>3j$Nv)g{x!ZS-9?M_1!7J3SyE;=T>dF=tb3KUfBJ;`{!CP3WXChh(G9XAm>ca|l zx(HwY8D_Rn$aLe& zqC^pgxG>R%KWEYvT_XSHV^5yIl({hkUGaKg6@c}dIkj#K#4Lyo|AFX#0?7_wPdohl znzy3NURe0aQTBbdRyg$GBCZq+<)9XD zW)>4dnmp4``AQY7jGc78gW~V@H!oBJ*?zZgnd$GvvgqP5lIi(rl>&ilZ>!la5U=-c zpbkFtL-vXq@7~~AeW2=O1ULz)KV?+`*c0$pf>>-Qryp~ZmKeyQP);Y-JB}S(BK~vx zDx*exq0IFjlUp}^0???&~w*`>=%fQ?J(W(jCxrq6FM0tQNV)I1B z3UT zEarK8$-QZsA1bySXCLEUV}ynl{^Zhy z1Qf6TyA`N@kLtzvp@~MLk<(z!S&MplEqL|nl7!jw@#64b7*%^{5`erP-K@LQ+doyh zHG-tQKY;lQ)&B&x$(h7hhPJL>ip>c(l1tefaf-+0GO|;wgymK2TAM5xJFBvNO{xGj zb+oH-&5G@c#2fP;_x}T}o^?u2SiGh%k?I0J7OaI>r%}3uk$#y<4wNZQ7ELg{Fd;uI zl5pXlKoQA58tPp?L}{;_pd@~^;qRJQ#!Q|bbR+AHmrdLs2Ca|x)aaS!o9OQJldI&c z${VjZRuvw6g~cPE19tk}d^C0T`qy)3B)n)q)5`!sTXKZUkEkhe>shN>q)U;vBJCpz z!kbw?bfkwB3Ck!g64FIn;Jsg1?D4fAWf5WdqZHtSL6b%me*t+|91GkA+e5i_YO_Sg7S~O6zOC_Ui1#&tg4AA9&-*?SSY2T4sqb1VT_Q)g-|46C}f3 z79vkAy>r51E4!#=CvSl_DMl}>u(XSZ&v2LNh(EPo+sCDkHvMqfKay>-ps7Fl_NoF7 zkG>ns`NU=n%^YjjjDDj#1+)8#-fARxiz+|MFaO~4c-sXUM!xbUp{JwQHCu((%(eIV zjszb~GITZp=!Uv(_L?QM0@?8;-Ml9z`T+v^ZU+EiJOsp(3^RNW~V z#L*CX6Y~iLCq3Tg<9b=`BBkIj0z<$_7)*|;7LgDvF8uzcSv801A>eS}MT~O*YKnCw z(?RYy{Qs-glj84r6wwdFBXe;pZErUESLU&XG7r;)Ev8*XPN2>Sv#^7=v69htuMhDs z;$t0e>}3cq(+0u_XP>f{SLX0(%fngD`mI2WGxDZ))eY_qjjMVqL{q+kxelOq7SWR- zqSuBhppXJi%8mnzvjTHL?5M8<&Kxo2K=DuZdU06+JqI`5GmidGmRtQB67cZVS80Xf z#GhdaqTt+M8B33uXph9EXD`{DGRbHQ>)>#V_|+xkh-G7Z~%hUS{oJ$!Kwyfbqyd$0;XmXWL_?lbnV%B51;$4d!_mY^< zt+Z;e={ZjFo<#qoYylXAtwlI28mDdM3GpTwjt#DC+d|Jv+7XbxYo*~rb$MeVK7>~o z-7Vuw=kVc}LzfMA3%NZ6uOh(BqJKWwJH5JS9YGPoJ%;jI9G-lxAj5Yz@K?+9H!}|B(3MzKZKYvYXDP)AuAhk));&+ay z>?RwOGam)udKdf98O-8&>yOwa9>xXk;tcHe1crOf% zrh#VY%L6w*i$ILYALlZI(6dlm&gh`PHu@^y?WREIhb*yqrQ`+|Y?DIcaGo5<4`;aK z?ENw6KxKCZQ_k!v1FBx_1APB7>OQw_;Q|&;E*DU)NBkdh?7l$12D>K7CY@dlkZ{wD zJtrzXy}#fcwx9fet8rQ!>mh{G-gxAkr;79HJ{Ge!3^+_vm3owgkAxNJKYNWcioo8# z#AXWtsxB#GpnZneOm=mlT$#!)z{L5rD8}YzZ5YTG42MMOK`TJEd+NV7H(jF0DfOf6 z>>z9oSO_(8cd`uDcaxqb*rah}XF88w=lh`~S(s+|p~7Ck7`?TD(L(iOER=qP2h{K= z`^IYjD*rdx6ubQ9t4tF>S`K$n4TM%47=0&vbfQW^z4cDpPYM{?XFpYgDXQq~5r$2} zD}HF9ugqpSbK2EdM{s_&i|rN62o2WG4~1_i$g6+TBpCgloln#RBeSqTu(*F`*$gpo0m`szFwNjo{3v?E5%CEAB_RQozdMA-!kW|k$UY`CT z`|^n0tA~qrr1SyPAsJFm4CrQ3igOxv2s|$enAQJmEiLZR(7-M!vuFCqZBrpxs~kvo z>yKttc;`U8r*T{Vg%wd&C4JSW9I-cF?~{-sHcF4kazmw;JXE<*y(!qbMR>6O?Cl@cRTL zi#&T$F@eU5%{`^>>jHqo)Ux(tQBlICSBr5D-5H9iGgavYoCld{z+Rf_yW?oqfWveF zj0WE7DX<;Zf5B+cREJl9^n3|%skJMHzXR`CePNdWch2Of4o2}`1tocb3Es1QMHjdU zIAu#}ya_pHTc|ov6Q}@-U;mTe(g#Czhr*%XP>2`thA7GxRW~{c%TA>G{rHGn#L*9H zM`Y{=!Q5bA?jQRvj1Dl2{_s?(b>Iy=mDRrUo(o5&CA*S&1CuuV4>SDVD1HS6n(>rK z%TKG`5zInB7Z05oZ-G|H5=e=!cukS*n^DJjfta7Vb!@y_EdHUl=EF_;3*m!58Wtn_ zmZux#qLT;x{l4`!VN{ZW2V>O>nVN-~s4=?Rc1`{#&IB zN;2JftHlU&E?-h`PGs#cqK}cV-_MLxg&Nq5dw;aEyxL4B^92deCrue`f-1;CPFX(m zuxpjh426oRmgX1oi+KBxtrIWYh7UbZYbu`J#F4^-ZSzzTpdV)B^NO%n#c7fQIQdEdmV^DlYP0VEHhr-h^A@T%^%64q=(8sJTVVC6Yv~vej&0fKX>P47;Xh8C zLjN%@(=U{TwgZ;T>k1?FTf{MW4t&99{+h(lcjFlE5MClF7joVJ+T#YW1}x7Pj`ZMfb+iR8sNYvzxvL! z*SRuOrmZ{e%FLMDvnkNH&RMU@Ngn4iJaFbcC~`ahaiXrF&JT&!3Xp@!KN2 zQ6+s%rV}q~U(LLEQ11{FMSxaDFX>0yPcGFW4Okue&rkk~KIDS=Rudo5!1v`Iv8;1n zoJ_MvLo5m(;)|T0m+FLX+{8!~b$hxaZd{}7?$bNtRXra{pon<@)c=p@cg;Z84E#nR zZ!vEka_x6iU&xx#=|u~)1=NKTc_VbharuTLr=}Y`6W^?ohr>saxvs8WCG)re2OQUd zIm;(!kmp}V==*euk+8BBE*H$PnwW#|c0EkBC=yy{0<4}^JZ}3!y<72W#mET$!Z0J4 z2&Z>$NZaGDkLTj)xj@W(;J^8cY`x3`|(k}Z+H>3r2KCCTGPOflpBf_|!YXXZl$ zvb9^M)gdl>zd376MO3(5HmJcu`VFK|j{z)E|1s5>p$n<7Js@SX;A!km(0!d5qr>-n ze26DDpq6>{+PKEpQC4w_oN(9?W#vR9EFCQ4lvVxbAaBiYE`-z~ayj$`YBBcW7r$!H z2O_uAKRi-MnFJJc>#Z}&L<^$I^`Xrpp3AxfjNPEJ%tP>32B(xLwTL@EVqFDZb3BRn_prm z&Y3a}wR~4&R2f9s)QLEIxknOrF3+v6*1HJ=dsHYY54h>a{c*b&ApA!Bf2ElP=Qx#T z*P5)v6H{Ers_%gfe7;7@uWfk&b%)u@lOR30<<-W>)xx|u^~!~J{troDnUcLnG+P`ht-5C;y1&AweJvzPkFi@<)0>=$Ve zKhNytLAN#PDSV(rC52^a(v(-k}=g`m)5gabUy#x;UtlGBl{=YcQIbe}lihkB>`LAtNK z+u2V**2d5wNRDRFg#$zvm%E-(lA`c9{3FBUKsR5|>r3sf6!WO7_Hb50BDRI@s7D+7 zl%x^!KA;dk;oI}v@?P^gu-z2IS_%L4m2UE824-N793k(?Ms4ExVw?6Fc{5fTmBn8S zRE92U=dHG{R49|D4ZjvNzMQ`}Xj}u=YH5AmbN>v>)Oat!c>$CWV`qGiKkh1=rh?V} zCe3CM@!fVwB=FX>-IESa(~TQ_IMfvb*aZ^MS#$WrSs%XV^ZR;8iU6Er%r4nNWPG${wT?|(z3w6-0cb}L7dpc{t zhgrpLwnuG+yCxX8%d0`NDFU-iwFicEs*=@V*XGzxnp$9lkgk+JX9rvy#sQEs_jS)X?Fg zB;eQ$s$h%g_Q%9uQo$zi>^B*7K+Z8D)DooAa#O`tD|d4Ytam@=*|nGxB2;9zbkizGG%QP&^S zg@e|!W~6Sk3pyDcm-RP^m!G7(>w3NMD2}nja&ZI#~*!T zOB*(9VdiDpzzfh^j~_5B1r3kDvA;Swqsw>)Z;rw@Y63c>cPo=SvU20Xg|}>Ph1lWy zc=!RMftLpaPK{><0NSp5_^==2@WpJDkD}}1}=0B=;;DxMkpC6A2$m987&iPOCX*+%G zw7ReT{^GI@4n?+&_+V;I)nFgafUR)Wh)9Qk6)#;zOWaJ5n$!V_DITNJqZ=!Q3S?a0 z1xBwVUxL$|5560a;B*c1j*lwN?}L-7i@(Q}3zd%5Mm+>0k-w%roLo}ZuMv@& zx6(PKS_J-f;+CIFqyxctL5FfFpvR z38^Cu%ag6<^;lvLOi!Hn(s<#+yEXVpea+cE*d9C)z2} zIxXdwpnQ^eU2?8|gA4KAe#Fyc>*lI&?}w&~O60E? z%6z_cWnR(|6Gcgr2|MN^4Wh8x2OnPey7S_J7j}by8_F*M<4b2+Ba3pE%MdofXK8*D zI74+Kc=`({dz*my@FXhZ8&fKLbnhnvGaa*|aRvHY@5BUcm`}r%+xPEvYJIdQb>C`R zWf=3Kq9cOUW}xPLka?WXRS{VtY$zVEev(nbBQK)KhtUccP9S4(Upt*kKxjJ( zDdIW83H5U|J&>4(ZzF^ni^4^(sw3mOou7YuP0-8=$Q6zA4++;!d<{mU)2DOgq*hxK zoqI6P72{~3zWR-wZ$YikByGd1#m%mWXZ`?7IkCm&`!jR+CkjA zZg`JbH>8Hk)W=Ki?H2xkmw7wA&dRk5EmROYbpa>cW23U0t_MiIVlxs3VJ%zBA*s)i z6Nw%GLZ)rQL&%1WM~{j`MHm}BLMM+u{oRN6R_f3`?6_>8F5?;&>ngtzLv-)GQWjGP z2`pF>x6;>C|C6Y8>WI67qKX}+{p&fBST{$x;tYoutUH>%YV(cp-y!$Iae53!E>~u) z3MzmVWLM2+RD2bU;2b?xOLY+g$yPQ+jG=H_sg%bahN3|+k(B4kI|tvFA?Mg-WyrYN z`DDTX&M4FS!h68$k;@Ge)-)o9chMukZM$WOrowySq%#ZN&3sPZBSrH?%YB%31(eMu z8*~X59b}4T*KgvE`!@9x*>xnPoa}5H0tqnlBWSHD*d3ozmztuos(v zO}&i5mas^z0l#>Rd2304(5Y-Tmt}_xbTa%(4Kbfzte^nasrqKE3fY8Rry~i<#|Xvc zCtq1!-Tgq=Sx#7ZiLXSoWwy#8S&OfHM-@V`RXT3FV=zz^6%%u8o7<{AX(xPOW1D-rT~pj=lx-*h!Vk;=1y%{qI+{np z{6+730k0qpGOLWSNG$5>J6_EaEMtd6LCtE-PP9(Vj&rg!lz1*B#IaYzXq!8xG&UG< zke<5gDwuK&z_L!OVL(nPL;$B4kBuM+yRa^KkYICwqihxi>JOFo^#Rm6NOXb67@)h6Nhsar7M-51~KRC z1$2YstF|mtV1qgzKFohV4ryz9tk{@MA^Q8;N<99gO%XaAp*0qo{6LgaJV0aYK7ExL zIkm6Ib0pL)UhQ4k1+a62OQhdh2gz%VM&4V&hXIiRPsR!_!}aaC(8<}=<7g;YqIdpzWH;%gXKOO2#;0L ziN$Yi=Z&LJ8>qaZsHJl(iWGErZL?lrAp3Nlgc5B@)HhZh?L+^s_X+m%ZRRuxK$%I4 z?mCd`uYFb#q!&|Y%KRswY^Lu%yop8xe-TiY24LT7;~a@*US&J9)z1eJQ)&eJwpG7# z-t_FJzN3nQ)FIbL;G_cgZrFDqER8Qy-~;Uo&|*Bd60aQov4>^1i3}Q7zh^NmP1jH) z%>1q!(EOjFn%ZHdtC);ZJm2{uV4n8M=@yz-h{*UKJpt(L;2dUt)xUEN4yn{htC}Lp zl*Ii{c!+EBAb??MC1`&(_Qo%7v)Fa6b5OKn##c{Tori{?i^J@aI8vdybZZ{*rMBL7|9JQ%GUU z)mCaYg7!M8YbyaGptN`rl&aZ9Db=o#_A}cjYWBS0Fu{>$V(Ut~DiR?l)v4}yon>%P zx6&*wsJ~g#Z0qkA;S@_+#JBP{W+iCuuRa$N0_V0?@9rdDJr^PF&<9p!!Ew!pApqfj zZoudTv Date: Thu, 5 Oct 2017 14:38:38 -0500 Subject: [PATCH 130/142] ZCS-3017 noop: correct attribute ordering in zimbra-attrs.xml --- store/conf/attrs/zimbra-attrs.xml | 136 +++++++++++++++--------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index dd7ee5eca6f..96a43ca5c7f 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9389,6 +9389,74 @@ TODO: delete them permanently from here This attribute has been renamed to zimbraNetworkAdminNGEnabled + + TRUE + Whether the declaration of the Sieve extension feature is mandatory by the 'require' control. If TRUE, before ZCS evaluates a Sieve extension test or action, it checks the corresponding capability string at 'require' control; and if the capability string is not declared in the 'require', the entire Sieve filter execution will be failed. If FALSE, any Sieve extensions can be used without declaring the capability string in the 'require' control. + + + + FALSE + Whether edit header commands in admin sieve scripts are enabled or disabled. If TRUE, the addheader, deleteheader and replaceheader commands will be executed during admin sieve script execution. + + + + Received,DKIM-Signature,Authentication-Results,Received-SPF,Message-ID,Content-Type,Content-Disposition,Content-Transfer-Encoding,MIME-Version,Auto-Submitted + Comma separated list of sieve immutable headers + + + + FALSE + Mark messages sent to a forwarding address as read + + + + 1d + + Sleep time between subsequent contact backups. 0 means that contact + backup is disabled. + + + + + 15d + + Duration for which the backups should be preserved. + + + + + FALSE + Enable end-user email address verification + + + + 1d + Expiry time for end-user email address verification + + + + RFC822 email address under verification for an account + + + + End-user email address verification status + + + + FALSE + Whether to enable zimbra network new generation HSM module. + + + + FALSE + Whether to enable zimbra network new generation backup module. + + + + FALSE + Whether to enable zimbra network new generation admin module. + + URL of ephemeral storage backend ldap://default @@ -9552,72 +9620,4 @@ TODO: delete them permanently from here Information about the latest run of zmmigrateattrs. Includes the URL of the destination ephemeral store and the state of the migration (in progress, completed, failed) - - TRUE - Whether the declaration of the Sieve extension feature is mandatory by the 'require' control. If TRUE, before ZCS evaluates a Sieve extension test or action, it checks the corresponding capability string at 'require' control; and if the capability string is not declared in the 'require', the entire Sieve filter execution will be failed. If FALSE, any Sieve extensions can be used without declaring the capability string in the 'require' control. - - - - FALSE - Whether edit header commands in admin sieve scripts are enabled or disabled. If TRUE, the addheader, deleteheader and replaceheader commands will be executed during admin sieve script execution. - - - - Received,DKIM-Signature,Authentication-Results,Received-SPF,Message-ID,Content-Type,Content-Disposition,Content-Transfer-Encoding,MIME-Version,Auto-Submitted - Comma separated list of sieve immutable headers - - - - FALSE - Mark messages sent to a forwarding address as read - - - - 1d - - Sleep time between subsequent contact backups. 0 means that contact - backup is disabled. - - - - - 15d - - Duration for which the backups should be preserved. - - - - - FALSE - Enable end-user email address verification - - - - 1d - Expiry time for end-user email address verification - - - - RFC822 email address under verification for an account - - - - End-user email address verification status - - - - FALSE - Whether to enable zimbra network new generation HSM module. - - - - FALSE - Whether to enable zimbra network new generation backup module. - - - - FALSE - Whether to enable zimbra network new generation admin module. - - From 8999e47b62c6b5c15f62e935f95a0d70a95a456c Mon Sep 17 00:00:00 2001 From: Greg Solovyev Date: Thu, 5 Oct 2017 19:06:58 +0000 Subject: [PATCH 131/142] remove oauth-specific datasource classes and constants This commit removes a bunch of classes and constants that I added previously to accommodate DataSources specific to importing external data from OAuth2-enabled APIs. I don't see a need in customizing the classes unless there is a change in LDAP schema that makes some attributes accessible only to specific types of datasources. Since specifics of datasource implementation are encapsulated in DataImport class, I don't see a need for any further import-specific constants or subclasses. In fact, most of the subclasses that we already have (pop3, yab, imap) could be removed, but that is outside of the scope of this change. --- .../java/com/zimbra/client/ZDataSource.java | 51 ++++++++- .../com/zimbra/client/ZGetInfoResult.java | 3 - .../src/java/com/zimbra/client/ZMailbox.java | 3 - .../com/zimbra/client/ZOAuthDataSource.java | 107 ------------------ .../com/zimbra/common/soap/MailConstants.java | 1 - .../soap/account/message/GetInfoResponse.java | 2 - .../soap/account/type/AccountDataSource.java | 28 ++++- .../account/type/AccountOAuthDataSource.java | 40 ------- .../type/AccountUnknownDataSource.java | 5 +- .../soap/admin/type/DataSourceType.java | 2 +- .../mail/message/CreateDataSourceRequest.java | 2 - .../message/CreateDataSourceResponse.java | 2 - .../mail/message/GetDataSourcesResponse.java | 9 +- .../soap/mail/message/ImportDataRequest.java | 1 - .../mail/message/ModifyDataSourceRequest.java | 5 +- .../mail/message/TestDataSourceRequest.java | 5 +- .../mail/message/TestDataSourceResponse.java | 1 - .../zimbra/soap/mail/type/MailDataSource.java | 24 +++- .../soap/mail/type/MailOAuthDataSource.java | 35 ------ .../soap/mail/type/OAuthDataSourceId.java | 21 ---- .../java/com/zimbra/soap/type/DataSource.java | 4 + .../com/zimbra/soap/type/DataSources.java | 12 +- .../com/zimbra/soap/type/OAuthDataSource.java | 10 -- .../cs/datasource/DataSourceManagerTest.java | 8 +- .../com/zimbra/cs/service/mail/ToXML.java | 2 - .../unittest/server/TestDataSourceServer.java | 31 ++--- 26 files changed, 134 insertions(+), 280 deletions(-) delete mode 100644 client/src/java/com/zimbra/client/ZOAuthDataSource.java delete mode 100644 soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java delete mode 100644 soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java delete mode 100644 soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java delete mode 100644 soap/src/java/com/zimbra/soap/type/OAuthDataSource.java diff --git a/client/src/java/com/zimbra/client/ZDataSource.java b/client/src/java/com/zimbra/client/ZDataSource.java index a8cf07638d7..dc50ae4d3e8 100644 --- a/client/src/java/com/zimbra/client/ZDataSource.java +++ b/client/src/java/com/zimbra/client/ZDataSource.java @@ -17,15 +17,19 @@ package com.zimbra.client; +import org.json.JSONException; + import com.zimbra.common.util.SystemUtil; import com.zimbra.soap.admin.type.DataSourceType; import com.zimbra.soap.mail.type.DataSourceNameOrId; import com.zimbra.soap.mail.type.MailDataSource; +import com.zimbra.soap.mail.type.MailUnknownDataSource; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.DataSources; -public class ZDataSource { +public class ZDataSource implements ToZJSONObject { protected DataSource data; + public static String SOURCE_HOST_YAHOO = "yahoo.com"; public ZDataSource() { data = DataSources.newDataSource(); @@ -50,10 +54,16 @@ public ZDataSource(DataSource data) { } public DataSource toJaxb() { - MailDataSource jaxbObject = new MailDataSource(); + MailUnknownDataSource jaxbObject = new MailUnknownDataSource(); jaxbObject.setId(data.getId()); jaxbObject.setName(data.getName()); jaxbObject.setEnabled(data.isEnabled()); + jaxbObject.setFolderId(data.getFolderId()); + jaxbObject.setRefreshToken(data.getRefreshToken()); + jaxbObject.setRefreshTokenUrl(data.getRefreshTokenUrl()); + jaxbObject.setImportOnly(data.isImportOnly()); + jaxbObject.setImportClass(data.getImportClass()); + jaxbObject.setHost(data.getHost()); return jaxbObject; } @@ -62,6 +72,21 @@ public DataSourceNameOrId toJaxbNameOrId() { return jaxbObject; } + @Override + public ZJSONObject toZJSONObject() throws JSONException { + ZJSONObject zjo = new ZJSONObject(); + zjo.put("id", data.getId()); + zjo.put("name", data.getName()); + zjo.put("enabled", data.isEnabled()); + zjo.put("folderId", data.getFolderId()); + zjo.put("refreshToken", data.getRefreshToken()); + zjo.put("refreshTokenUrl", data.getRefreshTokenUrl()); + zjo.put("importOnly", data.isImportOnly()); + zjo.put("importClass", data.getImportClass()); + zjo.put("host", data.getHost()); + return zjo; + } + public String getName() { return data.getName(); } @@ -77,12 +102,34 @@ public String getId() { public void setId(String id) { data.setId(id); } + public String getFolderId() { return data.getFolderId(); } + public void setFolderId(String folderid) { + data.setFolderId(folderid); + } + public void setRefreshToken(String val) { + data.setRefreshToken(val); + } + public void setRefreshTokenURL(String val) { + data.setRefreshTokenUrl(val); + } + public String getRefreshToken() { + return data.getRefreshToken(); + } + public String getRefreshTokenUrl() { + return data.getRefreshTokenUrl(); + } public String getImportClass() { return data.getImportClass(); } public void setImportClass(String importClass) { data.setImportClass(importClass); } + public String getHost() { + return data.getHost(); + } + public void setHost(String host) { + data.setHost(host); + } public void setEnabled(boolean enabled) { data.setEnabled(enabled); } public boolean isEnabled() { return SystemUtil.coalesce(data.isEnabled(), Boolean.FALSE); diff --git a/client/src/java/com/zimbra/client/ZGetInfoResult.java b/client/src/java/com/zimbra/client/ZGetInfoResult.java index 4da1c35a130..9d2f71963b7 100644 --- a/client/src/java/com/zimbra/client/ZGetInfoResult.java +++ b/client/src/java/com/zimbra/client/ZGetInfoResult.java @@ -41,7 +41,6 @@ import com.zimbra.soap.type.CalDataSource; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.ImapDataSource; -import com.zimbra.soap.type.OAuthDataSource; import com.zimbra.soap.type.Pop3DataSource; import com.zimbra.soap.type.RssDataSource; @@ -107,8 +106,6 @@ public List getDataSources() { newList.add(new ZCalDataSource((CalDataSource) ds)); } else if (ds instanceof RssDataSource) { newList.add(new ZRssDataSource((RssDataSource) ds)); - } else if (ds instanceof OAuthDataSource) { - newList.add(new ZOAuthDataSource((OAuthDataSource) ds)); } else { newList.add(new ZDataSource(ds)); } diff --git a/client/src/java/com/zimbra/client/ZMailbox.java b/client/src/java/com/zimbra/client/ZMailbox.java index 6e19fff423f..b23f75d4872 100644 --- a/client/src/java/com/zimbra/client/ZMailbox.java +++ b/client/src/java/com/zimbra/client/ZMailbox.java @@ -223,7 +223,6 @@ import com.zimbra.soap.type.CalDataSource; import com.zimbra.soap.type.DataSource; import com.zimbra.soap.type.ImapDataSource; -import com.zimbra.soap.type.OAuthDataSource; import com.zimbra.soap.type.Pop3DataSource; import com.zimbra.soap.type.RssDataSource; import com.zimbra.soap.type.SearchSortBy; @@ -4718,8 +4717,6 @@ public List getAllDataSources() throws ServiceException { result.add(new ZCalDataSource((CalDataSource) ds)); } else if (ds instanceof RssDataSource) { result.add(new ZRssDataSource((RssDataSource) ds)); - } else if (ds instanceof OAuthDataSource) { - result.add(new ZOAuthDataSource((OAuthDataSource) ds)); } else { result.add(new ZDataSource(ds)); } diff --git a/client/src/java/com/zimbra/client/ZOAuthDataSource.java b/client/src/java/com/zimbra/client/ZOAuthDataSource.java deleted file mode 100644 index 654543e99d2..00000000000 --- a/client/src/java/com/zimbra/client/ZOAuthDataSource.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.zimbra.client; - -import org.json.JSONException; - -import com.zimbra.common.service.ServiceException; -import com.zimbra.common.util.ZimbraLog; -import com.zimbra.soap.admin.type.DataSourceType; -import com.zimbra.soap.mail.type.DataSourceNameOrId; -import com.zimbra.soap.mail.type.MailOAuthDataSource; -import com.zimbra.soap.mail.type.OAuthDataSourceNameOrId; -import com.zimbra.soap.type.DataSource; -import com.zimbra.soap.type.DataSources; -import com.zimbra.soap.type.OAuthDataSource; - -public class ZOAuthDataSource extends ZDataSource implements ToZJSONObject { - public ZOAuthDataSource(OAuthDataSource data) { - this.data = DataSources.newOAuthDataSource(data); - } - - public ZOAuthDataSource(String name, boolean enabled, String refreshToken, String refreshTokenURL, String folderId, String importClass, boolean isImportOnly) - throws ServiceException { - data = DataSources.newOAuthDataSource(); - data.setName(name); - data.setEnabled(enabled); - ((OAuthDataSource)data).setRefreshToken(refreshToken); - ((OAuthDataSource)data).setRefreshTokenUrl(refreshTokenURL); - data.setImportClass(importClass); - try { - data.setFolderId(folderId); - } catch (NumberFormatException e) { - ZimbraLog.datasource.error("Cannot create ZOAuthDataSource with name %s and import class %s, because folder ID is invalid: %s", name, importClass, folderId); - throw ServiceException.INVALID_REQUEST("Invalid folder id", e); - } - data.setImportOnly(isImportOnly); - } - - private OAuthDataSource getData() { - return ((OAuthDataSource)data); - } - - @Override - public DataSource toJaxb() { - MailOAuthDataSource jaxbObject = new MailOAuthDataSource(); - jaxbObject.setId(data.getId()); - jaxbObject.setName(data.getName()); - jaxbObject.setRefreshToken(getData().getRefreshToken()); - jaxbObject.setRefreshTokenUrl(getData().getRefreshTokenUrl()); - jaxbObject.setFolderId(data.getFolderId()); - jaxbObject.setImportOnly(data.isImportOnly()); - jaxbObject.setImportClass(data.getImportClass()); - jaxbObject.setEnabled(data.isEnabled()); - return jaxbObject; - } - - @Override - public DataSourceNameOrId toJaxbNameOrId() { - OAuthDataSourceNameOrId jaxbObject = OAuthDataSourceNameOrId.createForId(data.getId()); - return jaxbObject; - } - - @Override - public DataSourceType getType() { return DataSourceType.oauth; } - - @Override - public ZJSONObject toZJSONObject() throws JSONException { - ZJSONObject zjo = new ZJSONObject(); - zjo.put("id", data.getId()); - zjo.put("name", data.getName()); - zjo.put("enabled", data.isEnabled()); - zjo.put("refreshToken", getData().getRefreshToken()); - zjo.put("refreshTokenUrl", getData().getRefreshTokenUrl()); - zjo.put("importClass", getData().getImportClass()); - zjo.put("folderId", data.getFolderId()); - zjo.put("importOnly", data.isImportOnly()); - return zjo; - } - public String getFolderId() { return data.getFolderId(); } - public ZOAuthDataSource setFolderId(String folderid) { - data.setFolderId(folderid); - return this; - } - - public ZOAuthDataSource setRefreshToken(String val) { - getData().setRefreshToken(val); - return this; - } - - public ZOAuthDataSource setRefreshTokenURL(String val) { - getData().setRefreshTokenUrl(val); - return this; - } - - public String getRefreshToken() { - return getData().getRefreshToken(); - } - - public String getRefreshTokenUrl() { - return getData().getRefreshTokenUrl(); - } - - public String getImportClass() { - return data.getImportClass(); - } - public void setImportClass(String importClass) { - data.setImportClass(importClass); - } -} diff --git a/common/src/java/com/zimbra/common/soap/MailConstants.java b/common/src/java/com/zimbra/common/soap/MailConstants.java index 37697544672..82f6bd6379b 100644 --- a/common/src/java/com/zimbra/common/soap/MailConstants.java +++ b/common/src/java/com/zimbra/common/soap/MailConstants.java @@ -1174,7 +1174,6 @@ private MailConstants() { public static final String E_DS_RSS = "rss"; public static final String E_DS_GAL = "gal"; public static final String E_DS_CAL = "cal"; - public static final String E_DS_OAUTH = "oauth"; public static final String E_DS_UNKNOWN = "unknown"; public static final String E_DS_LAST_ERROR = "lastError"; public static final String A_DS_IS_ENABLED = "isEnabled"; diff --git a/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java b/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java index 3560093b685..7d8cb598da3 100644 --- a/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java +++ b/soap/src/java/com/zimbra/soap/account/message/GetInfoResponse.java @@ -42,7 +42,6 @@ import com.zimbra.soap.account.type.AccountDataSource; import com.zimbra.soap.account.type.AccountGalDataSource; import com.zimbra.soap.account.type.AccountImapDataSource; -import com.zimbra.soap.account.type.AccountOAuthDataSource; import com.zimbra.soap.account.type.AccountPop3DataSource; import com.zimbra.soap.account.type.AccountRssDataSource; import com.zimbra.soap.account.type.AccountUnknownDataSource; @@ -250,7 +249,6 @@ public final class GetInfoResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=AccountRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=AccountGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=AccountCalDataSource.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=AccountOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=AccountUnknownDataSource.class) }) private List dataSources = Lists.newArrayList(); diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java index daa67946ef6..21634e6acdd 100644 --- a/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java +++ b/soap/src/java/com/zimbra/soap/account/type/AccountDataSource.java @@ -208,6 +208,20 @@ public class AccountDataSource implements DataSource { @XmlElement(name=MailConstants.E_ATTRIBUTE /* a */, required=false) private List attributes = Lists.newArrayList(); + /** + * @zm-api-field-tag data-source-refreshToken + * @zm-api-field-description refresh token for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) + private String refreshToken; + + /** + * @zm-api-field-tag data-source-refreshTokenUrl + * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) + private String refreshTokenUrl; + public AccountDataSource() { } @@ -239,6 +253,8 @@ public void copy(DataSource from) { importClass = from.getImportClass(); failingSince = from.getFailingSince(); lastError = from.getLastError(); + refreshToken = from.getRefreshToken(); + refreshTokenUrl = from.getRefreshTokenUrl(); setAttributes(from.getAttributes()); } @@ -345,12 +361,18 @@ public void addAttribute(String attribute) { public List getAttributes() { return Collections.unmodifiableList(attributes); } - + @Override + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } + @Override + public String getRefreshToken() { return refreshToken; } + @Override + public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } + @Override + public String getRefreshTokenUrl() { return refreshTokenUrl; } @Override public ConnectionType getConnectionType() { return AdsConnectionType.ACT_TO_CT.apply(adsConnectionType); } - @Override public void setConnectionType(ConnectionType connectionType) { this.adsConnectionType = AdsConnectionType.CT_TO_ACT.apply(connectionType); @@ -380,6 +402,8 @@ public Objects.ToStringHelper addToStringInfo( .add("importClass", importClass) .add("failingSince", failingSince) .add("lastError", lastError) + .add("refreshToken", refreshToken) + .add("refreshTokenUrl", refreshTokenUrl) .add("attributes", attributes); } diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java deleted file mode 100644 index b61de75647a..00000000000 --- a/soap/src/java/com/zimbra/soap/account/type/AccountOAuthDataSource.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.zimbra.soap.account.type; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlType; - -import com.zimbra.common.soap.MailConstants; -import com.zimbra.soap.type.OAuthDataSource; -@XmlType(propOrder = {}) -public class AccountOAuthDataSource extends AccountDataSource implements OAuthDataSource { - /** - * @zm-api-field-tag data-source-refreshToken - * @zm-api-field-description refresh token for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) - private String refreshToken; - - /** - * @zm-api-field-tag data-source-refreshTokenUrl - * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) - private String refreshTokenUrl; - - public AccountOAuthDataSource() { - } - - public AccountOAuthDataSource(OAuthDataSource data) { - super(data); - refreshToken = data.getRefreshToken(); - refreshTokenUrl = data.getRefreshTokenUrl(); - } - - public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } - public String getRefreshToken() { return refreshToken; } - - public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } - public String getRefreshTokenUrl() { return refreshTokenUrl; } - - -} diff --git a/soap/src/java/com/zimbra/soap/account/type/AccountUnknownDataSource.java b/soap/src/java/com/zimbra/soap/account/type/AccountUnknownDataSource.java index 28f3a81627c..ef6d5d700b1 100644 --- a/soap/src/java/com/zimbra/soap/account/type/AccountUnknownDataSource.java +++ b/soap/src/java/com/zimbra/soap/account/type/AccountUnknownDataSource.java @@ -20,11 +20,14 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import com.zimbra.soap.type.DataSource; @XmlAccessorType(XmlAccessType.NONE) public class AccountUnknownDataSource extends AccountDataSource { + public AccountUnknownDataSource(DataSource from) { + copy(from); + } public AccountUnknownDataSource() { } - } diff --git a/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java b/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java index 7134c58ef13..8f26dd6271c 100644 --- a/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java +++ b/soap/src/java/com/zimbra/soap/admin/type/DataSourceType.java @@ -26,7 +26,7 @@ @XmlEnum public enum DataSourceType { // case must match protocol - pop3, imap, caldav, contacts, yab, rss, cal, gal, xsync, tagmap, oauth, unknown; + pop3, imap, caldav, contacts, yab, rss, cal, gal, xsync, tagmap, unknown; public static DataSourceType fromString(String s) throws ServiceException { try { diff --git a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java index 866c59031f5..a9add74c6d8 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceRequest.java @@ -29,7 +29,6 @@ import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; -import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -57,7 +56,6 @@ public class CreateDataSourceRequest { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private DataSource dataSource; diff --git a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java index e824090e177..70f62db9287 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/CreateDataSourceResponse.java @@ -31,7 +31,6 @@ import com.zimbra.soap.mail.type.CaldavDataSourceId; import com.zimbra.soap.mail.type.GalDataSourceId; import com.zimbra.soap.mail.type.ImapDataSourceId; -import com.zimbra.soap.mail.type.OAuthDataSourceId; import com.zimbra.soap.mail.type.Pop3DataSourceId; import com.zimbra.soap.mail.type.RssDataSourceId; import com.zimbra.soap.mail.type.UnknownDataSourceId; @@ -54,7 +53,6 @@ public class CreateDataSourceResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=RssDataSourceId.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=GalDataSourceId.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=CalDataSourceId.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=OAuthDataSourceId.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=UnknownDataSourceId.class) }) private Id dataSource; diff --git a/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java b/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java index 5481325e3de..971c866d43b 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/GetDataSourcesResponse.java @@ -17,10 +17,6 @@ package com.zimbra.soap.mail.message; -import com.google.common.base.Objects; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - import java.util.Collections; import java.util.List; @@ -30,12 +26,14 @@ import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; +import com.google.common.base.Objects; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.mail.type.MailCalDataSource; import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; -import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -57,7 +55,6 @@ public class GetDataSourcesResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private List dataSources = Lists.newArrayList(); diff --git a/soap/src/java/com/zimbra/soap/mail/message/ImportDataRequest.java b/soap/src/java/com/zimbra/soap/mail/message/ImportDataRequest.java index 9fd8ea3e2ea..f4b1a8af5d6 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/ImportDataRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/ImportDataRequest.java @@ -21,7 +21,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import java.util.Collections; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; diff --git a/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java b/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java index 3e0dc5f35c2..d9d15ce4887 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/ModifyDataSourceRequest.java @@ -17,20 +17,18 @@ package com.zimbra.soap.mail.message; -import com.google.common.base.Objects; - import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; +import com.google.common.base.Objects; import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.mail.type.MailCalDataSource; import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; -import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -60,7 +58,6 @@ public class ModifyDataSourceRequest { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private DataSource dataSource; diff --git a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java index d56597b7ab2..55c6d3d3544 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java +++ b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceRequest.java @@ -17,20 +17,18 @@ package com.zimbra.soap.mail.message; -import com.google.common.base.Objects; - import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; +import com.google.common.base.Objects; import com.zimbra.common.soap.MailConstants; import com.zimbra.soap.mail.type.MailCalDataSource; import com.zimbra.soap.mail.type.MailCaldavDataSource; import com.zimbra.soap.mail.type.MailGalDataSource; import com.zimbra.soap.mail.type.MailImapDataSource; -import com.zimbra.soap.mail.type.MailOAuthDataSource; import com.zimbra.soap.mail.type.MailPop3DataSource; import com.zimbra.soap.mail.type.MailRssDataSource; import com.zimbra.soap.mail.type.MailUnknownDataSource; @@ -59,7 +57,6 @@ public class TestDataSourceRequest { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=MailRssDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=MailGalDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=MailCalDataSource.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* cal */, type=MailOAuthDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=MailUnknownDataSource.class) }) private DataSource dataSource; diff --git a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java index e16b5e5090e..cb8110cedef 100644 --- a/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java +++ b/soap/src/java/com/zimbra/soap/mail/message/TestDataSourceResponse.java @@ -46,7 +46,6 @@ public class TestDataSourceResponse { @XmlElement(name=MailConstants.E_DS_RSS /* rss */, type=TestDataSource.class), @XmlElement(name=MailConstants.E_DS_GAL /* gal */, type=TestDataSource.class), @XmlElement(name=MailConstants.E_DS_CAL /* cal */, type=TestDataSource.class), - @XmlElement(name=MailConstants.E_DS_OAUTH /* oauth */, type=TestDataSource.class), @XmlElement(name=MailConstants.E_DS_UNKNOWN /* unknown */, type=TestDataSource.class) }) private List dataSources = Lists.newArrayList(); diff --git a/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java b/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java index 42b81866cc0..842c1ec427d 100644 --- a/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java +++ b/soap/src/java/com/zimbra/soap/mail/type/MailDataSource.java @@ -248,7 +248,19 @@ public class MailDataSource implements DataSource { */ @XmlElement(name=MailConstants.E_DS_LAST_ERROR /* lastError */, required=false) private String lastError; + /** + * @zm-api-field-tag data-source-refreshToken + * @zm-api-field-description refresh token for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) + private String refreshToken; + /** + * @zm-api-field-tag data-source-refreshTokenUrl + * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token + */ + @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) + private String refreshTokenUrl; /** * @zm-api-field-tag data-source-attrs * @zm-api-field-description Properties for the data source @@ -270,6 +282,8 @@ public void copy(DataSource from) { setEnabled(from.isEnabled()); setImportOnly(from.isImportOnly()); host = from.getHost(); + refreshToken = from.getRefreshToken(); + refreshTokenUrl = from.getRefreshTokenUrl(); port = from.getPort(); mdsConnectionType = MdsConnectionType.CT_TO_MCT.apply( from.getConnectionType()); @@ -410,16 +424,22 @@ public void addAttribute(String attribute) { public List getAttributes() { return Collections.unmodifiableList(attributes); } - @Override public ConnectionType getConnectionType() { return MdsConnectionType.MCT_TO_CT.apply(mdsConnectionType); } - @Override public void setConnectionType(ConnectionType connectionType) { this.mdsConnectionType = MdsConnectionType.CT_TO_MCT.apply(connectionType); } + @Override + public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } + @Override + public String getRefreshToken() { return refreshToken; } + @Override + public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } + @Override + public String getRefreshTokenUrl() { return refreshTokenUrl; } public Objects.ToStringHelper addToStringInfo(Objects.ToStringHelper helper) { return helper diff --git a/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java b/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java deleted file mode 100644 index 6251c8c55eb..00000000000 --- a/soap/src/java/com/zimbra/soap/mail/type/MailOAuthDataSource.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.zimbra.soap.mail.type; - -import javax.xml.bind.annotation.XmlAttribute; - -import com.zimbra.common.soap.MailConstants; -import com.zimbra.soap.type.OAuthDataSource; - -public class MailOAuthDataSource extends MailDataSource implements OAuthDataSource { - /** - * @zm-api-field-tag data-source-refreshToken - * @zm-api-field-description refresh token for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN /* refreshToken */, required = false) - private String refreshToken; - - /** - * @zm-api-field-tag data-source-refreshTokenUrl - * @zm-api-field-description refreshTokenUrl for refreshing data source oauth token - */ - @XmlAttribute(name = MailConstants.A_DS_REFRESH_TOKEN_URL /* refreshTokenUrl */, required = false) - private String refreshTokenUrl; - - public MailOAuthDataSource() { - } - - public MailOAuthDataSource(OAuthDataSource data) { - super(data); - } - - public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } - public String getRefreshToken() { return refreshToken; } - - public void setRefreshTokenUrl(String refreshTokenUrl) { this.refreshTokenUrl = refreshTokenUrl; } - public String getRefreshTokenUrl() { return refreshTokenUrl; } -} diff --git a/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java b/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java deleted file mode 100644 index 0b2fed2b034..00000000000 --- a/soap/src/java/com/zimbra/soap/mail/type/OAuthDataSourceId.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.zimbra.soap.mail.type; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; - -import com.zimbra.soap.type.Id; - -@XmlAccessorType(XmlAccessType.NONE) -public class OAuthDataSourceId extends Id { - /** - * no-argument constructor wanted by JAXB - */ - @SuppressWarnings("unused") - protected OAuthDataSourceId() { - this((String) null); - } - - OAuthDataSourceId(String id) { - super(id); - } -} diff --git a/soap/src/java/com/zimbra/soap/type/DataSource.java b/soap/src/java/com/zimbra/soap/type/DataSource.java index e11b6d58ab1..a3f64622aff 100644 --- a/soap/src/java/com/zimbra/soap/type/DataSource.java +++ b/soap/src/java/com/zimbra/soap/type/DataSource.java @@ -92,4 +92,8 @@ public static ConnectionType fromString(String s) public Long getFailingSince(); public String getLastError(); public List getAttributes(); + public void setRefreshToken(String refreshToken); + public String getRefreshToken(); + public void setRefreshTokenUrl(String refreshTokenUrl); + public String getRefreshTokenUrl(); } diff --git a/soap/src/java/com/zimbra/soap/type/DataSources.java b/soap/src/java/com/zimbra/soap/type/DataSources.java index 9638a9bc2bb..d89af8a7b1e 100644 --- a/soap/src/java/com/zimbra/soap/type/DataSources.java +++ b/soap/src/java/com/zimbra/soap/type/DataSources.java @@ -20,9 +20,9 @@ import com.zimbra.soap.account.type.AccountCalDataSource; import com.zimbra.soap.account.type.AccountDataSource; import com.zimbra.soap.account.type.AccountImapDataSource; -import com.zimbra.soap.account.type.AccountOAuthDataSource; import com.zimbra.soap.account.type.AccountPop3DataSource; import com.zimbra.soap.account.type.AccountRssDataSource; +import com.zimbra.soap.account.type.AccountUnknownDataSource; public class DataSources { @@ -31,7 +31,7 @@ public static AccountDataSource newDataSource(DataSource data) { } public static AccountDataSource newDataSource() { - return new AccountDataSource(); + return new AccountUnknownDataSource(); } public static Pop3DataSource newPop3DataSource() { @@ -50,14 +50,6 @@ public static ImapDataSource newImapDataSource(ImapDataSource data) { return new AccountImapDataSource(data); } - public static OAuthDataSource newOAuthDataSource() { - return new AccountOAuthDataSource(); - } - - public static OAuthDataSource newOAuthDataSource(OAuthDataSource data) { - return new AccountOAuthDataSource(data); - } - public static RssDataSource newRssDataSource() { return new AccountRssDataSource(); } diff --git a/soap/src/java/com/zimbra/soap/type/OAuthDataSource.java b/soap/src/java/com/zimbra/soap/type/OAuthDataSource.java deleted file mode 100644 index 3c81e8ec95b..00000000000 --- a/soap/src/java/com/zimbra/soap/type/OAuthDataSource.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.zimbra.soap.type; - -public interface OAuthDataSource extends DataSource { - public void setRefreshToken(String refreshToken); - public String getRefreshToken(); - - public void setRefreshTokenUrl(String refreshTokenUrl); - public String getRefreshTokenUrl(); - -} diff --git a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java index d813091c2ca..77a0b75eb6e 100644 --- a/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java +++ b/store/src/java-test/com/zimbra/cs/datasource/DataSourceManagerTest.java @@ -115,20 +115,20 @@ public void testGetDataImportWithDefaultClass() throws ServiceException { } @Test - public void testGetDataImportOAuthClass() throws ServiceException { + public void testGetDataImportClass() throws ServiceException { Map testAttrs = new HashMap(); testAttrs.put(Provisioning.A_zimbraDataSourceDomain, "zimbra.com"); testAttrs.put(Provisioning.A_zimbraDataSourceImportClassName, "com.zimbra.cs.datasource.DataSourceManagerTest.TestDSImport"); - DataSource ds = new DataSource(testAccount, DataSourceType.oauth, OAUTH_DS_NAME, OAUTH_DS_ID, testAttrs, null); + DataSource ds = new DataSource(testAccount, DataSourceType.unknown, OAUTH_DS_NAME, OAUTH_DS_ID, testAttrs, null); assertNotNull("DataSource should not be NULL", ds); DataImport di = DataSourceManager.getInstance().getDataImport(ds); assertNull("should not be able to instantiate non existent DataImport class", di); testAttrs.put(Provisioning.A_zimbraDataSourceImportClassName, "com.zimbra.cs.gal.GalImport"); - ds = new DataSource(testAccount, DataSourceType.oauth, OAUTH_DS_NAME, OAUTH_DS_ID, testAttrs, null); + ds = new DataSource(testAccount, DataSourceType.unknown, OAUTH_DS_NAME, OAUTH_DS_ID, testAttrs, null); assertNotNull("DataSource should not be NULL", ds); di = DataSourceManager.getInstance().getDataImport(ds); assertNotNull("DataImport should not be NULL", di); - assertTrue("DataImport for 'oauth' should be GalImport", di instanceof GalImport); + assertTrue("DataImport for 'unknown' should be GalImport", di instanceof GalImport); } } diff --git a/store/src/java/com/zimbra/cs/service/mail/ToXML.java b/store/src/java/com/zimbra/cs/service/mail/ToXML.java index b91c1680023..7d154db7f4f 100644 --- a/store/src/java/com/zimbra/cs/service/mail/ToXML.java +++ b/store/src/java/com/zimbra/cs/service/mail/ToXML.java @@ -3172,8 +3172,6 @@ private static String getDsType(DataSource ds) { return MailConstants.E_DS_GAL; case cal: return MailConstants.E_DS_CAL; - case oauth: - return MailConstants.E_DS_OAUTH; default: return MailConstants.E_DS_UNKNOWN; } diff --git a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java index 118463bb8d4..21097b5f4fc 100644 --- a/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java +++ b/store/src/java/com/zimbra/qa/unittest/server/TestDataSourceServer.java @@ -20,7 +20,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import org.junit.After; import org.junit.Before; @@ -32,7 +31,6 @@ import com.zimbra.client.ZFolder; import com.zimbra.client.ZImapDataSource; import com.zimbra.client.ZMailbox; -import com.zimbra.client.ZOAuthDataSource; import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.account.Server; import com.zimbra.cs.datasource.DataSourceManager; @@ -62,25 +60,30 @@ public void testOAuthDS() throws Exception { String DSName = "testCustomDS"; String importClassName = "some.data.source.ClassName"; String refreshToken = "refresh-token"; - String refreshTokenUrl = "https://this.is.where.you/?refresh=the&token"; ZMailbox zmbox = TestUtil.getZMailbox(USER_NAME); ZFolder folder = TestUtil.createFolder(zmbox, "/testCustomDS"); - ZOAuthDataSource zds = new ZOAuthDataSource(DSName, true, refreshToken, refreshTokenUrl, folder.getId(), importClassName, true); + //ZOAuthDataSource zds = new ZOAuthDataSource(DSName, true, refreshToken, folder.getId(), importClassName, ZOAuthDataSource.SOURCE_HOST_YAHOO); + ZDataSource zds = new ZDataSource(DSName, true); + zds.setImportClass(importClassName); + zds.setRefreshToken(refreshToken); + zds.setHost(ZDataSource.SOURCE_HOST_YAHOO); + zds.setFolderId(folder.getId()); String dsId = zmbox.createDataSource(zds); assertNotNull("DataSource should have an ID", dsId); assertFalse("DataSource id should not be empty", dsId.isEmpty()); ZDataSource ds = zmbox.getDataSourceByName(DSName); assertNotNull("should retrieve a non-null DataSource", ds); - assertTrue("expecting ZOAuthDataSource", ds instanceof ZOAuthDataSource); - ZOAuthDataSource oads = (ZOAuthDataSource)ds; - assertNotNull("DataSource should have a name", oads.getName()); - assertEquals("Data source name should be " + DSName, oads.getName(), DSName); - assertNotNull("new DataSource should have an import class", oads.getImportClass()); - assertEquals("expecting import class: " + importClassName, importClassName, oads.getImportClass()); - assertNotNull("new DataSource should have a refresh token", oads.getRefreshToken()); - assertEquals("expecting refresh token: " + refreshToken, refreshToken, oads.getRefreshToken()); - assertNotNull("new DataSource should have a refresh token URL", oads.getRefreshTokenUrl()); - assertEquals("expecting refresh token URL: " + refreshTokenUrl, refreshTokenUrl, oads.getRefreshTokenUrl()); + //assertTrue("expecting ZOAuthDataSource", ds instanceof ZOAuthDataSource); + //ZOAuthDataSource oads = (ZOAuthDataSource)ds; + assertNotNull("DataSource should have a name", ds.getName()); + assertEquals("Data source name should be " + DSName, ds.getName(), DSName); + assertNotNull("new DataSource should have an import class", ds.getImportClass()); + assertEquals("expecting import class: " + importClassName, importClassName, ds.getImportClass()); + assertNotNull("new DataSource should have a refresh token", ds.getRefreshToken()); + assertEquals("expecting refresh token: " + refreshToken, refreshToken, ds.getRefreshToken()); + assertNull("new DataSource should NOT have a refresh token URL", ds.getRefreshTokenUrl()); + assertNotNull("new DataSource should have a host", ds.getHost()); + assertEquals("expecting host: " + ZDataSource.SOURCE_HOST_YAHOO, ZDataSource.SOURCE_HOST_YAHOO, ds.getHost()); } @Test From 1326a5ab920c9d413125d95eac8ee357ad40fe65 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 26 Sep 2017 16:04:07 +0100 Subject: [PATCH 132/142] ZCS-2572:iOS CardDAV addressbook for Mountpoint Was only treating mountpoint addressbooks as remote collections. Now treat them also as addressbooks. With this change, iOS 11 Contacts application is able to see a shared addressbook, create a contact in it and modify it. Note that High Sierra Contacts can't see shared addressbooks - this is because only one addressbook is allowed. AddressBookCollection: * Moved fields to top * sharable code moved to static method RemoteAddressbookCollection * New subclass of RemoteCollection * combines features of RemoteCollection and AddressBookCollection UrlNamespace - Call the new constructor where appropriate --- .../dav/resource/AddressbookCollection.java | 47 ++++++++++--------- .../resource/RemoteAddressbookCollection.java | 35 ++++++++++++++ .../zimbra/cs/dav/resource/UrlNamespace.java | 5 +- 3 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 store/src/java/com/zimbra/cs/dav/resource/RemoteAddressbookCollection.java diff --git a/store/src/java/com/zimbra/cs/dav/resource/AddressbookCollection.java b/store/src/java/com/zimbra/cs/dav/resource/AddressbookCollection.java index a1c87f10e46..1fa04f9b8ac 100644 --- a/store/src/java/com/zimbra/cs/dav/resource/AddressbookCollection.java +++ b/store/src/java/com/zimbra/cs/dav/resource/AddressbookCollection.java @@ -46,49 +46,54 @@ public class AddressbookCollection extends Collection { + private static QName[] SUPPORTED_REPORTS = { + DavElements.CardDav.E_ADDRESSBOOK_MULTIGET, + DavElements.CardDav.E_ADDRESSBOOK_QUERY, + DavElements.E_ACL_PRINCIPAL_PROP_SET, + DavElements.E_PRINCIPAL_MATCH, + DavElements.E_PRINCIPAL_PROPERTY_SEARCH, + DavElements.E_PRINCIPAL_SEARCH_PROPERTY_SET, + DavElements.E_EXPAND_PROPERTY + }; + public AddressbookCollection(DavContext ctxt, Folder f) throws DavException, ServiceException { super(ctxt, f); + setupAddressbookCollection(this, ctxt, f); + } + + protected static void setupAddressbookCollection(Collection coll, DavContext ctxt, Folder f) + throws ServiceException { Account acct = f.getAccount(); Locale lc = acct.getLocale(); - String description = L10nUtil.getMessage(MsgKey.carddavAddressbookDescription, lc, acct.getAttr(Provisioning.A_displayName), f.getName()); + String description = L10nUtil.getMessage(MsgKey.carddavAddressbookDescription, + lc, acct.getAttr(Provisioning.A_displayName), f.getName()); ResourceProperty rp = new ResourceProperty(DavElements.CardDav.E_ADDRESSBOOK_DESCRIPTION); rp.setMessageLocale(lc); rp.setStringValue(description); rp.setProtected(false); - addProperty(rp); - addProperty(ResourceProperty.AddMember.create(UrlNamespace.getFolderUrl(ctxt.getUser(), f.getName()))); + coll.addProperty(rp); + coll.addProperty(ResourceProperty.AddMember.create(UrlNamespace.getFolderUrl(ctxt.getUser(), + f.getName()))); rp = new ResourceProperty(DavElements.CardDav.E_SUPPORTED_ADDRESS_DATA); Element vcard = rp.addChild(DavElements.CardDav.E_ADDRESS_DATA); vcard.addAttribute(DavElements.P_CONTENT_TYPE, DavProtocol.VCARD_CONTENT_TYPE); vcard.addAttribute(DavElements.P_VERSION, DavProtocol.VCARD_VERSION); rp.setProtected(true); - addProperty(rp); - long maxSize = Provisioning.getInstance().getLocalServer().getLongAttr(Provisioning.A_zimbraFileUploadMaxSize, -1); + coll.addProperty(rp); + long maxSize = Provisioning.getInstance().getLocalServer().getLongAttr( + Provisioning.A_zimbraFileUploadMaxSize, -1); if (maxSize > 0) { rp = new ResourceProperty(DavElements.CardDav.E_MAX_RESOURCE_SIZE_ADDRESSBOOK); rp.setStringValue(Long.toString(maxSize)); rp.setProtected(true); - addProperty(rp); + coll.addProperty(rp); } if (f.getDefaultView() == MailItem.Type.CONTACT) { - addResourceType(DavElements.CardDav.E_ADDRESSBOOK); + coll.addResourceType(DavElements.CardDav.E_ADDRESSBOOK); } - mCtag = CtagInfo.makeCtag(f); - setProperty(DavElements.E_GETCTAG, mCtag); + coll.setProperty(DavElements.E_GETCTAG, CtagInfo.makeCtag(f)); } - private final String mCtag; - - private static QName[] SUPPORTED_REPORTS = { - DavElements.CardDav.E_ADDRESSBOOK_MULTIGET, - DavElements.CardDav.E_ADDRESSBOOK_QUERY, - DavElements.E_ACL_PRINCIPAL_PROP_SET, - DavElements.E_PRINCIPAL_MATCH, - DavElements.E_PRINCIPAL_PROPERTY_SEARCH, - DavElements.E_PRINCIPAL_SEARCH_PROPERTY_SET, - DavElements.E_EXPAND_PROPERTY - }; - @Override protected QName[] getSupportedReports() { return SUPPORTED_REPORTS; diff --git a/store/src/java/com/zimbra/cs/dav/resource/RemoteAddressbookCollection.java b/store/src/java/com/zimbra/cs/dav/resource/RemoteAddressbookCollection.java new file mode 100644 index 00000000000..bdd9c613c53 --- /dev/null +++ b/store/src/java/com/zimbra/cs/dav/resource/RemoteAddressbookCollection.java @@ -0,0 +1,35 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.cs.dav.resource; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.dav.DavContext; +import com.zimbra.cs.dav.DavException; +import com.zimbra.cs.mailbox.Mountpoint; + +public class RemoteAddressbookCollection extends RemoteCollection { + + public RemoteAddressbookCollection(DavContext ctxt, Mountpoint mp) + throws DavException, ServiceException { + super(ctxt, mp); + AddressbookCollection.setupAddressbookCollection(this, ctxt, mp); + } + + public short getRights() { + return mRights; + } +} diff --git a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java index 0061b839096..a8f7212974f 100644 --- a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java +++ b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java @@ -599,8 +599,11 @@ public static DavResource getResourceFromMailItem(DavContext ctxt, MailItem item Mountpoint mp = (Mountpoint) item; viewType = mp.getDefaultView(); // don't expose mounted calendars when using iCal style delegation model. - if (!ctxt.useIcalDelegation() && (viewType == MailItem.Type.APPOINTMENT || viewType == MailItem.Type.TASK)) { + if (!ctxt.useIcalDelegation() && + (viewType == MailItem.Type.APPOINTMENT || viewType == MailItem.Type.TASK)) { resource = new RemoteCalendarCollection(ctxt, mp); + } else if (viewType == MailItem.Type.CONTACT) { + resource = new RemoteAddressbookCollection(ctxt, mp); } else { resource = new RemoteCollection(ctxt, mp); } From 8fd2dac78f75a0480ca11869f393addc359c4f75 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 26 Sep 2017 20:19:27 +0100 Subject: [PATCH 133/142] ZCS-2572:TestCalDav Better DebugConfig support Support working with: DebugConfig.enableDAVclientCanChooseResourceBaseName set Used this for reducing noise of failures with caldavtester. It isn't suitable for production although we should implement support for the client being able to PUT to its own choice of URL for better IOP at some point. Since this tweak was added, we escape @ in URLs more than we used to and the tests didn't reflect that. --- .../com/zimbra/qa/unittest/TestCalDav.java | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/TestCalDav.java b/store/src/java/com/zimbra/qa/unittest/TestCalDav.java index 84e53166f91..0577bc6b321 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestCalDav.java +++ b/store/src/java/com/zimbra/qa/unittest/TestCalDav.java @@ -16,6 +16,12 @@ */ package com.zimbra.qa.unittest; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -38,9 +44,6 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import net.fortuna.ical4j.model.TimeZoneRegistry; -import net.fortuna.ical4j.model.TimeZoneRegistryFactory; - import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; @@ -51,10 +54,15 @@ import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -108,16 +116,8 @@ import com.zimbra.soap.mail.type.NewMountpointSpec; import com.zimbra.soap.type.SearchHit; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; +import net.fortuna.ical4j.model.TimeZoneRegistry; +import net.fortuna.ical4j.model.TimeZoneRegistryFactory; public class TestCalDav { @@ -342,7 +342,7 @@ public String getResponseAsString() { @Test public void testBadBasicAuth() throws Exception { - String calFolderUrl = getFolderUrl(dav1, "Calendar").replaceAll("@", "%40"); + String calFolderUrl = getFolderUrl(dav1, "Calendar"); HttpClient client = new HttpClient(); GetMethod method = new GetMethod(calFolderUrl); addBasicAuthHeaderForUser(method, dav1, "badPassword"); @@ -414,7 +414,9 @@ public static String getSchedulingInboxUrl(Account auth, Account target) throws public static String getFolderUrl(Account auth, String folderName) throws ServiceException { StringBuilder sb = getLocalServerRoot(); sb.append(UrlNamespace.getFolderUrl(auth.getName(), folderName)); - return sb.toString(); + return sb.toString() + .replaceAll(" ", "%20") + .replaceAll("@", "%40"); } public static String getPrincipalUrl(Account auth) throws ServiceException { @@ -780,20 +782,27 @@ public void testCreateUsingClientChosenName() throws ServiceException, IOExcepti Iterator iter = respElem.elementIterator(); boolean hasCalendarHref = false; boolean hasCalItemHref = false; + List hrefs = Lists.newArrayList(); while (iter.hasNext()) { Element child = iter.next(); if (DavElements.P_RESPONSE.equals(child.getName())) { Iterator hrefIter = child.elementIterator(DavElements.P_HREF); while (hrefIter.hasNext()) { Element href = hrefIter.next(); - calFolderUrl.endsWith(href.getText()); - hasCalendarHref = hasCalendarHref || calFolderUrl.endsWith(href.getText()); - hasCalItemHref = hasCalItemHref || url.endsWith(href.getText()); + String hrefText = href.getText(); + hrefs.add(hrefText); + calFolderUrl.endsWith(hrefText); + hasCalendarHref = hasCalendarHref || calFolderUrl.endsWith(hrefText); + hasCalItemHref = hasCalItemHref || url.endsWith(hrefText); } } } - assertTrue("propfind response contained entry for calendar", hasCalendarHref); - assertTrue("propfind response contained entry for calendar entry ", hasCalItemHref); + assertTrue( + String.format("PROPFIND RESPONSE should contain href for '%s' - only contained hrefs:%s", + calFolderUrl, Joiner.on(',').join(hrefs)), hasCalendarHref); + assertTrue( + String.format("PROPFIND RESPONSE should contain href for '%s' - only contained hrefs:%s", + url, Joiner.on(',').join(hrefs)), hasCalItemHref); doDeleteMethod(url, dav1, HttpStatus.SC_NO_CONTENT); } @@ -933,7 +942,7 @@ public void testCreateModifyDeleteAttendeeModifyAndCancel() throws ServiceExcept @Test public void testAndroidMeetingSeries() throws Exception { ZMailbox dav2MB = TestUtil.getZMailbox(DAV2); // Force creation of mailbox - shouldn't be needed - String calFolderUrl = getFolderUrl(dav1, "Calendar").replaceAll("@", "%40"); + String calFolderUrl = getFolderUrl(dav1, "Calendar"); String url = String.format("%s%s.ics", calFolderUrl, androidSeriesMeetingUid); HttpClient client = new HttpClient(); PutMethod putMethod = new PutMethod(url); @@ -1817,9 +1826,14 @@ public void testAppleCaldavProxyFunctions() throws ServiceException, IOException // Check that proxy read has sharee2 in it doc = groupMemberSetExpandProperty(sharer, sharee2, false); String davBaseName = "notAllowed@There"; - String url = String.format("%s%s", - getFolderUrl(sharee1, "Shared Calendar").replaceAll(" ", "%20").replaceAll("@", "%40"), davBaseName); - HttpMethodExecutor exe = doIcalPut(url, sharee1, simpleEvent(sharer), HttpStatus.SC_MOVED_TEMPORARILY); + String url = String.format("%s%s", getFolderUrl(sharee1, "Shared Calendar"), davBaseName); + HttpMethodExecutor exe; + if (DebugConfig.enableDAVclientCanChooseResourceBaseName) { + exe = doIcalPut(url, sharee1, simpleEvent(sharer), HttpStatus.SC_CREATED); + return; // rest of test deals with how redirecting to new name works - not needed here + } else { + exe = doIcalPut(url, sharee1, simpleEvent(sharer), HttpStatus.SC_MOVED_TEMPORARILY); + } String location = null; for (Header hdr : exe.respHeaders) { if ("Location".equals(hdr.getName())) { @@ -1828,7 +1842,7 @@ public void testAppleCaldavProxyFunctions() throws ServiceException, IOException } assertNotNull("Location Header not returned when creating", location); url = String.format("%s%s", - getFolderUrl(sharee1, "Shared Calendar").replaceAll(" ", "%20").replaceAll("@", "%40"), + getFolderUrl(sharee1, "Shared Calendar"), location.substring(location.lastIndexOf('/') + 1)); doIcalPut(url, sharee1, simpleEvent(sharer), HttpStatus.SC_CREATED); } From ac243ac79ede95f3c6d96c746dffee69ad1e1a6b Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Tue, 26 Sep 2017 21:15:11 +0100 Subject: [PATCH 134/142] ZCS-2572:Moved tests TestCalDav to TestCardDav Also moved fields to top. --- .../com/zimbra/qa/unittest/TestCalDav.java | 865 ++++++------------ .../com/zimbra/qa/unittest/TestCardDav.java | 382 ++++++++ .../com/zimbra/qa/unittest/ZimbraSuite.java | 1 + 3 files changed, 673 insertions(+), 575 deletions(-) create mode 100644 store/src/java/com/zimbra/qa/unittest/TestCardDav.java diff --git a/store/src/java/com/zimbra/qa/unittest/TestCalDav.java b/store/src/java/com/zimbra/qa/unittest/TestCalDav.java index 0577bc6b321..870da68c139 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestCalDav.java +++ b/store/src/java/com/zimbra/qa/unittest/TestCalDav.java @@ -67,11 +67,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.io.Closeables; -import com.zimbra.client.ZFolder; -import com.zimbra.client.ZFolder.View; import com.zimbra.client.ZMailbox; import com.zimbra.client.ZMessage; -import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.account.ZAttrProvisioning; import com.zimbra.common.calendar.ICalTimeZone; import com.zimbra.common.calendar.ParsedDateTime; @@ -110,11 +107,7 @@ import com.zimbra.soap.account.type.Pref; import com.zimbra.soap.mail.message.CreateMountpointRequest; import com.zimbra.soap.mail.message.CreateMountpointResponse; -import com.zimbra.soap.mail.message.SearchRequest; -import com.zimbra.soap.mail.message.SearchResponse; -import com.zimbra.soap.mail.type.ContactInfo; import com.zimbra.soap.mail.type.NewMountpointSpec; -import com.zimbra.soap.type.SearchHit; import net.fortuna.ical4j.model.TimeZoneRegistry; import net.fortuna.ical4j.model.TimeZoneRegistryFactory; @@ -138,6 +131,211 @@ public class TestCalDav { private Account dav4; private Account user1; + private final String[] componentsForBothTasksAndEvents = {"VEVENT", "VTODO", "VFREEBUSY"}; + private final String[] eventComponents = {"VEVENT", "VFREEBUSY"}; + private final String[] todoComponents = {"VTODO", "VFREEBUSY"}; + + public static final String expandPropertyGroupMemberSet = + "" + + "" + + " " + + " " + + " " + + " " + + " " + + ""; + + public static final String expandPropertyDelegateFor = + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + + public static String propFindSupportedReportSet = + "\n" + + " \n" + + " \n" + + " \n" + + ""; + + static String propFindEtagResType = "" + + " " + + " " + + " " + + " " + + ""; + + public static String propPatchGroupMemberSetTemplate = + "" + + "" + + " " + + " " + + " " + + " %%MEMBER%%" + + " " + + " " + + " " + + ""; + + static final String calendar_query_etags_by_vevent = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + final String propFindSupportedCalendarComponentSet = + "\n" + + " \n" + + " \n" + + " \n" + + ""; + + private static String androidSeriesMeetingTemplate = + "BEGIN:VCALENDAR\n" + + "VERSION:2.0\n" + + "PRODID:-//dmfs.org//mimedir.icalendar//EN\n" + + "BEGIN:VTIMEZONE\n" + + "TZID:Europe/London\n" + + "X-LIC-LOCATION:Europe/London\n" + + "BEGIN:DAYLIGHT\n" + + "TZOFFSETFROM:+0000\n" + + "TZOFFSETTO:+0100\n" + + "TZNAME:BST\n" + + "DTSTART:19700329T010000\n" + + "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\n" + + "END:DAYLIGHT\n" + + "BEGIN:STANDARD\n" + + "TZOFFSETFROM:+0100\n" + + "TZOFFSETTO:+0000\n" + + "TZNAME:GMT\n" + + "DTSTART:19701025T020000\n" + + "RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\n" + + "END:STANDARD\n" + + "END:VTIMEZONE\n" + + "BEGIN:VEVENT\n" + + "DTSTART;TZID=Europe/London:20141022T190000\n" + + "DESCRIPTION:Giggle\n" + + "SUMMARY:testAndroidMeetingSeries\n" + + "RRULE:FREQ=DAILY;COUNT=15;WKST=MO\n" + + "LOCATION:Egham Leisure Centre\\, Vicarage Road\\, Egham\\, United Kingdom\n" + + "TRANSP:OPAQUE\n" + + "STATUS:CONFIRMED\n" + + "ATTENDEE;PARTSTAT=ACCEPTED;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:%%ORG%%\n" + + "ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:%%ATT%%\n" + + "DURATION:PT1H\n" + + "LAST-MODIFIED:20141021T145905Z\n" + + "DTSTAMP:20141021T145905Z\n" + + "ORGANIZER:mailto:%%ORG%%\n" + + "CREATED:20141021T145905Z\n" + + "UID:%%UID%%\n" + + "BEGIN:VALARM\n" + + "TRIGGER;VALUE=DURATION:-PT15M\n" + + "ACTION:DISPLAY\n" + + "DESCRIPTION:Default Event Notification\n" + + "X-WR-ALARMUID:790cd474-6135-4705-b1a0-24d4b4fc3cf5\n" + + "END:VALARM\n" + + "END:VEVENT\n" + + "END:VCALENDAR\n"; + + public String androidSeriesMeetingUid = "6db50587-d283-49a1-9cf4-63aa27406829"; + + private static String VtimeZoneGMT_0600_0500 = + "BEGIN:VCALENDAR\n" + + "BEGIN:VTIMEZONE\n" + + "TZID:GMT-06.00/-05.00\n" + + "BEGIN:STANDARD\n" + + "DTSTART:16010101T010000\n" + + "TZOFFSETTO:-0600\n" + + "TZOFFSETFROM:-0500\n" + + "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=1SU;WKST=MO\n" + + "END:STANDARD\n" + + "BEGIN:DAYLIGHT\n" + + "DTSTART:16010101T030000\n" + + "TZOFFSETTO:-0500\n" + + "TZOFFSETFROM:-0600\n" + + "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2SU;WKST=MO\n" + + "END:DAYLIGHT\n" + + "END:VTIMEZONE\n" + + "END:VCALENDAR\n"; + + private static String VtimeZoneGMT_0800_0700 = + "BEGIN:VCALENDAR\n" + + "BEGIN:VTIMEZONE\n" + + "TZID:GMT-08.00/-07.00\n" + + "BEGIN:STANDARD\n" + + "DTSTART:16010101T010000\n" + + "TZOFFSETTO:-0800\n" + + "TZOFFSETFROM:-0700\n" + + "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=1SU;WKST=MO\n" + + "END:STANDARD\n" + + "BEGIN:DAYLIGHT\n" + + "DTSTART:16010101T030000\n" + + "TZOFFSETTO:-0700\n" + + "TZOFFSETFROM:-0800\n" + + "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2SU;WKST=MO\n" + + "END:DAYLIGHT\n" + + "END:VTIMEZONE\n" + + "END:VCALENDAR\n"; + + public static String LOTUS_NOTES_WITH_BAD_GMT_TZID = + "BEGIN:VCALENDAR\r\n" + + "X-LOTUS-CHARSET:UTF-8\r\n" + + "VERSION:2.0\r\n" + + "PRODID:-//Lotus Development Corporation//NONSGML Notes 8.5.3//EN_C\r\n" + + "METHOD:REQUEST\r\n" + + "BEGIN:VTIMEZONE\r\n" + + "TZID:GMT\r\n" + + "BEGIN:STANDARD\r\n" + + "DTSTART:19501029T020000\r\n" + + "TZOFFSETFROM:+0100\r\n" + + "TZOFFSETTO:+0000\r\n" + + "RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=-1SU;BYMONTH=10\r\n" + + "END:STANDARD\r\n" + + "BEGIN:DAYLIGHT\r\n" + + "DTSTART:19500326T020000\r\n" + + "TZOFFSETFROM:+0000\r\n" + + "TZOFFSETTO:+0100\r\n" + + "RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=-1SU;BYMONTH=3\r\n" + + "END:DAYLIGHT\r\n" + + "END:VTIMEZONE\r\n" + + "BEGIN:VEVENT\r\n" + + "DTSTART;TZID=\"GMT\":20150721T140000\r\n" + + "DTEND;TZID=\"GMT\":20150721T150000\r\n" + + "TRANSP:OPAQUE\r\n" + + "DTSTAMP:20150721T072350Z\r\n" + + "SEQUENCE:0\r\n" + + "ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=\"Administrator/zimbra\"\r\n" + + " ;RSVP=FALSE:mailto:administrator@example.com\r\n" + + "ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE\r\n" + + " :mailto:fred.flintstone@example.com\r\n" + + "CLASS:PUBLIC\r\n" + + "SUMMARY:new meeting\r\n" + + "ORGANIZER;CN=\"Administrator/zimbra\":mailto:administrator@example.com\r\n" + + "UID:F0197AA9F439EFC888257E890026367E-Lotus_Notes_Generated\r\n" + + "X-LOTUS-BROADCAST:FALSE\r\n" + + "X-LOTUS-UPDATE-SEQ:1\r\n" + + "X-LOTUS-UPDATE-WISL:$S:1;$L:1;$B:1;$R:1;$E:1;$W:1;$O:1;$M:1;RequiredAttendees:1;INetRequiredNames:1;AltRequiredNames:1;StorageRequiredNames:1;OptionalAttendees:1;INetOptionalNames:1;AltOptionalNames:1;StorageOptionalNames:1\r\n" + + "X-LOTUS-NOTESVERSION:2\r\n" + + "X-LOTUS-NOTICETYPE:I\r\n" + + "X-LOTUS-APPTTYPE:3\r\n" + + "X-LOTUS-CHILD-UID:F0197AA9F439EFC888257E890026367E\r\n" + + "END:VEVENT\r\n" + + "END:VCALENDAR\r\n"; + public static class MkColMethod extends EntityEnclosingMethod { @Override public String getName() { @@ -197,6 +395,10 @@ public static NamespaceContextForXPath forCalDAV() { return new NamespaceContextForXPath(caldavNSMap); } + public static NamespaceContextForXPath forCardDAV() { + return new NamespaceContextForXPath(TestCardDav.carddavNSMap); + } + @Override public String getNamespaceURI(String prefix) { if (prefix == null) { @@ -297,8 +499,10 @@ public static class HttpMethodExecutor { public String statusLine; public Header[] respHeaders; public byte[] responseBodyBytes; + public final String methodName; public HttpMethodExecutor(HttpClient client, HttpMethod method, int expectedCode) throws IOException { + methodName = method.getName(); try { respCode = HttpClientUtil.executeMethod(client, method); statusCode = method.getStatusCode(); @@ -335,8 +539,41 @@ public static HttpMethodExecutor execute(HttpClient client, HttpMethod method, i return new HttpMethodExecutor(client, method, expectedCode); } - public String getResponseAsString() { - return new String(responseBodyBytes); + public String getHeaderValue(String hdrName) { + for (Header hdr : respHeaders) { + if (hdrName.equals(hdr.getName())) { + return hdr.getValue(); + } + } + return null; + } + + public String getNonNullHeaderValue(String hdrName, String desc) { + String val = getHeaderValue(hdrName); + assertNotNull(String.format("%s:response for method '%s' missing header '%s'", + desc, methodName, hdrName)); + return val; + } + + public String getResponseAsString() throws UnsupportedEncodingException { + return new String(responseBodyBytes, MimeConstants.P_CHARSET_UTF8); + } + + public Document getResponseDoc() { + try { + return W3cDomUtil.parseXMLToDoc(getResponseAsString()); + } catch (XmlParseException | UnsupportedEncodingException e) { + ZimbraLog.test.info("Problem parsing response for method %s", methodName, e); + fail(String.format("Problem parsing response for method %s %s", methodName, e)); + return null; + } + } + + public Document getResponseDoc(String topDocElementName) { + Document doc = getResponseDoc(); + org.w3c.dom.Element docElement = doc.getDocumentElement(); + assertEquals("response doc element node name", topDocElementName, docElement.getLocalName()); + return doc; } } @@ -393,76 +630,62 @@ public static void addBasicAuthHeaderForUser(HttpMethod method, Account acct) th addBasicAuthHeaderForUser(method, acct, "test123"); } - public static StringBuilder getLocalServerRoot() throws ServiceException { + public static StringBuilder getLocalServerRoot() { StringBuilder sb = new StringBuilder(); - sb.append(TestUtil.getBaseUrl(localServer)); + try { + sb.append(TestUtil.getBaseUrl(localServer)); + } catch (ServiceException e) { + ZimbraLog.test.error("Problem getting local server root", e); + fail("Problem getting local server root " + e.getMessage()); + } return sb; } - public static String getSchedulingOutboxUrl(Account auth, Account target) throws ServiceException { + public static String getFullUrl(String url) { StringBuilder sb = getLocalServerRoot(); - sb.append(UrlNamespace.getSchedulingOutboxUrl(auth.getName(), target.getName())); - return sb.toString(); + sb.append(url); + return sb.toString().replaceAll(" ", "%20").replaceAll("@", "%40"); } - public static String getSchedulingInboxUrl(Account auth, Account target) throws ServiceException { - StringBuilder sb = getLocalServerRoot(); - sb.append(UrlNamespace.getSchedulingInboxUrl(auth.getName(), target.getName())); - return sb.toString(); + public static String getSchedulingOutboxUrl(Account auth, Account target) { + return getFullUrl(UrlNamespace.getSchedulingOutboxUrl(auth.getName(), target.getName())); } - public static String getFolderUrl(Account auth, String folderName) throws ServiceException { - StringBuilder sb = getLocalServerRoot(); - sb.append(UrlNamespace.getFolderUrl(auth.getName(), folderName)); - return sb.toString() - .replaceAll(" ", "%20") - .replaceAll("@", "%40"); + public static String getSchedulingInboxUrl(Account auth, Account target) { + return getFullUrl(UrlNamespace.getSchedulingInboxUrl(auth.getName(), target.getName())); } - public static String getPrincipalUrl(Account auth) throws ServiceException { - StringBuilder sb = getLocalServerRoot(); - sb.append(UrlNamespace.getPrincipalUrl(auth)); - return sb.toString(); + public static String getFolderUrl(Account auth, String folderName) { + return getFullUrl(UrlNamespace.getFolderUrl(auth.getName(), folderName)); } - public static String getCalendarProxyReadUrl(Account target) throws ServiceException { - StringBuilder sb = getLocalServerRoot(); - sb.append(UrlNamespace.getCalendarProxyReadUrl(target, target)); - return sb.toString(); + public static String getPrincipalUrl(Account auth) { + return getFullUrl(UrlNamespace.getPrincipalUrl(auth)); } - public static String getCalendarProxyWriteUrl(Account target) throws ServiceException { - StringBuilder sb = getLocalServerRoot(); - sb.append(UrlNamespace.getCalendarProxyWriteUrl(target, target)); - return sb.toString(); + public static String getCalendarProxyReadUrl(Account target) { + return getFullUrl(UrlNamespace.getCalendarProxyReadUrl(target, target)); } - static final String calendar_query_etags_by_vevent = - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + public static String getCalendarProxyWriteUrl(Account target) { + return getFullUrl(UrlNamespace.getCalendarProxyWriteUrl(target, target)); + } - public static Document calendarQuery(String url, Account acct) throws IOException, XmlParseException { - ReportMethod method = new ReportMethod(url); + public static Document doMethodYieldingMultiStatus(EntityEnclosingMethod method, Account acct, + String body) throws IOException, XmlParseException { addBasicAuthHeaderForUser(method, acct); HttpClient client = new HttpClient(); TestCalDav.HttpMethodExecutor executor; method.addRequestHeader("Content-Type", MimeConstants.CT_TEXT_XML); - method.setRequestEntity(new ByteArrayRequestEntity(calendar_query_etags_by_vevent.getBytes(), + method.setRequestEntity(new ByteArrayRequestEntity(body.getBytes(), MimeConstants.CT_TEXT_XML)); executor = new TestCalDav.HttpMethodExecutor(client, method, HttpStatus.SC_MULTI_STATUS); - String respBody = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); - Document doc = W3cDomUtil.parseXMLToDoc(respBody); - org.w3c.dom.Element docElement = doc.getDocumentElement(); - assertEquals("Report node name", DavElements.P_MULTISTATUS, docElement.getLocalName()); - return doc; + return executor.getResponseDoc(DavElements.P_MULTISTATUS); + } + + public static Document calendarQuery(String url, Account acct) throws IOException, XmlParseException { + ReportMethod method = new ReportMethod(url); + return doMethodYieldingMultiStatus(method, acct, calendar_query_etags_by_vevent); } /** @@ -593,12 +816,6 @@ public void testPropFindSupportedReportSetOnOutbox() throws Exception { UrlNamespace.getSchedulingOutboxUrl(user1.getName(), user1.getName())); } - String propFindSupportedReportSet = - "\n" + - " \n" + - " \n" + - " \n" + - ""; public void checkPropFindSupportedReportSet(Account user, String fullurl, String shorturl) throws Exception { PropFindMethod method = new PropFindMethod(fullurl); addBasicAuthHeaderForUser(method, user); @@ -662,12 +879,6 @@ private void checkSupportedReportSet(Element respElem, String shorturl) { assertTrue("calendar-query report should be advertised", supportsCalendarQuery); } - final String propFindSupportedCalendarComponentSet = - "\n" + - " \n" + - " \n" + - " \n" + - ""; public void checkPropFindSupportedCalendarComponentSet(Account user, String fullurl, String shorturl, String[] compNames) throws Exception { @@ -675,13 +886,11 @@ public void checkPropFindSupportedCalendarComponentSet(Account user, String full addBasicAuthHeaderForUser(method, user); HttpClient client = new HttpClient(); TestCalDav.HttpMethodExecutor executor; - String respBody; method.addRequestHeader("Content-Type", MimeConstants.CT_TEXT_XML); method.setRequestEntity(new ByteArrayRequestEntity(propFindSupportedCalendarComponentSet.getBytes(), MimeConstants.CT_TEXT_XML)); executor = new TestCalDav.HttpMethodExecutor(client, method, HttpStatus.SC_MULTI_STATUS); - respBody = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); - Document doc = W3cDomUtil.parseXMLToDoc(respBody); + Document doc = executor.getResponseDoc(); XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(TestCalDav.NamespaceContextForXPath.forCalDAV()); XPathExpression xPathExpr; @@ -707,10 +916,6 @@ public void checkPropFindSupportedCalendarComponentSet(Account user, String full } } - private final String[] componentsForBothTasksAndEvents = {"VEVENT", "VTODO", "VFREEBUSY"}; - private final String[] eventComponents = {"VEVENT", "VFREEBUSY"}; - private final String[] todoComponents = {"VTODO", "VFREEBUSY"}; - @Test public void testPropFindSupportedCalendarComponentSetOnInbox() throws Exception { checkPropFindSupportedCalendarComponentSet(user1, getSchedulingInboxUrl(user1, user1), @@ -891,54 +1096,6 @@ public void testCreateModifyDeleteAttendeeModifyAndCancel() throws ServiceExcept doGetMethod(dav2Url, dav2, HttpStatus.SC_NOT_FOUND); } - private static String androidSeriesMeetingTemplate = - "BEGIN:VCALENDAR\n" + - "VERSION:2.0\n" + - "PRODID:-//dmfs.org//mimedir.icalendar//EN\n" + - "BEGIN:VTIMEZONE\n" + - "TZID:Europe/London\n" + - "X-LIC-LOCATION:Europe/London\n" + - "BEGIN:DAYLIGHT\n" + - "TZOFFSETFROM:+0000\n" + - "TZOFFSETTO:+0100\n" + - "TZNAME:BST\n" + - "DTSTART:19700329T010000\n" + - "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\n" + - "END:DAYLIGHT\n" + - "BEGIN:STANDARD\n" + - "TZOFFSETFROM:+0100\n" + - "TZOFFSETTO:+0000\n" + - "TZNAME:GMT\n" + - "DTSTART:19701025T020000\n" + - "RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\n" + - "END:STANDARD\n" + - "END:VTIMEZONE\n" + - "BEGIN:VEVENT\n" + - "DTSTART;TZID=Europe/London:20141022T190000\n" + - "DESCRIPTION:Giggle\n" + - "SUMMARY:testAndroidMeetingSeries\n" + - "RRULE:FREQ=DAILY;COUNT=15;WKST=MO\n" + - "LOCATION:Egham Leisure Centre\\, Vicarage Road\\, Egham\\, United Kingdom\n" + - "TRANSP:OPAQUE\n" + - "STATUS:CONFIRMED\n" + - "ATTENDEE;PARTSTAT=ACCEPTED;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:%%ORG%%\n" + - "ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:%%ATT%%\n" + - "DURATION:PT1H\n" + - "LAST-MODIFIED:20141021T145905Z\n" + - "DTSTAMP:20141021T145905Z\n" + - "ORGANIZER:mailto:%%ORG%%\n" + - "CREATED:20141021T145905Z\n" + - "UID:%%UID%%\n" + - "BEGIN:VALARM\n" + - "TRIGGER;VALUE=DURATION:-PT15M\n" + - "ACTION:DISPLAY\n" + - "DESCRIPTION:Default Event Notification\n" + - "X-WR-ALARMUID:790cd474-6135-4705-b1a0-24d4b4fc3cf5\n" + - "END:VALARM\n" + - "END:VEVENT\n" + - "END:VCALENDAR\n"; - public String androidSeriesMeetingUid = "6db50587-d283-49a1-9cf4-63aa27406829"; - @Test public void testAndroidMeetingSeries() throws Exception { ZMailbox dav2MB = TestUtil.getZMailbox(DAV2); // Force creation of mailbox - shouldn't be needed @@ -961,13 +1118,7 @@ public void testAndroidMeetingSeries() throws Exception { GetMethod getMethod = new GetMethod(url); addBasicAuthHeaderForUser(getMethod, dav1); HttpMethodExecutor exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); - String etag = null; - for (Header hdr : exe.respHeaders) { - if (DavProtocol.HEADER_ETAG.equals(hdr.getName())) { - etag = hdr.getValue(); - } - } - assertNotNull("ETag from get", etag); + exe.getNonNullHeaderValue(DavProtocol.HEADER_ETAG, "GET of Calendar item"); // Check that we fail if the etag is wrong putMethod = new PutMethod(url); @@ -1014,13 +1165,6 @@ public void testAndroidMeetingSeries() throws Exception { HttpMethodExecutor.execute(client, deleteMethod, HttpStatus.SC_NO_CONTENT); } - static String propFindEtagResType = "" + - " " + - " " + - " " + - " " + - ""; - public String zvcalendarToString(ZVCalendar vcal) throws IOException { StringWriter calWriter = new StringWriter(); vcal.toICalendar(calWriter); @@ -1099,41 +1243,6 @@ public void testSimpleMkcol() throws Exception { HttpMethodExecutor.execute(client, method, HttpStatus.SC_CREATED); } - @Test - public void testMkcol4addressBook() throws Exception { - String xml = "" + - " " + - " " + - " " + - " " + - " " + - " " + - " OtherContacts" + - " Extra Contacts" + - " " + - " " + - ""; - StringBuilder url = getLocalServerRoot(); - url.append(DavServlet.DAV_PATH).append("/").append(dav1.getName()).append("/OtherContacts/"); - MkColMethod method = new MkColMethod(url.toString()); - addBasicAuthHeaderForUser(method, dav1); - HttpClient client = new HttpClient(); - method.addRequestHeader("Content-Type", MimeConstants.CT_TEXT_XML); - method.setRequestEntity(new ByteArrayRequestEntity(xml.getBytes(), MimeConstants.CT_TEXT_XML)); - HttpMethodExecutor.execute(client, method, HttpStatus.SC_MULTI_STATUS); - - ZMailbox.Options options = new ZMailbox.Options(); - options.setAccount(dav1.getName()); - options.setAccountBy(AccountBy.name); - options.setPassword(TestUtil.DEFAULT_PASSWORD); - options.setUri(TestUtil.getSoapUrl()); - options.setNoSession(true); - ZMailbox mbox = ZMailbox.getMailbox(options); - ZFolder folder = mbox.getFolderByPath("/OtherContacts"); - assertEquals("OtherContacts", folder.getName()); - assertEquals("OtherContacts default view", View.contact, folder.getDefaultView()); - } - public String makeFreeBusyRequestIcal(Account organizer, List attendees, Date start, Date end) throws IOException { ZVCalendar vcal = new ZVCalendar(); @@ -1269,25 +1378,6 @@ public void testPropPatchCalendarFreeBusySetSettingUsingEscapedUrls() throws Exc fbResponse, busyTentativeMarker), fbResponse.contains(busyTentativeMarker)); } - private static String VtimeZoneGMT_0600_0500 = - "BEGIN:VCALENDAR\n" + - "BEGIN:VTIMEZONE\n" + - "TZID:GMT-06.00/-05.00\n" + - "BEGIN:STANDARD\n" + - "DTSTART:16010101T010000\n" + - "TZOFFSETTO:-0600\n" + - "TZOFFSETFROM:-0500\n" + - "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=1SU;WKST=MO\n" + - "END:STANDARD\n" + - "BEGIN:DAYLIGHT\n" + - "DTSTART:16010101T030000\n" + - "TZOFFSETTO:-0500\n" + - "TZOFFSETFROM:-0600\n" + - "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2SU;WKST=MO\n" + - "END:DAYLIGHT\n" + - "END:VTIMEZONE\n" + - "END:VCALENDAR\n"; - @Test public void testFuzzyTimeZoneMatchGMT_06() throws Exception { try (ByteArrayInputStream bais = new ByteArrayInputStream(VtimeZoneGMT_0600_0500.getBytes())) { @@ -1302,25 +1392,6 @@ public void testFuzzyTimeZoneMatchGMT_06() throws Exception { } } - private static String VtimeZoneGMT_0800_0700 = - "BEGIN:VCALENDAR\n" + - "BEGIN:VTIMEZONE\n" + - "TZID:GMT-08.00/-07.00\n" + - "BEGIN:STANDARD\n" + - "DTSTART:16010101T010000\n" + - "TZOFFSETTO:-0800\n" + - "TZOFFSETFROM:-0700\n" + - "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=1SU;WKST=MO\n" + - "END:STANDARD\n" + - "BEGIN:DAYLIGHT\n" + - "DTSTART:16010101T030000\n" + - "TZOFFSETTO:-0700\n" + - "TZOFFSETFROM:-0800\n" + - "RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=3;BYDAY=2SU;WKST=MO\n" + - "END:DAYLIGHT\n" + - "END:VTIMEZONE\n" + - "END:VCALENDAR\n"; - @Test public void testFuzzyTimeZoneMatchGMT_08() throws Exception { try (ByteArrayInputStream bais = new ByteArrayInputStream(VtimeZoneGMT_0800_0700.getBytes())) { @@ -1335,51 +1406,6 @@ public void testFuzzyTimeZoneMatchGMT_08() throws Exception { } } - public static String LOTUS_NOTES_WITH_BAD_GMT_TZID = - "BEGIN:VCALENDAR\r\n" + - "X-LOTUS-CHARSET:UTF-8\r\n" + - "VERSION:2.0\r\n" + - "PRODID:-//Lotus Development Corporation//NONSGML Notes 8.5.3//EN_C\r\n" + - "METHOD:REQUEST\r\n" + - "BEGIN:VTIMEZONE\r\n" + - "TZID:GMT\r\n" + - "BEGIN:STANDARD\r\n" + - "DTSTART:19501029T020000\r\n" + - "TZOFFSETFROM:+0100\r\n" + - "TZOFFSETTO:+0000\r\n" + - "RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=-1SU;BYMONTH=10\r\n" + - "END:STANDARD\r\n" + - "BEGIN:DAYLIGHT\r\n" + - "DTSTART:19500326T020000\r\n" + - "TZOFFSETFROM:+0000\r\n" + - "TZOFFSETTO:+0100\r\n" + - "RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=-1SU;BYMONTH=3\r\n" + - "END:DAYLIGHT\r\n" + - "END:VTIMEZONE\r\n" + - "BEGIN:VEVENT\r\n" + - "DTSTART;TZID=\"GMT\":20150721T140000\r\n" + - "DTEND;TZID=\"GMT\":20150721T150000\r\n" + - "TRANSP:OPAQUE\r\n" + - "DTSTAMP:20150721T072350Z\r\n" + - "SEQUENCE:0\r\n" + - "ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=\"Administrator/zimbra\"\r\n" + - " ;RSVP=FALSE:mailto:administrator@example.com\r\n" + - "ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE\r\n" + - " :mailto:fred.flintstone@example.com\r\n" + - "CLASS:PUBLIC\r\n" + - "SUMMARY:new meeting\r\n" + - "ORGANIZER;CN=\"Administrator/zimbra\":mailto:administrator@example.com\r\n" + - "UID:F0197AA9F439EFC888257E890026367E-Lotus_Notes_Generated\r\n" + - "X-LOTUS-BROADCAST:FALSE\r\n" + - "X-LOTUS-UPDATE-SEQ:1\r\n" + - "X-LOTUS-UPDATE-WISL:$S:1;$L:1;$B:1;$R:1;$E:1;$W:1;$O:1;$M:1;RequiredAttendees:1;INetRequiredNames:1;AltRequiredNames:1;StorageRequiredNames:1;OptionalAttendees:1;INetOptionalNames:1;AltOptionalNames:1;StorageOptionalNames:1\r\n" + - "X-LOTUS-NOTESVERSION:2\r\n" + - "X-LOTUS-NOTICETYPE:I\r\n" + - "X-LOTUS-APPTTYPE:3\r\n" + - "X-LOTUS-CHILD-UID:F0197AA9F439EFC888257E890026367E\r\n" + - "END:VEVENT\r\n" + - "END:VCALENDAR\r\n"; - @Test public void testLondonTimeZoneCalledGMTkeepSameName() throws Exception { try (ByteArrayInputStream bais = new ByteArrayInputStream(LOTUS_NOTES_WITH_BAD_GMT_TZID.getBytes())) { @@ -1466,292 +1492,6 @@ public void testAttendeeSuppressedAutoDecline() throws Exception { attendeeDeleteFromCalendar(true /* suppressReply */); } - public static String simpleVcard = "BEGIN:VCARD\r\n" + - "VERSION:3.0\r\n" + - "FN:TestCal\r\n" + - "N:Dog;Scruffy\r\n" + - "EMAIL;TYPE=INTERNET,PREF:scruffy@example.com\r\n" + - "UID:SCRUFF1\r\n" + - "END:VCARD\r\n"; - - @Test - public void testCreateContactWithIfNoneMatchTesting() throws ServiceException, IOException { - String davBaseName = "SCRUFF1.vcf"; // Based on UID - String contactsFolderUrl = getFolderUrl(dav1, "Contacts"); - String url = String.format("%s%s", contactsFolderUrl, davBaseName); - HttpClient client = new HttpClient(); - PutMethod putMethod = new PutMethod(url); - addBasicAuthHeaderForUser(putMethod, dav1); - putMethod.addRequestHeader("Content-Type", "text/vcard"); - - putMethod.setRequestEntity(new ByteArrayRequestEntity(simpleVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); - // Bug 84246 this used to fail with 409 Conflict because we used to require an If-None-Match header - HttpMethodExecutor.execute(client, putMethod, HttpStatus.SC_CREATED); - - // Check that trying to put the same thing again when we don't expect it to exist (i.e. Using If-None-Match - // header) will fail. - putMethod = new PutMethod(url); - addBasicAuthHeaderForUser(putMethod, dav1); - putMethod.addRequestHeader("Content-Type", "text/vcard"); - putMethod.addRequestHeader(DavProtocol.HEADER_IF_NONE_MATCH, "*"); - putMethod.setRequestEntity(new ByteArrayRequestEntity(simpleVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); - HttpMethodExecutor.execute(client, putMethod, HttpStatus.SC_PRECONDITION_FAILED); - } - - private static String rachelVcard = - "BEGIN:VCARD\n" + - "VERSION:3.0\n" + - "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\n" + - "FN:La Rochelle\n" + - "N:Rochelle;La;;;\n" + - "EMAIL;TYPE=internet:rachel@fun.org\n" + - "CATEGORIES:BlueGroup\n" + - "REV:2015-04-04T13:55:56Z\n" + - "UID:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE\n" + - "X-BUSYMAC-MODIFIED-BY:Gren Elliot\n" + - "X-CREATED:2015-04-04T13:55:25Z\n" + - "END:VCARD\n"; - - private static String blueGroupCreate = - "BEGIN:VCARD\n" + - "VERSION:3.0\n" + - "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\n" + - "FN:BlueGroup\n" + - "N:BlueGroup\n" + - "REV:2015-04-04T13:55:56Z\n" + - "UID:F53A6F96-566F-46CC-8D48-A5263FAB5E38\n" + - "X-ADDRESSBOOKSERVER-KIND:group\n" + - "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE\n" + - "END:VCARD\n"; - - private static String parisVcard = - "BEGIN:VCARD\n" + - "VERSION:3.0\n" + - "FN:Paris Match\n" + - "N:Match;Paris;;;\n" + - "EMAIL;TYPE=internet:match@paris.fr\n" + - "CATEGORIES:BlueGroup\n" + - "REV:2015-04-04T13:56:50Z\n" + - "UID:BE43F16D-336E-4C3E-BAE6-22B8F245A986\n" + - "END:VCARD\n"; - - private static String blueGroupModify = - "BEGIN:VCARD\n" + - "VERSION:3.0\n" + - "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\n" + - "FN:BlueGroup\n" + - "N:BlueGroup\n" + - "REV:2015-04-04T13:56:50Z\n" + - "UID:F53A6F96-566F-46CC-8D48-A5263FAB5E38\n" + - "X-ADDRESSBOOKSERVER-KIND:group\n" + - "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:BE43F16D-336E-4C3E-BAE6-22B8F245A986\n" + - "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE\n" + - "END:VCARD\n"; - - @Test - public void testAppleStyleGroup() throws ServiceException, IOException { - String contactsFolderUrl = getFolderUrl(dav1, "Contacts"); - HttpClient client = new HttpClient(); - - PostMethod postMethod = new PostMethod(contactsFolderUrl); - addBasicAuthHeaderForUser(postMethod, dav1); - postMethod.addRequestHeader("Content-Type", "text/vcard"); - postMethod.setRequestEntity(new ByteArrayRequestEntity(rachelVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); - HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); - - postMethod = new PostMethod(contactsFolderUrl); - addBasicAuthHeaderForUser(postMethod, dav1); - postMethod.addRequestHeader("Content-Type", "text/vcard"); - postMethod.setRequestEntity(new ByteArrayRequestEntity(blueGroupCreate.getBytes(), MimeConstants.CT_TEXT_VCARD)); - HttpMethodExecutor exe = HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); - String groupLocation = null; - for (Header hdr : exe.respHeaders) { - if ("Location".equals(hdr.getName())) { - groupLocation = hdr.getValue(); - } - } - assertNotNull("Location Header returned when creating Group", groupLocation); - - postMethod = new PostMethod(contactsFolderUrl); - addBasicAuthHeaderForUser(postMethod, dav1); - postMethod.addRequestHeader("Content-Type", "text/vcard"); - postMethod.setRequestEntity(new ByteArrayRequestEntity(parisVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); - HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); - - String url = String.format("%s%s", contactsFolderUrl, "F53A6F96-566F-46CC-8D48-A5263FAB5E38.vcf"); - PutMethod putMethod = new PutMethod(url); - addBasicAuthHeaderForUser(putMethod, dav1); - putMethod.addRequestHeader("Content-Type", "text/vcard"); - putMethod.setRequestEntity(new ByteArrayRequestEntity(blueGroupModify.getBytes(), MimeConstants.CT_TEXT_VCARD)); - HttpMethodExecutor.execute(client, putMethod, HttpStatus.SC_NO_CONTENT); - - GetMethod getMethod = new GetMethod(url); - addBasicAuthHeaderForUser(getMethod, dav1); - getMethod.addRequestHeader("Content-Type", "text/vcard"); - exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); - String respBody = new String(exe.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); - String [] expecteds = { - "X-ADDRESSBOOKSERVER-KIND:group", - "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:BE43F16D-336E-4C3E-BAE6-22B8F245A986", - "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE" }; - for (String expected : expecteds) { - assertTrue(String.format("GET should contain '%s'\nBODY=%s", expected, respBody), - respBody.contains(expected)); - } - - // members are actually stored in a different way. Make sure it isn't a fluke - // that the GET response contained the correct members by checking that the members - // appear where expected in a search hit. - SearchRequest searchRequest = new SearchRequest(); - searchRequest.setSortBy("dateDesc"); - searchRequest.setLimit(8); - searchRequest.setSearchTypes("contact"); - searchRequest.setQuery("in:Contacts"); - ZMailbox mbox = TestUtil.getZMailbox(DAV1); - SearchResponse searchResp = mbox.invokeJaxb(searchRequest); - assertNotNull("JAXB SearchResponse object", searchResp); - List hits = searchResp.getSearchHits(); - assertNotNull("JAXB SearchResponse hits", hits); - assertEquals("JAXB SearchResponse hits", 3, hits.size()); - boolean seenGroup = false; - for (SearchHit hit : hits) { - ContactInfo contactInfo = (ContactInfo) hit; - if ("BlueGroup".equals(contactInfo.getFileAs())) { - seenGroup = true; - assertEquals("Number of members of group in search hit", 2, contactInfo.getContactGroupMembers().size()); - } - ZimbraLog.test.info("Hit %s class=%s", hit, hit.getClass().getName()); - } - assertTrue("Seen group", seenGroup); - } - - private static String smallBusyMacAttach = - "BEGIN:VCARD\r\n" + - "VERSION:3.0\r\n" + - "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\r\n" + - "FN:John Smith\r\n" + - "N:Smith;John;;;\r\n" + - "REV:2015-04-05T09:51:09Z\r\n" + - "UID:99E01E16-03B3-4487-AAEF-AEB496852C06\r\n" + - "X-BUSYMAC-ATTACH;ENCODING=b;X-FILENAME=favicon.ico:AAABAAEAEBAAAAEAIABoBAAA\r\n" + - " FgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAABMLAAATCwAAAAAAAAAAAAAAAAAAw4cAY8OHAM\r\n" + - " nDhwD8w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD8w4cAycOHAGMAAAAAw4cA\r\n" + - " Y8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/Dhw\r\n" + - " D/w4cAY8OHAMnDhwD/w4cA/7yYSv/y5Mb/8uXH//Llx//z5sr/8+bK//Pmyv/z58v/8+bK/8qq\r\n" + - " Y//DhwD/w4cA/8OHAMnDhwDhw4cA/8OHAP++q4D///////////////7////+//////////////\r\n" + - " /////////Yyan/w4cA/8OHAP/DhwDhw4cA4cOHAP/DhwD/t4QR/9/azv//////5t3K/9StVv/b\r\n" + - " t2b/27dm/9u3Z//cuGn/wpAh/8OHAP/DhwD/w4cA4cOHAOHDhwD/w4cA/8OHAP+2jzr/+fj2//\r\n" + - " n49f/BnU7/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAOHDhwDhw4cA/8OHAP/DhwD/\r\n" + - " w4cA/7ihbf//////8u/p/8GRJv/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwDhw4cA4cOHAP\r\n" + - " /DhwD/w4cA/8OHAP/BhgP/0siz///////d1L//wYgI/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA\r\n" + - " 4cOHAOHDhwD/w4cA/8OHAP/DhwD/w4cA/7eIIP/n49v//////8e0iP/DhwD/w4cA/8OHAP/Dhw\r\n" + - " D/w4cA/8OHAOHDhwDhw4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/rItA//39/P/6+vj/w6BQ/8OH\r\n" + - " AP/DhwD/w4cA/8OHAP/DhwDhw4cA4cOHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP+8p3r//v\r\n" + - " 79/+3p4v+8ix3/w4cA/8OHAP/DhwD/w4cA4cOHAOHDhwD/w4cA/8CHB//VsFz/3rxx/926bf/c\r\n" + - " uWv/xadh//Ht5///////1suz/7+HCv/DhwD/w4cA/8OHAOHDhwDhw4cA/8OHAP+wjT//+/r5//\r\n" + - " /////////////////////+/v7///////7+/v+8n17/w4cA/8OHAP/DhwDhw4cAycOHAP/DhwD/\r\n" + - " t4gd/+bYuP/16tP/9OjP//Toz//06M//8+fN//Pozv/t4MH/vZIx/8OHAP/DhwD/w4cAycOHAG\r\n" + - " DDhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA\r\n" + - " /8OHAGAAAAAAw4cAWsOHAMnDhwD8w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/Dhw\r\n" + - " D8w4cAycOHAFoAAAAAgAEAAAAAAAAAAAAAAABoQAAAAAAAAPC/AAAAAAAAAAAAAAAAAAAiQAAA\r\n" + - " AAAAAAAAAAAAAAAAAAAAAAAAgAEAAA==\r\n" + - "X-BUSYMAC-MODIFIED-BY:Gren Elliot\r\n" + - "X-CUSTOM:one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen\r\n" + - "X-CUSTOM:Here are my simple\\nmultiline\\nnotes\r\n" + - "X-CUSTOM;TYPE=pref:semi-colon\\;seperated\\;\"stuff\"\\;here\r\n" + - "X-CUSTOM:comma\\,\"stuff\"\\,'there'\\,too\r\n" + - "X-HOBBY:my backslash\\\\ hobbies\r\n" + - "X-CREATED:2015-04-05T09:50:44Z\r\n" + - "END:VCARD\r\n"; - - @Test - public void testXBusyMacAttach() throws ServiceException, IOException { - String contactsFolderUrl = getFolderUrl(dav1, "Contacts"); - HttpClient client = new HttpClient(); - - PostMethod postMethod = new PostMethod(contactsFolderUrl); - addBasicAuthHeaderForUser(postMethod, dav1); - postMethod.addRequestHeader("Content-Type", "text/vcard"); - postMethod.setRequestEntity(new ByteArrayRequestEntity(smallBusyMacAttach.getBytes(), - MimeConstants.CT_TEXT_VCARD)); - HttpMethodExecutor exe = HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); - String location = null; - for (Header hdr : exe.respHeaders) { - if ("Location".equals(hdr.getName())) { - location = hdr.getValue(); - } - } - assertNotNull("Location Header returned when creating", location); - String url = String.format("%s%s", contactsFolderUrl, location.substring(location.lastIndexOf('/') + 1)); - GetMethod getMethod = new GetMethod(url); - addBasicAuthHeaderForUser(getMethod, dav1); - getMethod.addRequestHeader("Content-Type", "text/vcard"); - exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); - String respBody = new String(exe.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); - String [] expecteds = { - "\r\nX-BUSYMAC-ATTACH;X-FILENAME=favicon.ico;ENCODING=B:AAABAAEAEBAAAAEAIABoBA\r\n", - "\r\n AAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAABMLAAATCwAAAAAAAAAAAAAAAAAAw4cAY8\r\n", - "\r\nX-BUSYMAC-MODIFIED-BY:Gren Elliot\r\n", - "\r\nX-CUSTOM:one two three four five six seven eight nine ten eleven twelve t\r\n hirteen fourteen fifteen", - "\r\nX-CUSTOM:Here are my simple\\Nmultiline\\Nnotes\r\n", - "\r\nX-CUSTOM;TYPE=pref:semi-colon\\;seperated\\;\"stuff\"\\;here\r\n", - "\r\nX-CUSTOM:comma\\,\"stuff\"\\,'there'\\,too\r\n", - "\r\nX-HOBBY:my backslash\\\\ hobbies\r\n", - "\r\nX-CREATED:2015-04-05T09:50:44Z\r\n" }; - for (String expected : expecteds) { - assertTrue(String.format("GET should contain '%s'\nBODY=%s", expected, respBody), - respBody.contains(expected)); - } - - SearchRequest searchRequest = new SearchRequest(); - searchRequest.setSortBy("dateDesc"); - searchRequest.setLimit(8); - searchRequest.setSearchTypes("contact"); - searchRequest.setQuery("in:Contacts"); - ZMailbox mbox = TestUtil.getZMailbox(DAV1); - SearchResponse searchResp = mbox.invokeJaxb(searchRequest); - assertNotNull("JAXB SearchResponse object", searchResp); - List hits = searchResp.getSearchHits(); - assertNotNull("JAXB SearchResponse hits", hits); - assertEquals("JAXB SearchResponse hits", 1, hits.size()); - } - - public static final String expandPropertyGroupMemberSet = - "" + - "" + - " " + - " " + - " " + - " " + - " " + - ""; - - public static final String expandPropertyDelegateFor = - "" + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - ""; - - public static String propPatchGroupMemberSetTemplate = - "" + - "" + - " " + - " " + - " " + - " %%MEMBER%%" + - " " + - " " + - " " + - ""; - private void setZimbraPrefAppleIcalDelegationEnabled(ZMailbox mbox, Boolean val) throws ServiceException { ModifyPrefsRequest modPrefsReq = new ModifyPrefsRequest(); @@ -1834,13 +1574,8 @@ public void testAppleCaldavProxyFunctions() throws ServiceException, IOException } else { exe = doIcalPut(url, sharee1, simpleEvent(sharer), HttpStatus.SC_MOVED_TEMPORARILY); } - String location = null; - for (Header hdr : exe.respHeaders) { - if ("Location".equals(hdr.getName())) { - location = hdr.getValue(); - } - } - assertNotNull("Location Header not returned when creating", location); + String location = + exe.getNonNullHeaderValue("Location", "When creating in shared calendar"); url = String.format("%s%s", getFolderUrl(sharee1, "Shared Calendar"), location.substring(location.lastIndexOf('/') + 1)); @@ -1861,10 +1596,7 @@ public static Document groupMemberSetExpandProperty(Account acct, Account member method.setRequestEntity( new ByteArrayRequestEntity(TestCalDav.expandPropertyGroupMemberSet.getBytes(), MimeConstants.CT_TEXT_XML)); executor = new TestCalDav.HttpMethodExecutor(client, method, HttpStatus.SC_MULTI_STATUS); - String respBody = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); - Document doc = W3cDomUtil.parseXMLToDoc(respBody); - org.w3c.dom.Element docElement = doc.getDocumentElement(); - assertEquals("Report node name", DavElements.P_MULTISTATUS, docElement.getLocalName()); + Document doc = executor.getResponseDoc(DavElements.P_MULTISTATUS); XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(TestCalDav.NamespaceContextForXPath.forCalDAV()); XPathExpression xPathExpr; @@ -1894,11 +1626,7 @@ public static Document delegateForExpandProperty(Account acct) method.setRequestEntity( new ByteArrayRequestEntity(expandPropertyDelegateFor.getBytes(), MimeConstants.CT_TEXT_XML)); executor = new TestCalDav.HttpMethodExecutor(client, method, HttpStatus.SC_MULTI_STATUS); - String respBody = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); - Document doc = W3cDomUtil.parseXMLToDoc(respBody); - org.w3c.dom.Element docElement = doc.getDocumentElement(); - assertEquals("Report node name", DavElements.P_MULTISTATUS, docElement.getLocalName()); - return doc; + return executor.getResponseDoc(DavElements.P_MULTISTATUS); } public static CreateMountpointResponse createCalendarMountPoint(ZMailbox mboxSharee, Account sharer) @@ -1931,10 +1659,7 @@ public static Document setGroupMemberSet(String url, Account acct, Account membe new ByteArrayRequestEntity(body.getBytes(), MimeConstants.CT_TEXT_XML)); executor = new TestCalDav.HttpMethodExecutor(client, method, HttpStatus.SC_MULTI_STATUS); String respBody = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); - Document doc = W3cDomUtil.parseXMLToDoc(respBody); - org.w3c.dom.Element docElement = doc.getDocumentElement(); - assertEquals("Report node name", DavElements.P_MULTISTATUS, docElement.getLocalName()); - return doc; + return executor.getResponseDoc( DavElements.P_MULTISTATUS); } @BeforeClass @@ -1964,21 +1689,11 @@ public void tearDown() throws Exception { } private void cleanUp() throws Exception { - if(TestUtil.accountExists(DAV1)) { - TestUtil.deleteAccount(DAV1); - } - if(TestUtil.accountExists(DAV2)) { - TestUtil.deleteAccount(DAV2); - } - if(TestUtil.accountExists(DAV3)) { - TestUtil.deleteAccount(DAV3); - } - if(TestUtil.accountExists(DAV4)) { - TestUtil.deleteAccount(DAV4); - } - if(TestUtil.accountExists(USER_NAME)) { - TestUtil.deleteAccount(USER_NAME); - } + TestUtil.deleteAccountIfExists(DAV1); + TestUtil.deleteAccountIfExists(DAV2); + TestUtil.deleteAccountIfExists(DAV3); + TestUtil.deleteAccountIfExists(DAV4); + TestUtil.deleteAccountIfExists(USER_NAME); try { TestUtil.deleteDistributionList(DL1); } catch (Exception e) { diff --git a/store/src/java/com/zimbra/qa/unittest/TestCardDav.java b/store/src/java/com/zimbra/qa/unittest/TestCardDav.java new file mode 100644 index 00000000000..2ac94fc5c24 --- /dev/null +++ b/store/src/java/com/zimbra/qa/unittest/TestCardDav.java @@ -0,0 +1,382 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Zimbra Collaboration Suite Server + * Copyright (C) 2017 Synacor, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software Foundation, + * version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * ***** END LICENSE BLOCK ***** + */ +package com.zimbra.qa.unittest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +import com.zimbra.client.ZFolder; +import com.zimbra.client.ZFolder.View; +import com.zimbra.client.ZMailbox; +import com.zimbra.common.account.Key.AccountBy; +import com.zimbra.common.mime.MimeConstants; +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.dav.DavProtocol; +import com.zimbra.cs.dav.service.DavServlet; +import com.zimbra.qa.unittest.TestCalDav.HttpMethodExecutor; +import com.zimbra.qa.unittest.TestCalDav.MkColMethod; +import com.zimbra.soap.mail.message.SearchRequest; +import com.zimbra.soap.mail.message.SearchResponse; +import com.zimbra.soap.mail.type.ContactInfo; +import com.zimbra.soap.type.SearchHit; + +import net.fortuna.ical4j.model.TimeZoneRegistry; +import net.fortuna.ical4j.model.TimeZoneRegistryFactory; + +public class TestCardDav { + + @Rule + public TestName testInfo = new TestName(); + + static final TimeZoneRegistry tzRegistry = TimeZoneRegistryFactory.getInstance().createRegistry(); + private static String DAV1; + + private Account dav1; + + private static String rachelVcard = + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\n" + + "FN:La Rochelle\n" + + "N:Rochelle;La;;;\n" + + "EMAIL;TYPE=internet:rachel@fun.org\n" + + "CATEGORIES:BlueGroup\n" + + "REV:2015-04-04T13:55:56Z\n" + + "UID:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE\n" + + "X-BUSYMAC-MODIFIED-BY:Gren Elliot\n" + + "X-CREATED:2015-04-04T13:55:25Z\n" + + "END:VCARD\n"; + + private static String blueGroupCreate = + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\n" + + "FN:BlueGroup\n" + + "N:BlueGroup\n" + + "REV:2015-04-04T13:55:56Z\n" + + "UID:F53A6F96-566F-46CC-8D48-A5263FAB5E38\n" + + "X-ADDRESSBOOKSERVER-KIND:group\n" + + "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE\n" + + "END:VCARD\n"; + + private static String parisVcard = + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "FN:Paris Match\n" + + "N:Match;Paris;;;\n" + + "EMAIL;TYPE=internet:match@paris.fr\n" + + "CATEGORIES:BlueGroup\n" + + "REV:2015-04-04T13:56:50Z\n" + + "UID:BE43F16D-336E-4C3E-BAE6-22B8F245A986\n" + + "END:VCARD\n"; + + private static String blueGroupModify = + "BEGIN:VCARD\n" + + "VERSION:3.0\n" + + "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\n" + + "FN:BlueGroup\n" + + "N:BlueGroup\n" + + "REV:2015-04-04T13:56:50Z\n" + + "UID:F53A6F96-566F-46CC-8D48-A5263FAB5E38\n" + + "X-ADDRESSBOOKSERVER-KIND:group\n" + + "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:BE43F16D-336E-4C3E-BAE6-22B8F245A986\n" + + "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE\n" + + "END:VCARD\n"; + + public static String simpleVcard = "BEGIN:VCARD\r\n" + + "VERSION:3.0\r\n" + + "FN:TestCal\r\n" + + "N:Dog;Scruffy\r\n" + + "EMAIL;TYPE=INTERNET,PREF:scruffy@example.com\r\n" + + "UID:SCRUFF1\r\n" + + "END:VCARD\r\n"; + + private static String smallBusyMacAttach = + "BEGIN:VCARD\r\n" + + "VERSION:3.0\r\n" + + "PRODID:-//BusyMac LLC//BusyContacts 1.0.2//EN\r\n" + + "FN:John Smith\r\n" + + "N:Smith;John;;;\r\n" + + "REV:2015-04-05T09:51:09Z\r\n" + + "UID:99E01E16-03B3-4487-AAEF-AEB496852C06\r\n" + + "X-BUSYMAC-ATTACH;ENCODING=b;X-FILENAME=favicon.ico:AAABAAEAEBAAAAEAIABoBAAA\r\n" + + " FgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAABMLAAATCwAAAAAAAAAAAAAAAAAAw4cAY8OHAM\r\n" + + " nDhwD8w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD8w4cAycOHAGMAAAAAw4cA\r\n" + + " Y8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/Dhw\r\n" + + " D/w4cAY8OHAMnDhwD/w4cA/7yYSv/y5Mb/8uXH//Llx//z5sr/8+bK//Pmyv/z58v/8+bK/8qq\r\n" + + " Y//DhwD/w4cA/8OHAMnDhwDhw4cA/8OHAP++q4D///////////////7////+//////////////\r\n" + + " /////////Yyan/w4cA/8OHAP/DhwDhw4cA4cOHAP/DhwD/t4QR/9/azv//////5t3K/9StVv/b\r\n" + + " t2b/27dm/9u3Z//cuGn/wpAh/8OHAP/DhwD/w4cA4cOHAOHDhwD/w4cA/8OHAP+2jzr/+fj2//\r\n" + + " n49f/BnU7/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAOHDhwDhw4cA/8OHAP/DhwD/\r\n" + + " w4cA/7ihbf//////8u/p/8GRJv/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwDhw4cA4cOHAP\r\n" + + " /DhwD/w4cA/8OHAP/BhgP/0siz///////d1L//wYgI/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA\r\n" + + " 4cOHAOHDhwD/w4cA/8OHAP/DhwD/w4cA/7eIIP/n49v//////8e0iP/DhwD/w4cA/8OHAP/Dhw\r\n" + + " D/w4cA/8OHAOHDhwDhw4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/rItA//39/P/6+vj/w6BQ/8OH\r\n" + + " AP/DhwD/w4cA/8OHAP/DhwDhw4cA4cOHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP+8p3r//v\r\n" + + " 79/+3p4v+8ix3/w4cA/8OHAP/DhwD/w4cA4cOHAOHDhwD/w4cA/8CHB//VsFz/3rxx/926bf/c\r\n" + + " uWv/xadh//Ht5///////1suz/7+HCv/DhwD/w4cA/8OHAOHDhwDhw4cA/8OHAP+wjT//+/r5//\r\n" + + " /////////////////////+/v7///////7+/v+8n17/w4cA/8OHAP/DhwDhw4cAycOHAP/DhwD/\r\n" + + " t4gd/+bYuP/16tP/9OjP//Toz//06M//8+fN//Pozv/t4MH/vZIx/8OHAP/DhwD/w4cAycOHAG\r\n" + + " DDhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA\r\n" + + " /8OHAGAAAAAAw4cAWsOHAMnDhwD8w4cA/8OHAP/DhwD/w4cA/8OHAP/DhwD/w4cA/8OHAP/Dhw\r\n" + + " D8w4cAycOHAFoAAAAAgAEAAAAAAAAAAAAAAABoQAAAAAAAAPC/AAAAAAAAAAAAAAAAAAAiQAAA\r\n" + + " AAAAAAAAAAAAAAAAAAAAAAAAgAEAAA==\r\n" + + "X-BUSYMAC-MODIFIED-BY:Gren Elliot\r\n" + + "X-CUSTOM:one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen\r\n" + + "X-CUSTOM:Here are my simple\\nmultiline\\nnotes\r\n" + + "X-CUSTOM;TYPE=pref:semi-colon\\;seperated\\;\"stuff\"\\;here\r\n" + + "X-CUSTOM:comma\\,\"stuff\"\\,'there'\\,too\r\n" + + "X-HOBBY:my backslash\\\\ hobbies\r\n" + + "X-CREATED:2015-04-05T09:50:44Z\r\n" + + "END:VCARD\r\n"; + + @Before + public void setUp() throws Exception { + if (!TestUtil.fromRunUnitTests) { + TestUtil.cliSetup(); + } + DAV1 = "carddav-" + testInfo.getMethodName().toLowerCase() + "-dav1"; + cleanUp(); + dav1 = TestUtil.createAccount(DAV1); + } + + @After + public void cleanUp() throws Exception { + TestUtil.deleteAccountIfExists(DAV1); + } + @Test + public void badBasicAuthToContacts() throws Exception { + String calFolderUrl = TestCalDav.getFolderUrl(dav1, "Contacts"); + HttpClient client = new HttpClient(); + GetMethod method = new GetMethod(calFolderUrl); + TestCalDav.addBasicAuthHeaderForUser(method, dav1, "badPassword"); + HttpMethodExecutor.execute(client, method, HttpStatus.SC_UNAUTHORIZED); + } + + @Test + public void mkcol4addressBook() throws Exception { + String xml = "" + + " " + + " " + + " " + + " " + + " " + + " " + + " OtherContacts" + + " Extra Contacts" + + " " + + " " + + ""; + StringBuilder url = TestCalDav.getLocalServerRoot(); + url.append(DavServlet.DAV_PATH).append("/").append(dav1.getName()).append("/OtherContacts/"); + MkColMethod method = new MkColMethod(url.toString()); + TestCalDav.addBasicAuthHeaderForUser(method, dav1); + HttpClient client = new HttpClient(); + method.addRequestHeader("Content-Type", MimeConstants.CT_TEXT_XML); + method.setRequestEntity(new ByteArrayRequestEntity(xml.getBytes(), MimeConstants.CT_TEXT_XML)); + HttpMethodExecutor.execute(client, method, HttpStatus.SC_MULTI_STATUS); + + ZMailbox.Options options = new ZMailbox.Options(); + options.setAccount(dav1.getName()); + options.setAccountBy(AccountBy.name); + options.setPassword(TestUtil.DEFAULT_PASSWORD); + options.setUri(TestUtil.getSoapUrl()); + options.setNoSession(true); + ZMailbox mbox = ZMailbox.getMailbox(options); + ZFolder folder = mbox.getFolderByPath("/OtherContacts"); + assertEquals("OtherContacts", folder.getName()); + assertEquals("OtherContacts default view", View.contact, folder.getDefaultView()); + } + + @Test + public void createContactWithIfNoneMatchTesting() throws ServiceException, IOException { + String davBaseName = "SCRUFF1.vcf"; // Based on UID + String contactsFolderUrl = TestCalDav.getFolderUrl(dav1, "Contacts"); + String url = String.format("%s%s", contactsFolderUrl, davBaseName); + HttpClient client = new HttpClient(); + PutMethod putMethod = new PutMethod(url); + TestCalDav.addBasicAuthHeaderForUser(putMethod, dav1); + putMethod.addRequestHeader("Content-Type", "text/vcard"); + + putMethod.setRequestEntity( + new ByteArrayRequestEntity(simpleVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); + // Bug 84246 this used to fail with 409 Conflict because we used to require an If-None-Match header + HttpMethodExecutor.execute(client, putMethod, HttpStatus.SC_CREATED); + + // Check that trying to put the same thing again when we don't expect it to exist (i.e. Using If-None-Match + // header) will fail. + putMethod = new PutMethod(url); + TestCalDav.addBasicAuthHeaderForUser(putMethod, dav1); + putMethod.addRequestHeader("Content-Type", "text/vcard"); + putMethod.addRequestHeader(DavProtocol.HEADER_IF_NONE_MATCH, "*"); + putMethod.setRequestEntity( + new ByteArrayRequestEntity(simpleVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); + HttpMethodExecutor.execute(client, putMethod, HttpStatus.SC_PRECONDITION_FAILED); + } + + @Test + public void appleStyleGroup() throws ServiceException, IOException { + String contactsFolderUrl = TestCalDav.getFolderUrl(dav1, "Contacts"); + HttpClient client = new HttpClient(); + + PostMethod postMethod = new PostMethod(contactsFolderUrl); + TestCalDav.addBasicAuthHeaderForUser(postMethod, dav1); + postMethod.addRequestHeader("Content-Type", "text/vcard"); + postMethod.setRequestEntity( + new ByteArrayRequestEntity(rachelVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); + HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); + + postMethod = new PostMethod(contactsFolderUrl); + TestCalDav.addBasicAuthHeaderForUser(postMethod, dav1); + postMethod.addRequestHeader("Content-Type", "text/vcard"); + postMethod.setRequestEntity( + new ByteArrayRequestEntity(blueGroupCreate.getBytes(), MimeConstants.CT_TEXT_VCARD)); + HttpMethodExecutor exe = HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); + String groupLocation = null; + for (Header hdr : exe.respHeaders) { + if ("Location".equals(hdr.getName())) { + groupLocation = hdr.getValue(); + } + } + assertNotNull("Location Header returned when creating Group", groupLocation); + + postMethod = new PostMethod(contactsFolderUrl); + TestCalDav.addBasicAuthHeaderForUser(postMethod, dav1); + postMethod.addRequestHeader("Content-Type", "text/vcard"); + postMethod.setRequestEntity(new ByteArrayRequestEntity(parisVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); + HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); + + String url = String.format("%s%s", contactsFolderUrl, "F53A6F96-566F-46CC-8D48-A5263FAB5E38.vcf"); + PutMethod putMethod = new PutMethod(url); + TestCalDav.addBasicAuthHeaderForUser(putMethod, dav1); + putMethod.addRequestHeader("Content-Type", "text/vcard"); + putMethod.setRequestEntity(new ByteArrayRequestEntity(blueGroupModify.getBytes(), + MimeConstants.CT_TEXT_VCARD)); + HttpMethodExecutor.execute(client, putMethod, HttpStatus.SC_NO_CONTENT); + + GetMethod getMethod = new GetMethod(url); + TestCalDav.addBasicAuthHeaderForUser(getMethod, dav1); + getMethod.addRequestHeader("Content-Type", "text/vcard"); + exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); + String respBody = new String(exe.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); + String [] expecteds = { + "X-ADDRESSBOOKSERVER-KIND:group", + "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:BE43F16D-336E-4C3E-BAE6-22B8F245A986", + "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:07139DE2-EA7B-46CB-A970-C4DF7F72D9AE" }; + for (String expected : expecteds) { + assertTrue(String.format("GET should contain '%s'\nBODY=%s", expected, respBody), + respBody.contains(expected)); + } + + // members are actually stored in a different way. Make sure it isn't a fluke + // that the GET response contained the correct members by checking that the members + // appear where expected in a search hit. + SearchRequest searchRequest = new SearchRequest(); + searchRequest.setSortBy("dateDesc"); + searchRequest.setLimit(8); + searchRequest.setSearchTypes("contact"); + searchRequest.setQuery("in:Contacts"); + ZMailbox mbox = TestUtil.getZMailbox(DAV1); + SearchResponse searchResp = mbox.invokeJaxb(searchRequest); + assertNotNull("JAXB SearchResponse object", searchResp); + List hits = searchResp.getSearchHits(); + assertNotNull("JAXB SearchResponse hits", hits); + assertEquals("JAXB SearchResponse hits", 3, hits.size()); + boolean seenGroup = false; + for (SearchHit hit : hits) { + ContactInfo contactInfo = (ContactInfo) hit; + if ("BlueGroup".equals(contactInfo.getFileAs())) { + seenGroup = true; + assertEquals("Number of members of group in search hit", + 2, contactInfo.getContactGroupMembers().size()); + } + ZimbraLog.test.info("Hit %s class=%s", hit, hit.getClass().getName()); + } + assertTrue("Seen group", seenGroup); + } + + @Test + public void xBusyMacAttach() throws ServiceException, IOException { + String contactsFolderUrl = TestCalDav.getFolderUrl(dav1, "Contacts"); + HttpClient client = new HttpClient(); + + PostMethod postMethod = new PostMethod(contactsFolderUrl); + TestCalDav.addBasicAuthHeaderForUser(postMethod, dav1); + postMethod.addRequestHeader("Content-Type", "text/vcard"); + postMethod.setRequestEntity(new ByteArrayRequestEntity(smallBusyMacAttach.getBytes(), + MimeConstants.CT_TEXT_VCARD)); + HttpMethodExecutor exe = HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); + String location = null; + for (Header hdr : exe.respHeaders) { + if ("Location".equals(hdr.getName())) { + location = hdr.getValue(); + } + } + assertNotNull("Location Header returned when creating", location); + String url = String.format("%s%s", contactsFolderUrl, location.substring(location.lastIndexOf('/') + 1)); + GetMethod getMethod = new GetMethod(url); + TestCalDav.addBasicAuthHeaderForUser(getMethod, dav1); + getMethod.addRequestHeader("Content-Type", "text/vcard"); + exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); + String respBody = new String(exe.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); + String [] expecteds = { + "\r\nX-BUSYMAC-ATTACH;X-FILENAME=favicon.ico;ENCODING=B:AAABAAEAEBAAAAEAIABoBA\r\n", + "\r\n AAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAABMLAAATCwAAAAAAAAAAAAAAAAAAw4cAY8\r\n", + "\r\nX-BUSYMAC-MODIFIED-BY:Gren Elliot\r\n", + "\r\nX-CUSTOM:one two three four five six seven eight nine ten eleven twelve t\r\n hirteen fourteen fifteen", + "\r\nX-CUSTOM:Here are my simple\\Nmultiline\\Nnotes\r\n", + "\r\nX-CUSTOM;TYPE=pref:semi-colon\\;seperated\\;\"stuff\"\\;here\r\n", + "\r\nX-CUSTOM:comma\\,\"stuff\"\\,'there'\\,too\r\n", + "\r\nX-HOBBY:my backslash\\\\ hobbies\r\n", + "\r\nX-CREATED:2015-04-05T09:50:44Z\r\n" }; + for (String expected : expecteds) { + assertTrue(String.format("GET should contain '%s'\nBODY=%s", expected, respBody), + respBody.contains(expected)); + } + + SearchRequest searchRequest = new SearchRequest(); + searchRequest.setSortBy("dateDesc"); + searchRequest.setLimit(8); + searchRequest.setSearchTypes("contact"); + searchRequest.setQuery("in:Contacts"); + ZMailbox mbox = TestUtil.getZMailbox(DAV1); + SearchResponse searchResp = mbox.invokeJaxb(searchRequest); + assertNotNull("JAXB SearchResponse object", searchResp); + List hits = searchResp.getSearchHits(); + assertNotNull("JAXB SearchResponse hits", hits); + assertEquals("JAXB SearchResponse hits", 1, hits.size()); + } +} diff --git a/store/src/java/com/zimbra/qa/unittest/ZimbraSuite.java b/store/src/java/com/zimbra/qa/unittest/ZimbraSuite.java index b2f2540e0b3..6c33093dc1c 100644 --- a/store/src/java/com/zimbra/qa/unittest/ZimbraSuite.java +++ b/store/src/java/com/zimbra/qa/unittest/ZimbraSuite.java @@ -109,6 +109,7 @@ public class ZimbraSuite { sClasses.add(TestJaxbProvisioning.class); sClasses.add(TestAclPush.class); sClasses.add(TestCalDav.class); + sClasses.add(TestCardDav.class); sClasses.add(TestCalDavImportServer.class); sClasses.add(TestContactCSV.class); sClasses.add(TestStoreManager.class); From 2c90501d11694c87f6afb457d398f47b8f4e8233 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 27 Sep 2017 09:41:07 +0100 Subject: [PATCH 135/142] ZCS-2572:TestCardDav.createInSharedAddressBook --- .../com/zimbra/qa/unittest/TestCardDav.java | 189 +++++++++++++++--- 1 file changed, 166 insertions(+), 23 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/TestCardDav.java b/store/src/java/com/zimbra/qa/unittest/TestCardDav.java index 2ac94fc5c24..0d0600e5544 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestCardDav.java +++ b/store/src/java/com/zimbra/qa/unittest/TestCardDav.java @@ -19,11 +19,19 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; +import java.util.Collections; import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; -import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; @@ -35,16 +43,22 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import com.google.common.collect.Maps; import com.zimbra.client.ZFolder; import com.zimbra.client.ZFolder.View; import com.zimbra.client.ZMailbox; import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.mime.MimeConstants; import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.XmlParseException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Account; +import com.zimbra.cs.dav.DavElements; import com.zimbra.cs.dav.DavProtocol; +import com.zimbra.cs.dav.resource.UrlNamespace; import com.zimbra.cs.dav.service.DavServlet; import com.zimbra.qa.unittest.TestCalDav.HttpMethodExecutor; import com.zimbra.qa.unittest.TestCalDav.MkColMethod; @@ -53,19 +67,26 @@ import com.zimbra.soap.mail.type.ContactInfo; import com.zimbra.soap.type.SearchHit; -import net.fortuna.ical4j.model.TimeZoneRegistry; -import net.fortuna.ical4j.model.TimeZoneRegistryFactory; - public class TestCardDav { @Rule public TestName testInfo = new TestName(); - - static final TimeZoneRegistry tzRegistry = TimeZoneRegistryFactory.getInstance().createRegistry(); private static String DAV1; + private static String DAV2; private Account dav1; + public static final Map carddavNSMap; + static { + Map aMap = Maps.newHashMapWithExpectedSize(2); + aMap.put("D", DavElements.WEBDAV_NS_STRING); + aMap.put("C", DavElements.CARDDAV_NS_STRING); + aMap.put("CS", DavElements.CS_NS_STRING); + aMap.put("A", DavElements.APPLE_NS_STRING); + aMap.put("Y", DavElements.YAHOO_NS_STRING); + carddavNSMap = Collections.unmodifiableMap(aMap); + } + private static String rachelVcard = "BEGIN:VCARD\n" + "VERSION:3.0\n" + @@ -163,12 +184,37 @@ public class TestCardDav { "X-CREATED:2015-04-05T09:50:44Z\r\n" + "END:VCARD\r\n"; + // iOS/11.0 (15A372) + private static String iosContactsPropfind = + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n"; + @Before public void setUp() throws Exception { if (!TestUtil.fromRunUnitTests) { TestUtil.cliSetup(); } DAV1 = "carddav-" + testInfo.getMethodName().toLowerCase() + "-dav1"; + DAV2 = "carddav-" + testInfo.getMethodName().toLowerCase() + "-dav2"; cleanUp(); dav1 = TestUtil.createAccount(DAV1); } @@ -176,9 +222,24 @@ public void setUp() throws Exception { @After public void cleanUp() throws Exception { TestUtil.deleteAccountIfExists(DAV1); + TestUtil.deleteAccountIfExists(DAV2); + } + + public static Document doIosContactsPropOnAddressbookHomeSet(Account acct) + throws IOException, XmlParseException { + TestCalDav.PropFindMethod method = new TestCalDav.PropFindMethod( + TestCalDav.getFullUrl(UrlNamespace.getAddressbookHomeSetUrl(acct.getName()))); + method.addRequestHeader("Depth", "1"); + method.addRequestHeader("Brief", "t"); + method.addRequestHeader("Prefer", "return=minimal"); + method.addRequestHeader("Accept", "*/*"); + Document doc = TestCalDav.doMethodYieldingMultiStatus(method, acct, iosContactsPropfind); + return doc; } + @Test public void badBasicAuthToContacts() throws Exception { + assertNotNull("Test account object", dav1); String calFolderUrl = TestCalDav.getFolderUrl(dav1, "Contacts"); HttpClient client = new HttpClient(); GetMethod method = new GetMethod(calFolderUrl); @@ -223,6 +284,7 @@ public void mkcol4addressBook() throws Exception { @Test public void createContactWithIfNoneMatchTesting() throws ServiceException, IOException { + assertNotNull("Test account object", dav1); String davBaseName = "SCRUFF1.vcf"; // Based on UID String contactsFolderUrl = TestCalDav.getFolderUrl(dav1, "Contacts"); String url = String.format("%s%s", contactsFolderUrl, davBaseName); @@ -265,18 +327,13 @@ public void appleStyleGroup() throws ServiceException, IOException { postMethod.setRequestEntity( new ByteArrayRequestEntity(blueGroupCreate.getBytes(), MimeConstants.CT_TEXT_VCARD)); HttpMethodExecutor exe = HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); - String groupLocation = null; - for (Header hdr : exe.respHeaders) { - if ("Location".equals(hdr.getName())) { - groupLocation = hdr.getValue(); - } - } - assertNotNull("Location Header returned when creating Group", groupLocation); + exe.getNonNullHeaderValue("Location", "When creating Group"); postMethod = new PostMethod(contactsFolderUrl); TestCalDav.addBasicAuthHeaderForUser(postMethod, dav1); postMethod.addRequestHeader("Content-Type", "text/vcard"); - postMethod.setRequestEntity(new ByteArrayRequestEntity(parisVcard.getBytes(), MimeConstants.CT_TEXT_VCARD)); + postMethod.setRequestEntity(new ByteArrayRequestEntity(parisVcard.getBytes(), + MimeConstants.CT_TEXT_VCARD)); HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); String url = String.format("%s%s", contactsFolderUrl, "F53A6F96-566F-46CC-8D48-A5263FAB5E38.vcf"); @@ -291,7 +348,7 @@ public void appleStyleGroup() throws ServiceException, IOException { TestCalDav.addBasicAuthHeaderForUser(getMethod, dav1); getMethod.addRequestHeader("Content-Type", "text/vcard"); exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); - String respBody = new String(exe.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); + String respBody = exe.getResponseAsString(); String [] expecteds = { "X-ADDRESSBOOKSERVER-KIND:group", "X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:BE43F16D-336E-4C3E-BAE6-22B8F245A986", @@ -339,19 +396,13 @@ public void xBusyMacAttach() throws ServiceException, IOException { postMethod.setRequestEntity(new ByteArrayRequestEntity(smallBusyMacAttach.getBytes(), MimeConstants.CT_TEXT_VCARD)); HttpMethodExecutor exe = HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); - String location = null; - for (Header hdr : exe.respHeaders) { - if ("Location".equals(hdr.getName())) { - location = hdr.getValue(); - } - } - assertNotNull("Location Header returned when creating", location); + String location = exe.getNonNullHeaderValue("Location", "When creating VCARD"); String url = String.format("%s%s", contactsFolderUrl, location.substring(location.lastIndexOf('/') + 1)); GetMethod getMethod = new GetMethod(url); TestCalDav.addBasicAuthHeaderForUser(getMethod, dav1); getMethod.addRequestHeader("Content-Type", "text/vcard"); exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); - String respBody = new String(exe.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); + String respBody = exe.getResponseAsString(); String [] expecteds = { "\r\nX-BUSYMAC-ATTACH;X-FILENAME=favicon.ico;ENCODING=B:AAABAAEAEBAAAAEAIABoBA\r\n", "\r\n AAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAABMLAAATCwAAAAAAAAAAAAAAAAAAw4cAY8\r\n", @@ -379,4 +430,96 @@ public void xBusyMacAttach() throws ServiceException, IOException { assertNotNull("JAXB SearchResponse hits", hits); assertEquals("JAXB SearchResponse hits", 1, hits.size()); } + + private String sharedContactFolderName() throws ServiceException { + ZMailbox sharerZmbox = TestUtil.getZMailbox(DAV2); + return String.format("%s's Contacts", sharerZmbox.getName()); + } + + private void shareContacts() throws ServiceException { + ZMailbox sharerZmbox = TestUtil.getZMailbox(DAV2); + ZMailbox shareeZmbox = TestUtil.getZMailbox(DAV1); + TestUtil.createMountpoint(sharerZmbox, "Contacts", shareeZmbox, sharedContactFolderName()); + } + + @Test(timeout=100000) + public void createInSharedAddressBook() throws ServiceException, IOException { + Account dav2 = TestUtil.createAccount(DAV2); + assertNotNull("Test account object", dav2); + shareContacts(); + String contactsFolderUrl = TestCalDav.getFolderUrl(dav1, sharedContactFolderName()); + HttpClient client = new HttpClient(); + + PostMethod postMethod = new PostMethod(contactsFolderUrl); + TestCalDav.addBasicAuthHeaderForUser(postMethod, dav1); + postMethod.addRequestHeader("Content-Type", "text/vcard"); + postMethod.setRequestEntity(new ByteArrayRequestEntity(parisVcard.getBytes(), + MimeConstants.CT_TEXT_VCARD)); + HttpMethodExecutor exe = HttpMethodExecutor.execute(client, postMethod, HttpStatus.SC_CREATED); + String location = + exe.getNonNullHeaderValue("Location", "When creating VCARD in shared address book"); + String url = String.format("%s%s",contactsFolderUrl, + location.substring(location.lastIndexOf('/') + 1)); + GetMethod getMethod = new GetMethod(url); + TestCalDav.addBasicAuthHeaderForUser(getMethod, dav1); + getMethod.addRequestHeader("Content-Type", "text/vcard"); + exe = HttpMethodExecutor.execute(client, getMethod, HttpStatus.SC_OK); + } + + @Test(timeout=100000) + public void iosContactsPropfindABHome() throws ServiceException, IOException { + Account dav2 = TestUtil.createAccount(DAV2); + assertNotNull("Test account object", dav2); + shareContacts(); + XPath xpath = XPathFactory.newInstance().newXPath(); + xpath.setNamespaceContext(TestCalDav.NamespaceContextForXPath.forCardDAV()); + Document propfindResponseDoc = doIosContactsPropOnAddressbookHomeSet(dav1); + try { + String mpResp = "/D:multistatus/D:response"; + String collectionXp = "D:propstat/D:prop/D:resourcetype/D:collection"; + String abXp = "D:propstat/D:prop/D:resourcetype/C:addressbook"; + String mpXp = "D:propstat/D:prop/D:resourcetype/Y:mountpoint"; + XPathExpression respNodesExpression = xpath.compile(mpResp); + XPathExpression hrefTextExpression = xpath.compile("D:href/text()"); + XPathExpression collectionExpression = xpath.compile(collectionXp); + XPathExpression abExpression = xpath.compile(abXp); + XPathExpression mpExpression = xpath.compile(mpXp); + NodeList responseNodes = (NodeList) respNodesExpression.evaluate( + propfindResponseDoc, XPathConstants.NODESET); + assertNotNull("No response nodes found in multistatus response to PROPFIND", responseNodes); + boolean seenShare = false; + String expectedShareHref = UrlNamespace.getFolderUrl(dav1.getName(), sharedContactFolderName()) + .replaceAll(" ", "%20").replaceAll("@", "%40"); + for (int ndx = 0; ndx < responseNodes.getLength(); ndx++) { + org.w3c.dom.Element respNode = (org.w3c.dom.Element) responseNodes.item(ndx); + String text = (String) hrefTextExpression.evaluate(respNode, XPathConstants.STRING); + if (expectedShareHref.equals(text)) { + seenShare = true; + NodeList colNodes = (NodeList) collectionExpression.evaluate( + respNode, XPathConstants.NODESET); + assertNotNull(String.format("No %s/%s elements present for shared addressbook", + mpResp, collectionXp), colNodes); + assertEquals(String.format("Number of %s/%s elements present for shared addressbook", + mpResp, collectionXp), 1, colNodes.getLength()); + + NodeList abNodes = (NodeList) abExpression.evaluate(respNode, XPathConstants.NODESET); + assertNotNull(String.format("No %s/%s elements present for shared addressbook", + mpResp, abXp), abNodes); + assertEquals(String.format("Number of %s/%s elements present for shared addressbook", + mpResp, abXp), 1, abNodes.getLength()); + + NodeList mpNodes = (NodeList) mpExpression.evaluate(respNode, XPathConstants.NODESET); + assertNotNull(String.format("No %s/%s elements present for shared addressbook", + mpResp, mpXp), mpNodes); + assertEquals(String.format("Number of %s/%s elements present for shared addressbook", + mpResp, mpXp), 1, mpNodes.getLength()); + break; + } + } + assertTrue("Should have been response node in multistatus for shared addressbook", seenShare); + } catch (XPathExpressionException e) { + ZimbraLog.test.warn("xpath problem", e); + fail("Problem with XPath expression"); + } + } } From 1e0d95d70c7a4c3675effef36ca1d751c4ee96f8 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Wed, 27 Sep 2017 13:31:53 +0100 Subject: [PATCH 136/142] ZCS-2572:Escape more '@' with %40 in http hrefs --- .../src/java/com/zimbra/cs/dav/property/ResourceProperty.java | 2 +- store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java | 4 ++-- store/src/java/com/zimbra/cs/dav/service/DavServlet.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/store/src/java/com/zimbra/cs/dav/property/ResourceProperty.java b/store/src/java/com/zimbra/cs/dav/property/ResourceProperty.java index 0e54dc38f83..af44145c03a 100644 --- a/store/src/java/com/zimbra/cs/dav/property/ResourceProperty.java +++ b/store/src/java/com/zimbra/cs/dav/property/ResourceProperty.java @@ -171,7 +171,7 @@ public void setVisible(boolean v) { protected Element createHref(String path) { Element e = org.dom4j.DocumentHelper.createElement(DavElements.E_HREF); - e.setText(HttpUtil.urlEscape(path)); + e.setText(HttpUtil.urlEscape(path).replaceAll("@", "%40")); return e; } diff --git a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java index a8f7212974f..0440670069d 100644 --- a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java +++ b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java @@ -276,7 +276,7 @@ public static String getAclUrl(String principal, String type) throws DavExceptio buf.append(account.getName()); else buf.append(principal); - return getAbsoluteUrl(null, buf.toString()); + return getAbsoluteUrl(null, buf.toString().replaceAll("@", "%40")); } catch (ServiceException e) { throw new DavException("cannot create ACL URL for principal "+principal, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); } @@ -337,7 +337,7 @@ public static String getCalendarProxyWriteUrl(Account authAccount, Account targe } public static String getPrincipalUrl(String user) { - return HttpUtil.urlEscape(PRINCIPALS_PATH + user + "/"); + return HttpUtil.urlEscape(PRINCIPALS_PATH + user + "/").replaceAll("@", "%40"); } public static String getPrincipalCollectionUrl(Account acct) throws ServiceException { diff --git a/store/src/java/com/zimbra/cs/dav/service/DavServlet.java b/store/src/java/com/zimbra/cs/dav/service/DavServlet.java index a60cd88478c..1f8f5f9e801 100644 --- a/store/src/java/com/zimbra/cs/dav/service/DavServlet.java +++ b/store/src/java/com/zimbra/cs/dav/service/DavServlet.java @@ -431,7 +431,7 @@ public static String getDavUrl(String user) throws DavException, ServiceExceptio Account account = prov.get(AccountBy.name, user); if (account == null) throw new DavException("unknown user "+user, HttpServletResponse.SC_NOT_FOUND, null); - return getServiceUrl(account, DAV_PATH); + return getServiceUrl(account, DAV_PATH).replaceAll("@", "%40"); } private boolean isCtagRequest(DavContext ctxt) throws DavException { From 8fc8058d9d6f7224bd273f175ee2d2320d31b280 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 28 Sep 2017 10:42:57 +0100 Subject: [PATCH 137/142] ZCS-2572:UrlNamespace HomeSerUrls Added `getCalendarHomeSetUrl` and `getAddressbookHomeSetUrl` --- .../src/java/com/zimbra/cs/dav/resource/UrlNamespace.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java index 0440670069d..4dd3cdc50cb 100644 --- a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java +++ b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java @@ -344,6 +344,14 @@ public static String getPrincipalCollectionUrl(Account acct) throws ServiceExcep return HttpUtil.urlEscape(PRINCIPALS_PATH); } + public static String getCalendarHomeSetUrl(String authUser) { + return DavServlet.DAV_PATH + "/" + authUser.replaceAll("@", "%40"); + } + + public static String getAddressbookHomeSetUrl(String authUser) { + return getCalendarHomeSetUrl(authUser); + } + public static String getSchedulingInboxUrl(String authUser, String user) { StringBuilder url = new StringBuilder(); // always use authenticated user's inbox. From 21d86e507541664441f46713372a669dc1d17c71 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 28 Sep 2017 12:56:05 +0100 Subject: [PATCH 138/142] UrlNamespace PMD recommended changes --- .../zimbra/cs/dav/resource/UrlNamespace.java | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java index 4dd3cdc50cb..381c0bb915c 100644 --- a/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java +++ b/store/src/java/com/zimbra/cs/dav/resource/UrlNamespace.java @@ -60,6 +60,18 @@ */ public class UrlNamespace { public static final String ATTACHMENTS_PREFIX = "/attachments"; + public static final String PRINCIPALS = "principals"; + public static final String PRINCIPAL_USERS = "users"; + public static final String PRINCIPALS_PATH = "/" + PRINCIPALS + "/" + PRINCIPAL_USERS + "/"; + + public static final String ACL_USER = PRINCIPALS_PATH; + public static final String ACL_GUEST = "/" + PRINCIPALS + "/" + "guests" + "/"; + public static final String ACL_GROUP = "/" + PRINCIPALS + "/" + "groups" + "/"; + public static final String ACL_COS = "/" + PRINCIPALS + "/" + "cos" + "/"; + public static final String ACL_DOMAIN = "/" + PRINCIPALS + "/" + "domain" + "/"; + + private static Map ,Pair>sRenamedResourceMap = + MapUtil.newLruMap(100); public static class UrlComponents { public String user; @@ -72,7 +84,8 @@ public static class UrlComponents { * @return user and path info as UrlComponents */ - public static UrlComponents parseUrl(String url) { + public static UrlComponents parseUrl(String urlToParse) { + String url = urlToParse; UrlComponents uc = new UrlComponents(); int index = url.indexOf(DavServlet.DAV_PATH); @@ -200,7 +213,7 @@ public static java.util.Collection getResources( DavContext ctxt, String user, String path, boolean includeChildren) throws DavException { ArrayList rss = new ArrayList(); - if (user.equals("")) { + if ("".equals(user)) { try { rss.add(new Principal(ctxt.getAuthAccount(), DavServlet.DAV_PATH)); return rss; @@ -254,16 +267,6 @@ public static DavResource getResourceByItemId(DavContext ctxt, String user, int return getResourceFromMailItem(ctxt, item); } - public static final String PRINCIPALS = "principals"; - public static final String PRINCIPAL_USERS = "users"; - public static final String PRINCIPALS_PATH = "/" + PRINCIPALS + "/" + PRINCIPAL_USERS + "/"; - - public static final String ACL_USER = PRINCIPALS_PATH; - public static final String ACL_GUEST = "/" + PRINCIPALS + "/" + "guests" + "/"; - public static final String ACL_GROUP = "/" + PRINCIPALS + "/" + "groups" + "/"; - public static final String ACL_COS = "/" + PRINCIPALS + "/" + "cos" + "/"; - public static final String ACL_DOMAIN = "/" + PRINCIPALS + "/" + "domain" + "/"; - /* RFC 3744 */ public static String getAclUrl(String principal, String type) throws DavException { Account account = null; @@ -396,8 +399,6 @@ private static String getAbsoluteUrl(Account user, String path) throws ServiceEx return DavServlet.getServiceUrl(server, domain, path); } - private static Map ,Pair>sRenamedResourceMap = MapUtil.newLruMap(100); - public static void addToRenamedResource(String user, String path, DavResource rsc) { synchronized (sRenamedResourceMap) { sRenamedResourceMap.put(new Pair(user, path.toLowerCase()), @@ -464,7 +465,7 @@ private static DavResource getMailItemResource(DavContext ctxt, String user, Str MailItem item = null; // simple case. root folder or if id is specified. - if (path.equals("/")) { + if ("/".equals(path)) { item = mbox.getFolderByPath(octxt, "/"); } else if (id > 0) { item = mbox.getItemById(octxt, id, MailItem.Type.UNKNOWN); @@ -644,9 +645,10 @@ public static DavResource getResourceFromMailItem(DavContext ctxt, MailItem item case CONTACT : resource = new AddressObject(ctxt, (Contact)item); break; + default: + break; } } catch (ServiceException e) { - resource = null; ZimbraLog.dav.info("cannot create DavResource", e); } return resource; @@ -725,6 +727,7 @@ private static DavResource getPhantomResource(DavContext ctxt, String user) thro break; default: resource = null; + break; } return resource; From 474b734f43b5e806c9b5656e02b81cd3d44ccb04 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 28 Sep 2017 12:59:13 +0100 Subject: [PATCH 139/142] DavServlet PMD recommended changes --- .../com/zimbra/cs/dav/service/DavServlet.java | 81 +++++++++---------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/store/src/java/com/zimbra/cs/dav/service/DavServlet.java b/store/src/java/com/zimbra/cs/dav/service/DavServlet.java index 1f8f5f9e801..859e04df143 100644 --- a/store/src/java/com/zimbra/cs/dav/service/DavServlet.java +++ b/store/src/java/com/zimbra/cs/dav/service/DavServlet.java @@ -112,6 +112,31 @@ public class DavServlet extends ZimbraServlet { private static Map sMethods; + private static final Set PROXY_REQUEST_HEADERS = ImmutableSet.of( + DavProtocol.HEADER_DAV, + DavProtocol.HEADER_DEPTH, + DavProtocol.HEADER_CONTENT_TYPE, + DavProtocol.HEADER_ETAG, + DavProtocol.HEADER_IF_MATCH, + DavProtocol.HEADER_OVERWRITE, + DavProtocol.HEADER_DESTINATION); + + private static final Set IGNORABLE_PROXY_REQUEST_HEADERS = ImmutableSet.of( + DavProtocol.HEADER_AUTHORIZATION, + DavProtocol.HEADER_HOST, + DavProtocol.HEADER_USER_AGENT, + DavProtocol.HEADER_CONTENT_LENGTH); + + private static final Set PROXY_RESPONSE_HEADERS = ImmutableSet.of( + DavProtocol.HEADER_DAV, + DavProtocol.HEADER_ALLOW, + DavProtocol.HEADER_CONTENT_TYPE, + DavProtocol.HEADER_ETAG, + DavProtocol.HEADER_LOCATION); + + private static final Set IGNORABLE_PROXY_RESPONSE_HEADERS = ImmutableSet.of( + DavProtocol.HEADER_DATE, + DavProtocol.HEADER_CONTENT_LENGTH); @Override public void init() throws ServletException { super.init(); @@ -353,11 +378,9 @@ public void service(HttpServletRequest req, HttpServletResponse resp) throws Ser try { Upload upload = ctxt.getUpload(); if (upload.getSize() > 0 && upload.getContentType().startsWith("text")) { - if (ZimbraLog.dav.isDebugEnabled()) { - StringBuilder logMsg = new StringBuilder("REQUEST\n").append( - new String(ByteUtil.readInput(upload.getInputStream(), -1, 20480), "UTF-8")); - ZimbraLog.dav.debug(logMsg.toString()); - } + StringBuilder logMsg = new StringBuilder("REQUEST\n").append( + new String(ByteUtil.readInput(upload.getInputStream(), -1, 20480), "UTF-8")); + ZimbraLog.dav.debug(logMsg.toString()); } } catch (DavException de) { throw de; @@ -405,11 +428,10 @@ else if (e.getStatus() == HttpServletResponse.SC_MOVED_TEMPORARILY || } catch (IllegalStateException ise) { ZimbraLog.dav.debug("can't write error msg", ise); } + } catch (MailServiceException.NoSuchItemException nsie) { + sendError(resp, HttpServletResponse.SC_NOT_FOUND, ctxt.getUri()+" not found", null, Level.info); + return; } catch (ServiceException e) { - if (e instanceof MailServiceException.NoSuchItemException) { - sendError(resp, HttpServletResponse.SC_NOT_FOUND, ctxt.getUri()+" not found", null, Level.info); - return; - } sendError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "error handling method "+method.getName(), e); } catch (Exception e) { try { @@ -455,13 +477,13 @@ private boolean isCtagRequest(DavContext ctxt) throws DavException { } private static class CacheStates { - boolean ctagCacheEnabled = MemcachedConnector.isConnected(); - boolean gzipAccepted = false; - boolean cacheThisCtagResponse = false; - CtagResponseCacheKey ctagCacheKey = null; - String acctVerSnapshot = null; - Map ctagsSnapshot = null; - CtagResponseCache ctagResponseCache = null; + private final boolean ctagCacheEnabled = MemcachedConnector.isConnected(); + private boolean gzipAccepted = false; + private boolean cacheThisCtagResponse = false; + private CtagResponseCacheKey ctagCacheKey = null; + private String acctVerSnapshot = null; + private Map ctagsSnapshot = null; + private CtagResponseCache ctagResponseCache = null; } private CacheStates checkCachedResponse(DavContext ctxt, Account authUser) throws IOException, DavException, ServiceException { @@ -633,33 +655,6 @@ private void cacheCleanUp(DavContext ctxt, CacheStates cache) throws IOException } } - private static final Set PROXY_REQUEST_HEADERS = ImmutableSet.of( - DavProtocol.HEADER_DAV, - DavProtocol.HEADER_DEPTH, - DavProtocol.HEADER_CONTENT_TYPE, - DavProtocol.HEADER_ETAG, - DavProtocol.HEADER_IF_MATCH, - DavProtocol.HEADER_OVERWRITE, - DavProtocol.HEADER_DESTINATION); - - private static final Set IGNORABLE_PROXY_REQUEST_HEADERS = ImmutableSet.of( - DavProtocol.HEADER_AUTHORIZATION, - DavProtocol.HEADER_HOST, - DavProtocol.HEADER_USER_AGENT, - DavProtocol.HEADER_CONTENT_LENGTH); - - private static final Set PROXY_RESPONSE_HEADERS = ImmutableSet.of( - DavProtocol.HEADER_DAV, - DavProtocol.HEADER_ALLOW, - DavProtocol.HEADER_CONTENT_TYPE, - DavProtocol.HEADER_ETAG, - DavProtocol.HEADER_LOCATION); - - private static final Set IGNORABLE_PROXY_RESPONSE_HEADERS = ImmutableSet.of( - DavProtocol.HEADER_DATE, - DavProtocol.HEADER_CONTENT_LENGTH); - - private boolean isProxyRequest(DavContext ctxt, DavMethod m) throws IOException, DavException, ServiceException { Provisioning prov = Provisioning.getInstance(); ItemId target = null; From f372431efd7ce65ea85f20703755a0c0a78aa797 Mon Sep 17 00:00:00 2001 From: Gren Elliot Date: Thu, 28 Sep 2017 12:59:50 +0100 Subject: [PATCH 140/142] TestCalDav PMD recommended changes --- .../com/zimbra/qa/unittest/TestCalDav.java | 81 ++++++++++--------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/store/src/java/com/zimbra/qa/unittest/TestCalDav.java b/store/src/java/com/zimbra/qa/unittest/TestCalDav.java index 870da68c139..5637f817ce2 100644 --- a/store/src/java/com/zimbra/qa/unittest/TestCalDav.java +++ b/store/src/java/com/zimbra/qa/unittest/TestCalDav.java @@ -109,12 +109,8 @@ import com.zimbra.soap.mail.message.CreateMountpointResponse; import com.zimbra.soap.mail.type.NewMountpointSpec; -import net.fortuna.ical4j.model.TimeZoneRegistry; -import net.fortuna.ical4j.model.TimeZoneRegistryFactory; - public class TestCalDav { - static final TimeZoneRegistry tzRegistry = TimeZoneRegistryFactory.getInstance().createRegistry(); private static String TEST_NAME = "TestCalDav"; private static String USER_NAME = TEST_NAME + "-user1"; private static String DAV1 = TEST_NAME + "dav1"; @@ -135,6 +131,15 @@ public class TestCalDav { private final String[] eventComponents = {"VEVENT", "VFREEBUSY"}; private final String[] todoComponents = {"VTODO", "VFREEBUSY"}; + private static final Map caldavNSMap; + static { + Map aMap = Maps.newHashMapWithExpectedSize(2); + aMap.put("D", DavElements.WEBDAV_NS_STRING); + aMap.put("C", DavElements.CALDAV_NS_STRING); + aMap.put("CS", DavElements.CS_NS_STRING); + caldavNSMap = Collections.unmodifiableMap(aMap); + } + public static final String expandPropertyGroupMemberSet = "" + "" + @@ -166,26 +171,26 @@ public class TestCalDav { " \n" + ""; - static String propFindEtagResType = "" + - " " + - " " + - " " + - " " + - ""; + public static String propFindEtagResType = "" + + " " + + " " + + " " + + " " + + ""; public static String propPatchGroupMemberSetTemplate = - "" + - "" + - " " + - " " + - " " + - " %%MEMBER%%" + - " " + - " " + - " " + - ""; - - static final String calendar_query_etags_by_vevent = + "" + + "" + + " " + + " " + + " " + + " %%MEMBER%%" + + " " + + " " + + " " + + ""; + + public static final String calendar_query_etags_by_vevent = "\n" + " \n" + " \n" + @@ -197,7 +202,7 @@ public class TestCalDav { " \n" + ""; - final String propFindSupportedCalendarComponentSet = + public static final String propFindSupportedCalendarComponentSet = "\n" + " \n" + " \n" + @@ -376,15 +381,6 @@ public ReportMethod(String uri) { } } - private static final Map caldavNSMap; - static { - Map aMap = Maps.newHashMapWithExpectedSize(2); - aMap.put("D", DavElements.WEBDAV_NS_STRING); - aMap.put("C", DavElements.CALDAV_NS_STRING); - aMap.put("CS", DavElements.CS_NS_STRING); - caldavNSMap = Collections.unmodifiableMap(aMap); - } - public static class NamespaceContextForXPath implements javax.xml.namespace.NamespaceContext { private final Map nsMap; @@ -579,6 +575,7 @@ public Document getResponseDoc(String topDocElementName) { @Test public void testBadBasicAuth() throws Exception { + assertNotNull("Test account object", dav1); String calFolderUrl = getFolderUrl(dav1, "Calendar"); HttpClient client = new HttpClient(); GetMethod method = new GetMethod(calFolderUrl); @@ -588,6 +585,7 @@ public void testBadBasicAuth() throws Exception { @Test public void testPostToSchedulingOutbox() throws Exception { + assertNotNull("Test account object", dav1); String url = getSchedulingOutboxUrl(dav1, dav1); HttpClient client = new HttpClient(); PostMethod method = new PostMethod(url); @@ -605,6 +603,7 @@ public void testPostToSchedulingOutbox() throws Exception { @Test public void testBadPostToSchedulingOutbox() throws Exception { + assertNotNull("Test account object", dav2); String url = getSchedulingOutboxUrl(dav2, dav2); HttpClient client = new HttpClient(); PostMethod method = new PostMethod(url); @@ -806,12 +805,14 @@ public void testCalendarQueryOnOutbox() throws Exception { @Test public void testPropFindSupportedReportSetOnInbox() throws Exception { + assertNotNull("Test account object", user1); checkPropFindSupportedReportSet(user1, getSchedulingInboxUrl(user1, user1), UrlNamespace.getSchedulingInboxUrl(user1.getName(), user1.getName())); } @Test public void testPropFindSupportedReportSetOnOutbox() throws Exception { + assertNotNull("Test account object", user1); checkPropFindSupportedReportSet(user1, getSchedulingOutboxUrl(user1, user1), UrlNamespace.getSchedulingOutboxUrl(user1.getName(), user1.getName())); } @@ -918,24 +919,28 @@ public void checkPropFindSupportedCalendarComponentSet(Account user, String full @Test public void testPropFindSupportedCalendarComponentSetOnInbox() throws Exception { + assertNotNull("Test account object", user1); checkPropFindSupportedCalendarComponentSet(user1, getSchedulingInboxUrl(user1, user1), UrlNamespace.getSchedulingInboxUrl(user1.getName(), user1.getName()), componentsForBothTasksAndEvents); } @Test public void testPropFindSupportedCalendarComponentSetOnOutbox() throws Exception { + assertNotNull("Test account object", user1); checkPropFindSupportedCalendarComponentSet(user1, getSchedulingOutboxUrl(user1, user1), UrlNamespace.getSchedulingOutboxUrl(user1.getName(), user1.getName()), componentsForBothTasksAndEvents); } @Test public void testPropFindSupportedCalendarComponentSetOnCalendar() throws Exception { + assertNotNull("Test account object", user1); checkPropFindSupportedCalendarComponentSet(user1, getFolderUrl(user1, "Calendar"), UrlNamespace.getFolderUrl(user1.getName(), "Calendar"), eventComponents); } @Test public void testPropFindSupportedCalendarComponentSetOnTasks() throws Exception { + assertNotNull("Test account object", user1); checkPropFindSupportedCalendarComponentSet(user1, getFolderUrl(user1, "Tasks"), UrlNamespace.getFolderUrl(user1.getName(), "Tasks"), todoComponents); } @@ -1098,7 +1103,7 @@ public void testCreateModifyDeleteAttendeeModifyAndCancel() throws ServiceExcept @Test public void testAndroidMeetingSeries() throws Exception { - ZMailbox dav2MB = TestUtil.getZMailbox(DAV2); // Force creation of mailbox - shouldn't be needed + TestUtil.getZMailbox(DAV2); // Force creation of mailbox - shouldn't be needed String calFolderUrl = getFolderUrl(dav1, "Calendar"); String url = String.format("%s%s.ics", calFolderUrl, androidSeriesMeetingUid); HttpClient client = new HttpClient(); @@ -1235,6 +1240,7 @@ public ZVCalendar simpleMeeting(Account organizer, List attendees, S @Test public void testSimpleMkcol() throws Exception { + assertNotNull("Test account object", dav1); StringBuilder url = getLocalServerRoot(); url.append(DavServlet.DAV_PATH).append("/").append(dav1.getName()).append("/simpleMkcol/"); MkColMethod method = new MkColMethod(url.toString()); @@ -1379,7 +1385,7 @@ public void testPropPatchCalendarFreeBusySetSettingUsingEscapedUrls() throws Exc } @Test - public void testFuzzyTimeZoneMatchGMT_06() throws Exception { + public void testFuzzyTimeZoneMatchGMT06() throws Exception { try (ByteArrayInputStream bais = new ByteArrayInputStream(VtimeZoneGMT_0600_0500.getBytes())) { ZVCalendar tzcal = ZCalendar.ZCalendarBuilder.build(bais, MimeConstants.P_CHARSET_UTF8); assertNotNull("tzcal", tzcal); @@ -1393,7 +1399,7 @@ public void testFuzzyTimeZoneMatchGMT_06() throws Exception { } @Test - public void testFuzzyTimeZoneMatchGMT_08() throws Exception { + public void testFuzzyTimeZoneMatchGMT08() throws Exception { try (ByteArrayInputStream bais = new ByteArrayInputStream(VtimeZoneGMT_0800_0700.getBytes())) { ZVCalendar tzcal = ZCalendar.ZCalendarBuilder.build(bais, MimeConstants.P_CHARSET_UTF8); assertNotNull("tzcal", tzcal); @@ -1444,7 +1450,7 @@ private void attendeeDeleteFromCalendar(boolean suppressReply) throws Exception addBasicAuthHeaderForUser(method, dav1); ZMailbox organizer = TestUtil.getZMailbox(DAV2); - ZMailbox dav1MB = TestUtil.getZMailbox(DAV1); // Force creation of mailbox - shouldn't be needed + TestUtil.getZMailbox(DAV1); // Force creation of mailbox - shouldn't be needed String subject = String.format("%s %s", TEST_NAME, suppressReply ? "testInvite which shouldNOT be replied to" : "testInvite to be auto-declined"); Date startDate = new Date(System.currentTimeMillis() + Constants.MILLIS_PER_DAY); @@ -1484,11 +1490,13 @@ private void attendeeDeleteFromCalendar(boolean suppressReply) throws Exception @Test public void testAttendeeAutoDecline() throws Exception { + assertNotNull("Test account object", dav1); attendeeDeleteFromCalendar(false /* suppressReply */); } @Test public void testAttendeeSuppressedAutoDecline() throws Exception { + assertNotNull("Test account object", dav1); attendeeDeleteFromCalendar(true /* suppressReply */); } @@ -1658,7 +1666,6 @@ public static Document setGroupMemberSet(String url, Account acct, Account membe method.setRequestEntity( new ByteArrayRequestEntity(body.getBytes(), MimeConstants.CT_TEXT_XML)); executor = new TestCalDav.HttpMethodExecutor(client, method, HttpStatus.SC_MULTI_STATUS); - String respBody = new String(executor.responseBodyBytes, MimeConstants.P_CHARSET_UTF8); return executor.getResponseDoc( DavElements.P_MULTISTATUS); } From a937046f7e220d3ee37c642b206fb70bf8307d76 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Mon, 9 Oct 2017 12:58:05 +0530 Subject: [PATCH 141/142] ZCS-3132 Fixing NG attributes --- .../common/account/ZAttrProvisioning.java | 22 +-- store/conf/attrs/zimbra-attrs.xml | 15 +- .../com/zimbra/cs/account/ZAttrConfig.java | 174 +----------------- .../com/zimbra/cs/account/ZAttrServer.java | 174 +----------------- .../admin/GetAdminExtensionZimlets.java | 22 +-- 5 files changed, 34 insertions(+), 373 deletions(-) diff --git a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java index dd6cddbc019..3ff02825f13 100644 --- a/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java +++ b/common/src/java/com/zimbra/common/account/ZAttrProvisioning.java @@ -11587,24 +11587,8 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) - public static final String A_zimbraNetworkAdminNGEnabled = "zimbraNetworkAdminNGEnabled"; - - /** - * Whether to enable zimbra network new generation backup module. - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public static final String A_zimbraNetworkBackupNGEnabled = "zimbraNetworkBackupNGEnabled"; - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @since ZCS 8.8.5 - */ @ZAttr(id=2130) - public static final String A_zimbraNetworkHSMNGEnabled = "zimbraNetworkHSMNGEnabled"; + public static final String A_zimbraNetworkAdminNGEnabled = "zimbraNetworkAdminNGEnabled"; /** * Contents of a signed Zimbra license key - an XML string. @@ -11621,9 +11605,7 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc public static final String A_zimbraNetworkMobileNGEnabled = "zimbraNetworkMobileNGEnabled"; /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @since ZCS 8.8.0 */ diff --git a/store/conf/attrs/zimbra-attrs.xml b/store/conf/attrs/zimbra-attrs.xml index 96a43ca5c7f..afe63263d49 100755 --- a/store/conf/attrs/zimbra-attrs.xml +++ b/store/conf/attrs/zimbra-attrs.xml @@ -9372,10 +9372,9 @@ TODO: delete them permanently from here outgoing sieve script defined by admin (not able to edit and view from the end user) applied after the end user filter rule - + TRUE Whether to enable zimbra network new generation modules. - This attribute has been replaced with individual attributes @@ -9442,17 +9441,7 @@ TODO: delete them permanently from here End-user email address verification status - - FALSE - Whether to enable zimbra network new generation HSM module. - - - - FALSE - Whether to enable zimbra network new generation backup module. - - - + FALSE Whether to enable zimbra network new generation admin module. diff --git a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java index 98400e59ea7..fd0288cb98a 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrConfig.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrConfig.java @@ -47521,7 +47521,7 @@ public Map unsetNetworkAdminEnabled(Map attrs) { * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public boolean isNetworkAdminNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); } @@ -47534,7 +47534,7 @@ public boolean isNetworkAdminNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47550,7 +47550,7 @@ public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -47564,7 +47564,7 @@ public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGE * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); @@ -47579,157 +47579,13 @@ public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.Servic * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public Map unsetNetworkAdminNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); return attrs; } - /** - * Whether to enable zimbra network new generation backup module. - * - * @return zimbraNetworkBackupNGEnabled, or false if unset - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public boolean isNetworkBackupNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @param zimbraNetworkBackupNGEnabled new value - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @param zimbraNetworkBackupNGEnabled new value - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - return attrs; - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public Map unsetNetworkBackupNGEnabled(Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); - return attrs; - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @return zimbraNetworkHSMNGEnabled, or false if unset - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public boolean isNetworkHSMNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, false, true); - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @param zimbraNetworkHSMNGEnabled new value - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @param zimbraNetworkHSMNGEnabled new value - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - return attrs; - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public Map unsetNetworkHSMNGEnabled(Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); - return attrs; - } - /** * Contents of a signed Zimbra license key - an XML string. * @@ -47865,9 +47721,7 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -47879,9 +47733,7 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -47896,9 +47748,7 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -47914,9 +47764,7 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -47930,9 +47778,7 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/account/ZAttrServer.java b/store/src/java/com/zimbra/cs/account/ZAttrServer.java index c9912bb0bc4..921ee4d4f5b 100644 --- a/store/src/java/com/zimbra/cs/account/ZAttrServer.java +++ b/store/src/java/com/zimbra/cs/account/ZAttrServer.java @@ -35550,7 +35550,7 @@ public Map unsetNetworkAdminEnabled(Map attrs) { * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public boolean isNetworkAdminNGEnabled() { return getBooleanAttr(Provisioning.A_zimbraNetworkAdminNGEnabled, false, true); } @@ -35563,7 +35563,7 @@ public boolean isNetworkAdminNGEnabled() { * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35579,7 +35579,7 @@ public void setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled) throws * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGEnabled, Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, zimbraNetworkAdminNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); @@ -35593,7 +35593,7 @@ public Map setNetworkAdminNGEnabled(boolean zimbraNetworkAdminNGE * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.ServiceException { HashMap attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); @@ -35608,157 +35608,13 @@ public void unsetNetworkAdminNGEnabled() throws com.zimbra.common.service.Servic * * @since ZCS 8.8.5 */ - @ZAttr(id=2132) + @ZAttr(id=2130) public Map unsetNetworkAdminNGEnabled(Map attrs) { if (attrs == null) attrs = new HashMap(); attrs.put(Provisioning.A_zimbraNetworkAdminNGEnabled, ""); return attrs; } - /** - * Whether to enable zimbra network new generation backup module. - * - * @return zimbraNetworkBackupNGEnabled, or false if unset - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public boolean isNetworkBackupNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkBackupNGEnabled, false, true); - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @param zimbraNetworkBackupNGEnabled new value - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public void setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled) throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @param zimbraNetworkBackupNGEnabled new value - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public Map setNetworkBackupNGEnabled(boolean zimbraNetworkBackupNGEnabled, Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, zimbraNetworkBackupNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - return attrs; - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public void unsetNetworkBackupNGEnabled() throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation backup module. - * - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2131) - public Map unsetNetworkBackupNGEnabled(Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkBackupNGEnabled, ""); - return attrs; - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @return zimbraNetworkHSMNGEnabled, or false if unset - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public boolean isNetworkHSMNGEnabled() { - return getBooleanAttr(Provisioning.A_zimbraNetworkHSMNGEnabled, false, true); - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @param zimbraNetworkHSMNGEnabled new value - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public void setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled) throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @param zimbraNetworkHSMNGEnabled new value - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public Map setNetworkHSMNGEnabled(boolean zimbraNetworkHSMNGEnabled, Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, zimbraNetworkHSMNGEnabled ? Provisioning.TRUE : Provisioning.FALSE); - return attrs; - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @throws com.zimbra.common.service.ServiceException if error during update - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public void unsetNetworkHSMNGEnabled() throws com.zimbra.common.service.ServiceException { - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); - getProvisioning().modifyAttrs(this, attrs); - } - - /** - * Whether to enable zimbra network new generation HSM module. - * - * @param attrs existing map to populate, or null to create a new map - * @return populated map to pass into Provisioning.modifyAttrs - * - * @since ZCS 8.8.5 - */ - @ZAttr(id=2130) - public Map unsetNetworkHSMNGEnabled(Map attrs) { - if (attrs == null) attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraNetworkHSMNGEnabled, ""); - return attrs; - } - /** * Whether to enable zimbra network new generation mobile sync module. * @@ -35832,9 +35688,7 @@ public Map unsetNetworkMobileNGEnabled(Map attrs) } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @return zimbraNetworkModulesNGEnabled, or true if unset * @@ -35846,9 +35700,7 @@ public boolean isNetworkModulesNGEnabled() { } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @throws com.zimbra.common.service.ServiceException if error during update @@ -35863,9 +35715,7 @@ public void setNetworkModulesNGEnabled(boolean zimbraNetworkModulesNGEnabled) th } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @param zimbraNetworkModulesNGEnabled new value * @param attrs existing map to populate, or null to create a new map @@ -35881,9 +35731,7 @@ public Map setNetworkModulesNGEnabled(boolean zimbraNetworkModule } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @throws com.zimbra.common.service.ServiceException if error during update * @@ -35897,9 +35745,7 @@ public void unsetNetworkModulesNGEnabled() throws com.zimbra.common.service.Serv } /** - * Deprecated since: 8.8.5. This attribute has been replaced with - * individual attributes. Orig desc: Whether to enable zimbra network new - * generation modules. + * Whether to enable zimbra network new generation modules. * * @param attrs existing map to populate, or null to create a new map * @return populated map to pass into Provisioning.modifyAttrs diff --git a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java index 36b3986800f..3775ecba9ba 100644 --- a/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java +++ b/store/src/java/com/zimbra/cs/service/admin/GetAdminExtensionZimlets.java @@ -55,14 +55,12 @@ private void doExtensionZimlets(ZimbraSoapContext zsc, Map conte boolean mobileNGEnabled = true; boolean networkAdminEnabled = true; - boolean hsmNGEnabled = true; - boolean backupRestoreNGEnabled = true; + boolean networkNGEnabled = true; try { + networkNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkModulesNGEnabled(); mobileNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkMobileNGEnabled(); networkAdminEnabled = Provisioning.getInstance().getLocalServer().isNetworkAdminNGEnabled(); - hsmNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkHSMNGEnabled(); - backupRestoreNGEnabled = Provisioning.getInstance().getLocalServer().isNetworkBackupNGEnabled(); } catch (ServiceException e) { ZimbraLog.mailbox.warn("Exception while getting zimbraNetworkModulesNG related attributes.", e); @@ -77,27 +75,27 @@ private void doExtensionZimlets(ZimbraSoapContext zsc, Map conte if (z.isExtension()) { boolean include = true; - if ("com_zimbra_mobilesync".equals(z.getName()) && mobileNGEnabled) { + if ("com_zimbra_mobilesync".equals(z.getName()) && mobileNGEnabled && networkNGEnabled) { include = !mobileNGEnabled; if (!include) { ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkMobileNGEnabled is true.", z.getName()); } } - if ("com_zimbra_hsm".equals(z.getName()) && hsmNGEnabled) { - include = !hsmNGEnabled; + if ("com_zimbra_hsm".equals(z.getName()) && networkNGEnabled) { + include = !networkNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworHSMNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworNGEnabled is true.", z.getName()); } } - if ("com_zimbra_backuprestore".equals(z.getName()) && backupRestoreNGEnabled) { - include = !backupRestoreNGEnabled; + if ("com_zimbra_backuprestore".equals(z.getName()) && networkNGEnabled) { + include = !networkNGEnabled; if (!include) { - ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkBackupNGEnabled is true.", z.getName()); + ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkNGEnabled is true.", z.getName()); } } - if ("com_zimbra_delegatedadmin".equals(z.getName()) && networkAdminEnabled) { + if ("com_zimbra_delegatedadmin".equals(z.getName()) && networkAdminEnabled && networkNGEnabled) { include = !networkAdminEnabled; if (!include) { ZimbraLog.mailbox.info("Disabled '%s' as zimbraNetworkAdminNGEnabled is true.", z.getName()); From 9df3008d567cec4f1c867764079aee6508cc3356 Mon Sep 17 00:00:00 2001 From: Rupali Desai Date: Thu, 26 Oct 2017 11:43:14 +0530 Subject: [PATCH 142/142] ZCS-3347 Reapplying fix to 8.8.5 branch --- store/src/java/com/zimbra/cs/service/admin/FlushCache.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/store/src/java/com/zimbra/cs/service/admin/FlushCache.java b/store/src/java/com/zimbra/cs/service/admin/FlushCache.java index 14356e20ecd..14d41202b12 100644 --- a/store/src/java/com/zimbra/cs/service/admin/FlushCache.java +++ b/store/src/java/com/zimbra/cs/service/admin/FlushCache.java @@ -226,7 +226,6 @@ public static void sendFlushRequest(Map context, String appContex private static void flushCacheOnAllServers(ZimbraSoapContext zsc, FlushCacheRequest req) throws ServiceException { req.getCache().setAllServers(false); // make sure we don't go round in loops - Element request = zsc.jaxbToElement(req); Provisioning prov = Provisioning.getInstance(); String localServerId = prov.getLocalServer().getId(); @@ -235,7 +234,7 @@ private static void flushCacheOnAllServers(ZimbraSoapContext zsc, FlushCacheRequ if (localServerId.equals(server.getId())) { continue; } - + Element request = zsc.jaxbToElement(req); ZimbraLog.misc.debug("Flushing cache on server: %s", server.getName()); String adminUrl = URLUtil.getAdminURL(server, AdminConstants.ADMIN_SERVICE_URI); SoapHttpTransport mTransport = new SoapHttpTransport(adminUrl);