Difference between revisions of "Glenno-Notes"

(Restrict authenticated users to send email from account or aliases)
(Restrict authenticated users to send email from account or aliases)
Line 6: Line 6:
 
By default, when users authenticate to postfix via SASL, they can set the FROM: header to any address they choose, allowing spoofing. The instructions below outline how to configure postfix to restrict a sender's from address to their Zimbra primary header or any aliases on the account.
 
By default, when users authenticate to postfix via SASL, they can set the FROM: header to any address they choose, allowing spoofing. The instructions below outline how to configure postfix to restrict a sender's from address to their Zimbra primary header or any aliases on the account.
  
# The first part, which does what you're requesting, is to add one of "reject_sender_login_mismatch" or "reject_authenticated_sender_login_mismatch" to postfix's smtpd_sender_restrictions.
+
# The first part, which does what you're requesting, is to add one of "reject_sender_login_mismatch" or "reject_authenticated_sender_login_mismatch" to postfix's smtpd_sender_restrictions.<code><pre>% postconf -e smtpd_sender_restrictions=permit_mynetworks,reject_sender_login_mismatch</pre></code>or<code><pre>% postconf -e smtpd_sender_restrictions=permit_mynetworks,reject_sender_login_mismatch</pre></code>
 +
# Having that work depends on setting the smtpd_sender_login_maps, which is empty by default (and leaving it empty after setting reject_*sender_login_mismatch will prevent anyone from being able to send mail).
 +
## If your users do not have account aliases, i.e. if you expect valid users to only send from and perform smtp authentication using their primary account name (shown in the zimbraMailDeliveryAddress attribute on the account), then it will be OK to use the existing virtual mailbox maps. Use the single quotes as shown in the command below to prevent the command shell from parsing the variable name.<code><pre> % postconf -e smtpd_sender_login_maps='$virtual_mailbox_maps'</pre></code>
 +
## If you expect valid users to potentially use account aliases, or if they might be allowed to send mail from additional addresses (shown in the zimbraAllowFromAddress account attribute), it will be necessary to create a new ldap lookup file. The easiest way is to start with a copy of the file referenced above.<code><pre>% cp ~/conf/ldap-vmm.cf ~/conf/ldap-slm.cf</pre></code>Edit the new file ldap-slm.cf and change the query_filter and result_attribute lines to match these:<code><pre>query_filter = (&(|(zimbraMailDeliveryAddress=%s)(mail=%s)(zimbraAllowFromAddress=%s))(zimbraMailStatus=enabled))</pre></code><code><pre>result_attribute = zimbraMailDeliveryAddress,mail,zimbraAllowFromAddress</pre></code>Then set postfix's smtpd_sender_login_maps to reference the new file for lookups.<code><pre>% postconf -e smtpd_sender_login_maps=proxy:ldap:/opt/zimbra/conf/ldap-slm.cf</pre></code>
 +
# If you configure smtpd_sender_login_maps to use a new file like this, it will also be necessary to update proxy_read_maps. Run this first to get the current setting; I'm not showing it here because it's a few lines long.<code><pre>% postconf proxy_read_maps</pre></code>Then modify it to contain everything that was there before plus a reference to smtpd_sender_login_maps. Again, make sure to use the single quotes to prevent the shell from trying to expand postfix's variables.<code><pre>% postconf -e proxy_read_maps='...previous-proxy_read_maps-content... $smtpd_sender_login_maps'</pre></code>
 +
# Then you'll need postfix to reload its configuration.<code><pre>% postfix reload</pre></code>
  
