You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ma...@apache.org on 2016/01/26 11:04:59 UTC

svn commit: r1726757 [1/4] - in /james/project/trunk/server/protocols/jmap/doc: ./ spec/

Author: matthieu
Date: Tue Jan 26 10:04:59 2016
New Revision: 1726757

URL: http://svn.apache.org/viewvc?rev=1726757&view=rev
Log:
Import jmap specification to track progress in James implementation

Added:
    james/project/trunk/server/protocols/jmap/doc/
    james/project/trunk/server/protocols/jmap/doc/spec/
    james/project/trunk/server/protocols/jmap/doc/spec/LICENSE.md
    james/project/trunk/server/protocols/jmap/doc/spec/account.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/apimodel.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/authentication.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/calendar.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/calendarevent.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/calendareventlist.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/contact.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/contactgroup.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/contactlist.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/datamodel.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/mailbox.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/message.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/messagelist.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/push.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/searchsnippet.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/thread.mdwn
    james/project/trunk/server/protocols/jmap/doc/spec/upload.mdwn

Added: james/project/trunk/server/protocols/jmap/doc/spec/LICENSE.md
URL: http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/doc/spec/LICENSE.md?rev=1726757&view=auto
==============================================================================
--- james/project/trunk/server/protocols/jmap/doc/spec/LICENSE.md (added)
+++ james/project/trunk/server/protocols/jmap/doc/spec/LICENSE.md Tue Jan 26 10:04:59 2016
@@ -0,0 +1,190 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+   
+   Copyright 2016 FastMail Pty Ltd
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

Added: james/project/trunk/server/protocols/jmap/doc/spec/account.mdwn
URL: http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/doc/spec/account.mdwn?rev=1726757&view=auto
==============================================================================
--- james/project/trunk/server/protocols/jmap/doc/spec/account.mdwn (added)
+++ james/project/trunk/server/protocols/jmap/doc/spec/account.mdwn Tue Jan 26 10:04:59 2016
@@ -0,0 +1,116 @@
+## Accounts
+
+A single login may provide access to multiple accounts, for example if another user is sharing their mail with the logged in user.
+
+All data belongs to an account. With the exception of a few explicit operations to copy data between accounts, all methods take an *accountId* argument that specifies on which account the operations are to take place. This argument is always optional; if not specified, the primary account is used. All ids (other than Account ids of course) are only unique within their account.
+
+An **Account** object has the following properties:
+
+- **id**: `String`
+  The id of the account. This property is immutable.
+- **name**: `String`
+  A user-friendly string to show when presenting content from this account. e.g. the email address of the account.
+- **isPrimary**: `Boolean`
+  This MUST be true for exactly one of the accounts returned.
+- **capabilities**: `AccountCapabilities`
+  An object describing general capabilities of this server.
+- **mail**: `MailCapabilities|null`
+  If `null`, this account does not support mail, and any use of the mail-related methods with this account will result in an `accountNoMail` error. Otherwise, it will be an object describing certain capabilities of the mail system.
+- **contacts**: `ContactsCapabilities|null`
+  If `null`, this account does not support contacts, and any use of the contacts-related methods with this account will result in an `accountNoContacts` error. Otherwise, it will be an object describing certain capabilities of the contacts system.
+- **calendars**: `CalendarsCapabilities|null`
+  If `null`, this account does not support calendars, and any use of the calendar-related methods with this account will result in an `accountNoCalendars` error. Otherwise, it will be an object describing certain capabilities of the calendars system.
+
+An **AccountCapabilities** object has the following properties:
+
+- **maxSizeUpload**: `Number`
+  The maximum file size, in bytes, that the server will accept for a single file upload (for any purpose).
+
+A **MailCapabilities** object has the following properties:
+
+- **isReadOnly**: `Boolean`
+  True if the user has read-only access to the mail in this account. The user may not use the `set`-type mail methods with this account.
+- **maxSizeMessageAttachments**: `Number`
+  The maximum total size of attachments, in bytes, allowed for messages. A server MAY still reject messages with a lower attachment size total (for example, if the body includes several megabytes of text, causing the size of the encoded MIME structure to be over some server-defined limit).
+- **canDelaySend**: `Boolean`
+  Does the server support inserting a message into the outbox to be sent later at a user-specified time?
+- **messageListSortOptions**: `String[]`
+  A list of all the message properties the server supports for sorting by. This MAY include properties the client does not recognise (for example custom properties specified in the vendor extension). Clients MUST just ignore any unknown properties in the list.
+
+A **ContactsCapabilities** object has the following properties:
+
+- **isReadOnly**: `Boolean`
+  True if the user has read-only access to the contacts in this account. The user may not use the `set`-type contacts methods with this account.
+
+A **CalendarsCapabilities** object has the following properties:
+
+- **isReadOnly**: `Boolean`
+  True if the user has read-only access to the calendars in this account. The user may not use the `set`-type calendar methods with this account.
+
+The AccountCapabilities, MailCapabilities, ContactsCapabilities and CalendarsCapabilities objects MAY also contain one or more properties prefixed with "vnd-" + a name that uniquely identifies the vendor. For example `"vnd-com.fastmail"`. The value type for these properties is undefined. These properties allow vendors to be able to inform their own clients of custom capabilities. Unknown properties of this form MUST be ignored by clients.
+
+### getAccounts
+
+To fetch the complete list of accounts to which the user has access, make a call to `getAccounts`. It takes a sole, optional argument:
+
+- **sinceState**: `String|null`
+  This is the `state` string from a previous call to *getAccounts*.
+
+The response to *getAccounts* is called *accounts*. It has the following arguments:
+
+- **state**: `String`
+   A string representing the state on the server for **all** the data contained within the Account objects. If the data changes, this string will change.
+- **list**: `Account[]|null`
+  An array of all Account objects. If *sinceState* was supplied and it is identical to the current state, this property is `null`.
+
+The following errors may be returned instead of the `accounts` response:
+
+`invalidArguments`: Returned if the `sinceState` argument is included and has the wrong type.
+
+Example of a successful request:
+
+    ["getAccounts", {}, "#0"]
+
+and response:
+
+    [ "accounts", {
+      "state": "f6a7e214",
+      "list": [
+        {
+          "id": "6asf5",
+          "name": "user@example.com",
+          "isPrimary": true,
+          "capabilities": {
+            maxSizeUpload: 1000000000
+          },
+          "mail": {
+            "isReadOnly": false,
+            "maxSizeMessageAttachments": 50000000,
+            "canDelaySend": true,
+            "messageListSortOptions": [
+              "id", "date", "subject", "from", "to",
+              "isUnread", "isPinned", "threadUnread", "threadPinned"
+            ],
+          },
+          "contacts": {
+            "isReadOnly": false
+          },
+          "calendars": {
+            "isReadOnly": false
+          }
+        },
+        {
+          "id": "e12e1a",
+          "name": "shared.user@example.com",
+          "isPrimary": false,
+          "capabilities": {
+            maxSizeUpload: 0
+          },
+          "mail": null,
+          "contacts": null,
+          "calendars": {
+            "isReadOnly": true
+          }
+        }
+      ]
+    }, "#0" ]