<code><pre>% postconf -e smtpd_sender_restrictions=permit_mynetworks,reject_sender_login_mismatch</pre></code>
+
At this point it should be ready. Note that some or all of these changes will be reverted by a ZCS upgrade. [http://bugzilla.zimbra.com/show_bug.cgi?id=11258 Bug 11258] is on file to manage this functionality in ZCS configuration which should reduce the configuration complexity and allow the configuration to be preserved during upgrades.
or
 
<code><pre>% postconf -e smtpd_sender_restrictions=permit_mynetworks,reject_sender_login_mismatch</pre></code>
 
 
 
## Having that work depends on setting the smtpd_sender_login_maps, which is empty by default (and leaving it empty after setting reject_*sender_login_mismatch will prevent anyone from being able to send mail). If your users do not have account aliases, i.e. if you expect valid users to only send from and perform smtp authentication using their primary account name (shown in the zimbraMailDeliveryAddress attribute on the account), then it will be OK to use the existing virtual mailbox maps. Use the single quotes as shown in the command below to prevent the command shell from parsing the variable name.
 
 
 
<code><pre> % postconf -e smtpd_sender_login_maps='$virtual_mailbox_maps'</pre></code>
 
 
 
## If you expect valid users to potentially use account aliases, or if they might be allowed to send mail from additional addresses (shown in the zimbraAllowFromAddress account attribute), it will be necessary to create a new ldap lookup file. The easiest way is to start with a copy of the file referenced above.
 
 
 
 
 
<code><pre>% cp ~/conf/ldap-vmm.cf ~/conf/ldap-slm.cf</pre></code>
 
 
 
Edit the new file ldap-slm.cf and change the query_filter and result_attribute lines to match these:
 
 
 
<code><pre>query_filter = (&(|(zimbraMailDeliveryAddress=%s)(mail=%s)(zimbraAllowFromAddress=%s))(zimbraMailStatus=enabled))
 
 
 
result_attribute = zimbraMailDeliveryAddress,mail,zimbraAllowFromAddress</pre></code>
 
 
 
Then set postfix's smtpd_sender_login_maps to reference the new file for lookups.
 
 
 
<code><pre>% postconf -e smtpd_sender_login_maps=proxy:ldap:/opt/zimbra/conf/ldap-slm.cf</pre></code>
 
 
 
# If you configure smtpd_sender_login_maps to use a new file like this, it will also be necessary to update proxy_read_maps. Run this first to get the current setting; I'm not showing it here because it's a few lines long.
 
 
 
<code><pre>% postconf proxy_read_maps</pre></code>
 
 
 
Then modify it to contain everything that was there before plus a reference to smtpd_sender_login_maps. Again, make sure to use the single quotes to prevent the shell from trying to expand postfix's variables.
 
 
 
<code><pre>% postconf -e proxy_read_maps='...previous-proxy_read_maps-content... $smtpd_sender_login_maps'</pre></code>
 
 
 
# Then you'll need postfix to reload its configuration.
 
 
 
<code><pre>% postfix reload</pre></code>
 
 
 
At this point it should be ready. Please let me know if you have any questions about this since it is somewhat complicated. Note that some or all of these changes will be reverted by a ZCS upgrade. We do have Bug 11258 on file to manage this functionality in ZCS configuration which should reduce the configuration complexity and allow the configuration to be preserved during upgrades. This is currently targeted for the release named "IronMaiden" which will probably be version ZCS 8.
 
 
 
http://bugzilla.zimbra.com/show_bug.cgi?id=11258
 
  
 
For additional reference, here's a link to the postfix documentation with more information about the postfix configuration parameters.
 
For additional reference, here's a link to the postfix documentation with more information about the postfix configuration parameters.

Revision as of 01:17, 7 December 2010

Attention.png - This article is NOT official Zimbra documentation. It is a user contribution and may include unsupported customizations, references, suggestions, or information.

Restrict authenticated users to send email from account or aliases

By default, when users authenticate to postfix via SASL, they can set the FROM: header to any address they choose, allowing spoofing. The instructions below outline how to configure postfix to restrict a sender's from address to their Zimbra primary header or any aliases on the account.

  1. The first part, which does what you're requesting, is to add one of "reject_sender_login_mismatch" or "reject_authenticated_sender_login_mismatch" to postfix's smtpd_sender_restrictions.
    % postconf -e smtpd_sender_restrictions=permit_mynetworks,reject_sender_login_mismatch
    or
    % postconf -e smtpd_sender_restrictions=permit_mynetworks,reject_sender_login_mismatch
  2. Having that work depends on setting the smtpd_sender_login_maps, which is empty by default (and leaving it empty after setting reject_*sender_login_mismatch will prevent anyone from being able to send mail).
    1. If your users do not have account aliases, i.e. if you expect valid users to only send from and perform smtp authentication using their primary account name (shown in the zimbraMailDeliveryAddress attribute on the account), then it will be OK to use the existing virtual mailbox maps. Use the single quotes as shown in the command below to prevent the command shell from parsing the variable name.
       % postconf -e smtpd_sender_login_maps='$virtual_mailbox_maps'
    2. If you expect valid users to potentially use account aliases, or if they might be allowed to send mail from additional addresses (shown in the zimbraAllowFromAddress account attribute), it will be necessary to create a new ldap lookup file. The easiest way is to start with a copy of the file referenced above.
      % cp ~/conf/ldap-vmm.cf ~/conf/ldap-slm.cf
      Edit the new file ldap-slm.cf and change the query_filter and result_attribute lines to match these:
      query_filter = (&(|(zimbraMailDeliveryAddress=%s)(mail=%s)(zimbraAllowFromAddress=%s))(zimbraMailStatus=enabled))
      result_attribute = zimbraMailDeliveryAddress,mail,zimbraAllowFromAddress
      Then set postfix's smtpd_sender_login_maps to reference the new file for lookups.
      % postconf -e smtpd_sender_login_maps=proxy:ldap:/opt/zimbra/conf/ldap-slm.cf
  3. If you configure smtpd_sender_login_maps to use a new file like this, it will also be necessary to update proxy_read_maps. Run this first to get the current setting; I'm not showing it here because it's a few lines long.
    % postconf proxy_read_maps
    Then modify it to contain everything that was there before plus a reference to smtpd_sender_login_maps. Again, make sure to use the single quotes to prevent the shell from trying to expand postfix's variables.
    % postconf -e proxy_read_maps='...previous-proxy_read_maps-content... $smtpd_sender_login_maps'
  4. Then you'll need postfix to reload its configuration.
    % postfix reload

At this point it should be ready. Note that some or all of these changes will be reverted by a ZCS upgrade. Bug 11258 is on file to manage this functionality in ZCS configuration which should reduce the configuration complexity and allow the configuration to be preserved during upgrades.

For additional reference, here's a link to the postfix documentation with more information about the postfix configuration parameters. http://www.postfix.org/postconf.5.html#smtpd_sender_restrictions

Fresh sync of LDAP replica

% zmcontrol stop
% ps wwaux|grep slap   # verify ldap is stopped
% mkdir /tmp/ldap_bak
% cp -arp /opt/zimbra/data/ldap/hdb/db/ /tmp/ldap_bak/
% rm -rf /opt/zimbra/data/ldap/hdb/db/*
% cp /tmp/ldap_bak/db/DB_CONFIG /opt/zimbra/data/ldap/hdb/db/
% zmcontrol start

Consolidating one HSM volume to another

Supposing you have multiple HSM volumes, and want to migrate the data from an inactive volume to another (allowing you to remove the inactive volume). There isn't a standard Zimbra procedure for this scenario. However, it is possible to move the blobs from one volume to another. You need to be sure Zimbra services are completely stopped during the process, or you risk data loss. It would be wise to firewall off client access (http/s, imap, smtp, etc.) until you've verified the migration worked.

Assuming the volume you want to retire is /opt/zimbra/store3 and the volume you want to move data to is /opt/zimbra/store2:

1. Get info from zmvolume:

Store 2:
path: /opt/zimbra/store2
Volume id: 2

Store 3:
path: /opt/zimbra/store3
Volume id: 3
(ensure current status isn't true)

2. Full backup in case restore is necessary:

% zmbackup -f -a all -sync

3. Stop Zimbra, backup MySQL, backup file listing of blobs, move blobs:

% zmcontrol stop
% mkdir /opt/zimbra/db/data.bak
% cp -a /opt/zimbra/db/data/* /opt/zimbra/db/data.bak/
% find /opt/zimbra/store3/ -name '*.msg' -ls| sed 's/.\+\/opt\//@/' > /tmp/store3-blobs.txt
% cp -a /opt/zimbra/store3/* /opt/zimbra/store2/

4. Update blob pointers in MySQL:

% mysql.server start

Test the following script, and run again by removing the echo in front of "mysql" if the output looks good:

store2id=2
store3id=3
for i in /opt/zimbra/db/data/mboxgroup*;
 do
 x=`echo $i | sed 's/.\+\///'`;
 echo "Updating $i...";
 echo mysql $x -e "UPDATE mail_item SET volume_id=$store2id WHERE volume_id=$store3id;"
done

5. Verify migration:

Start Zimbra and check that mailboxes can retrieve the moved messages (should not get NO_SUCH_BLOB errors when clicking on messages that were migrated).

If all looks good, remove store3 via zmvolume and then archive the directory (if you're confident everything is fine, delete). Same goes for /opt/zimbra/db/data.bak.

If things aren't working, stopping all services and restoring the old MySQL tables from /opt/zimbra/db/data.bak should work. You can use /tmp/store3-blobs.txt to know which blobs to clean out of /opt/zimbra/store2.

Output in mailbox.log when mailboxd stops and starts

Shutdown:

2010-08-31 16:00:06,751 INFO  [Shutdown] [] log - Shutdown hook executing
2010-08-31 16:00:07,274 INFO  [Shutdown] [] StatsImageServlet - Servlet StatsImageServlet shutting down
2010-08-31 16:00:07,275 INFO  [Shutdown] [] FileUploadServlet - Servlet FileUploadServlet shutting down
2010-08-31 16:00:07,277 INFO  [Shutdown] [] PublicICalServlet - Servlet PublicICalServlet shutting down
2010-08-31 16:00:07,277 INFO  [Shutdown] [] account - Servlet PreAuthServlet shutting down
2010-08-31 16:00:07,277 INFO  [Shutdown] [] mailbox - Servlet UserServlet shutting down
2010-08-31 16:00:07,277 INFO  [Shutdown] [] ContentServlet - Servlet ContentServlet shutting down
2010-08-31 16:00:07,277 INFO  [Shutdown] [] soap - Servlet AdminServlet shutting down
2010-08-31 16:00:07,278 INFO  [Shutdown] [] TcpServer/7025 - LmtpServer initiating shutdown
2010-08-31 16:00:07,419 INFO  [Shutdown] [] TcpServer/110 - Pop3Server initiating shutdown
2010-08-31 16:00:07,420 INFO  [Pop3Server] [] TcpServer/110 - finished accept loop
2010-08-31 16:00:07,521 INFO  [Shutdown] [] TcpServer/110 - Pop3Server shutting down idle thread pool
2010-08-31 16:00:07,521 INFO  [Shutdown] [] TcpServer/995 - Pop3SSLServer initiating shutdown
2010-08-31 16:00:07,522 INFO  [Pop3SSLServer] [] TcpServer/995 - finished accept loop
2010-08-31 16:00:07,720 INFO  [Shutdown] [] TcpServer/995 - Pop3SSLServer shutting down idle thread pool
2010-08-31 16:00:07,721 INFO  [Shutdown] [] TcpServer/143 - ImapServer initiating shutdown
2010-08-31 16:00:07,721 INFO  [ImapServer] [] TcpServer/143 - finished accept loop
2010-08-31 16:00:07,816 INFO  [Shutdown] [] TcpServer/143 - ImapServer shutting down idle thread pool
2010-08-31 16:00:07,816 INFO  [Shutdown] [] TcpServer/993 - ImapSSLServer initiating shutdown
2010-08-31 16:00:07,816 INFO  [ImapSSLServer] [] TcpServer/993 - finished accept loop
2010-08-31 16:00:07,877 INFO  [Shutdown] [] TcpServer/993 - ImapSSLServer shutting down idle thread pool

....
2010-08-31 16:00:09,172 WARN  [Shutdown] [] ZimbraHttpConnectionManager - shutting down http client idle connection reaper thread
2010-08-31 16:00:09,173 INFO  [Shutdown] [] soap - Servlet SoapServlet shutting down
2010-08-31 16:00:09,342 INFO  [Shutdown] [] log - Shutdown hook complete

Startup:

2010-08-31 16:05:26,172 INFO  [main] [] soap - Servlet SoapServlet starting up
2010-08-31 16:05:26,501 INFO  [main] [] soap - Adding service AccountService to SoapServlet
2010-08-31 16:05:26,861 INFO  [main] [] soap - Adding service MailService to SoapServlet
2010-08-31 16:05:27,940 INFO  [main] [] soap - Adding service IMService to SoapServlet
2010-08-31 16:05:27,986 INFO  [main] [] misc - version=6.0.8_GA_2637 release=20100811142254 builddate=20100811-1424 buildhost=build01.lab.zimbra.com
2010-08-31 16:05:27,989 INFO  [main] [] misc - LANG environment is set to: C
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property java.home=/opt/zimbra/jdk1.6.0_21/jre
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property java.runtime.version=1.6.0_21-b06
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property java.version=1.6.0_21
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property java.vm.info=mixed mode
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property java.vm.name=Java HotSpot(TM) Server VM
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property java.vm.version=17.0-b16
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property os.arch=i386
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property os.name=Linux
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property os.version=2.6.9-22.EL
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property sun.arch.data.model=32
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property sun.cpu.endian=little
2010-08-31 16:05:27,989 INFO  [main] [] misc - System property sun.cpu.isalist=
2010-08-31 16:05:27,990 INFO  [main] [] misc - System property sun.os.patch.level=unknown
2010-08-31 16:05:28,117 INFO  [main] [] system - Setting mysql connector property: maxActive=100
2010-08-31 16:05:28,139 INFO  [main] [] system - Setting mysql connector property: maxActive=100
2010-08-31 16:05:31,018 INFO  [main] [] sqltrace - Setting slow SQL threshold to 2000ms
...
2010-08-31 16:05:40,890 INFO  [LmtpServer] [] TcpServer/7025 - starting accept loop
2010-08-31 16:05:40,905 INFO  [Pop3Server] [] TcpServer/110 - starting accept loop
2010-08-31 16:05:41,062 INFO  [Pop3SSLServer] [] TcpServer/995 - starting accept loop
2010-08-31 16:05:41,106 INFO  [ImapServer] [] TcpServer/143 - starting accept loop
2010-08-31 16:05:41,218 INFO  [ImapSSLServer] [] TcpServer/993 - starting accept loop
...
2010-08-31 16:05:45,017 INFO  [main] [] log - Started SslSelectChannelConnector@0.0.0.0:443
2010-08-31 16:05:45,020 INFO  [main] [] log - Started SslSelectChannelConnector@0.0.0.0:7071
2010-08-31 16:05:45,020 INFO  [main] [] log - Started SelectChannelConnector@0.0.0.0:7072

SSL Cert Installation: Unmatching certificate and private key error

If you're seeing this error:

root@zimbra:/tmp# /opt/zimbra/bin/zmcertmgr verifycrt comm /opt/zimbra/ssl/zimbra/commercial/commercial.key commercial.crt commercial_ca.crt
** Verifying commercial.crt against /opt/zimbra/ssl/zimbra/commercial/commercial.key
XXXXX ERROR: Unmatching certificate (commercial.crt) and private key (/opt/zimbra/ssl/zimbra/commercial/commercial.key) pair. 

It may be that the commercial.crt doesn't match the signature from commercial.key. The following two hashes should match, but don't:

# openssl x509 -noout -modulus -in commercial.crt | openssl md5
f4033675a216bbbe0712917e3281fe3c
# openssl rsa -noout -modulus -in commercial.key | openssl md5
76991327ac5bdae0840270dffeb4b214

Here is an example of two matching certificate and key files deployed for LDAP:

# openssl x509 -noout -modulus -in /opt/zimbra/conf/slapd.crt | openssl md5
59688017a0601a37a07d8fcd4ec9908c
# openssl rsa -noout -modulus -in /opt/zimbra/conf/slapd.key | openssl md5
59688017a0601a37a07d8fcd4ec9908c

If you have the CSR you can check to which key it belongs:

openssl req -noout -modulus -in server.csr | openssl md5

For a full explanation of the above commands: http://kb.wisc.edu/middleware/page.php?id=4064

Installing a Thawte SSL Certificate in ZCS 5.x and 6.x

Use the following instructions to install a commercial Thawte SSL certificate. All the commands below should be performed as the root user (not zimbra).

1. Begin by generating a Certificate Signing Request (CSR).

# /opt/zimbra/bin/zmcertmgr createcsr comm -new –subject "/C=US/ST=CO/L=Broomfield/O=VMware/OU=Zimbra Collaboration Suite" –subjectAltNames host.example.com


2. Next, submit the CSR to the Thawte and get a commercial certificate in X.509/PEM format.

https://search.thawte.com/support/ssl-digital-certificates/index?page=content&id=SO13187

Save the new certificate to a temporary file (e.g. /tmp/comm.crt).


3. Determine which SSL product you bought from Thawte.

https://search.thawte.com/support/ssl-digital-certificates/index?page=content&id=SO1498&actp=LIST&viewlocale=en_US

Depending on which it is, click the corresponding ApacheSSL from the link above. For the directions below, we'll assume it's plain SSL Web Server:

https://search.thawte.com/support/ssl-digital-certificates/index?page=content&id=SO14822


4. Download the Intermediate Certificate Authority in Apache format (X.509/PEM):

The Intermediate CA you download depends on which Thawte SSL product was bought. Below, we're assuming SSL Web Server:

https://search.thawte.com/support/ssl-digital-certificates/index?page=content&actp=CROSSLINK&id=AR1374

# cd /tmp && wget https://search.thawte.com/library/VERISIGN/ALL_OTHER/thawte%20ca/SSL_CA_Bundle.pem


5. Download the Root Certificate Authority:

https://www.thawte.com/roots/index.html

Again, the Root CA you download depends on the Thawte SSL product purchased. The Root CA below is for SSL Web Server:

# cd /tmp && wget https://www.thawte.com/roots/thawte_Premium_Server_CA.pem


6. Combine Root and Intermediate CAs:

cat /tmp/thawte_Premium_Server_CA.pem /tmp/SSL_CA_Bundle.pem > /tmp/commercial_ca.crt

The order of files matters: first the Root CA followed by the Intermediate CA.

Look at commercial_ca.crt and make sure there are line breaks (there should be no more than 64 characters per line). If the file is not formatted correctly, Zimbra won't be able to import it.


7. Verify:

# /opt/zimbra/bin/zmcertmgr verifycrt comm /opt/zimbra/ssl/zimbra/commercial/commercial.key /tmp/comm.crt /tmp/commercial_ca.crt


8. Deploy:

# /opt/zimbra/bin/zmcertmgr deploycrt comm /tmp/comm.crt /tmp/commercial_ca.crt


Bulk delete items from all users matching query via zmmailbox

Suppose you have the following scenario:

We have an administrative assistant who left the company (admin_assistant@example.com). She had created reoccurring appointments on several people's calendars which now cannot be removed. Restoring the administrative assistant's account is not an option since she was removed a while back and our oldest backup doesn't contain her account. Any suggestions on how to remove the appointments?

As an administrator, you can script zmmailbox to search all accounts for appointments with an organizer of admin_assistant@example.com, and then delete those appointments.


#!/bin/bash
# tested on ZCS 6.0.8

if [ `whoami` != "zimbra" ]; then
  echo "You must be the zimbra user to run this script."
  exit 0
fi

# change query below to what you want to match
# the example searches for a body matching "Organizer: admin_assistant@example.com"
query="\"\\\"Organizer: admin_assistant@example.com\\\"\""

# change to search the type(s) of items you want to match
# types are: message,conversation,contact,appointment,document,task,wiki
type="appointment"

for acct in `zmprov -l gaa`
# if you want to search specific accounts, use the for loop below
# for acct in "99@test2.test" "100@test2.test" "101@test2.test" "102@test2.test" "103@test2.test"
do
  echo "Searching account $acct..."
  ITEMS=`zmmailbox -z -m $acct search -t $type "$query" | awk '{ if (NR>4 && NF) {print $2}}' | tr '\n' ,`
  if [ -n "$ITEMS" ]; then
    echo " Deleting item(s) " $ITEMS
    # Remove echo after verifying the search results
    echo zmmailbox -z -m $acct di $ITEMS
  fi
done

Credit to: King0770-Notes-Removal_of_Bad_Contact_Address

Deciphering zmstat charts

MySQL: InnoDB Buffer Pool Hit Rate

In general, should stay above 995.

Bad

Innodb bad.png

Better

Innodb better.png

Ideal

Innodb perfect.png

Mailboxd: Minor Garbage Collection Time and Mailboxd: Major Garbage Collection Time

If the GC time starts getting over a few percent, especially repeatedly, then it's something that users will notice.

Listing of zmprov commands

Taken from version 6.0.7 of com.zimbra.cs.account.ProvUtil.java

ADD_ACCOUNT_ALIAS("addAccountAlias", "aaa", "{name@domain|id} {alias@domain}", Category.ACCOUNT, 2, 2),
ADD_ACCOUNT_LOGGER("addAccountLogger", "aal", "[-s/--server hostname] {name@domain|id} {logging-category} {debug|info|warn|error}", Category.LOG, 3, 5),
ADD_DISTRIBUTION_LIST_ALIAS("addDistributionListAlias", "adla", "{list@domain|id} {alias@domain}", Category.LIST, 2, 2),
ADD_DISTRIBUTION_LIST_MEMBER("addDistributionListMember", "adlm", "{list@domain|id} {member@domain}+", Category.LIST, 2, Integer.MAX_VALUE),
AUTO_COMPLETE_GAL("autoCompleteGal", "acg", "{domain} {name}", Category.SEARCH, 2, 2),
CHECK_PASSWORD_STRENGTH("checkPasswordStrength", "cps", "{name@domain|id} {password}", Category.ACCOUNT, 2, 2),
CHECK_RIGHT("checkRight", "ckr", "{target-type} [{target-id|target-name}] {grantee-id|grantee-name (note:can only check internal user)} {right}", Category.RIGHT, 3, 4, null, new RightCommandHelp()),
COPY_COS("copyCos", "cpc", "{src-cos-name|id} {dest-cos-name}", Category.COS, 2, 2),
COUNT_ACCOUNT("countAccount", "cta", "{domain|id}", Category.DOMAIN, 1, 1),
CREATE_ACCOUNT("createAccount", "ca", "{name@domain} {password} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 2, Integer.MAX_VALUE),        
CREATE_ALIAS_DOMAIN("createAliasDomain", "cad", "{alias-domain-name} {local-domain-name|id} [attr1 value1 [attr2 value2...]]", Category.DOMAIN, 2, Integer.MAX_VALUE),
CREATE_BULK_ACCOUNTS("createBulkAccounts", "cabulk"),  //("  CreateBulkAccounts(cabulk) {domain} {namemask} {number of accounts to create} ");
CREATE_CALENDAR_RESOURCE("createCalendarResource",  "ccr", "{name@domain} {password} [attr1 value1 [attr2 value2...]]", Category.CALENDAR, 2, Integer.MAX_VALUE),
CREATE_COS("createCos", "cc", "{name} [attr1 value1 [attr2 value2...]]", Category.COS, 1, Integer.MAX_VALUE),
CREATE_DATA_SOURCE("createDataSource", "cds", "{name@domain} {ds-type} {ds-name} zimbraDataSourceEnabled {TRUE|FALSE} zimbraDataSourceFolderId {folder-id} 
        [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 3, Integer.MAX_VALUE),                
CREATE_DISTRIBUTION_LIST("createDistributionList", "cdl", "{list@domain}", Category.LIST, 1, Integer.MAX_VALUE),
CREATE_DISTRIBUTION_LISTS_BULK("createDistributionListsBulk", "cdlbulk"),
CREATE_DOMAIN("createDomain", "cd", "{domain} [attr1 value1 [attr2 value2...]]", Category.DOMAIN, 1, Integer.MAX_VALUE),
CREATE_SERVER("createServer", "cs", "{name} [attr1 value1 [attr2 value2...]]", Category.SERVER, 1, Integer.MAX_VALUE),
CREATE_IDENTITY("createIdentity", "cid", "{name@domain} {identity-name} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 2, Integer.MAX_VALUE),        
CREATE_SIGNATURE("createSignature", "csig", "{name@domain} {signature-name} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 2, Integer.MAX_VALUE),
CREATE_XMPP_COMPONENT("createXMPPComponent", "cxc", "{short-name} {domain}  {server} {classname} {category} {type} [attr value1 [attr2 value2...]]", Category.CONFIG, 6, Integer.MAX_VALUE),
DELETE_ACCOUNT("deleteAccount", "da", "{name@domain|id}", Category.ACCOUNT, 1, 1),
DELETE_CALENDAR_RESOURCE("deleteCalendarResource",  "dcr", "{name@domain|id}", Category.CALENDAR, 1, 1),
DELETE_COS("deleteCos", "dc", "{name|id}", Category.COS, 1, 1),
DELETE_DATA_SOURCE("deleteDataSource", "dds", "{name@domain|id} {ds-name|ds-id}", Category.ACCOUNT, 2, 2),                        
DELETE_DISTRIBUTION_LIST("deleteDistributionList", "ddl", "{list@domain|id}", Category.LIST, 1, 1),
DELETE_DOMAIN("deleteDomain", "dd", "{domain|id}", Category.DOMAIN, 1, 1),
DELETE_IDENTITY("deleteIdentity", "did", "{name@domain|id} {identity-name}", Category.ACCOUNT, 2, 2),
DELETE_SIGNATURE("deleteSignature", "dsig", "{name@domain|id} {signature-name}", Category.ACCOUNT, 2, 2),
DELETE_SERVER("deleteServer", "ds", "{name|id}", Category.SERVER, 1, 1),
DELETE_XMPP_COMPONENT("deleteXMPPComponent", "dxc", "{xmpp-component-name}", Category.CONFIG, 1, 1),
DESCRIBE("describe", "desc", "[[-v] [-ni] [{entry-type}]] | [-a {attribute-name}]", Category.MISC, 0, Integer.MAX_VALUE, null, null, true),
EXIT("exit", "quit", "", Category.MISC, 0, 0),
FLUSH_CACHE("flushCache", "fc", "[-a] {skin|locale|license|account|config|cos|domain|group|server|zimlet|<extension-cache-type>} [name1|id1 [name2|id2...]]", Category.MISC, 1, Integer.MAX_VALUE),
GENERATE_DOMAIN_PRE_AUTH("generateDomainPreAuth", "gdpa", "{domain|id} {name|id|foreignPrincipal} {by} {timestamp|0} {expires|0}", Category.MISC, 5, 6),
GENERATE_DOMAIN_PRE_AUTH_KEY("generateDomainPreAuthKey", "gdpak", "[-f] {domain|id}", Category.MISC, 1, 2),
GET_ACCOUNT("getAccount", "ga", "[-e] {name@domain|id} [attr1 [attr2...]]", Category.ACCOUNT, 1, Integer.MAX_VALUE),
GET_DATA_SOURCES("getDataSources", "gds", "{name@domain|id} [arg1 [arg2...]]", Category.ACCOUNT, 1, Integer.MAX_VALUE),                
GET_IDENTITIES("getIdentities", "gid", "{name@domain|id} [arg1 [arg...]]", Category.ACCOUNT, 1, Integer.MAX_VALUE),
GET_SIGNATURES("getSignatures", "gsig", "{name@domain|id} [arg1 [arg...]]", Category.ACCOUNT, 1, Integer.MAX_VALUE),
GET_ACCOUNT_MEMBERSHIP("getAccountMembership", "gam", "{name@domain|id}", Category.ACCOUNT, 1, 2),
GET_ALL_ACCOUNTS("getAllAccounts","gaa", "[-v] [-e] [-s server] [{domain}]", Category.ACCOUNT, 0, 5),
GET_ACCOUNT_LOGGERS("getAccountLoggers", "gal", "[-s/--server hostname] {name@domain|id}", Category.LOG, 1, 3),
GET_ALL_ACCOUNT_LOGGERS("getAllAccountLoggers", "gaal", "[-s/--server hostname]", Category.LOG, 0, 2),
GET_ALL_ADMIN_ACCOUNTS("getAllAdminAccounts", "gaaa", "[-v] [-e] [attr1 [attr2...]]", Category.ACCOUNT, 0, Integer.MAX_VALUE),
GET_ALL_CALENDAR_RESOURCES("getAllCalendarResources", "gacr", "[-v] [-e] [-s server] [{domain}]", Category.CALENDAR, 0, 5),
GET_ALL_CONFIG("getAllConfig", "gacf", "[attr1 [attr2...]]", Category.CONFIG, 0, Integer.MAX_VALUE),
GET_ALL_COS("getAllCos", "gac", "[-v]", Category.COS, 0, 1),
GET_ALL_DISTRIBUTION_LISTS("getAllDistributionLists", "gadl", "[-v] [{domain}]", Category.LIST, 0, 2),
GET_ALL_DOMAINS("getAllDomains", "gad", "[-v] [-e] [attr1 [attr2...]]", Category.DOMAIN, 0, Integer.MAX_VALUE),
GET_ALL_EFFECTIVE_RIGHTS("getAllEffectiveRights", "gaer", "{grantee-type} {grantee-id|grantee-name} [expandSetAttrs] [expandGetAttrs]", Category.RIGHT, 2, 4),
GET_ALL_FREEBUSY_PROVIDERS("getAllFbp", "gafbp", "[-v]", Category.FREEBUSY, 0, 1),
GET_ALL_RIGHTS("getAllRights", "gar", "[-v] [{target-type}]", Category.RIGHT, 0, 2),
GET_ALL_SERVERS("getAllServers", "gas", "[-v] [-e] [service]", Category.SERVER, 0, 3),
GET_ALL_XMPP_COMPONENTS("getAllXMPPComponents", "gaxcs", "", Category.CONFIG, 0, 0),
GET_AUTH_TOKEN_INFO("getAuthTokenInfo", "gati", "{auth-token}", Category.MISC, 1, 1),
GET_CALENDAR_RESOURCE("getCalendarResource",     "gcr", "{name@domain|id} [attr1 [attr2...]]", Category.CALENDAR, 1, Integer.MAX_VALUE), 
GET_CONFIG("getConfig", "gcf", "{name}", Category.CONFIG, 1, 1),
GET_COS("getCos", "gc", "{name|id} [attr1 [attr2...]]", Category.COS, 1, Integer.MAX_VALUE),
GET_DISTRIBUTION_LIST("getDistributionList", "gdl", "{list@domain|id} [attr1 [attr2...]]", Category.LIST, 1, Integer.MAX_VALUE),
GET_DISTRIBUTION_LIST_MEMBERSHIP("getDistributionListMembership", "gdlm", "{name@domain|id}", Category.LIST, 1, 1),
GET_DOMAIN("getDomain", "gd", "[-e] {domain|id} [attr1 [attr2...]]", Category.DOMAIN, 1, Integer.MAX_VALUE),
GET_DOMAIN_INFO("getDomainInfo", "gdi", "name|id|virtualHostname {value} [attr1 [attr2...]]", Category.DOMAIN, 2, Integer.MAX_VALUE), 
GET_EFFECTIVE_RIGHTS("getEffectiveRights", "ger", "{target-type} [{target-id|target-name}] {grantee-id|grantee-name} [expandSetAttrs] [expandGetAttrs]", Category.RIGHT, 1, 5, 
        null, new RightCommandHelp()),

// for testing the provisioning interface only, comment out after testing, the soap is only used by admin console
GET_CREATE_OBJECT_ATTRS("getCreateObjectAttrs", "gcoa", "{target-type} {domain-id|domain-name} {cos-id|cos-name} {grantee-id|grantee-name}", Category.RIGHT, 3, 4),

GET_FREEBUSY_QUEUE_INFO("getFreebusyQueueInfo", "gfbqi", "[{provider-name}]", Category.FREEBUSY, 0, 1),
GET_GRANTS("getGrants", "gg", "[-t {target-type} [{target-id|target-name}]] [-g {grantee-type} {grantee-id|grantee-name} [{0|1 (whether to include grants granted to groups the grantee belongs)}]]", 
        Category.RIGHT, 2, 7, null, new RightCommandHelp()),
GET_MAILBOX_INFO("getMailboxInfo", "gmi", "{account}", Category.MAILBOX, 1, 1),
GET_PUBLISHED_DISTRIBUTION_LIST_SHARE_INFO("getPublishedDistributionListShareInfo", "gpdlsi", "{dl-name|dl-id} [{owner-name|owner-id}]", Category.SHARE, 1, 2),
GET_QUOTA_USAGE("getQuotaUsage", "gqu", "{server}", Category.MAILBOX, 1, 1),        
GET_RIGHT("getRight", "gr", "{right}", Category.RIGHT, 1, 1),
GET_RIGHTS_DOC("getRightsDoc", "grd", "[java packages]", Category.RIGHT, 0, Integer.MAX_VALUE),
GET_SERVER("getServer", "gs", "[-e] {name|id} [attr1 [attr2...]]", Category.SERVER, 1, Integer.MAX_VALUE),
GET_SHARE_INFO("getShareInfo", "gsi", "{owner-name|owner-id}", Category.SHARE, 1, 1),
GET_XMPP_COMPONENT("getXMPPComponent", "gxc", "{name|id} [attr1 [attr2...]]", Category.CONFIG, 1, Integer.MAX_VALUE),
GRANT_RIGHT("grantRight", "grr", "{target-type} [{target-id|target-name}] {grantee-type} [{grantee-id|grantee-name} [secret]] {[-]right}", Category.RIGHT, 3, 6, null, new RightCommandHelp()),
HELP("help", "?", "commands", Category.MISC, 0, 1),
IMPORT_NOTEBOOK("importNotebook", "impn", "{name@domain} {directory} {folder}", Category.NOTEBOOK),
INIT_NOTEBOOK("initNotebook", "in", "[{name@domain}]", Category.NOTEBOOK),
INIT_DOMAIN_NOTEBOOK("initDomainNotebook", "idn", "{domain} [{name@domain}]", Category.NOTEBOOK),
LDAP(".ldap", ".l"), 
MODIFY_ACCOUNT("modifyAccount", "ma", "{name@domain|id} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 3, Integer.MAX_VALUE),
MODIFY_CALENDAR_RESOURCE("modifyCalendarResource",  "mcr", "{name@domain|id} [attr1 value1 [attr2 value2...]]", Category.CALENDAR, 3, Integer.MAX_VALUE),
MODIFY_CONFIG("modifyConfig", "mcf", "attr1 value1 [attr2 value2...]", Category.CONFIG, 2, Integer.MAX_VALUE),
MODIFY_COS("modifyCos", "mc", "{name|id} [attr1 value1 [attr2 value2...]]", Category.COS, 3, Integer.MAX_VALUE),
MODIFY_DATA_SOURCE("modifyDataSource", "mds", "{name@domain|id} {ds-name|ds-id} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 4, Integer.MAX_VALUE),                
MODIFY_DISTRIBUTION_LIST("modifyDistributionList", "mdl", "{list@domain|id} attr1 value1 [attr2 value2...]", Category.LIST, 3, Integer.MAX_VALUE),
MODIFY_DOMAIN("modifyDomain", "md", "{domain|id} [attr1 value1 [attr2 value2...]]", Category.DOMAIN, 3, Integer.MAX_VALUE),
MODIFY_IDENTITY("modifyIdentity", "mid", "{name@domain|id} {identity-name} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 4, Integer.MAX_VALUE),
MODIFY_SIGNATURE("modifySignature", "msig", "{name@domain|id} {signature-name|signature-id} [attr1 value1 [attr2 value2...]]", Category.ACCOUNT, 4, Integer.MAX_VALUE),
MODIFY_SERVER("modifyServer", "ms", "{name|id} [attr1 value1 [attr2 value2...]]", Category.SERVER, 3, Integer.MAX_VALUE),
MODIFY_XMPP_COMPONENT("modifyXMPPComponent", "mxc", "{name@domain} [attr1 value1 [attr value2...]]", Category.CONFIG, 3, Integer.MAX_VALUE),
PUBLISH_DISTRIBUTION_LIST_SHARE_INFO("publishDistributionListShareInfo", "pdlsi", "{+|-} {dl-name@domain|id} {owner-name|owner-id} [{folder-path|folder-id}]", Category.SHARE, 3, 4),
PUSH_FREEBUSY("pushFreebusy", "pfb", "[account-id ...]", Category.FREEBUSY, 1, Integer.MAX_VALUE),
PUSH_FREEBUSY_DOMAIN("pushFreebusyDomain", "pfbd", "{domain}", Category.FREEBUSY, 1, 1),
PURGE_ACCOUNT_CALENDAR_CACHE("purgeAccountCalendarCache", "pacc", "{name@domain|id} [...]", Category.CALENDAR, 1, Integer.MAX_VALUE),
RECALCULATE_MAILBOX_COUNTS("recalculateMailboxCounts", "rmc", "{name@domain|id}", Category.MAILBOX, 1, 1),
REMOVE_ACCOUNT_ALIAS("removeAccountAlias", "raa", "{name@domain|id} {alias@domain}", Category.ACCOUNT, 2, 2),
REMOVE_ACCOUNT_LOGGER("removeAccountLogger", "ral", "[-s/--server hostname] [{name@domain|id}] [{logging-category}]", Category.LOG, 0, 4),
REMOVE_DISTRIBUTION_LIST_ALIAS("removeDistributionListAlias", "rdla", "{list@domain|id} {alias@domain}", Category.LIST, 2, 2),
REMOVE_DISTRIBUTION_LIST_MEMBER("removeDistributionListMember", "rdlm", "{list@domain|id} {member@domain}", Category.LIST, 2, Integer.MAX_VALUE),
RENAME_ACCOUNT("renameAccount", "ra", "{name@domain|id} {newName@domain}", Category.ACCOUNT, 2, 2),
RENAME_CALENDAR_RESOURCE("renameCalendarResource",  "rcr", "{name@domain|id} {newName@domain}", Category.CALENDAR, 2, 2),
RENAME_COS("renameCos", "rc", "{name|id} {newName}", Category.COS, 2, 2),
RENAME_DISTRIBUTION_LIST("renameDistributionList", "rdl", "{list@domain|id} {newName@domain}", Category.LIST, 2, 2),
RENAME_DOMAIN("renameDomain", "rd", "{domain|id} {newDomain}", Category.DOMAIN, 2, 2, Via.ldap),
REINDEX_MAILBOX("reIndexMailbox", "rim", "{name@domain|id} {start|status|cancel} [{types|ids} {type or id} [,type or id...]]", Category.MAILBOX, 2, Integer.MAX_VALUE, null, new ReindexCommandHelp()),
REVOKE_RIGHT("revokeRight", "rvr", "{target-type} [{target-id|target-name}] {grantee-type} [{grantee-id|grantee-name}] {[-]right}", Category.RIGHT, 3, 5, null, new RightCommandHelp()),
SEARCH_ACCOUNTS("searchAccounts", "sa", "[-v] {ldap-query} [limit {limit}] [offset {offset}] [sortBy {attr}] [sortAscending 0|1*] [domain {domain}]", Category.SEARCH, 1, Integer.MAX_VALUE),
SEARCH_CALENDAR_RESOURCES("searchCalendarResources", "scr", "[-v] domain attr op value [attr op value...]", Category.SEARCH),
SEARCH_GAL("searchGal", "sg", "{domain} {name} [limit {limit}] [offset {offset}] [sortBy {attr}]", Category.SEARCH, 2, Integer.MAX_VALUE),
SELECT_MAILBOX("selectMailbox", "sm", "{account-name} [{zmmailbox commands}]", Category.MAILBOX, 1, Integer.MAX_VALUE),        
SET_ACCOUNT_COS("setAccountCos", "sac", "{name@domain|id} {cos-name|cos-id}", Category.ACCOUNT, 2, 2),
SET_PASSWORD("setPassword", "sp", "{name@domain|id} {password}", Category.ACCOUNT, 2, 2),
GET_ALL_MTA_AUTH_URLS("getAllMtaAuthURLs", "gamau", "", Category.SERVER, 0, 0),
GET_ALL_REVERSE_PROXY_URLS("getAllReverseProxyURLs", "garpu", "", Category.SERVER, 0, 0),
GET_ALL_REVERSE_PROXY_BACKENDS("getAllReverseProxyBackends", "garpb", "", Category.SERVER, 0, 0),
GET_ALL_MEMCACHED_SERVERS("getAllMemcachedServers", "gamcs", "", Category.SERVER, 0, 0),
RELOAD_MEMCACHED_CLIENT_CONFIG("reloadMemcachedClientConfig", "rmcc", "all | mailbox-server [...]", Category.MISC, 1, Integer.MAX_VALUE, Via.soap),
GET_MEMCACHED_CLIENT_CONFIG("getMemcachedClientConfig", "gmcc", "all | mailbox-server [...]", Category.MISC, 1, Integer.MAX_VALUE, Via.soap),
SOAP(".soap", ".s"),
SYNC_GAL("syncGal", "syg", "{domain} [{token}]", Category.MISC, 1, 2),
UPDATE_TEMPLATES("updateTemplates", "ut", "[-h host] {template-directory}", Category.NOTEBOOK, 1, 3);

Listing of zmmailbox commands

Taken from version 6.0.7 of com.zimbra.cs.zclient.ZMailboxUtil.java

ADD_FILTER_RULE("addFilterRule", "afrl", "{name}  [*active|inactive] [any|*all] {conditions}+ {actions}+", "add filter rule", Category.FILTER,  2, Integer.MAX_VALUE, O_AFTER, O_BEFORE, 
        O_FIRST, O_LAST),
ADD_MESSAGE("addMessage", "am", "{dest-folder-path} {filename-or-dir} [{filename-or-dir} ...]", "add a message to a folder", Category.MESSAGE, 2, Integer.MAX_VALUE, O_TAGS, 
        O_DATE, O_FLAGS, O_NO_VALIDATION),
ADMIN_AUTHENTICATE("adminAuthenticate", "aa", "{admin-name} {admin-password}", "authenticate as an admin. can only be used by an admin", Category.ADMIN, 2, 2, O_URL),
AUTHENTICATE("authenticate", "a", "{name} {password}", "authenticate as account and open mailbox", Category.MISC, 2, 2, O_URL),
AUTO_COMPLETE("autoComplete", "ac", "{query}", "contact auto autocomplete", Category.CONTACT,  1, 1, O_VERBOSE),
AUTO_COMPLETE_GAL("autoCompleteGal", "acg", "{query}", "gal auto autocomplete", Category.CONTACT,  1, 1, O_VERBOSE),
// CHECK_PERMISSION("checkPermission", "cp", "[right1 [right2...]]", "check if the user has the specified right on target.", Category.PERMISSION, 0, Integer.MAX_VALUE, O_VERBOSE),
CREATE_CONTACT("createContact", "cct", "[attr1 value1 [attr2 value2...]]", "create contact", Category.CONTACT, 2, Integer.MAX_VALUE, O_FOLDER, O_IGNORE, O_TAGS),
CREATE_FOLDER("createFolder", "cf", "{folder-name}", "create folder", Category.FOLDER, 1, 1, O_VIEW, O_COLOR, O_FLAGS, O_URL),
CREATE_IDENTITY("createIdentity", "cid", "{identity-name} [attr1 value1 [attr2 value2...]]", "create identity", Category.ACCOUNT, 1, Integer.MAX_VALUE),
CREATE_MOUNTPOINT("createMountpoint", "cm", "{folder-name} {owner-id-or-name} {remote-item-id-or-path}", "create mountpoint", Category.FOLDER, 3, 3, O_VIEW, O_COLOR, O_FLAGS),
CREATE_SEARCH_FOLDER("createSearchFolder", "csf", "{folder-name} {query}", "create search folder", Category.FOLDER, 2, 2, O_SORT, O_TYPES, O_COLOR),
CREATE_SIGNATURE("createSignature", "csig", "{signature-name} [signature-value}", "create signature", Category.ACCOUNT, 2, 2),
CREATE_TAG("createTag", "ct", "{tag-name}", "create tag", Category.TAG, 1, 1, O_COLOR),
DELETE_CONTACT("deleteContact", "dct", "{contact-ids}", "hard delete contact(s)", Category.CONTACT, 1, 1),
DELETE_CONVERSATION("deleteConversation", "dc", "{conv-ids}", "hard delete conversastion(s)", Category.CONVERSATION, 1, 1),
DELETE_ITEM("deleteItem", "di", "{item-ids}", "hard delete item(s)", Category.ITEM, 1, 1),
DELETE_IDENTITY("deleteIdentity", "did", "{identity-name}", "delete an identity", Category.ACCOUNT, 1, 1),
DELETE_FILTER_RULE("deleteFilterRule", "dfrl", "{name}", "add filter rule", Category.FILTER,  1, 1),
DELETE_FOLDER("deleteFolder", "df", "{folder-path}", "hard delete a folder (and subfolders)", Category.FOLDER, 1, 1),
DELETE_MESSAGE("deleteMessage", "dm", "{msg-ids}", "hard delete message(s)", Category.MESSAGE, 1, 1),
DELETE_SIGNATURE("deleteSignature", "dsig", "{signature-name|signature-id}", "delete signature", Category.ACCOUNT, 1, 1),
DELETE_TAG("deleteTag", "dt", "{tag-name}", "delete a tag", Category.TAG, 1, 1),
EMPTY_FOLDER("emptyFolder", "ef", "{folder-path}", "empty all the items in a folder (including subfolders)", Category.FOLDER, 1, 1),
EXIT("exit", "quit", "", "exit program", Category.MISC, 0, 0),
FLAG_CONTACT("flagContact", "fct", "{contact-ids} [0|1*]", "flag/unflag contact(s)", Category.CONTACT, 1, 2),
FLAG_CONVERSATION("flagConversation", "fc", "{conv-ids} [0|1*]", "flag/unflag conversation(s)", Category.CONVERSATION, 1, 2),
FLAG_ITEM("flagItem", "fi", "{item-ids} [0|1*]", "flag/unflag item(s)", Category.ITEM, 1, 2),
FLAG_MESSAGE("flagMessage", "fm", "{msg-ids} [0|1*]", "flag/unflag message(s)", Category.MESSAGE, 1, 2),
GET_ALL_CONTACTS("getAllContacts", "gact", "[attr1 [attr2...]]", "get all contacts", Category.CONTACT, 0, Integer.MAX_VALUE, O_VERBOSE, O_FOLDER),
GET_ALL_FOLDERS("getAllFolders", "gaf", "", "get all folders", Category.FOLDER, 0, 0, O_VERBOSE),
GET_ALL_TAGS("getAllTags", "gat", "", "get all tags", Category.TAG, 0, 0, O_VERBOSE),
GET_APPOINTMENT_SUMMARIES("getAppointmentSummaries", "gaps", "{start-date-spec} {end-date-spec} {folder-path}", "get appointment summaries", Category.APPOINTMENT, 2, 3, O_VERBOSE),
GET_CONTACTS("getContacts", "gct", "{contact-ids} [attr1 [attr2...]]", "get contact(s)", Category.CONTACT, 1, Integer.MAX_VALUE, O_VERBOSE),
GET_CONVERSATION("getConversation", "gc", "{conv-id}", "get a converation", Category.CONVERSATION, 1, 1, O_VERBOSE),
GET_IDENTITIES("getIdentities", "gid", "", "get all identites", Category.ACCOUNT, 0, 0, O_VERBOSE),
GET_FILTER_RULES("getFilterRules", "gfrl", "", "get filter rules", Category.FILTER,  0, 0),
GET_FOLDER("getFolder", "gf", "{folder-path}", "get folder", Category.FOLDER, 1, 1, O_VERBOSE),
GET_FOLDER_REQUEST("getFolderRequest", "gfr", "{folder-id}", "get folder request (always issues a GetFolderRequest)", Category.FOLDER, 1, 1, O_VERBOSE),
GET_FOLDER_GRANT("getFolderGrant", "gfg", "{folder-path}", "get folder grants", Category.FOLDER, 1, 1, O_VERBOSE),
GET_MESSAGE("getMessage", "gm", "{msg-id}", "get a message", Category.MESSAGE, 1, 1, O_VERBOSE),
GET_MAILBOX_SIZE("getMailboxSize", "gms", "", "get mailbox size", Category.MISC, 0, 0, O_VERBOSE),
GET_PERMISSION("getPermission", "gp", "[right1 [right2...]]", "get rights currently granted", Category.PERMISSION, 0, Integer.MAX_VALUE, O_VERBOSE),
GET_REST_URL("getRestURL", "gru", "{relative-path}", "do a GET on a REST URL relative to the mailbox", Category.MISC, 1, 1,
        O_OUTPUT_FILE, O_START_TIME, O_END_TIME, O_URL),
GET_SIGNATURES("getSignatures", "gsig", "", "get all signatures", Category.ACCOUNT, 0, 0, O_VERBOSE),
GRANT_PERMISSION("grantPermission", "grp", "{account {name}|group {name}|domain {name}||all|public|guest {email} [{password}]|key {email} [{accesskey}] {[-]right}}", "allow or deny 
       a right to a grantee or a group of grantee. to deny a right, put a '-' in front of the right", Category.PERMISSION, 2, 4),
HELP("help", "?", "commands", "return help on a group of commands, or all commands. Use -v for detailed help.", Category.MISC, 0, 1, O_VERBOSE),
IMPORT_URL_INTO_FOLDER("importURLIntoFolder", "iuif", "{folder-path} {url}", "add the contents to the remote feed at {target-url} to the folder", Category.FOLDER, 2, 2),
LIST_PERMISSION("listPermission", "lp", "", "list and describe all rights that can be granted", Category.PERMISSION, 0, 0, O_VERBOSE),
MARK_CONVERSATION_READ("markConversationRead", "mcr", "{conv-ids} [0|1*]", "mark conversation(s) as read/unread", Category.CONVERSATION, 1, 2),
MARK_CONVERSATION_SPAM("markConversationSpam", "mcs", "{conv} [0|1*] [{dest-folder-path}]", "mark conversation as spam/not-spam, and optionally move", Category.CONVERSATION, 1, 3),
MARK_ITEM_READ("markItemRead", "mir", "{item-ids} [0|1*]", "mark item(s) as read/unread", Category.ITEM, 1, 2),
MARK_FOLDER_READ("markFolderRead", "mfr", "{folder-path}", "mark all items in a folder as read", Category.FOLDER, 1, 1),
MARK_MESSAGE_READ("markMessageRead", "mmr", "{msg-ids} [0|1*]", "mark message(s) as read/unread", Category.MESSAGE, 1, 2),
MARK_MESSAGE_SPAM("markMessageSpam", "mms", "{msg} [0|1*] [{dest-folder-path}]", "mark a message as spam/not-spam, and optionally move", Category.MESSAGE, 1, 3),
MARK_TAG_READ("markTagRead", "mtr", "{tag-name}", "mark all items with this tag as read", Category.TAG, 1, 1),
MODIFY_CONTACT("modifyContactAttrs", "mcta", "{contact-id} [attr1 value1 [attr2 value2...]]", "modify a contact", Category.CONTACT, 3, Integer.MAX_VALUE, O_REPLACE, O_IGNORE),
MODIFY_FILTER_RULE("modifyFilterRule", "mfrl", "{name} [*active|inactive] [any|*all] {conditions}+ {actions}+", "add filter rule", Category.FILTER,  2, Integer.MAX_VALUE),
MODIFY_FOLDER_CHECKED("modifyFolderChecked", "mfch", "{folder-path} [0|1*]", "modify whether a folder is checked in the UI", Category.FOLDER, 1, 2),
MODIFY_FOLDER_COLOR("modifyFolderColor", "mfc", "{folder-path} {new-color}", "modify a folder's color", Category.FOLDER, 2, 2),
MODIFY_FOLDER_EXCLUDE_FREE_BUSY("modifyFolderExcludeFreeBusy", "mfefb", "{folder-path} [0|1*]", "change whether folder is excluded from free-busy", Category.FOLDER, 1, 2),
MODIFY_FOLDER_FLAGS("modifyFolderFlags", "mff", "{folder-path} {folder-flags}", "replaces the flags on the folder (subscribed, checked, etc.)", Category.FOLDER, 2, 2),
MODIFY_FOLDER_GRANT("modifyFolderGrant", "mfg", "{folder-path} {account {name}|group {name}|domain {name}|all|public|guest {email} [{password}]|key {email} [{accesskey}] {permissions|none}}", 
       "add/remove a grant to a folder", Category.FOLDER, 3, 5),
MODIFY_FOLDER_URL("modifyFolderURL", "mfu", "{folder-path} {url}", "modify a folder's URL", Category.FOLDER, 2, 2),
MODIFY_IDENTITY("modifyIdentity", "mid", "{identity-name} [attr1 value1 [attr2 value2...]]", "modify an identity", Category.ACCOUNT, 1, Integer.MAX_VALUE),
MODIFY_ITEM_FLAGS("modifyItemFlags", "mif", "{item-ids} {item-flags}", "replaces the flags on the items (answered, unread, flagged, etc.)", Category.ITEM, 2, 2),
MODIFY_SIGNATURE("modifySignature", "msig", "{signature-name|signature-id} {value}", "modify signature value", Category.ACCOUNT, 2, 2),
MODIFY_TAG_COLOR("modifyTagColor", "mtc", "{tag-name} {tag-color}", "modify a tag's color", Category.TAG, 2, 2),
MOVE_CONTACT("moveContact", "mct", "{contact-ids} {dest-folder-path}", "move contact(s) to a new folder", Category.CONTACT, 2, 2),
MOVE_CONVERSATION("moveConversation", "mc", "{conv-ids} {dest-folder-path}", "move conversation(s) to a new folder", Category.CONVERSATION, 2, 2),
MOVE_ITEM("moveItem", "mi", "{item-ids} {dest-folder-path}", "move item(s) to a new folder", Category.ITEM, 2, 2),
MOVE_MESSAGE("moveMessage", "mm", "{msg-ids} {dest-folder-path}", "move message(s) to a new folder", Category.MESSAGE, 2, 2),
NOOP("noOp", "no", "", "do a NoOp SOAP call to the server", Category.MISC, 0, 1),
POST_REST_URL("postRestURL", "pru", "{relative-path} {file-name}", "do a POST on a REST URL relative to the mailbox", Category.MISC, 2, 2,
        O_CONTENT_TYPE, O_IGNORE_ERROR, O_PRESERVE_ALARMS, O_URL),
RENAME_FOLDER("renameFolder", "rf", "{folder-path} {new-folder-path}", "rename folder", Category.FOLDER, 2, 2),
RENAME_SIGNATURE("renameSignature", "rsig", "{signature-name|signature-id} {new-name}", "rename signature", Category.ACCOUNT, 2, 2),
RENAME_TAG("renameTag", "rt", "{tag-name} {new-tag-name}", "rename tag", Category.TAG, 2, 2),
REVOKE_PERMISSION("revokePermission", "rvp", "{account {name}|group {name}|domain {name}||all|public|guest {email} [{password}]|key {email} [{accesskey}] {[-]right}}", "revoke a right previously 
       granted to a grantee or a group of grantees. to revoke a denied right, put a '-' in front of the right", Category.PERMISSION, 2, 4),
SEARCH("search", "s", "{query}", "perform search", Category.SEARCH, 0, 1, O_LIMIT, O_SORT, O_TYPES, O_VERBOSE, O_CURRENT, O_NEXT, O_PREVIOUS),
SEARCH_CONVERSATION("searchConv", "sc", "{conv-id} {query}", "perform search on conversation", Category.SEARCH, 0, 2, O_LIMIT, O_SORT, O_TYPES, O_VERBOSE, O_CURRENT, O_NEXT, O_PREVIOUS),
SELECT_MAILBOX("selectMailbox", "sm", "{account-name}", "select a different mailbox. can only be used by an admin", Category.ADMIN, 1, 1),
SYNC_FOLDER("syncFolder", "sf", "{folder-path}", "synchronize folder's contents to the remote feed specified by folder's {url}", Category.FOLDER, 1, 1),
TAG_CONTACT("tagContact", "tct", "{contact-ids} {tag-name} [0|1*]", "tag/untag contact(s)", Category.CONTACT, 2, 3),
TAG_CONVERSATION("tagConversation", "tc", "{conv-ids} {tag-name} [0|1*]", "tag/untag conversation(s)", Category.CONVERSATION, 2, 3),
TAG_ITEM("tagItem", "ti", "{item-ids} {tag-name} [0|1*]", "tag/untag item(s)", Category.ITEM, 2, 3),
TAG_MESSAGE("tagMessage", "tm", "{msg-ids} {tag-name} [0|1*]", "tag/untag message(s)", Category.MESSAGE, 2, 3);
Jump to: navigation, search