Added: james/project/trunk/server/protocols/jmap/doc/spec/apimodel.mdwn
URL: http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/doc/spec/apimodel.mdwn?rev=1726757&view=auto
==============================================================================
--- james/project/trunk/server/protocols/jmap/doc/spec/apimodel.mdwn (added)
+++ james/project/trunk/server/protocols/jmap/doc/spec/apimodel.mdwn Tue Jan 26 10:04:59 2016
@@ -0,0 +1,259 @@
+# JMAP: The Spec
+
+<div id="last-update">Last updated 2016-01-15</div>
+
+This is a specification. It is meant to be readable but it also has to be comprehensive, so it can be dense in places. If you want to get a quick idea of how JMAP works, you should probably read the [guide for client developers](client.html) first. This has lots of example exchanges and should give you a good feel for what JMAP is all about. The spec is heavier going; it attempts to document exactly what each method should do, and what should happen in a myriad of edge cases.
+
+There are undoubtably edge cases that are not yet covered. If you find one, please email <ed...@jmap.io> or make a pull request on GitHub if you have a proposed fix.
+
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119](https://tools.ietf.org/html/rfc2119).
+
+## The JSON API model
+
+JSON is a text-based data interchange format as specified in [RFC7159](https://tools.ietf.org/html/rfc7159). The I-JSON format defined in [RFC7493](https://tools.ietf.org/html/rfc7493) is a strict subset of this, adding restrictions to avoid potentially confusing scenarios (for example, it mandates that an object MUST NOT have two properties with the same key). All data sent from the client to the server or from the server to the client MUST be valid I-JSON according to the RFC, encoded in UTF-8.
+
+### The structure of an exchange
+
+The client initiates an API request by sending the server a JSON array. Each element in this array is another array representing a method invocation on the server. The server will process the method calls and return a response consisting of an array in the same format. Each method call always contains three elements:
+
+1. The **name** of the method to call, or the name of the response from the server. This is a `String`.
+2. An `Object` containing *named* **arguments** for that method or response.
+3. A **client id**: an arbitrary `String` to be echoed back with the responses emitted by that method call (as we'll see lower down, a method may return 1 or more responses, as some methods make implicit calls to other ones).
+
+Example query:
+
+    [
+      ["method1", {"arg1": "arg1data", "arg2": "arg2data"}, "#1"],
+      ["method2", {"arg1": "arg1data"}, "#2"],
+      ["method3", {}, "#3"]
+    ]
+
+The method calls MUST be processed sequentially, in order. Each API request
+(which, as shown, may contain multiple method calls) receives a JSON
+response in exactly the same format. The output of the methods MUST be added
+to the array in the same order as the methods are processed.
+
+Example response:
+
+    [
+      ["responseFromMethod1", {"arg1": 3, "arg2": "foo"}, "#1"],
+      ["responseFromMethod2", {"isBlah": true}, "#2"],
+      ["anotherResponseFromMethod2", {"data": 10, "yetmoredata": "Hello"}, "#2"],
+      ["aResponseFromMethod3", {}, "#3"]
+    ]
+
+### Errors
+
+If the data sent as an API request is not valid JSON or does not match the structure above, an error will be returned at the transport level. For example, when using JMAP over HTTP, a `400 Bad Request` error will be returned at the HTTP level.
+
+Possible errors for each method are specified in the method descriptions. If a method encounters an error, an `error` response must be inserted at the current point in the output array and, unless otherwise specified, no further processing must happen within that method.
+
+Any further method calls in the request MUST then be processed as normal.
+
+An `error` response looks like this:
+
+    ["error", {
+      type: "unknownMethod"
+    }, "client-id"]
+
+The response name is `error`, and it has a type property as specified in the method description. Other properties may be present with further information; these are detailed in the method descriptions where appropriate.
+
+If an unknown method is called, an `unknownMethod` error (this is the type shown in the example above) MUST be inserted and then the next method call MUST be processed as normal.
+
+If an unknown argument or invalid arguments (wrong type, or in violation of other specified constraints) are supplied to a method, an `invalidArguments` error MUST be inserted and then the next method call MUST be processed as normal.
+
+### Vendor-specific extensions
+
+Individual services will have custom features they wish to expose over JMAP. This may take the form of extra datatypes and/or methods not in the spec, or extra arguments to JMAP methods, or extra properties on existing data types (which may also appear in arguments to methods that take property names). To ensure compatibility with clients that don't know about a specific custom extension, and for compatibility with future versions of JMAP, the server MUST ONLY expose these extensions if the client explicitly opts in. Without opt-in, the server MUST just follow the spec and reject anything that does not conform to it as specified.
+
+Any vendor extensions supported by the server are advertised to the client in the capabilities property on the Account object. The client opt-in happens at the transport layer (see the next section).
+
+### JMAP over HTTPS
+
+To make an API request over HTTP (support for other protocols may be added in future extensions to the spec), the client makes an authenticated POST request to the API URL; see the Authentication section of the spec for how to discover this URL and how to authenticate requests.
+
+The request MUST have a content type of `application/json` and be encoded in utf-8.
+
+The request MAY include an `X-JMAP-Version` header, the value of which is a number for the spec version the client would like to use (the list of versions supported by each account can be discovered by the client by inspecting the capabilities property of the Account object). If omitted, the server MUST presume a value equal to the *lowest* supported version common to all accounts.
+
+The request MAY include an 'X-JMAP-Extensions' header, the value of which is a comma-separated list of 'vendor-extension-name:extension-version` the client would like to use. For example, "com.fastmail.message:1,com.fastmail.savedSearch:4". Any white-space should be ignored when evaluating this header.
+
+The server will respond with one of the following HTTP response codes:
+
+#### `200`: OK
+
+The API request was successful. The response will be of type `application/json` and consists of the response to the API calls, as described above.
+
+#### `400`: Bad Request
+
+The request was malformed. For example, it may have had the wrong content type, or have had a JSON object that did not conform to the API calling structure (see *The structure of an exchange* above). The client SHOULD NOT retry the same request.
+
+#### `401`: Unauthorized
+
+The `Authorization` header was missing or did not contain a valid token. Reauthenticate and then retry the request. There is no content in the response.
+
+#### `404`: Not Found
+
+The API endpoint has moved. See the Authentication section of the spec for how to rediscover the current URL to use. There is no content in the response.
+
+#### `412`: Precondition Failed
+
+This means either the JMAP version specified in an `X-JMAP-Version` header, or an extension/version specified in an `X-JMAP-Extensions` header is not supported by one of the accounts used in a method.
+
+After authentication, but before processing any methods, the server MUST scan the methods in the request and check the requested JMAP version and extensions are supported by all the accounts referenced by the methods (unknown account ids MUST just be skipped; these method calls will error out when processed). If there are any accounts that do not support the requested version and extensions, this HTTP error code is returned and the server MUST NOT process any of the methods.
+
+#### `500`: Internal Server Error
+
+Something has gone wrong internally, and the server is in a broken state. Don't automatically retry. There is no content in the response.
+
+#### `503`: Service Unavailable
+
+The server is currently down. Try again later with exponential backoff. There is no content in the response.
+
+### Security
+
+As always, the server must be strict about data received from the client. Arguments need to be checked for validity; a malicious user could attempt to find an exploit through the API. In case of invalid arguments (unknown/insufficient/wrong type for data etc.) the method should return an `invalidArguments` error and terminate.
+
+### Concurrency
+
+To ensure the client always sees a consistent view of the data, the state accessed by a method call MUST NOT change during the execution of the method, except due to actions by the method call itself. The state MAY change in-between method calls (even within a single API request).
+
+### The Number datatype
+
+The JSON datatypes are limited to those found in JavaScript. A `Number` in JavaScript is represented as a signed double (64-bit floating point). However, except where explicitly specified, all numbers used in this API are unsigned integers <= 2^53 (the maximum integer that may be reliably stored in a double). This implicitly limits the maximum length of message lists in queries and the like.
+
+### The Date datatypes
+
+Where the API specifies `Date` as a type, it means a string in [RFC3339](https://tools.ietf.org/html/rfc3339) *date-time* format, with the *time-offset* component always `Z` (i.e. the date-time MUST be in UTC time) and *time-secfrac* always omitted. The "T" and "Z" MUST always be upper-case. For example, `"2014-10-30T14:12:00Z"`.
+
+Where the API specifies `LocalDate` as a type, it means a string in the same format as `Date`, but with the `Z` omitted from the end. This only occurs in relation to calendar events. The interpretation in absolute time depends upon the time zone for the event, which MAY not be a fixed offset (for example when daylight saving time occurs).
+
+### Use of `null`
+
+Unless otherwise specified, a missing property in a request, response or object MUST be intepreted exactly the same as that property having the value `null`. If `null` is not a valid value for that property this would typically cause an error to occur. This rule does not apply to the [top-level datatypes](#data-model-overview), where a missing property usually indicates that the sender wants to leave the existing property value untouched (e.g. in a [*setFoos*](#setfoos) request or a [*getFooUpdates*](#getfooupdates) response).
+
+### CRUD methods
+
+JMAP defines various types of objects and provides a uniform interface for creating, retrieving, updating and deleting them. A **data type** is a collection of named, typed properties, just like the schema for a database table. Each row of the table is a **record**. For a `Foo` data type, records of that type would be fetched via a `getFoos` call and modified via a `setFoos` call. Delta updates may be fetched via a `getFooUpdates` call. These methods all follow a standard format as described below.
+
+### getFoos
+
+Objects of type **Foo** are fetched via a call to *getFoos*. Methods with a name starting with `get` MUST NOT alter state on the server.
+
+This method may take some or all of the following arguments. The getter for a particular data type may not implement all of the arguments (for example if the data type only has two properties, there is little point in being able to just return one of them etc.); see the docs of the type in question. However, if one of the following arguments is available, it will behave exactly as specified below.
+
+- **ids**: `String[]|null`
+  The ids of the Foo objects to return. If `null` then **all** records of the data type are returned.
+- **properties**: `String[]|null`
+  If supplied, only the properties listed in the array are returned for each Foo object. If `null`, all properties of the object are returned. The id of the object is **always** returned, even if not explicitly requested.
+- **sinceState**: `String|null`
+  The *state* argument from a *foos* response may be passed back to future *getFoos* calls as the *sinceState* argument. If the current state is the same, the server SHOULD skip fetching the records and return a result indicating there is no change (this is essentially like an ETag). Most types support the more sophisticated *getFooUpdates* call instead to allow for delta updates. However, for small collections of data that change infrequently, this might be used. If available, this argument is always optional.
+
+The response to `getFoos` is called `foos`. It has the following arguments:
+
+- **state**: `String`
+  A string representing the state on the server for **all** the data of this type. If the data changes, this string will change. It is used to get delta updates, if supported for the type.
+- **list**: `Foo[]|null`
+  An array of the Foo objects requested. This is the **empty array** if no objects were requested (and *ids* argument was passed with an empty array), or none were found (the user has no objects of this type, or none of the ids given were valid). If *sinceState* was supplied and it is identical to the current state, this property is `null` (the client already has up to date data so the server may skip returning it).
+- **notFound**: `String[]|null`
+  This array contains the ids passed to the method for records that do not exist, or `null` if all requested ids were found. It will always be `null` if the *ids* argument in the call was `null`.
+
+The following error may be returned instead of the `foos` response:
+
+`invalidArguments`: Returned if one of the arguments is of the wrong type, or otherwise invalid. A `description` property MAY be present on the response object to help debug with an explanation of what the problem was.
+
+### getFooUpdates
+
+When the state of the set of Foo records changes on the server (whether due to creation, updates or deletion), the *state* property of the *foos* response will change. The *getFooUpdates* call allows a client to efficiently update the state of any its Foo cache to match the new state on the server. It takes the following arguments:
+
+- **sinceState**: `String`
+  The current state of the client. This is the string that was returned as the *state* argument in the *foos* response. The server will return the changes made since this state.
+- **maxChanges**: `Number|null`
+  The maximum number of Foo ids to return in the response. The server MAY choose to clamp this value to a particular maximum or set a maximum if none is given by the client. If supplied by the client, the value MUST be a positive integer greater than 0. If a value outside of this range is given, the server MUST reject the call with an `invalidArguments` error.
+- **fetchRecords**: `Boolean|null`
+  If `true`, after outputting the *fooUpdates* response, the server will make an implicit call to *getFoos* with the *changed* property of the response as the *ids* argument. If `false` or `null`, no implicit call will be made.
+- **fetchRecordProperties**: `String[]|null`
+  If the *getFoos* method takes a *properties* argument, this argument is passed through on implicit calls (see the *fetchRecords* argument).
+
+The response to *getFooUpdates* is called *fooUpdates*. It has the following arguments:
+
+- **oldState**: `String`
+  This is the *sinceState* argument echoed back; the state from which the server is returning changes.
+- **newState**: `String`
+  This is the state the client will be in after applying the set of changes to the old state.
+- **hasMoreUpdates**: `Boolean`
+  If `true`, the client may call *getFooUpdates* again with the *newState* returned to get further updates. If `false`, *newState* is the current server state.
+- **changed**: `String[]`
+  An array of Foo ids for records which have been created or changed but not destroyed since the oldState.
+- **removed**: `String[]`
+  An array of Foo ids for records which have been destroyed since the old state.
+
+The *maxChanges* argument (and *hasMoreUpdates* response argument) is available for data types with potentially large amounts of data (i.e. those for which there is a *getFooList* method available for loading the data in pages).  If a *maxChanges* is supplied, or set automatically by the server, the server must try to limit the number of ids across *changed* and *removed* to the number given. If there are more changes than this between the client's state and the current server state, the update returned MUST take the client to an intermediate state, from which the client can continue to call *getFooUpdates* until it is fully up to date. The server MAY return more ids than the *maxChanges* total if this is required for it to be able to produce an update to an intermediate state, but it SHOULD try to keep it close to the maximum requested.
+
+If a Foo record has been modified AND deleted since the oldState, the server should just return the id in the *removed* response, but MAY return it in the changed response as well. If a Foo record has been created AND deleted since the oldState, the server should remove the Foo id from the response entirely, but MAY include it in the *removed* response, and optionally the *changed* response as well.
+
+The following errors may be returned instead of the *fooUpdates* response:
+
+`invalidArguments`: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A *description* property MAY be present on the response object to help debug with an explanation of what the problem was.
+
+`cannotCalculateChanges`: Returned if the server cannot calculate the changes from the state string given by the client. Usually due to the client's state being too old, or the server being unable to produce an update to an intermediate state when there are too many updates. The client MUST invalidate its Foo cache. The error object MUST also include a `newState: String` property with the current state for the type.
+
+### setFoos
+
+Modifying the state of Foo objects on the server is done via the *setFoos* method. This encompasses creating, updating and destroying Foo records. This has two benefits:
+
+1. It allows the server to sort out ordering and dependencies that may exist if doing multiple operations at once (for example to ensure there is always a minimum number of a certain record type).
+2. Only a single call is required to make all changes to a particular type, so the *ifInState* requirement will not be invalidated by a previous method call in the same request.
+
+The *setFoos* method takes the following arguments:
+
+- **ifInState**: `String|null`
+  This is a state string as returned by the *getFoos* method. If supplied, the string must match the current state, otherwise the method will be aborted and a `stateMismatch` error returned. If `null`, the change will be applied to the current state.
+- **create**: `String[Foo]|null`
+  A map of *creation id* (an arbitrary string set by the client) to Foo objects (containing all properties except the id, unless otherwise stated in the specific documentation of the data type). If `null`, no objects will be created.
+- **update**: `String[Foo]|null`
+  A map of id to a Foo object. The object may omit any property; only properties that have changed need be included. If `null`, no objects will be updated.
+- **destroy**: `String[]|null`
+  A list of ids for Foo objects to permanently delete. If `null`, no objects will be deleted.
+
+Each create, update or destroy is considered an atomic unit. It is permissible for the server to commit some of the changes but not others, however it is not permissible to only commit part of an update to a single record (e.g. update a *name* property but not a *count* property, if both are supplied in the update object).
+
+If a create, update or destroy is rejected, the appropriate error should be added to the notCreated/notUpdated/notDestroyed property of the response and the server MUST continue to the next create/update/destroy. It does not terminate the method.
+
+If an id given cannot be found, the update or destroy MUST be rejected with a `notFound` set error.
+
+Some record objects may hold references to others (foreign keys). When records are created or modified, they may reference other records being created *in the same API request* by using the creation id prefixed with a `#`. The order of the method calls in the request by the client MUST be such that the record being referenced is created in the same or an earlier call. The server thus never has to look ahead. Instead, while processing a request (a series of method calls), the server MUST keep a simple map for the duration of the request of creation id to record id for each newly created record, so it can substitute in the correct value if necessary in later method calls.
+
+The response to *setFoos* is called *foosSet*. It has the following arguments:
+
+- **oldState**: `String|null`
+  The state string that would have been returned by *getFoos* before making the requested changes, or `null` if the server doesn't know what the previous state string was.
+- **newState**: `String`
+  The state string that will now be returned by *getFoos*.
+- **created**: `String[Foo]`
+  A map of the creation id to an object containing any **server-assigned** properties of the Foo object (including the id) for all successfully created records.
+- **updated**: `String[]`
+  A list of Foo ids for records that were successfully updated.
+- **destroyed**: `String[]`
+  A list of Foo ids for records that were successfully destroyed.
+- **notCreated**: `String[SetError]`
+  A map of creation id to a SetError object for each record that failed to be created. The possible errors are defined in the description of the method for specific data types.
+- **notUpdated**: `String[SetError]`
+  A map of Foo id to a SetError object for each record that failed to be updated. The possible errors are defined in the description of the method for specific data types.
+- **notDestroyed**: `String[SetError]`
+  A map of Foo id to a SetError object for each record that failed to be destroyed. The possible errors are defined in the description of the method for specific data types.
+
+A **SetError** object has the following properties:
+
+- **type**: `String`
+  The type of error.
+- **description**: `String|null`
+  A description of the error to display to the user.
+
+Other properties may also be present on the object, as described in the relevant methods.
+
+The following errors may be returned instead of the `foosSet` response:
+
+`invalidArguments`: Returned if one of the arguments is of the wrong type, or otherwise invalid. A `description` property MAY be present on the response object to help debug with an explanation of what the problem was.
+
+`stateMismatch`: Returned if an `ifInState` argument was supplied and it does not match the current state.

Added: james/project/trunk/server/protocols/jmap/doc/spec/authentication.mdwn
URL: http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/doc/spec/authentication.mdwn?rev=1726757&view=auto
==============================================================================
--- james/project/trunk/server/protocols/jmap/doc/spec/authentication.mdwn (added)
+++ james/project/trunk/server/protocols/jmap/doc/spec/authentication.mdwn Tue Jan 26 10:04:59 2016
@@ -0,0 +1,171 @@
+## Authentication
+
+Before connecting to any JMAP service, the client must first gain an access token. It cannot just use a username/password directly. This allows the server to know (and show the user) which clients currently have access to the account, and to be able to revoke access individually.
+
+The server may support multiple different mechanisms for authenticating a user to gain the access token. It is expected that further types may be added in future extensions to the JMAP specification (for example [FIDO](https://fidoalliance.org/)).
+
+### Service autodiscovery
+
+There are three common autodiscovery methods in use for internet protocols:
+
+- **DNS srv**
+  See [RFC6186](https://tools.ietf.org/html/rfc6186) and [RFC6764](https://tools.ietf.org/html/rfc6764)
+- **.well-known/`servicename`**
+  See [RFC5785](https://tools.ietf.org/html/rfc5785)
+- **autoconfig.example.com**/**autodiscover.example.com**
+  Used by [Thunderbird](https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration/FileFormat/HowTo) and Outlook.
+
+A JMAP-supporting email host for the domain `example.com` SHOULD publish a SRV record `_jmaps._tcp.example.com` which gives a hostname and port (usually port `443`).
+
+The authentication URL is `https://hostname/.well-known/jmap` (following any redirects).
+
+Other autodiscovery options using `autoconfig.example.com` or `autodiscover.example.com` may be added to a future version of JMAP to support clients which can't use SRV lookup.
+
+### Getting an access token
+
+Authorization always starts with the client making a POST request to the authentication URL (found either via service autodiscovery or manual entry). The request MUST be of type `application/json` and specify an `Accept: application/json` header. The body of the request MUST be a single JSON object, encoded in UTF-8, with the following properties:
+
+- **username**: `String`
+  The username the client wishes to authenticate. This is normally the primary email address of the user.
+- **clientName**: `String`
+  The name of the client software. e.g. `Mozilla Thunderbird`.
+- **clientVersion**: `String`
+  Information to identify the version of the client.  This MUST change for any changed client code (e.g. a version control tag or counter for development software) and SHOULD sort lexically later for newer versions.
+- **deviceName**: `String`
+  A human-friendly string to identify the device making the request, e.g. "Joe Blogg's iPhone".
+
+The server may use the client/device information to help identify the login to the user in a login log or other security reporting. Although hopefully unnecessary, they may also be helpful for working around client bugs in the future.
+
+The server will respond with one of the following HTTP status codes:
+
+#### `200`: Success, but more authorization required.
+
+The response body will be a single JSON object with the following properties.
+
+- **continuationToken**: `String`
+  A token from the server to allow it to connect the next request with previous requests in the login process. This SHOULD be of limited time validity (e.g. 15 minutes from previous call).
+- **methods**: `String[]`
+  A list of the supported authentication methods to continue with authentication. This will often have only have one item in it. Allowed values are `"password"`, `"external"` and `"oauth"`. More options may be added in future extensions to JMAP.
+- **prompt**: `String|null`
+  A message to display in the client to the user.
+
+This is the standard response to an initial request. Note, a server may return this even if the username is not actually active, to prevent enumeration. The client should then pick one of the *methods* from the list in the response to continue with authentication (if no methods supported by the client are in the list, it will not be able to log in to this account):
+
+- `"password"`: the client should prompt the user for a password. If the `prompt` property is non-null, this message should be displayed to the user to explain what input is required. The prompt MUST be treated as plain text, but the client SHOULD automatically hyperlink any URLs it finds in the text if a system browser is available. If `prompt == null`, the client SHOULD just show a generic password prompt message.
+- `"external"`: the user must do something out-of-band to authorize the app. The server SHOULD return a prompt string to display to the user to tell them what they need to do. Again, the client MUST treat the prompt as plain text, but SHOULD automatically hyperlink any URLs it finds if a system browser is available. The client MUST also offer a continue button (or similar) for the user to indicate to the client when they have completed the out-of-band authentication.
+- `"oauth"`: OAuth based authentication. For OAuth integration, see the docs of the service in question, since every service implements it slightly differently and the client must register with the service beforehand to use it. If using this method, an access token is obtained entirely through the OAuth mechanism. See the "Refetching URL endpoints" section below for how to obtain the URL endpoints after successfully authenticating using OAuth.
+
+If using `"password"` or `"external"`, the user will at some point indicate to the client to continue authentication. At this point the client submits a POST request to the same URL as before, with the body being a single JSON object with the following properties:
+
+- **token**: `String`
+  The *continuationToken* the server sent from the previous request.
+- **method**: `String`
+  The method chosen to continue authentication.
+- **password**: `String` (optional)
+  The password entered by the user (if `method == password`). The client SHOULD NOT store the password the user entered beyond what is required to submit it to the server in this step.
+
+The server will then return one of the same set of responses as before, which should be handled the same (for example, if 2FA is required, a `200` response may be returned again and a second password prompted for, with a `prompt` text explaining to the user that a one-time password has been SMSed to them).
+
+#### `201`: Authentication is complete, access token created.
+
+The response body will be a single JSON object with the following properties.
+
+- **versions**: `Number[]`
+  The list of supported JMAP-spec versions. If the client does not opt in to a particular version, then the lowest/oldest version in the list will be used by the server.
+- **extensions**: `String[Number[]]`
+  As described in the API Model, specific vendors may need to add custom extensions to the JMAP protocol, including new datatypes, extra properties on existing datatypes and extra methods. To ensure compability, these extensions must be explicitly opted into by the client.
+
+  The *extensions* property is a map of a name that uniquely identifies the extension (including a unique string identifying the vendor) to a list of version numbers supported for that extension. e.g. `"com.fastmail.message": [ 1 ]`.
+
+  A client may opt in to an extension by sending `"extension-name:extension-version"` in the `X-JMAP-Extensions` header of the request (or as specified for any future non-HTTP transport). It is up to the vendor to document exactly what the extension provides.
+
+  It is expected that this mechanism is mainly used for custom clients by the vendor for their own server. Where features are added that are more universally useful, it is hoped they will quickly be standardised in a future version of this spec, to maintain open compatibility between vendors.
+- **accessToken**: `String`
+  The secret token to be used by the client to authenticate all future JMAP requests. The client should keep this secure, preferably in an OS keychain or the like. Since tokens should not be reused across devices or clients, the client SHOULD NOT reveal this token to the user.
+- **api**: `String`
+  The URL to use for JMAP API requests.
+- **eventSource**: `String`
+  The URL to connect to for push events (see the Push section of this spec).
+- **upload**: `String`
+  The URL endpoint to use when uploading files (see the Upload section of this spec).
+- **download**: `String`
+  The URL endpoint to use when downloading files, in [RFC6570 URI Template](https://tools.ietf.org/html/rfc6570) (level 1) format. The URL MUST contain a variable called `blobId`. The URL SHOULD contain a variable called `name`. The client may use this template in combination with a blobId to download any binary data (files) referenced by other objects. Since a blob is not associated with a particular name, the template SHOULD allow a name to be substituted in as well; the server will return this as the filename if it sets a `Content-Disposition` header. To download the data the client MUST make an authenticated GET request (see below for how to authenticate requests) to the expanded URL, and then follow any redirects.
+
+URLs are returned only after logging in. This allows different URLs to be used for users located in different geographic datacentres within the same service.
+
+Note, if authentication is done via IP or mobile subscriber ID or some similar mechanism, a `201` response MAY be returned in response to the initial request (with just the username and client info).
+
+#### `400`: Malformed request
+
+The request is of the wrong content type, or does not contain data in the expected format. The client MUST NOT retry the same request.
+
+#### `401`: Authentication step failed
+
+Returned in response to a continuation request which failed (e.g. the password entered was not correct, or the out-of-band step was not completed successfully). The response body will be a single JSON object with the same properties as the `200` response.
+
+#### `403`: Restart authentication
+
+This normally means the continuation token has expired, but it can be returned for any other reason. The client MUST restart authentication (go back to sending the username and client info to the server).
+
+#### `429`: Rate limited
+
+Returned if the server is temporarily blocking this IP/client from authenticating. This may be due to too many failed password attempts, or detected username enumeration attempts, or any other reason. (Legitimate) clients should wait a while then try again.
+
+### Refetching URL endpoints
+
+A server MAY (although SHOULD NOT) move end points for any services other than authentication at any time. If a request to the API/file upload/event source endpoint returns a `404`, the client MUST refetch the URL endpoints. To do this, it should make an authenticated GET request to the authentication URL (see below for how to authenticate requests).
+
+For OAuth logins, this is how the URLs may be fetched initially as well.
+
+The server MUST respond with one of the following status codes:
+
+#### `200`: OK
+
+The request was successful. The response will be of type `application/json` and consists of a single JSON object containing the following properties:
+
+- **versions**: `Number[]`
+  The list of JMAP-spec versions supported by the account.
+- **extensions**: `String[Number[]]`
+  Map of extension names to version number of that extension (see above).
+- **api**: `String`
+  The URL to use for JMAP API requests.
+- **eventSource**: `String`
+  The URL to connect to for push events (see the Push section of this spec).
+- **upload**: `String`
+  The URL endpoint to use when uploading files (see the Upload section of this spec).
+- **download**: `String`
+  The URL endpoint to use when downloading files (see above).
+
+#### `401`: Unauthorized
+
+The `Authorization` header was missing or did not contain a valid token. Reauthenticate and then retry the request. There is no content in the response.
+
+#### `404`: Not Found
+
+The JMAP server is no longer here. There is no content in the response.
+
+#### `500`: Internal Server Error
+
+Something has gone wrong internally, and the server is in a broken state. Don't automatically retry. There is no content in the response.
+
+#### `503`: Service Unavailable
+
+The server is currently down. Try again later with exponential backoff. There is no content in the response.
+
+### Revoking an access token
+
+The validity of an access token is determined by the server. It may be valid for a limited time only, or expire after a certain time of inactivity, or be valid indefinitely etc. If an access token expires, it MUST NOT be resurrected. The client MUST restart the authentication process to get a new access token.
+
+A client may revoke an access token at any time by making a DELETE HTTP request to the authentication URL (used to get the token in the first place), with the correct `Authorization` header (see below). The response from the server will be one of the following:
+
+`204`: Success (the access token has now been revoked).
+
+`401`: Failed due to due to no `Authorization` header, or `Authorization` header is not a valid access token.
+
+No content is returned in either case.
+
+For OAuth, see the provider's documentation on revoking access tokens.
+
+### Authenticating HTTP requests
+
+All HTTP requests other than to the authentication URL must be authenticated. To do this, the client MUST add an `Authorization` header to each request with the value being the access token. This applies to OAuth tokens too, but see the provider's documentation for the details of what value to use for the header.

Added: james/project/trunk/server/protocols/jmap/doc/spec/calendar.mdwn
URL: http://svn.apache.org/viewvc/james/project/trunk/server/protocols/jmap/doc/spec/calendar.mdwn?rev=1726757&view=auto
==============================================================================
--- james/project/trunk/server/protocols/jmap/doc/spec/calendar.mdwn (added)
+++ james/project/trunk/server/protocols/jmap/doc/spec/calendar.mdwn Tue Jan 26 10:04:59 2016
@@ -0,0 +1,192 @@
+## Calendars
+
+A Calendar is a named collection of events. All events are associated with one, and only one, calendar.
+
+A **Calendar** object has the following properties:
+
+- **id**: `String`
+  The id of the calendar. This property is immutable.
+- **name**: `String`
+  The user-visible name of the calendar. This may be any UTF-8 string of at least 1 character in length and maximum 256 bytes in size.
+- **color**: `String`
+  Any valid CSS color value. The color to be used when displaying events associated with the calendar. The color SHOULD have sufficient contrast to be used as text on a white background.
+- **sortOrder**: `Number`
+  Defines the sort order of calendars when presented in the UI, so it is
+  consistent between devices. The number MUST be an integer in the range
+  0 <= sortOrder < 2^31.
+
+  A calendar with a lower order should be displayed before a calendar with
+  a higher order in any list of calendars in the client's UI. Calendars with
+  equal order should be sorted in alphabetical order by name. The sorting
+  should take into locale-specific character order convention.
+- **isVisible**: `Boolean`
+  Should the calendar's events be displayed to the user at the moment?
+- **mayReadFreeBusy**: `Boolean`
+  The user may read the free-busy information for this calendar. In JMAP
+  terms, this means the user may use this calendar as part of a filter in a
+  *getCalendarEventList* call, however unless `mayRead == true`, the events
+  returned for this calendar will only contain free-busy information, and be stripped of any other data.
+  This property MUST be `true` if *mayRead* is `true`.
+- **mayReadItems**: `Boolean`
+  The user may fetch the events in this calendar. In JMAP terms, this means
+  the user may use this calendar as part of a filter in a
+  *getCalendarEventList* call
+- **mayAddItems**: `Boolean`
+  The user may add events to this calendar. In JMAP terms, this means the
+  user may call *setCalendarEvents* to create new events in this calendar or
+  move existing events into this calendar from another calendar.
+  This property MUST be `false` if the account to which this calendar belongs
+  has the *isReadOnly* property set to `true`.
+- **mayModifyItems**: `Boolean`
+  The user may edit events in this calendar by calling *setCalendarEvents* with
+  the *update* argument referencing events in this collection.
+  This property MUST be `false` if the account to which this calendar belongs
+  has the *isReadOnly* property set to `true`.
+- **mayRemoveItems**: `Boolean`
+  The user may remove events from this calendar by calling *setCalendarEvents*
+  with the *destroy* argument referencing events in this collection, or by
+  updating their *calendarId* property to a different calendar.
+  This property MUST be `false` if the account to which this calendar belongs
+  has the *isReadOnly* property set to `true`.
+- **mayRename**: `Boolean`
+  The user may rename the calendar.
+  This property MUST be `false` if the account to which this calendar belongs
+  has the *isReadOnly* property set to `true`.
+- **mayDelete**: `Boolean`
+  The user may delete the calendar itself.
+  This property MUST be `false` if the account to which this calendar belongs
+  has the *isReadOnly* property set to `true`.
+
+
+### getCalendars
+
+Calendars can either be fetched explicitly by id, or all of them at once. To fetch calendars, make a call to `getCalendars`. It takes the following arguments:
+
+- **accountId**: `String|null`
+  The Account to fetch the calendars for. If `null`, the primary account is used.
+- **ids**: `String|null`
+  The ids of the calendars to fetch. If `null`, all calendars in the account are be fetched.
+
+The response to *getCalendars* is called *calendars*. It has the following arguments:
+
+- **accountId**: `String`
+  The id of the account used for the call.
+- **state**: `String`
+  A string representing the state on the server for **all** calendars. If a property of a calendar changes, or a new calendar is created, or a calendar is destroyed, this string will change. It is used to get delta updates.
+- **list**: `Calendar[]`
+  An array of the Calendar objects requested. This will be the **empty array** if the *ids* argument was the empty array, or contained only ids for calendars that could not be found.
+- **notFound**: `String[]|null`
+  This array contains the ids passed to the method for calendars that do not exist, or `null` if all requested ids were found. It will always be `null` if the *ids* argument in the call was `null`.
+
+The following errors may be returned instead of the *calendars* response:
+
+`accountNotFound`: Returned if an *accountId* was explicitly included with the request, but it does not correspond to a valid account.
+
+`accountNoCalendars`: Returned if the *accountId* given corresponds to a valid account, but does not contain any calendar data.
+
+`invalidArguments`: Returned if one of the arguments is of the wrong type, or otherwise invalid. A `description` property MAY be present on the response object to help debug with an explanation of what the problem was.
+
+### getCalendarUpdates
+
+The *getCalendarUpdates* call allows a client to efficiently update the state of its cached calendars to match the new state on the server. It takes the following arguments:
+
+- **accountId**: `String|null`
+  The id of the account to use for this call. If `null`, the primary account will be used.
+- **sinceState**: `String`
+  The current state of the client. This is the string that was returned as the *state* argument in the *calendars* response. The server will return the changes made since this state.
+- **fetchRecords**: `Boolean|null`
+  If `true`, after outputting a *calendarUpdates* response, an implicit call will be made to *getCalendars* with the *changed* property of the response as the *ids* argument. If `false` or `null`, no implicit call will be made.
+
+The response to *getCalendarUpdates* is called *calendarUpdates*. It has the following arguments:
+
+- **accountId**: `String`
+  The id of the account used for the call.
+- **oldState**: `String`
+  This is the *sinceState* argument echoed back; the state from which the server is returning changes.
+- **newState**: `String`
+  This is the state the client will be in after applying the set of changes to the old state.
+- **changed**: `String[]`
+  An array of Calendar ids where a property of the calendar has changed between the old state and the new state, or the calendar has been created, and the calendar has not been destroyed.
+- **removed**: `String[]`
+  An array of Calendar ids for calendars which have been destroyed since the old state.
+
+If a calendar has been modified AND deleted since the oldState, the server should just return the id in the *removed* array, but MAY return it in the *changed* array as well. If a calendar has been created AND deleted since the oldState, the server SHOULD remove the calendar id from the response entirely, but MAY include it in the *removed* array, and optionally the *changed* array as well.
+
+The following errors may be returned instead of the `calendarUpdates` response:
+
+`accountNotFound`: Returned if an *accountId* was explicitly included with the request, but it does not correspond to a valid account.
+
+`accountNoCalendars`: Returned if the *accountId* given corresponds to a valid account, but does not contain any calendar data.
+
+`invalidArguments`: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A `description` property MAY be present on the response object to help debug with an explanation of what the problem was.
+
+`cannotCalculateChanges`: Returned if the server cannot calculate the changes from the state string given by the client. Usually due to the client's state being too old. The client MUST invalidate its Calendar cache. The error object MUST also include a `newState: String` property with the current state for the type.
+
+### setCalendars
+
+Modifying the state of Calendar objects on the server is done via the *setCalendars* method. This encompasses creating, updating and destroying Calendar records.
+
+The *setCalendars* method takes the following arguments:
+
+- **accountId**: `String|null`
+  The id of the account to use for this call. If `null`, the primary account will be used.
+- **ifInState**: `String|null`
+  This is a state string as returned by the *getCalendars* method. If supplied, the string must match the current state, otherwise the method will be aborted and a `stateMismatch` error returned.
+- **create**: `String[Calendar]|null`
+  A map of *creation id* (an arbitrary string set by the client) to Calendar objects (containing all properties except the id).
+- **update**: `String[Calendar]|null`
+  A map of id to a Calendar object. The object may omit any property; only properties that have changed need be included.
+- **destroy**: `String[]|null`
+  A list of ids for Calendar objects to permanently delete.
+
+Each create, update or destroy is considered an atomic unit. It is permissible for the server to commit some of the changes but not others, however it is not permissible to only commit part of an update to a single calendar (e.g. update the *name* property but not the *isVisible* property if both are supplied in the update object).
+
+If a create, update or destroy is rejected, the appropriate error should be added to the notCreated/notUpdated/notDestroyed property of the response and the server MUST continue to the next create/update/destroy. It does not terminate the method.
+
+If an id given cannot be found, the update or destroy MUST be rejected with a `notFound` set error.
+
+The *mayXXX* properties are optional when creating a calendar. All default to `true`. If present, they MUST all be set to `true`. These properties are *read-only* to the client and may not be modified in an update call. Restrictions may only be set by the server, or when sharing calendars with other accounts (setting up sharing is not yet defined in this spec).
+
+A calendar MAY be deleted that is currently associated with one or more events. In this case, the events belonging to this calendar MUST also be deleted. Conceptually, this MUST happen prior to the calendar itself being deleted, and MUST generate a **push** event that modifies the state of the *CalendarEvent* type for the account, and has a *clientId* of `null`, to indicate that a change has been made to the event data not explicitly requested by the client.
+
+The response to *setCalendars* is called *calendarsSet*. It has the following arguments:
+
+- **accountId**: `String`
+  The id of the account used for the call.
+- **oldState**: `String|null`
+  The state string that would have been returned by *getCalendars* before making the requested changes, or `null` if the server doesn't know what the previous state string was.
+- **newState**: `String`
+  The state string that will now be returned by *getCalendars*.
+- **created**: `String[Calendar]`
+  A map of the creation id to an object containing the **id** property for all successfully created calendars.
+- **updated**: `String[]`
+  A list of ids for groups that were successfully updated.
+- **destroyed**: `String[]`
+  A list of ids for calendars that were successfully destroyed.
+- **notCreated**: `String[SetError]`
+  A map of creation id to a SetError object for each calendar that failed to be created. The possible errors are defined in the description of the method for specific data types.
+- **notUpdated**: `String[SetError]`
+  A map of Calendar id to a SetError object for each calendar that failed to be updated. The possible errors are defined in the description of the method for specific data types.
+- **notDestroyed**: `String[SetError]`
+  A map of Calendar id to a SetError object for each calendar that failed to be destroyed. The possible errors are defined in the description of the method for specific data types.
+
+A **SetError** object has the following properties:
+
+- **type**: `String`
+  The type of error.
+- **description**: `String|null`
+  A description of the error to display to the user.
+
+If any of the properties in a create or update are invalid (immutable and different to the current server value, wrong type, invalid value for the property – like a zero-length *name*), the server MUST reject the create/update with a SetError of type `invalidProperties`. The SetError object SHOULD contain a property called *properties* of type `String[]` that lists **all** the properties that were invalid. The object MAY also contain a *description* property of type `String` with a user-friendly description of the problems.
+
+The following errors may be returned instead of the *calendarEventsSet* response:
+
+`accountNotFound`: Returned if an *accountId* was explicitly included with the request, but it does not correspond to a valid account.
+
+`accountNoCalendars`: Returned if the *accountId* given corresponds to a valid account, but does not contain any calendar data.
+
+`accountReadOnly`: Returned if the account has `isReadOnly == true`.
+
+`invalidArguments`: Returned if one of the arguments is of the wrong type, or otherwise invalid. A *description* property MAY be present on the response object to help debug with an explanation of what the problem was.
+
+`stateMismatch`: Returned if an *ifInState* argument was supplied and it does not match the current state.



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org