RFC 2244

ACAP -- Application Configuration Access Protocol

๐Ÿ“… published November 1997, from ietf

RFC 2244: ACAP -- Application Configuration Access Protocol ๐Ÿ’–

Okay bestie, RFC 2244 is ACAP, the Application Configuration Access Protocol ๐ŸŽ€ It came from the Network Working Group in November 1997 and is a Standards Track document. The authors are C. Newman (Innosoft) and J. G. Myers (Netscape) ๐Ÿ‘‘ The title block doesn't list any RFCs that it obsoletes or updates, so there's no drama there โœจ

Status of this Memo ๐ŸŒธ

This doc specifies an Internet standards track protocol for the Internet community, and it asks for discussion and suggestions for improvements ๐Ÿ’… For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited ๐Ÿฆ‹

Copyright (C) The Internet Society 1997. All Rights Reserved.

Abstract โญ

ACAP, the Application Configuration Access Protocol, is built to support remote storage and access of program option, configuration and preference information ๐Ÿงš The data store model lets a client get at interesting data pretty simply, lets new information get added without a server reconfiguration, and promotes using both standardized data and custom or proprietary data ๐Ÿซถ Two key features are "inheritance", which can manage default values for configuration settings, and access control lists, which let interesting personal information be shared while group information stays restricted ๐Ÿ”ฅ

Table of Contents ๐Ÿ“

Status of this Memo ...............................................    i
Copyright Notice ..................................................    i
Abstract ..........................................................    i
ACAP Protocol Specification .......................................    1
1.       Introduction .............................................    1
1.1.     Conventions Used in this Document ........................    1
1.2.     ACAP Data Model ..........................................    1
1.3.     ACAP Design Goals ........................................    1
1.4.     Validation ...............................................    2
1.5.     Definitions ..............................................    2
1.6.     ACAP Command Overview ....................................    4
2.       Protocol Framework .......................................    4
2.1.     Link Level ...............................................    4
2.2.     Commands and Responses ...................................    4
2.2.1.   Client Protocol Sender and Server Protocol Receiver ......    4
2.2.2.   Server Protocol Sender and Client Protocol Receiver ......    5
2.3.     Server States ............................................    6
2.3.1.   Non-Authenticated State ..................................    6
2.3.2.   Authenticated State ......................................    6
2.3.3.   Logout State .............................................    6
2.4.     Operational Considerations ...............................    7
2.4.1.   Untagged Status Updates ..................................    7
2.4.2.   Response when No Command in Progress .....................    7
2.4.3.   Auto-logout Timer ........................................    7
2.4.4.   Multiple Commands in Progress ............................    8
2.5.     Server Command Continuation Request ......................    8
2.6.     Data Formats .............................................    8
2.6.1.   Atom .....................................................    9
2.6.2.   Number ...................................................    9
2.6.3.   String ...................................................    9
2.6.3.1. 8-bit and Binary Strings .................................   10
2.6.4.   Parenthesized List .......................................   10
2.6.5.   NIL ......................................................   10
3.       Protocol Elements ........................................   10
3.1.     Entries and Attributes ...................................   10
3.1.1.   Predefined Attributes ....................................   11
3.1.2.   Attribute Metadata .......................................   12
3.2.     ACAP URL scheme ..........................................   13
3.2.1.   ACAP URL User Name and Authentication Mechanism ..........   13
3.2.2.   Relative ACAP URLs .......................................   14
3.3.     Contexts .................................................   14
3.4.     Comparators ..............................................   15
3.5.     Access Control Lists (ACLs) ..............................   17
3.6.     Server Response Codes ....................................   18
4.       Namespace Conventions ....................................   21
4.1.     Dataset Namespace ........................................   21
4.2.     Attribute Namespace ......................................   21
4.3.     Formal Syntax for Dataset and Attribute Namespace ........   22
5.       Dataset Management .......................................   23
5.1.     Dataset Inheritance ......................................   23
5.2.     Dataset Attributes .......................................   24
5.3.     Dataset Creation .........................................   25
5.4.     Dataset Class Capabilities ...............................   25
5.5.     Dataset Quotas ...........................................   26
6.       Command and Response Specifications ......................   26
6.1.     Initial Connection .......................................   26
6.1.1.   ACAP Untagged Response ...................................   26
6.2.     Any State ................................................   27
6.2.1.   NOOP Command .............................................   27
6.2.2.   LANG Command .............................................   28
6.2.3.   LANG Intermediate Response ...............................   28
6.2.4.   LOGOUT Command ...........................................   29
6.2.5.   OK Response ..............................................   29
6.2.6.   NO Response ..............................................   29
6.2.7.   BAD Response .............................................   30
6.2.8.   BYE Untagged Response ....................................   30
6.2.9.   ALERT Untagged Response ..................................   31
6.3.     Non-Authenticated State ..................................   31
6.3.1.   AUTHENTICATE Command .....................................   31
6.4.     Searching ................................................   33
6.4.1.   SEARCH Command ...........................................   33
6.4.2.   ENTRY Intermediate Response ..............................   37
6.4.3.   MODTIME Intermediate Response ............................   38
6.4.4.   REFER Intermediate Response ..............................   38
6.4.5.   Search Examples ..........................................   38
6.5.     Contexts .................................................   39
6.5.1.   FREECONTEXT Command ......................................   39
6.5.2.   UPDATECONTEXT Command ....................................   40
6.5.3.   ADDTO Untagged Response ..................................   40
6.5.4.   REMOVEFROM Untagged Response .............................   41
6.5.5.   CHANGE Untagged Response .................................   41
6.5.6.   MODTIME Untagged Response ................................   42
6.6.     Dataset modification .....................................   42
6.6.1.   STORE Command ............................................   42
6.6.2.   DELETEDSINCE Command .....................................   45
6.6.3.   DELETED Intermediate Response ............................   45
6.7.     Access Control List Commands .............................   45
6.7.1.   SETACL Command ...........................................   46
6.7.2.   DELETEACL Command ........................................   46
6.7.3.   MYRIGHTS Command .........................................   47
6.7.4.   MYRIGHTS Intermediate Response ...........................   47
6.7.5.   LISTRIGHTS Command .......................................   47
6.7.6.   LISTRIGHTS Intermediate Response .........................   48
6.8.     Quotas ...................................................   48
6.8.1.   GETQUOTA Command .........................................   48
6.8.3.   QUOTA Untagged Response ..................................   49
6.9.     Extensions ...............................................   49
7.       Registration Procedures ..................................   49
7.1.     ACAP Capabilities ........................................   50
7.2.     ACAP Response Codes ......................................   50
7.3.     Dataset Classes ..........................................   51
7.4.     Vendor Subtree ...........................................   51
8.       Formal Syntax ............................................   52
9.       Multi-lingual Considerations .............................   61
10.      Security Considerations ..................................   62
11.      Acknowledgments ..........................................   63
12.      Authors' Addresses .......................................   63
Appendices ........................................................   64
A.       References ...............................................   64
B.       ACAP Keyword Index .......................................   66
C.       Full Copyright Statement

ACAP Protocol Specification ๐Ÿฆ‹

1. Introduction โœจ

1.1. Conventions Used in this Document ๐Ÿ“

In examples, "C:" and "S:" mark lines sent by the client and the server respectively. If such lines are wrapped without a new "C:" or "S:" label, the wrapping is for editorial clarity and isn't part of the command ๐Ÿ™ˆ

The key words "REQUIRED", "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in "Key words for use in RFCs to Indicate Requirement Levels" [KEYWORDS]. So those words in caps are the official requirement levels, not just vibes ๐Ÿ’œ

1.2. ACAP Data Model ๐Ÿงฉ

An ACAP server exports a hierarchical tree of entries ๐ŸŒณ Each level of the tree is called a dataset, and each dataset is made up of a list of entries. Every entry has a unique name and can hold any number of named attributes. Each attribute can be single valued or multi-valued, and it can have associated metadata to help with access and interpretation of the value ๐Ÿ’–

The rules a client uses to interpret the data within a portion of ACAP's tree of entries are called a dataset class ๐ŸŽ€

1.3. ACAP Design Goals ๐ŸŒˆ

ACAP's main job is to let users get at their configuration data from multiple network-connected computers. The vibe is that users can sit down in front of any network-connected computer, run any ACAP-enabled application, and still have access to their own configuration data ๐Ÿ’… Because lots of applications are hoped to become ACAP-enabled, client simplicity was preferred over server or protocol simplicity whenever that was reasonable ๐Ÿ”ฅ

ACAP is also meant to be easy to manage ๐Ÿ‘‘ That's why it includes "inheritance", which lets one dataset inherit default attributes from another dataset. Access control lists are included too, so management can be delegated, and quotas are included to control storage ๐Ÿงš Finally, an ACAP server that conforms to this base specification should be able to support most dataset classes defined in the future without needing a server reconfiguration or upgrade โญ

ACAP is built for clients that only get sometimes connected to the server ๐Ÿ“ฑ, so every entry gets a server-maintained modification time that lets the client spot changes ๐Ÿ‘€. The client can also ask the server for a list of entries that were removed since it last checked in ๐Ÿ—‘๏ธ.

ACAP assumes a dataset could be huge and/or the client might be on a slow connection ๐ŸŒ, so it offers server sorting, selective fetching and change notification for entries in a dataset ๐Ÿ”ฅ.

Like most Internet protocols, security, scalability and internationalization were big priorities ๐ŸŒ๐Ÿ”.

With all that in mind, we kept ACAP as simple as possible โœจ. It's a traditional text-based Internet protocol, which makes debugging SO much easier ๐Ÿ™ˆ. It's built on the super successful IMAP [IMAP4] framework, with a few upgrades ๐Ÿ’….

1.4. Validation

By default, any value can be stored in any attribute the user has permission and quota for ๐Ÿ’–. This is what lets people add new simple dataset classes without reconfiguring or upgrading the server ๐Ÿงš.

Sometimes, like when a value has special meaning to the server, it's super useful for the server to do the checking by returning the INVALID response code to a STORE command ๐Ÿ›ก๏ธ. These cases MUST be explicitly identified in the dataset class specification, which SHOULD include specific fixed rules for validation. Since a given ACAP server might not know about a particular dataset class specification, clients MUST NOT depend on enforced validation being there on the server ๐Ÿ˜ญ.

1.5. Definitions

  • access control list (ACL): A set of identifier, rights pairs associated with an object. An ACL is used to determine which operations a user is permitted to perform on that object. See section 3.5.
  • attribute: A named value within an entry. See section 3.1.
  • comparator: A named function which can be used to perform one or more of three comparison operations: ordering, equality and substring matching. See section 3.4.
  • context: An ordered subset of entries in a dataset, created by a SEARCH command with a MAKECONTEXT modifier. See section 3.3.
  • dataset: One level of hierarchy in ACAP's tree of entries.
  • dataset class specification: The rules which allow a client to interpret the data within a portion of ACAP's tree of entries.
  • entry: A set of attributes with a unique entry name. See section 3.1.
  • metadata: Information describing an attribute, its value and any access controls associated with that attribute. See section 3.1.2.
  • NIL: This represents the non-existence of a particular data item.
  • NUL: A control character encoded as 0 in US-ASCII [US-ASCII].
  • octet: An 8-bit value. On most modern computer systems, an octet is one byte.
  • SASL: Simple Authentication and Security Layer [SASL].
  • UTC: Universal Coordinated Time as maintained by the Bureau International des Poids et Mesures (BIPM).
  • UTF-8: An 8-bit transformation format of the Universal Character Set [UTF8]. Note that an incompatible change was made to the coded character set referenced by [UTF8], so for the purpose of this document, UTF-8 refers to the UTF-8 encoding as defined by version 2.0 of Unicode [UNICODE-2], or ISO 10646 [ISO-10646] including amendments one through seven.

1.6. ACAP Command Overview

The AUTHENTICATE, NOOP, LANG and LOGOUT commands are the basic protocol services ๐Ÿงƒ. SEARCH is the one that selects, sorts, fetches and monitors changes to attribute values and metadata ๐Ÿ‘€. UPDATECONTEXT and FREECONTEXT help with monitoring those changes too ๐Ÿฆ‹. STORE adds, modifies and deletes entries and attributes โœ๏ธ. DELETEDSINCE helps a client re-synchronize a cache with the server ๐Ÿ”„. And GETQUOTA, SETACL, DELETEACL, LISTRIGHTS and MYRIGHTS let you check storage quotas and examine or change access permissions ๐Ÿ”.

2. Protocol Framework โœจ

The ACAP protocol assumes a reliable data stream, such as the one TCP provides ๐Ÿงต. When TCP is used, an ACAP server listens on port 674 ๐ŸŽ€.

2.2. Commands and Responses

An ACAP session has three parts: setting up the client/server connection, an initial greeting from the server, and then client/server interactions ๐Ÿ’ฌ. Each interaction is a client command, server data, and a server completion result.

ACAP is a text-based, line-oriented protocol ๐Ÿ“. Basically, what clients and servers send are lines, meaning sequences of characters that end with a CRLF ๐ŸŒธ. The protocol receiver of an ACAP client or server is either reading a line, or reading a sequence of octets with a known count (a literal) followed by a line ๐Ÿงฉ. Both clients and servers must be capable of handling lines of arbitrary length ๐Ÿ’ช.

2.2.1. Client Protocol Sender and Server Protocol Receiver

The client command begins an operation ๐Ÿš€. Each client command is prefixed with an identifier (an alphanumeric string of no more than 32 characters, e.g., A0001, A0002, etc.) called a "tag" ๐Ÿท๏ธ. A different tag SHOULD be generated by the client for each command ๐Ÿ’œ.

There are two cases where a line from the client does not represent a complete command ๐Ÿ™ƒ. In one case, a command argument is quoted with an octet count (see the description of literal in section 2.6.3); in the other, the command arguments require server feedback (see the AUTHENTICATE command). In some of these cases, the server sends a command continuation request if it's ready for the next part of the command. This response is prefixed with the token "+" โž•.

Note: If, instead, the server detected an error in a command, it sends a BAD completion response with tag matching the command (as described below) to reject the command and prevent the client from sending any more of the command. It is also possible for the server to send a completion or intermediate response for some other command (if multiple commands are in progress), or untagged data. In either case, the command continuation request is still pending; the client takes the appropriate action for the response, and reads another response from the server.

The ACAP server reads a command line from the client, parses the command and its arguments, and transmits server data and a server command completion result ๐Ÿง .

2.2.2. Server Protocol Sender and Client Protocol Receiver

Data the server sends to the client comes in four forms: command continuation requests, command completion results, intermediate responses, and untagged responses ๐Ÿ“ฆ.

A command continuation request is prefixed with the token "+" โž•.

A command completion result tells you whether the operation succeeded or failed ๐Ÿ. It's tagged with the same tag as the client command that began the operation, so if more than one command is in progress, the tag tells you which command the response belongs to ๐Ÿ”–. There are three possible server completion responses: OK (success), NO (failure), or BAD (protocol error, such as an unrecognized command or a command syntax error) โœ…โŒ๐Ÿ™….

An intermediate response returns data that only makes sense in the context of a command in progress ๐Ÿงฉ. It's tagged with the same tag as the client command that began the operation, so again, the tag is how you match it up. A tagged response other than OK, NO, or BAD is an intermediate response ๐ŸŽˆ.

An untagged response returns data or status messages that can be interpreted outside the context of a command in progress ๐ŸŒˆ. It's prefixed with the token "*" โญ. Untagged data may be sent as a result of a client command, or it may be sent unilaterally by the server. There's no syntactic difference between untagged data that resulted from a specific command and untagged data that were sent unilaterally ๐Ÿซถ.

The protocol receiver of an ACAP client reads a response line from the server. It then takes action on the response based on the first token of the response, which may be a tag, a "*", or a "+" as described above ๐ŸŽฏ.

A client MUST be prepared to accept any server response at all times ๐Ÿšจ. This includes untagged data that it may not have requested ๐Ÿ™ˆ.

This topic is discussed in greater detail in the Server Responses section ๐Ÿ“–.

2.3. Server States

An ACAP server is in one of three states ๐ŸŒท. Most commands are only valid in certain states. It's a protocol error for the client to attempt a command while the server is in an inappropriate state for that command ๐Ÿ™…โ€โ™€๏ธ. In this case, the server responds with a BAD command completion result.

2.3.1. Non-Authenticated State

In non-authenticated state, the user must supply authentication credentials before most commands will be permitted ๐Ÿ”‘. This state is entered when a connection starts ๐Ÿšช.

2.3.2. Authenticated State

In authenticated state, the user is authenticated and most commands will be permitted ๐Ÿ‘‘. This state is entered when acceptable authentication credentials have been provided ๐Ÿ’….

2.3.3. Logout State

In logout state, the session is being terminated, and the server will close the connection ๐Ÿ‘‹. This state can be entered because of a client request or a unilateral server decision ๐Ÿฅ€.

            +--------------------------------------+
            |initial connection and server greeting|
            +--------------------------------------+
                      || (1)                  || (2)
                      VV                      ||
            +-----------------+               ||
            |non-authenticated|               ||
            +-----------------+               ||
             || (4)      || (3)               ||
             ||          VV                   ||
             ||          +----------------+   ||
             ||          | authenticated  |   ||
             ||          +----------------+   ||
             ||            || (4)             ||
             VV            VV                 VV
            +--------------------------------------+
            |     logout and close connection      |
            +--------------------------------------+

         (1) connection (ACAP greeting)
         (2) rejected connection (BYE greeting)
         (3) successful AUTHENTICATE command
         (4) LOGOUT command, server shutdown, or connection closed

2.4. Operational Considerations

2.4.1. Untagged Status Updates

At any time, a server can send data that the client did not request ๐Ÿ“ฌ.

2.4.2. Response when No Command in Progress

Server implementations are permitted to send an untagged response while there's no command in progress ๐ŸŒ™. Server implementations that send such responses MUST deal with flow control considerations ๐Ÿšฆ. Specifically, they must either (1) verify that the size of the data does not exceed the underlying transport's available window size, or (2) use non-blocking writes ๐ŸŒŠ.

2.4.3. Auto-logout Timer

If a server has an inactivity auto-logout timer, that timer MUST be of at least 30 minutes duration. Any command the server receives from the client during that interval MUST reset the auto-logout timer, and I mean ANY command ๐Ÿ’…

2.4.4. Multiple Commands in Progress โณ

The client doesn't have to wait for a command to finish before sending the next one, as long as it stays within the flow control limits of the underlying data stream ๐ŸŒŠ The server doesn't have to finish one command before starting the next either, UNLESS two commands would get tangled up because one changes the results of the other ๐Ÿ™ˆ If that kind of mix-up could happen, the server runs the commands to completion in the order the client gave them. Order matters, bestie ๐Ÿ’œ

2.5. Server Command Continuation Request ๐ŸŽ€

The command continuation request is marked with a "+" token instead of a tag. It basically means "I'm ready, keep going" โœจ

The server uses this response in the AUTHENTICATE command to send server data to the client and ask for more client data. It also gets used when an argument to any command is a synchronizing literal (see section 2.6.3).

The client is not permitted to send the octets of a synchronizing literal unless the server says it's expecting them. This lets the server handle commands and reject errors one line at a time, assuming it checks for non-synchronizing literals at the end of each line ๐Ÿง The rest of the command, including the CRLF that ends it, comes after the literal octets. If there are more command arguments, the literal octets are followed by a space and then those arguments.

Example:

C: A099 FREECONTEXT {10}
S: + "Ready for additional command text"
C: FRED
C: FOOB
S: A099 OK "FREECONTEXT completed"
C: A044 BLURDYBLOOP {102856}
S: A044 BAD "No such command as 'BLURDYBLOOP'"

2.6. Data Formats ๐Ÿ“

ACAP uses textual commands and responses. Data in ACAP can be one of five forms: atom, number, string, parenthesized list or NIL. Five options, so many vibes ๐Ÿ’…

2.6.1. Atom ๐ŸŒธ

An atom is one to 1024 non-special characters. It has to begin with a letter ๐Ÿ”ค Atoms are used for protocol keywords.

2.6.2. Number ๐Ÿ”ข

A number is one or more digit characters, and it represents a numeric value. Numbers are limited to the range of an unsigned 32-bit integer: 0 < number < 4,294,967,296. Big number energy ๐Ÿ˜ค

2.6.3. String ๐Ÿฆ‹

A string comes in one of two forms: literal and quoted string. The literal form is the general one ๐Ÿ™Œ The quoted string form is the alternative. It skips the overhead of processing a literal, but it comes with restrictions on what can go inside it.

A literal is a sequence of zero or more octets (including CR and LF). It's prefixed with an octet count, written as an open brace ({), the number of octets, a close brace (}), and then CRLF. For literals sent from server to client, the octet data follows right after the CRLF ๐Ÿง

There are two kinds of literals sent from client to server. The first one has an open brace ({) and the number of octets, immediately followed by a close brace (}) and CRLF. That's a synchronizing literal. When the client sends one, it must wait to receive a command continuation request before sending the octet data (and the rest of the command) ๐Ÿ›‘ The second one is the non-synchronizing literal, which lets the client send a string without waiting for a command continuation request. The difference is a plus (+) between the number of octets and the close brace (}), and the octet data sitting right after the CRLF. Quick and no waiting ๐Ÿƒโ€โ™€๏ธ

A quoted string is a sequence of zero to 1024 octets, excluding NUL, CR and LF, with double quote (<">) characters at each end ๐Ÿ’ฌ

The empty string can be written as "" (a quoted string with zero characters between the quotes), as {0} followed by CRLF (a synchronizing literal with an octet count of 0), or as {0+} followed by a CRLF (a non-synchronizing literal with an octet count of 0). Three ways to say nothing, iconic ๐Ÿซถ

Note: Even if the octet count is 0, a client sending a synchronizing literal must wait to receive a command continuation request. Yes, even for zero ๐Ÿ™ˆ

2.6.3.1. 8-bit and Binary Strings ๐Ÿงฌ

Most strings in ACAP are restricted to UTF-8 characters, and they may not contain NUL octets. Attribute values MAY contain any octets, including NUL. Attribute values are the exception to the rule, and they're allowed to be wild ๐Ÿฆ‹

2.6.4. Parenthesized List ๐Ÿงฉ

Data structures are shown as a "parenthesized list": a sequence of data items, separated by spaces, with parentheses at each end. A parenthesized list can hold other parenthesized lists, using multiple levels of parentheses to show nesting. Lists within lists, very layered ๐Ÿช†

The empty list is written as (), a parenthesized list with no members.

2.6.5. NIL ๐Ÿšซ

The special atom "NIL" means that a particular data item doesn't exist. It's represented as a string or a parenthesized list, and it's different from the empty string "" or the empty parenthesized list () ๐Ÿ‘‘ NIL is not the same as nothing-but-empty, which is a whole vibe.

3. Protocol Elements โœจ

This section defines the data formats and other protocol elements used throughout ACAP. Basically the building blocks ๐Ÿงฑ

3.1. Entries and Attributes ๐Ÿ’œ

Inside a dataset, each entry name is made up of zero or more UTF-8 characters, other than slash (/). A slash-separated list of entries, one at each level of the hierarchy, forms the full path to an entry ๐Ÿ—‚๏ธ

Each entry is made of a set of attributes. Each attribute has a hierarchical name in UTF-8, and each part of that name is separated by a period (.).

An attribute's value is either single or multi-valued. A single value is NIL (meaning it has no value), or a string of zero or more octets. A multi-value is a list of zero or more strings, and each of those strings has zero or more octets.

Attribute names are not allowed to contain asterisk (*) or percent (%). They MUST be valid UTF-8 strings that don't contain NUL. Invalid attribute names result in a BAD response. Entry names are not allowed to begin with . or contain slash (/). They MUST be valid UTF-8 strings that don't contain NUL. Invalid entry names in the entry field of a command result in a BAD response. Strict but fair ๐Ÿ˜ค

Using non-visible UTF-8 characters in attribute and entry names is discouraged. Please don't be sneaky with invisible characters ๐Ÿ™ƒ

3.1.1. Predefined Attributes ๐Ÿ“‹

Attribute names that don't contain a dot (.) are reserved for standardized attributes, which have meaning in any dataset. The ACAP protocol defines the following attributes.

  • entry: Contains the name of the entry. It MUST be single valued. Illegal or multi-valued values for the entry attribute are protocol errors, and they MUST result in a BAD completion response. This one is a special case, so pay attention ๐Ÿšจ
  • modtime: Contains the date and time that any read-write metadata in the entry was last modified. This value MUST be in UTC, and MUST be automatically updated by the server โฐ

The value is 14 or more US-ASCII digits. The first four are the year, the next two are the month, the next two are the day of the month, the next two are the hour (0 - 23), the next two are the minute, and the next two are the second. Any further digits are fractions of a second ๐Ÿ”ข

The time, especially fractions of a second, doesn't need to be accurate. It is REQUIRED, though, that any two entries in a dataset changed by successive modifications have strictly ascending modtime values. Also, each STORE command within a dataset (including simultaneous stores from different connections) MUST use different modtime values. No two stores can share a timestamp, that's the rule ๐Ÿ™…โ€โ™€๏ธ

This attribute has enforced validation, so any attempt to STORE a value in it MAY result in a NO response with an INVALID response code.

  • subdataset: If this attribute is set, it shows that a sub-dataset of this entry exists ๐ŸŒณ

The value is a list of relative ACAP URLs (see section 3.2) that can be used to locate the sub-dataset. The base URL is the full path to the entry, followed by a slash (/). The value . means a subdataset is located directly under this one. Multiple values mean there are replicated copies of the subdataset ๐Ÿ‘ฏ

For example, if the dataset /folder/site/ has an entry public-folder with a subdataset attribute of ., then the dataset /folder/site/public-folder/ exists. If the value of the subdataset attribute was instead //other.acap.domain//folder/site/public-folder/, that would mean the dataset is actually located on a different ACAP server ๐ŸŒ

A dataset can be created by storing a subdataset attribute that includes .. A sub-hierarchy of datasets is deleted by storing a NIL value to the subdataset attribute on the entry in the parent dataset ๐Ÿ—‘๏ธ

This attribute has enforced syntax validation. Specifically, if someone tries to STORE a non-list value (other than NIL), an empty list, or a value that doesn't follow the URL syntax rules [BASIC-URL, REL-URL], that results in a NO response with an INVALID response code. Rules are rules, babe ๐Ÿ“

3.1.2. Attribute Metadata ๐Ÿท๏ธ

Each attribute is made up of metadata items that describe the attribute, its value, and any associated access controls. Metadata items are either read-only, in which case the client is never permitted to modify the item, or read-write, in which case the client may modify the item if the access control list (ACL) permits ๐Ÿ”

The following metadata items are defined in this specification:

  • acl: The access control list for the attribute, if one exists. If the attribute doesn't have an ACL, NIL is returned. Read-write. See section 3.5 for the contents of an ACL.
  • attribute: The attribute name. Read-only.
  • myrights: The set of rights that the client has to the attribute. Read-only. See section 3.5 for the possible rights.
  • size: The length of the value. For a multi-value, this is a list of lengths, one for each of the values. Read-only.
  • value: The value. For a multi-value, this is a list of single values. Read-write.

More metadata items may be defined in extensions to this protocol. Servers MUST respond to unrecognized metadata by returning a BAD command completion result. No mystery metadata gets a free pass ๐Ÿ•ต๏ธโ€โ™€๏ธ

3.2. ACAP URL scheme ๐Ÿ”—

ACAP URLs are used within the ACAP protocol for the "subdataset" attribute, referrals and inheritance. They give you a convenient syntax for pointing at other ACAP datasets ๐Ÿ—บ๏ธ The ACAP URL follows the common Internet scheme syntax defined in [BASIC-URL], except that plaintext passwords are not permitted. If :<port> is omitted, the port defaults to 674.

An ACAP URL has the following general form:

url-acap  = "acap://" url-server "/" url-enc-entry [url-filter]
            [url-extension]

The <url-server> element includes the hostname, plus the optional user name, authentication mechanism and port number. The <url-enc-entry> element holds the name of an entry path, encoded according to the rules in [BASIC-URL] ๐Ÿฆ‹

3.2. ACAP URL Continued ๐ŸŒธ

okay bestie, the <url-filter> is totally optional ๐Ÿ’… It's a list of the attribute names you're vibing with. If you leave it out, the URL points at all the attributes of the named entry ๐Ÿซถ And <url-extension> is reserved for future extensions to this URL scheme, so hands off for now ๐Ÿ™…โ€โ™€๏ธ

Now the important part ๐Ÿšจ unsafe or reserved characters like " " or "?" MUST be hex encoded, the way the URL spec [BASIC-URL] explains. Once they're hex encoded, the octets get read as UTF-8 [UTF8] โœจ


3.2.1. ACAP URL User Name and Authentication Mechanism ๐ŸŽ€

so you can include a user name and/or an authentication mechanism ๐Ÿ’– They get used in the AUTHENTICATE command once you've connected to the ACAP server. If you don't include either one, the default is SASL ANONYMOUS [SASL-ANON] ๐Ÿซ  If there's a mechanism but no user name, one SHOULD be obtained from that mechanism, or asked for from the user, whichever makes sense ๐Ÿค” If there's a user name but no mechanism, then ;AUTH=* is assumed ๐ŸŒท

The ;AUTH= parameter works the same way as in the IMAP URL Scheme [IMAP-URL] ๐Ÿงš

Also, if unsafe or reserved characters like " " or ";" show up in the user name or the authentication mechanism, they MUST be encoded the way the URL spec [BASIC-URL] describes ๐Ÿ”


3.2.2. Relative ACAP URLs ๐Ÿฆ‹

Because ACAP uses / as the hierarchy separator for dataset paths, it plays super nicely with the relative URL rules in [REL-URL] ๐Ÿ’œ

The <aauth> grammar element counts as part of the user name when you're resolving relative ACAP URLs ๐Ÿ‘‘

So the base URL for a relative URL stored in an attribute's value is built by taking the path to the dataset that holds that attribute, adding a /, then the entry name of the entry holding that attribute, and then one more / ๐Ÿง 


3.3. Contexts ๐ŸŽ€

A context is a subset of entries from a dataset (or datasets), made with a SEARCH command using the MAKECONTEXT modifier โœจ Context names are strings the client makes up itself, and they must not start with the slash (/) character ๐Ÿ™…

When a client makes a context, it can ask for automatic notification of changes ๐Ÿ”” It can also ask for the entries inside a context to be enumerated. That's basically what makes a "virtual scrollbar" possible on the client side ๐Ÿ“œ๐Ÿ’…

A context only lives inside the ACAP session it was created in. Close the connection and every context tied to it gets thrown out automatically ๐Ÿ—‘๏ธ A server is required to support at least 100 active contexts within a session. If it can handle a larger limit, it must advertise that in a CONTEXTLIMIT capability ๐Ÿ’ช


3.4. Comparators ๐Ÿ”

A comparator is a named function that takes two input values, and it can do one or more of four operations: ordering, equality, prefix matching and substring matching ๐ŸŒˆ

Ordering is used for the SORT search modifier and for the COMPARE and COMPARESTRICT search keys. Ordering comparators can tell you the ordinal precedence of any two values. When you use one for ordering, you can put a + or a - in front of its name to ask for normal or reversed order. No prefix means + ๐Ÿ“ˆ๐Ÿ“‰

A comparator can give certain values an undefined ordinal precedence. Those always collate with equal value after everything else, whether you're going normal or reversed ๐Ÿซฅ Unless the comparator's definition says otherwise, multi-values and NIL values have an undefined ordinal precedence.

Equality is used for the EQUAL search modifier. It just checks whether two values count as equal under the comparator function. When you compare a single value to a multi-value, they're equal if any one of the multiple values matches the single value ๐Ÿ‘ฏ

Prefix matching is for the PREFIX search modifier. It checks whether the search value is a prefix of the item being searched. For a prefix search on a multi-value, it's a match if the value is a prefix of any one of the multiple values ๐ŸŒท

Substring matching is for the SUBSTRING search modifier. It checks whether the search value is a substring of the item being searched. For a substring search on a multi-value, it's a match if the value is a substring of any one of the multiple values ๐Ÿง

Rules for naming and registering comparators will show up in a future spec ๐Ÿ”ฎ Servers MUST respond to unknown or improperly used comparators with a BAD command completion result โ—

These comparators are defined by this standard and MUST be implemented ๐Ÿ‘‘

i;octet (Operations: Ordering, Equality, Prefix match, Substring match)

For collation, i;octet treats an attribute's value as a series of unsigned octets with ordinal values from 0 to 255. When ordering two strings, each octet pair gets compared in sequence until they're unequal or you hit the end of the string. If the shorter string is a prefix of the longer one, the shorter one counts as having a smaller ordinal value. The "i;octet" and "+i;octet" forms put smaller ordinal values first, and the "-i;octet" form puts larger ordinal values first ๐Ÿ”ข

For equality, two strings are equal if they're the same length and contain the same octets in the same order. NIL is equal only to itself ๐Ÿซถ

For non-binary, non-nil single values, i;octet ordering is equivalent to the ANSI C [ISO-C] strcmp() function applied to the C string representations of the values. For those same values, i;octet substring match is equivalent to the ANSI C strstr() function applied to the C string representations ๐Ÿงท

i;ascii-casemap (Operations: Ordering, Equality, Prefix match, Substring match)

The i;ascii-casemap comparator first maps the attribute values so every US-ASCII letter becomes uppercase (octet values 0x61 to 0x7A become 0x41 to 0x5A respectively), then applies the i;octet comparator as described above. So "hello" and "HELLO" have the same ordinal value and count as equal ๐Ÿ™Œ

i;ascii-numeric (Operations: Ordering, Equality)

The i;ascii-numeric comparator reads strings as decimal positive integers written with US-ASCII digits. Any value that doesn't begin with a US-ASCII digit counts as equal to the others, with an ordinal value higher than all non-NIL single-valued attributes ๐Ÿ™ƒ Otherwise, all US-ASCII digits (octet values 0x30 to 0x39) are read from the start of the string up to the first non-digit or the end of the string ๐Ÿ”Ÿ


3.5. Access Control Lists (ACLs) ๐Ÿ”

An access control list is a set of identifier and rights pairs, used to restrict access to a given dataset, attribute, or attribute within an entry ๐Ÿ›ก๏ธ An ACL is a multi-value, where each value holds an identifier, then a tab character, then the rights. The syntax is defined by the acl rule in the formal syntax in section 8 ๐Ÿ“–

The identifier is a UTF-8 string. The identifier anyone is reserved to refer to the universal identity (all authentications, including anonymous) ๐ŸŒ All user name strings accepted by the AUTHENTICATE command are reserved as identifiers for the corresponding user ๐Ÿ‘ค Identifiers starting with a slash (/) are reserved for authorization groups, which will be defined in a future spec ๐Ÿ”ฎ Identifiers MAY be prefixed with a dash (-) to show a revocation of rights ๐Ÿšซ All other identifiers have implementation-defined meanings ๐Ÿคทโ€โ™€๏ธ

Rights is a string listing a (possibly empty) set of alphanumeric characters. Each character lists a set of operations being controlled. Letters are reserved for "standard" rights, listed below. The set of standard rights may only be extended by a standards-track or IESG approved experimental RFC ๐Ÿ“œ Digits are reserved for implementation or site defined rights ๐Ÿ”ข The currently defined standard rights are:

x - search (use EQUAL search key with i;octet comparator)
r - read (access with SEARCH command)
w - write (modify with STORE command)
i - insert (perform STORE on a previously NIL value)
a - administer (perform SETACL or STORE on ACL attribute/metadata)

An implementation may force rights to always or never be granted. Implementations are expected to grant implicit read and administer rights to a user's personal dataset storage, in order to avoid denial of service problems ๐Ÿซ‚ Rights are never tied, unlike the IMAP ACL extension [IMAP-ACL] ๐Ÿ™…โ€โ™€๏ธ

It's possible for multiple identifiers in an access control list to apply to a given user (or other authentication identity). For example, an ACL may include rights granted to the identifier matching the user, one or more implementation-defined identifiers matching groups that include the user, and/or the identifier anyone. These get combined by taking the union of all positive rights that apply to a given user, then subtracting the union of all negative rights that apply to that user ๐Ÿงฎ A client MAY skip this calculation by using the MYRIGHTS command and metadata items โšก

Each attribute of each entry of a dataset may potentially have an ACL. If an attribute in an entry doesn't have an ACL, access is controlled by a default ACL for that attribute in the dataset, if one exists. If there's no default ACL for that attribute in the dataset, access is controlled by a default ACL for that dataset. The default ACL for a dataset must exist ๐Ÿ›๏ธ

To do any access or manipulation on an entry in a dataset, the client must have 'r' rights on the entry attribute of that entry ๐Ÿ‘€ Implementations should take care not to reveal, through error messages, that an entry exists when the client lacks 'r' rights. A client does not need access to the subdataset attribute of the parent dataset to access the contents of a dataset ๐Ÿ—๏ธ

Many ACL commands and responses include an "acl object" parameter, which says what the ACL applies to. It's a parenthesized list. The list contains just the dataset name when referring to the default ACL for a dataset. It contains a dataset name and an attribute name when referring to the default ACL for an attribute in a dataset. And it contains a dataset name, an attribute name, and an entry name when referring to the ACL for an attribute of an entry of a dataset ๐ŸŽฏ


3.6. Server Response Codes โœจ

Okay bestie, let's dig into the response codes! ๐ŸŽ€ An OK, NO, BAD, ALERT or BYE response from the server MAY contain a response code, which is basically extra detail that describes what happened in a machine-parsable way ๐Ÿค–โœจ. A response code is data inside parentheses, shaped like an atom, which might be followed by a space and some arguments ๐Ÿ’–. Response codes only exist when there's a specific action a client can take based on the extra info ๐Ÿ’…. To leave room for future extensions, each code is a slash-separated hierarchy, and every level adds more detail about the error ๐Ÿฆ‹. Clients MUST tolerate the extra hierarchical detail they don't understand, no cap ๐Ÿซถ.

The currently defined response codes are:

  • AUTH-TOO-WEAK: This one comes back on a tagged NO result from an AUTHENTICATE command ๐Ÿ™…โ€โ™€๏ธ. It means site security policy forbids the requested mechanism for that authentication identity ๐Ÿ”’.
  • ENCRYPT-NEEDED: Also on a tagged NO result from an AUTHENTICATE command ๐Ÿ’œ. It means site security policy requires a strong encryption mechanism for the specified authentication identity and mechanism ๐Ÿ”.
  • INVALID: This shows up when a STORE command included data the server implementation doesn't allow ๐Ÿ™ˆ. It MUST NOT be used unless the dataset class specification for the attribute in question explicitly permits enforced server validation ๐Ÿšซ. The argument is the attribute that was invalid ๐Ÿ’€.
  • MODIFIED: A conditional store failed because the modtime on the entry is later than the modtime given with the STORE command's UNCHANGEDSINCE modifier โฐ. The argument is the entry that got modified ๐Ÿ“.
  • NOEXIST: A search or NOCREATE store failed because a dataset didn't exist ๐Ÿซฅ. The argument is the dataset that doesn't exist ๐Ÿ“.
  • PERMISSION: A command failed due to insufficient permission, based on the access control list or implicit rights ๐Ÿšช. The argument is the acl-object that caused the failure ๐Ÿ”‘.
  • QUOTA: A STORE or SETACL command that would have grown the dataset failed because there wasn't enough quota ๐Ÿ“ฆ.
  • REFER: This can come back in a tagged NO response to any command that takes a dataset name as a parameter ๐Ÿ‘‰. It has one or more arguments written as relative URLs, and it's a referral, meaning you should retry the command using one of those relative URLs ๐Ÿงš.
  • SASL: This can show up in the tagged OK response to a successful AUTHENTICATE command ๐ŸŽ‰. It includes the optional final server response data from the server, as specified by SASL [SASL] โœจ.
  • TOOMANY: This may be returned in a tagged OK response to a SEARCH command that includes the LIMIT modifier ๐ŸŒธ. The argument gives the total number of matching entries ๐Ÿ”ข.
  • TOOOLD: The modtime given in the DELETEDSINCE command is too old, so deletedsince info isn't available anymore ๐Ÿฅ€.
  • TRANSITION-NEEDED: This occurs on a NO response to an AUTHENTICATE command ๐Ÿ”„. It means the user name is valid, but the entry in the authentication database needs updating before that mechanism can be used to authenticate ๐Ÿ› ๏ธ. This can happen when someone has an entry in a system authentication database like Unix /etc/passwd but lacks credentials suitable for the specified mechanism ๐Ÿ™ƒ.
  • TRYLATER: A command failed because of a temporary server failure โณ. The client MAY continue using local information and try the command later ๐Ÿซง.
  • TRYFREECONTEXT: This may be returned in a tagged NO response to a SEARCH command that includes the MAKECONTEXT modifier ๐Ÿงฉ. It means a new context can't be created because the server has a limit on existing contexts ๐Ÿšง.
  • WAYTOOMANY: This may be returned in a tagged NO response to a SEARCH command that includes a HARDLIMIT search modifier ๐Ÿ˜ญ. It means the SEARCH would have returned more entries than HARDLIMIT allowed ๐Ÿ™….

Additional response codes MUST be registered with IANA according to the proceedures in section 7.2 ๐Ÿ“‹. Client implementations MUST tolerate response codes that they do not recognize ๐Ÿซถ.


4. Namespace Conventions โœจ

4.1. Dataset Namespace

The dataset namespace is a slash-separated hierarchy ๐Ÿ—‚๏ธ. The first component is a dataset class. Dataset classes MUST have a vendor prefix (vendor.<vendor/product>) or be specified in a standards track or IESG approved experimental RFC ๐Ÿ’…. See section 7.3 for the registration template ๐Ÿ“„.

The second component of the dataset name is "site", "group", "host", or "user", referring to server-wide data, administrative group data, per-host data and per-user data respectively ๐ŸŒˆ. For "group", "host", and "user" areas, the third component of the path is the group name, the fully qualified host domain name, or the user name ๐Ÿ . A path of the form "/<dataset-class>/~/" is a convenient abbreviation for "/<dataset-class>/user/<current-user>/" ๐Ÿ’œ.

Dataset names that begin with "/byowner/" are reserved as an alternate view of the namespace ๐Ÿ‘€. This gives you a way to see all the dataset classes a particular owner uses ๐Ÿซฃ. For example, "/byowner/~/<dataset-class>/" is an alternate name for "/<dataset-class>/~/" ๐Ÿฆ‹. Byowner lists the dataset classes owned by a given user, and you do this with the dataset "/byowner/user/<current-user>/" plus the NOINHERIT SEARCH modifier ๐ŸŽ€.

The dataset "/" can be used to find all dataset classes visible to the current user ๐Ÿ”. A dataset of the form "/<dataset-class>/user/" can be used to find all users who have made a dataset or entry of that class visible to the current user ๐Ÿ‘‘.

The formal syntax for a dataset name is defined by the "dataset-name" rule in section 4.3 ๐Ÿ“.

4.2. Attribute Namespace

Attribute names that don't contain a dot (".") are reserved for standardized attributes that have meaning in any dataset ๐ŸŒธ. To keep client implementations simple, the attribute namespace is meant to be unique across all datasets ๐Ÿง . To get there, attribute names are prefixed with the dataset class name followed by a dot (".") ๐Ÿ“. Attributes that affect management of the dataset are prefixed with "dataset." ๐Ÿ› ๏ธ. A subtree of the "vendor." attribute namespace may be registered with IANA according to the rules in section 7.4 ๐Ÿ“‘. ACAP implementors are encouraged to help define interoperable dataset class specifications rather than using the private attribute namespace ๐Ÿซถ.

Some users or sites may want their own private attributes on certain dataset classes ๐Ÿ™‹. To allow that, the "user.<user-name>." and "site." subtrees are reserved for user-specific and site-specific attributes respectively, and they will not be standardized ๐Ÿ”’. These attributes aren't interoperable, so they're discouraged in favor of defining standard attributes ๐Ÿ™…โ€โ™€๏ธ. A future extension is expected to permit discovery of syntax for user or site-specific attributes ๐Ÿ”ฎ. Clients that want to display user or site-specific attributes should display the value of any non-NIL single-valued "user.<user-name>." or "site." attribute that has valid UTF-8 syntax ๐Ÿ’….

The formal syntax for an attribute name is defined by the "attribute-name" rule in the next section โœจ.

4.3. Formal Syntax for Dataset and Attribute Namespace

The naming conventions for datasets and attributes are defined by the following ABNF ๐Ÿ“œ. Note that this grammar is not part of the ACAP protocol syntax in section 8, because dataset names and attribute names are encoded as strings within the ACAP protocol ๐Ÿ™ˆ.

attribute-dacl  = "dataset.acl" *("." name-component)

attribute-dset  = dataset-std 1*("." name-component)
                  ;; MUST be defined in a dataset class specification

attribute-name  = attribute-std / attr-site / attr-user / vendor-name

attribute-std   = "entry" / "subdataset" / "modtime" /
                  "dataset.inherit" / attribute-dacl / attribute-dset

attr-site       = "site" 1*("." name-component)

attr-user       = "user." name-component 1*("." name-component)

byowner         = "/byowner/" owner "/"
                  [dataset-class "/" dataset-sub]

dataset-class   = dataset-std / vendor-name

dataset-normal  = "/" [dataset-class "/"
                  (owner-prefix / dataset-tail)]

dataset-name    = byowner / dataset-normal
dataset-std     = name-component
                  ;; MUST be registered with IANA and the spec MUST
                  ;; be published as a standards track or
                  ;; IESG-approved experimental RFC

dataset-sub     = *(dname-component "/")
                  ;; The rules for this portion of the namespace may
                  ;; be further restricted by the dataset class
                  ;; specification.

dataset-tail    = owner "/" dataset-sub

dname-component = 1*UTF8-CHAR
                  ;; MUST NOT begin with "." or contain "/"

name-component  = 1*UTF8-CHAR
                  ;; MUST NOT contain ".", "/", "%", or "*"

owner           = "site" / owner-host / owner-group /
                  owner-user / "~"

owner-group     = "group/" dname-component

owner-host      = "host/" dname-component

owner-prefix    = "group/" / "host/" / "user/"

owner-user      = "user/" dname-component

vendor-name     = vendor-token *("." name-component)

vendor-token    = "vendor." name-component
                  ;; MUST be registered with IANA

5. Dataset Management ๐ŸŽ€

The entry with an empty name ("") in the dataset holds the management information for the dataset as a whole ๐Ÿ“.

5.1. Dataset Inheritance

A dataset can inherit data from another dataset ๐Ÿงฌ. The dataset that data is inherited from is called the base dataset ๐ŸŒฑ. Data in the base dataset appears in the inheriting dataset, unless it gets overridden by a STORE to the inheriting dataset ๐Ÿ’ซ.

The base dataset is usually a system-wide or group-wide set of defaults ๐Ÿฐ. A system-wide dataset usually has one inheriting dataset per user, so each user can add to or tweak the defaults as needed ๐Ÿ’….

An entry that exists in both the inheriting and base dataset inherits a modtime equal to the greater of the two modtimes โฐ. An attribute in such an entry is inherited from the base dataset if it was never modified by a STORE command in the inheriting dataset, or if DEFAULT was stored to that attribute ๐Ÿ™Œ. This means default entries can be amended instead of replaced in the inheriting dataset, which is honestly so iconic ๐ŸŒˆโœจ.

So, the subdataset attribute does NOT just get copied down the chain ๐Ÿ™…โ€โ™€๏ธ ๐Ÿ’…. If the base dataset has a subdataset attribute and the inheriting dataset doesn't, the inheriting one gets a virtual value: a list containing a "." โœจ. That subdataset becomes a "virtual" dataset, basically a virtual copy of the base dataset with every subdataset attribute swapped to a list containing "." ๐Ÿฆ‹. Bestie, the big catch is that a virtual dataset is invisible if NOINHERIT is specified on the SEARCH command ๐Ÿ™ˆ.

Servers MUST support at least two levels of inheritance ๐Ÿ‘‘. Picture this: a user's dataset like "/options/user/fred/common" inherits from a group dataset like "/options/group/dinosaur operators/common", which then inherits from a server-wide dataset like "/options/site/common" ๐Ÿฆ•. Iconic chain, no notes ๐Ÿซถ.

5.2. Dataset Attributes

These attributes handle managing the dataset and live in the "" entry of a dataset ๐ŸŽ€. The big deal here is that none of them get inherited ๐Ÿ™…โ€โ™€๏ธ.

  • dataset.acl: This holds the default access control list for the dataset ๐Ÿ”. It gets validated, so if you STORE an invalid access control list, you'll get a NO response with an INVALID response code ๐Ÿ’€.
  • dataset.acl.<attribute>: Same energy, but for one specific attribute inside the dataset ๐ŸŒธ. It's validated too, so an invalid access control list in a STORE command gets a NO response with an INVALID response code ๐Ÿ˜ญ.
  • dataset.inherit: This holds the name of the dataset to inherit from, following the rules from the previous section ๐Ÿงš. It MAY refer to a non-existent dataset, in which case nothing gets inherited ๐ŸŒˆ. It's validated as well, so illegal dataset syntax or trying to store a multi-value gets a NO response with an INVALID response code ๐Ÿ™ˆ.

5.3. Dataset Creation

Okay, so when a dataset is first made (by storing a "." in the subdataset attribute, or by storing an entry in a dataset that didn't exist before), its attributes get initialized from the values in the parent dataset under the /byowner/ hierarchy ๐Ÿ’–. For dataset.inherit, the right hierarchy component gets added on top โœจ. Quick note: \t means the US-ASCII horizontal tab character ๐ŸŽ€.

Here's the example, with an entry like this:

entry path        "/byowner/user/joe/"
dataset.acl       ("joe\txrwia" "fred\txr")
dataset.inherit   "/byowner/site"

If a new dataset class "/byowner/user/joe/new" gets created, it ends up with these dataset attributes ๐Ÿฆ‹:

entry path        "/byowner/user/joe/new/"
dataset.acl       ("joe\txrwia" "fred\txr")
dataset.inherit   "/byowner/site/new"

And yes, the dataset "/byowner/user/joe/new/" is equivalent to "/new/user/joe/" ๐Ÿ’…. Main character energy ๐Ÿ‘‘.

5.4. Dataset Class Capabilities

Some dataset classes, or features of them, are only useful if there's an active updating client or the server has built-in support for the feature ๐ŸŒŸ. That's why the dataset class "capability" is reserved, so clients or servers can advertise these features ๐Ÿ“ฃ. The "entry" attribute in this class is the name of the dataset class whose features are being described ๐Ÿ“. The attributes are prefixed with capability.<dataset-class>. and get defined by that dataset class's own specification ๐Ÿง.

Since any unprivileged user can run an active client for themselves, a per-user capability dataset is super useful ๐Ÿ™Œ. The dataset /capability/~/ holds info about every feature available to the user (through inheritance), and /capability/site/ holds info about every feature the site supports ๐Ÿ’œ.

5.5. Dataset Quotas

Okay, quotas are implementation dependent, both how they're managed and what they cover ๐Ÿคทโ€โ™€๏ธ. Clients can check the applicable quota limit and usage (in bytes) with the GETQUOTA command ๐Ÿ“Š. Servers can warn the client about a low quota situation with the QUOTA untagged response ๐Ÿšจ.

6. Command and Response Specifications

This section describes ACAP commands and responses ๐Ÿ’…. Commands are sorted first by the state they're allowed in, then by a general category of command type ๐Ÿ—‚๏ธ.

Command arguments, marked "Arguments:" in the command descriptions, are described by what they do, not by their syntax โœจ. The exact syntax lives in the Formal Syntax section ๐Ÿ“–. Some commands send back specific server data, marked "Data:" in the descriptions ๐ŸŽ. Check the Responses section for those, and the Formal Syntax section for the precise syntax. Any command CAN return server data, which is why commands that don't specifically need server data say "no specific data for this command" instead of "none" ๐Ÿ™ˆ.

Hmm, careful: "CAN" is not a keyword and I shouldn't capitalise it. Let me rewrite that sentence in the final, with no caps.

The "Result:" in each command description covers the possible tagged status responses, plus any special interpretation of them ๐ŸŽฏ.

6.1. Initial Connection

Upon session startup, the server sends one of two untagged responses: ACAP or BYE ๐ŸŒ…. The untagged BYE response is covered in section 6.2.8 ๐Ÿ’Œ.

6.1.1. ACAP Untagged Response

Data:       capability list

The untagged ACAP response says the session is ready for commands ๐ŸŽ‰. It also has a space-separated list of the capabilities the server supports ๐Ÿงƒ. Each capability is a list: the capability name, optionally followed by capability-specific string arguments ๐ŸŽ€.

ACAP capability names MUST be registered with IANA, following the rules in section 7.1 ๐Ÿ“‹. Client implementations SHOULD NOT require any capability name beyond the ones defined in this specification ๐Ÿ™…โ€โ™€๏ธ, and they MUST tolerate any unknown capability names ๐Ÿซถ. A client implementation MAY be configurable to require SASL mechanisms other than CRAM-MD5 [CRAM-MD5] for site security policy reasons ๐Ÿ”’.

The following initial capabilities are defined ๐Ÿ‘‡:

  • CONTEXTLIMIT: This has one argument, a number for the maximum number of contexts the server supports per connection ๐Ÿ”ข. The number 0 means the server has no limit. Otherwise, this number MUST be greater than 100 ๐Ÿ’ฏ.
  • IMPLEMENTATION: This has one argument, a string describing the server implementation ๐Ÿ› ๏ธ. ACAP clients MUST NOT alter their behavior based on this value ๐Ÿšซ. It's mainly for debugging ๐Ÿ›.
  • SASL: This includes a list of the authentication mechanisms the server supports ๐Ÿ”. See section 6.3.1 ๐Ÿ‘€.

Example:

S: * ACAP (IMPLEMENTATION "ACME v3.5")
          (SASL "CRAM-MD5") (CONTEXTLIMIT "200")

6.2. Any State

These commands and responses are valid in any state ๐ŸŒ.

6.2.1. NOOP Command

Arguments:  none
Data:       no specific data for this command (but see below)
Result:     OK - noop completed
            BAD - command unknown or arguments invalid

NOOP always succeeds, and it does nothing ๐Ÿ˜ด. It can be used to reset any inactivity auto-logout timer on the server โฐ.

Example:

C: a002 NOOP

S: a002 OK "NOOP completed"

6.2.2. LANG Command

Arguments:  list of language preferences
Data:       intermediate response: LANG
Result:     OK - lang completed
            NO - no matching language available
            BAD - command unknown or arguments invalid

You can send one or more arguments to tell the server which languages you'd like for error messages ๐ŸŒ. The server checks each of your preferences in order against its table of available error string languages ๐Ÿ”. For a match, the client's language tag MUST be a prefix of the server's tag, and it has to match up to a "-" or the end of the string ๐Ÿงฉ. If there's a match, the server sends an intermediate LANG response and then an OK response ๐ŸŽŠ. The LANG response shows the language it actually picked, plus the right comparators to use with the languages listed in the LANG command ๐Ÿฆ‹.

If no LANG command is issued, all error text strings MUST be in the registered language "i-default" [CHARSET-LANG-POLICY], which is meant for an international audience ๐ŸŒ.

Example:

C: A003 LANG "fr-ca" "fr" "en-ca" "en-uk"
S: A003 LANG "fr-ca" "i;octet" "i;ascii-numeric"
        "i;ascii-casemap" "en;primary" "fr;primary"
S: A003 OK "Bonjour"

6.2.3. LANG Intermediate Response

Data:       language for error responses
            appropriate comparators

The LANG response tells you which language will be used for error responses, plus the comparators that suit the languages listed in the LANG command ๐Ÿ—ฃ๏ธ. The comparators SHOULD go in approximate order, from most efficient (usually "i;octet") to most appropriate for human text in the preferred language ๐Ÿ“ˆ.

6.2.4. LOGOUT Command

Arguments:  none
Data:       mandatory untagged response: BYE
Result:     OK - logout completed
            BAD - command unknown or arguments invalid

LOGOUT tells the server the client is done with the session ๐Ÿ‘‹. The server must send a BYE untagged response before the (tagged) OK response, and then close the network connection ๐Ÿšช.

Example:

C: A023 LOGOUT
S: * BYE "ACAP Server logging out"
S: A023 OK "LOGOUT completed"
(Server and client then close the connection)

6.2.5. OK Response

Data:       optional response code
            human-readable text

The OK response is an information message from the server โœ…. When it's tagged, it means the associated command finished successfully ๐Ÿฅณ. The human-readable text can be shown to the user as an information message ๐Ÿ’ฌ. The untagged form is information-only, and the nature of that information MAY be indicated by a response code ๐Ÿ“.

Example:

S: * OK "Master ACAP server is back up"

6.2.6. NO Response

Data:       optional response code
            human-readable text

The NO response is an operational error message from the server ๐Ÿ˜ฌ. When it's tagged, the associated command didn't complete successfully ๐Ÿ’”. The untagged form is a warning, and the command may still complete successfully ๐Ÿซ . The human-readable text describes the situation ๐Ÿ“ฃ.

Example:

C: A010 SEARCH "/addressbook/" DEPTH 3 RETURN ("*")
                EQUAL "entry" "+i;octet" "bozo"
S: * NO "Master ACAP server is down, your data may

         be out of date."
S: A010 OK "search done"
   ...
C: A222 STORE ("/folder/site/comp.mail.misc"
               "folder.creation-time" "19951206103412")
S: A222 NO (PERMISSION ("/folder/site/")) "Permission
denied"

6.2.7. BAD Response

Data:       optional response code
            human-readable text

Pull the Data block above into the final output exactly as written.

The BAD response is the server's way of saying "something went wrong" ๐Ÿ™…โ€โ™€๏ธ. When it's tagged, it's a protocol-level error in the client's command, and the tag tells you which command caused it. The untagged form is a protocol-level error where the server can't figure out which command it belongs to, and it can also mean an internal server failure. Either way, the human-readable text explains what happened ๐Ÿ’ฌ.

Example:

C: ...empty line...
S: * BAD "Empty command line"
C: A443 BLURDYBLOOP
S: A443 BAD "Unknown command"
C: A444 NOOP Hello
S: A444 BAD "invalid arguments"

6.2.8. BYE Untagged Response ๐Ÿ‘‹

Data:

optional response code
human-readable text

The untagged BYE response means the server is about to close the connection ๐Ÿšช. The client can show the human-readable text to the user in a status report. BYE can show up as part of a normal logout sequence, or as a panic shutdown announcement from the server ๐Ÿ˜ฑ. Some server implementations also use it to announce an inactivity auto-logout ๐Ÿ’ค.

BYE is also one of two possible greetings at session startup ๐ŸŒ…. When it shows up there, it means the server isn't willing to accept a session from this client ๐Ÿšซ.

Example:

S: * BYE "Auto-logout; idle for too long"

6.2.9. ALERT Untagged Response ๐Ÿšจ

Data:

optional response code
human-readable text

The human-readable text carries a special, human-generated alert, and it MUST be presented to the user in a way that grabs their attention ๐Ÿ“ฃ. This is meant for vital messages from the server administrator, like a heads-up that the server is going down for maintenance soon ๐Ÿ› ๏ธ.

Example:

S: * ALERT "This ACAP server will be shut down in
                       10 minutes for system maintenance."

6.3. Non-Authenticated State ๐Ÿ”

In non-authenticated state, the AUTHENTICATE command sets up authentication and moves you into authenticated state ๐Ÿšชโœจ. It's a general mechanism that works for a whole range of authentication techniques.

Server implementations may allow non-authenticated access to certain information by supporting the SASL ANONYMOUS [SASL-ANON] mechanism ๐Ÿ•ต๏ธโ€โ™€๏ธ.

Once you're authenticated (including as anonymous), you can't go back to non-authenticated state. No re-entry, bestie ๐Ÿšซ.

Only the any-state commands (NOOP, LANG and LOGOUT) and the AUTHENTICATE command are valid in non-authenticated state ๐Ÿ’….


6.3.1. AUTHENTICATE Command ๐Ÿชช

Arguments/Data/Result:

Arguments:  SASL mechanism name
            optional initial response

Data:       continuation data may be requested

Result:     OK - authenticate completed, now in authenticated state
            NO - authenticate failure: unsupported authentication
                 mechanism, credentials rejected
            BAD - command unknown or arguments invalid,
                 authentication exchange cancelled

The AUTHENTICATE command tells the server which SASL [SASL] authentication mechanism you want to use ๐Ÿ”‘. If the server supports it, the two sides run an authentication exchange to authenticate and identify the user. Optionally, they can also negotiate a security layer for the rest of the protocol interactions ๐Ÿ›ก๏ธ. If the server doesn't support the requested mechanism, it turns down the AUTHENTICATE command with a tagged NO response ๐Ÿ™…โ€โ™€๏ธ.

The authentication exchange is a back-and-forth of server challenges and client answers, and the details depend on the mechanism. A server challenge is a command continuation request with the "+" token, followed by a string ๐Ÿ”. The client answer is a line containing a string. If the client wants to cancel the exchange, it should send a line with a single unquoted "*" ๐Ÿ›‘. If the server gets that answer, it must reject the AUTHENTICATE command with a tagged BAD response ๐Ÿ’€.

The optional initial-response argument saves a round trip ๐Ÿš€. It's for mechanisms that send no data in the initial challenge. When you use it with one of those mechanisms, the server doesn't send the empty initial challenge to the client. Instead, it treats the initial-response data as if it had been sent in reply to that empty challenge โœจ. If you use the initial-response argument with a mechanism that does send data in the initial challenge, the server rejects the AUTHENTICATE command with a tagged NO response ๐Ÿ™ƒ.

The service name for this protocol's profile of SASL is "acap" ๐Ÿท๏ธ.

If a security layer gets negotiated through the SASL exchange, it takes effect right after the CRLF that concludes the authentication exchange for the client, and after the CRLF of the tagged OK response from the server ๐Ÿ”’.

All ACAP implementations MUST implement the CRAM-MD5 SASL mechanism [CRAM-MD5], although they MAY offer a configuration option to disable it if site security policy dictates ๐Ÿง. The example below is the same one described in the CRAM-MD5 specification.

Example:

S: * ACAP (IMPLEMENTATION "Blorfysoft v3.5")
                         (SASL "CRAM-MD5" "KERBEROS_V4")
C: A001 AUTHENTICATE "CRAM-MD5"
S: + "<1896.697170952@postoffice.reston.mci.net>"
C: "tim b913a602c7eda7a495b4e6e7334d3890"
S: A001 OK "CRAM-MD5 authentication successful"

If an AUTHENTICATE command fails with a NO response, the client may try another mechanism by sending another AUTHENTICATE command ๐Ÿ”„. In other words, the client can go through the authentication types in decreasing order of preference ๐Ÿฅ‡๐Ÿฅˆ๐Ÿฅ‰.


6.4. Searching ๐Ÿ”Ž

This section covers the SEARCH command, which is how you grab data from datasets ๐Ÿ“š.


6.4.1. SEARCH Command ๐Ÿ”

Arguments/Data/Result:

Arguments:  dataset or context name
            optional list of modifiers
            search criteria

Data:       intermediate responses: ENTRY, MODTIME, REFER
            untagged responses: ADDTO, REMOVEFROM, CHANGE, MODTIME

Result:     OK - search completed
            NO - search failure: can't perform search
            BAD - command unknown or arguments invalid

The SEARCH command finds a subset of entries in a dataset and sends that subset's info back to the client ๐ŸŽฏ. Inherited entries and attributes are included in the search, unless the NOINHERIT search modifier is used or the user doesn't have permission to read the attributes in the base dataset ๐Ÿงฌ.

The first argument to SEARCH says what gets searched ๐Ÿ—‚๏ธ. If the string starts with a slash ("/"), it's the name of a dataset. Otherwise, it's the name of a context that an earlier SEARCH command in the session created ๐Ÿงญ.

A successful SEARCH command MAY result in intermediate ENTRY responses, and it MUST result in a MODTIME intermediate response โฐ.

After the first argument come zero or more modifiers. Each modifier can only be specified once ๐Ÿšซ. Here are the defined modifiers:

DEPTH number Tells SEARCH how far to traverse the dataset tree ๐ŸŒณ. ENTRY responses include the full path to the entry. A value of "0" means traverse the entire tree, and "1" is the default, which only searches the specified dataset. If a dataset gets traversed that isn't on the current server, a REFER intermediate response is returned for that subtree, and the search keeps going ๐Ÿช„.

HARDLIMIT number If the SEARCH command would return more than number entries, the SEARCH fails with a NO completion result and a WAYTOOMANY response code ๐Ÿ™€.

LIMIT number number Caps how many intermediate ENTRY responses the search can generate ๐Ÿงข. The first numeric argument is the limit, and the second is how many entries to return if the matches go over the limit. If the limit gets exceeded, SEARCH still succeeds, and the total number of matches comes back in a TOOMANY response code in the tagged OK response ๐Ÿ”ข.

MAKECONTEXT [ENUMERATE] [NOTIFY] context Makes SEARCH create a context with the name given in the argument, which refers to the matching entries ๐Ÿ—ƒ๏ธ. If the SEARCH succeeds, that context name can be given to later SEARCH commands to search within the matching entries. If a context with that name already exists, it gets freed first. If a new context can't be created because the server has hit its limit on existing contexts, the command fails and returns a TRYFREECONTEXT response code in the NO completion response ๐Ÿงน.

The optional "ENUMERATE" and "NOTIFY" arguments can be included to ask for enumeration of the context (for virtual scroll bars) or for change notifications on the context ๐Ÿ“œ. If "NOTIFY" isn't requested, the context is a snapshot of the entries at the time the SEARCH was issued ๐Ÿ“ธ.

ENUMERATE asks that the contents of the context be ordered according to the SORT modifier, and that sequential numbers, starting with one, get assigned to the entries in the context ๐Ÿ”ข. That lets the RANGE modifier fetch portions of the ordered context ๐Ÿฐ.

NOTIFY asks the server to send untagged ADDTO, REMOVEFROM, CHANGE, and MODTIME responses while the context created by this SEARCH command exists ๐Ÿ””. The server MAY issue untagged ADDTO, REMOVEFROM, CHANGE and MODTIME notifications for a context at any time between the SEARCH command with MAKECONTEXT NOTIFY and the completion of a FREECONTEXT command for that context โณ. Notifications only cover changes that happen after the server receives the SEARCH command that created the context ๐ŸŽฌ. After it sends a sequence of ADDTO, REMOVEFROM or CHANGE notifications, the server MUST send an untagged MODTIME notification, which says the client has all updates to the entries in the context up to and including the given modtime value ๐Ÿ. Servers are allowed a reasonable delay to batch change notifications before sending them to the client ๐Ÿ“ฆ.

The position arguments of the ADDTO, REMOVEFROM and CHANGE notifications are 0 if ENUMERATE isn't requested 0๏ธโƒฃ.

NOINHERIT Makes the SEARCH command operate without inheritance ๐Ÿ™…โ€โ™€๏ธ. It can be used to tell which values are explicit overrides. If MAKECONTEXT is also specified, the created context isn't affected by inheritance either ๐Ÿงฌ.

RETURN (metadata...) Says what should come back in intermediate ENTRY responses ๐Ÿ“. If this modifier isn't specified, no intermediate ENTRY responses get returned ๐Ÿค.

Okay so the RETURN modifier is where it gets fun ๐ŸŽ€. Inside the parentheses you can list an optional set of attributes, and each one can optionally be followed by its own parenthesized list of metadata. If you leave off that metadata list, it defaults to (value) ๐Ÿ’–.

You can also use a trailing * on an attribute name to ask for every attribute that starts with that prefix, and a * all by itself asks for everything ๐ŸŒˆ. If you do that with a trailing * and skip the metadata list, it defaults to (attribute value), and the matching results get grouped in parentheses so they're easy to spot โœจ.

Once the last intermediate ENTRY response comes back, the server sends one intermediate MODTIME response to close things out ๐Ÿฆ‹.

SORT (attribute comparator ...) ๐Ÿ’… This one decides what order your ENTRY replies come back in. It takes a parenthesized list of one or more attribute/comparator pairs. The attribute says what to sort on, and the comparator names the collation rule used on that attribute's values. The next pair only gets used to order two entries when all the pairs before it said those two entries collate the same, so it's like a tiebreaker chain ๐Ÿ“.

If you use SORT together with MAKECONTEXT, then SORT sets the order of entries in the context that gets created ๐Ÿงš.

If you don't include SORT, or none of the attribute/comparator pairs can tell two entries apart, the server just uses whatever order the entries already have in the context or dataset being searched ๐Ÿซถ.

Next up are the search criteria. These are made of one or more search keys, and you can combine them with AND and OR. Check out this example, where the newline is only there so it's readable and isn't actually part of the criteria ๐Ÿ‘‘:

AND COMPARE "modtime" "+i;octet" "19951206103400"
    COMPARE "modtime" "-i;octet" "19960112000000"

That one finds every entry modified between 10:34 December 6 1995 and midnight January 12, 1996 UTC ๐Ÿฅน.

Here are the search keys we've got right now ๐Ÿ”ฅ:

  • ALL: matches every entry ๐Ÿ’œ.
  • AND search-key1 search-key2: entries that match both search keys โœจ.
  • COMPARE attribute comparator value: entries where the attribute's value collates with the given comparator the same as or later than the given value ๐ŸŒธ.
  • COMPARESTRICT attribute comparator value: same idea, but strictly later than the given value, so ties don't count ๐Ÿ™ˆ.
  • EQUAL attribute comparator value: entries where the attribute's value is equal to the given value under that comparator ๐ŸŽ€.
  • NOT search-key: entries that do NOT match the search key you gave ๐Ÿ’€.
  • OR search-key1 search-key2: entries that match either one ๐Ÿฆ‹.
  • PREFIX attribute comparator value: entries that begin with the given value under that comparator. If the comparator can't do substring matching, the server sends back a BAD response ๐Ÿงš.
  • RANGE start end time: entries inside a range of the enumerated context's ordering. The lowest-ordered entry gets number one, the next one gets number two, and so on. The two numbers say the lowest and highest numbers to match. The time tells the server the client has processed notifications for that context up to that point. If the context has changed since then, the server MUST either return a NO with a MODIFIED response code, or return the same results SEARCH would have returned if none of those changes had happened ๐Ÿ˜ญ.

RANGE only works on enumerated contexts. If you use RANGE with a dataset or a non-enumerated context, the server MUST return a BAD response ๐Ÿšซ.

  • SUBSTRING attribute comparator value: entries that contain the given value under that comparator. If the comparator can't do substring matching, you get a BAD response ๐Ÿ’….

6.4.2. ENTRY Intermediate Response

Data: entry name and entry data ๐ŸŒท

The ENTRY intermediate response shows up as a result of a SEARCH or STORE command. This is how dataset entries actually make it back to the client ๐Ÿ’–.

The ENTRY response starts with the entry name if you sent a SEARCH command without the DEPTH modifier. In every other case it starts with the entry path. After that comes a set of zero or more items, one for each metadata item in the RETURN search modifier. Results that match an attribute pattern, or that return several metadata items, get wrapped in parentheses โœจ.

6.4.3. MODTIME Intermediate Response

Data: modtime value โฐ

The MODTIME intermediate response shows up as a result of a SEARCH command. It tells the client that the context that was just created, or the ENTRY responses returned earlier, include every update to those entries up to and including the modtime value in the argument ๐Ÿซถ.

6.4.4. REFER Intermediate Response

Data: dataset path and relative ACAP URLs ๐Ÿ—บ๏ธ

The REFER intermediate response shows up during a multi-level SEARCH where one of the levels lives on a different server. It names the dataset that isn't on the current server, plus one or more relative ACAP URLs that say where that dataset might be found ๐Ÿงš.

6.4.5. Search Examples

Here are some SEARCH command exchanges between the client and server ๐Ÿ‘€:

C: A046 SEARCH "/addressbook/" DEPTH 3 RETURN ("addressbook.Alias"
        "addressbook.Email" "addressbook.List") OR NOT EQUAL
        "addressbook.Email" "i;octet" NIL NOT EQUAL
        "addressbook.List" "i;octet" NIL
S: A046 ENTRY "/addressbook/user/joe/A0345" "fred"
        "fred@stone.org" NIL
S: A046 ENTRY "/addressbook/user/fred/A0537" "joe" "joe@stone.org"
        NIL
S: A046 ENTRY "/addressbook/group/Dinosaur Operators/A423"
        "saurians" NIL "1"
S: A046 MODTIME "19970728105252"
S: A046 OK "SEARCH completed"

C: A047 SEARCH "/addressbook/user/fred/" RETURN ("*") EQUAL "entry"
        "i;octet" "A0345"
S: A047 ENTRY "A0345" (("modtime" "19970728102226")

        ("addressbook.Alias" "fred") ("addressbook.Email"
        "fred@stone.org") ("addressbook.CommonName"
        "Fred Flintstone") ("addressbook.Surname" "Flintstone")
        ("addressbook.GivenName" "Fred"))
S: A047 MODTIME "19970728105258"
S: A047 OK "SEARCH completed"

C: A048 SEARCH "/options/~/vendor.example/" RETURN
        ("option.value"("size" "value" "myrights"))
        SORT ("entry" "i;octet") COMPARE "modtime" "i;octet"
        "19970727123225"
S: A048 ENTRY "blurdybloop" (5 "ghoti" "rwia")
S: A048 ENTRY "buckybits" (2 "10" "rwia")
S: A048 ENTRY "windowSize" (7 "100x100" "rwia")
S: A048 MODTIME "19970728105304"
S: A048 OK "SEARCH completed"

C: A049 SEARCH "/addressbook/~/public" RETURN ("addressbook.Alias"
        "addressbook.Email") MAKECONTEXT ENUMERATE "blob" LIMIT 100 1
        SORT ("addressbook.Alias" "i;octet") NOT EQUAL
        "addressbook.Email" NIL
S: A049 ENTRY "A437" "aaguy" "aaguy@stone.org"
S: A049 MODTIME "19970728105308"
S: A049 OK (TOOMANY 347) "Context 'blob' created"

C: A050 SEARCH "blob" RANGE 2 2 "19970728105308" ALL
S: A050 ENTRY "A238" "abguy" "abguy@stone.org"
S: A050 MODTIME "19970728105310"
S: A050 OK "SEARCH Completed"

6.5. Contexts

The following commands use contexts that were created by a SEARCH command with a MAKECONTEXT modifier ๐Ÿงฉ.

6.5.1. FREECONTEXT Command

Arguments: context name Data: no specific data for this command Result:

  • OK: freecontext completed ๐ŸŽ‰
  • NO: freecontext failure, no such context ๐Ÿ™…โ€โ™€๏ธ
  • BAD: command unknown or arguments invalid ๐Ÿ’€

The FREECONTEXT command tells the server to free all the state tied to the named context. After that, the context can't be searched anymore, and the server stops sending untagged responses for it. It also stops counting against the server's limit on how many contexts it can hold ๐Ÿซง.

C: A683 FREECONTEXT "blurdybloop"
S: A683 OK "Freecontext completed"

6.5.2. UPDATECONTEXT Command

Arguments: list of context names Data: untagged responses: ADDTO REMOVEFROM CHANGE MODTIME Result:

  • OK: updatecontext completed, all updates are done ๐Ÿฅณ
  • NO: updatecontext failed, no such context or not a notify context ๐Ÿ˜ฌ
  • BAD: command unknown or arguments invalid ๐Ÿซ 

The UPDATECONTEXT command makes sure the client gets notified of every change the server knows about for the contexts listed as arguments, up to the current time ๐Ÿ“ฌ. The contexts you list have to have already been handed to a successful SEARCH command with a MAKECONTEXT NOTIFY modifier. If any read-write metadata in the context changed since the last MODTIME for that context, a MODTIME untagged response MUST be returned. That still applies to metadata that isn't in the context's RETURN modifier ๐Ÿ‘€.

The server can send untagged ADDTO, REMOVEFROM, CHANGE, and MODTIME at any time. UPDATECONTEXT is basically the way to "prod" the server into sending any notifications it hasn't sent yet ๐Ÿ””.

The UPDATECONTEXT command SHOULD NOT be used to poll for updates. Don't be that person ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’….

C: Z4S9 UPDATECONTEXT "blurdybloop" "blarfl"
S: Z4S9 OK "client has been notified of all changes"

6.5.3. ADDTO Untagged Response

Data: context name entry name position metadata list

The untagged ADDTO response tells the client that an entry got added to a context ๐ŸŒฑ. It includes the position number of the new entry (the first entry in the context is numbered 1), plus any metadata in the entry that matches the RETURN statement from when the context was created โœจ.

For enumerated contexts, ADDTO also bumps the position of every member whose position was greater than or equal to the ADDTO position number, adding one to each. For non-enumerated contexts, the position field is always 0 ๐Ÿงš.

S: * ADDTO "blurdybloop" "fred" 15
        ("addressbook.Email" "fred@stone.org")

6.5.4. REMOVEFROM Untagged Response

Data: context name entry name old position

The untagged REMOVEFROM response tells the client that an entry got removed from a context ๐Ÿ—‘๏ธ. It includes the position number the removed entry used to have (the first entry in the context is numbered 1).

For enumerated contexts, REMOVEFROM subtracts one from the position numbers of every member whose position was greater than the REMOVEFROM position number. For non-enumerated contexts, the position field is always 0 ๐ŸŒธ.

S: * REMOVEFROM "blurdybloop" "fred" 15 is the last example from the previous bit, so here it is:

S: * REMOVEFROM "blurdybloop" "fred" 15

6.5.5. CHANGE Untagged Response โœจ

Data:

  • context name
  • entry name
  • old position
  • new position
  • metadata list

The untagged CHANGE response tells the client that an entry in a context either moved to a new position in that context, or had the values of one or more attributes from the RETURN modifier change (the RETURN modifier that was set when the context was created). ๐Ÿ’–

The response includes the entry's previous and current position numbers (these are 0 if ENUMERATE wasn't specified on the context), plus the attribute metadata requested in the RETURN modifier when the context was created. ๐Ÿฆ‹

For enumerated contexts, the CHANGE response quietly shifts the position numbers of every entry that sat between the old and new positions. If old position is less than new position, then one is subtracted from all entries with position numbers in that range. Otherwise, one is added to all entries with position numbers in that range. If old position and new position are the same, no implicit renumbering happens at all. ๐Ÿ”ข

CHANGE responses are not sent for entries whose positions shifted implicitly because of another ADDTO, REMOVEFROM or CHANGE response. Those shifts already come with their own updates, so no need to double up. ๐Ÿ’…

Example:

S: * CHANGE "blurdybloop" "fred" 15 10
                 ("addressbook.Email" "fred@stone.org")

6.5.6. MODTIME Untagged Response ๐Ÿ•ฐ๏ธ

Data:

  • context name
  • modtime value

The untagged MODTIME response tells the client that it has received every update to entries in the context whose modtime values are less than or equal to the modtime value in the argument. Basically a "you're caught up to here" message. ๐Ÿซถ

Example:

S: * MODTIME mycontext "19970320162338"

6.6. Dataset modification ๐ŸŒธ

These commands and responses handle changing datasets. Let's go! ๐Ÿš€

6.6.1. STORE Command ๐Ÿ’พ

Arguments: entry store list

Data: intermediate responses: ENTRY

Result:

  • OK - store completed
  • NO - store failure: can't store that name, or UNCHANGEDSINCE specified and entry changed
  • BAD - command unknown or arguments invalid, or invalid UTF-8 syntax in attribute name

STORE creates, modifies, or deletes the named entries in the named datasets. Any metadata that isn't specified in the command stays exactly as it was. ๐ŸŽ€

Setting the "value" metadata of an attribute to NIL removes that attribute from the entry. Setting the "value" of the "entry" attribute to NIL removes the whole entry from the dataset and cancels inheritance for the entire entry. Setting the "value" of the "entry" attribute to DEFAULT removes that entry from the inheriting dataset and reverts the entry and its attributes to inherited values, if there are any. And changing the value of the "entry" attribute renames the entry. โœ๏ธ

Storing DEFAULT to the "value" metadata of an attribute is the same as storing NIL, except that inheritance is turned on for that attribute. If a non-NIL value gets inherited, then an ENTRY intermediate response is sent to tell the client about the change. That ENTRY response includes the entry-path, plus the attribute name and value metadata for each attribute that reverted to a non-NIL inherited setting. ๐Ÿ‘€

Storing NIL to the "value" metadata of an attribute MAY be treated the same as storing DEFAULT to that "value", if there is a NIL value in the base dataset. ๐Ÿค”

The STORE command is followed by one or more entry store lists. Each entry store list starts with an entry path, followed by STORE modifiers, followed by zero or more attribute store items. Each attribute store item is made up of the attribute name followed by NIL (to remove the attribute's value), DEFAULT (to revert the item to any inherited value), a single value (to set the attribute's single value), or a list of metadata items to modify. These STORE modifiers are allowed:

  • NOCREATE: By default, the server MUST create any datasets needed to store the entry, including multiple hierarchy levels. If NOCREATE is specified, the STORE command fails with a NOEXIST error unless the parent dataset already exists. ๐Ÿ—๏ธ
  • UNCHANGEDSINCE: If the "modtime" of the entry is later than the unchangedsince time, then the store fails with a MODIFIED response code. Using UNCHANGEDSINCE with a time of "00000101000000" will always fail if the entry exists. Clients writing to a shared dataset are encouraged to use UNCHANGEDSINCE when modifying an existing entry. ๐Ÿ™ˆ

The server MUST either make all the changes specified in a single STORE command, or make none of them. If it succeeds, the server MUST update the "modtime" attribute for every entry that was changed. โฐ

It's illegal to list any metadata item within an attribute twice, any attribute within an entry twice, or any entry path twice. The server MUST return a BAD response if this happens. ๐Ÿšซ

The server MAY re-order the strings in a multi-value on STORE and MAY remove duplicate strings. However, SEARCH MUST return multi-values and the associated size list metadata in a consistent order. ๐Ÿ“‹

Example:

C: A342 STORE ("/addressbook/user/fred/ABC547"
                    "addressbook.TelephoneNumber" "555-1234"
                    "addressbook.CommonName" "Barney Rubble"
                    "addressbook.AlternateNames" ("value"
                    ("Barnacus Rubble" "Coco Puffs Thief"))
                    "addressbook.Email" NIL)
S: A342 OK "Store completed"
C: A343 STORE ("/addressbook/user/joe/ABD42"
                    UNCHANGEDSINCE "19970320162338"
                    "user.joe.hair-length" "10 inches")
S: A343 NO (MODIFIED) "'ABD42' has been changed
                    by somebody else."
C: A344 STORE ("/addressbook/group/Developers/ACD54"
                    "entry" NIL)
S: A344 OK "Store completed"
C: A345 STORE ("/option/~/common/SMTPserver"
                    "option.value" DEFAULT)
S: A345 ENTRY "/option/~/common/SMTPserver"

                    "option.value" "smtp.server.do.main"
S: A345 OK "Store completed"
C: A347 STORE ("/addressbook/~/" "dataset.inherit"
                    "/addressbook/group/Developers")
S: A347 OK "Store completed"

6.6.2. DELETEDSINCE Command ๐Ÿ—‘๏ธ

Arguments:

  • dataset name
  • time

Data: intermediate response: DELETED

Result:

  • OK - DELETEDSINCE completed
  • NO - DELETEDSINCE failure: can't read dataset, or date too far in the past
  • BAD - command unknown or arguments invalid

DELETEDSINCE sends back, in intermediate DELETED replies, the names of entries that were deleted from the named dataset since the given time. Little trip down memory lane! ๐Ÿ•ฐ๏ธ

Servers may impose a limit on the number or age of deleted entry names they keep track of. If the server doesn't have information going back to the specified time, the command fails and returns a TOOOLD response code in the tagged NO response. ๐Ÿ˜ฌ

Example:

C: Z4S9 DELETEDSINCE "/folder/site/" 19951205103412
S: Z4S9 DELETED "blurdybloop"
S: Z4S9 DELETED "anteaters"
S: Z4S9 OK "DELETEDSINCE completed"
C: Z4U3 DELETEDSINCE "/folder/site/" 19951009040854
S: Z4U3 NO (TOOOLD) "Don't have that information"

6.6.3. DELETED Intermediate Response ๐Ÿ‘‹

Data: entry name

The intermediate DELETED response shows up as a result of a DELETEDSINCE command. It returns an entry that was deleted from the dataset named in that DELETEDSINCE command. Gone but not forgotten! ๐Ÿฅ€

6.7. Access Control List Commands ๐Ÿ”

The commands in this section manage access control lists (ACLs). Permissions are serious business, bestie. ๐Ÿ’…

6.7.1. SETACL Command ๐Ÿ”‘

Arguments:

  • acl object
  • authentication identifier
  • access rights

Data: no specific data for this command

Result:

  • OK - setacl completed
  • NO - setacl failure: can't set acl
  • BAD - command unknown or arguments invalid

The SETACL command changes the access control list on the specified object so that the specified identifier is granted the permissions listed in rights. If the object didn't already have an access control list, one gets created. โœจ

Example:

C: A123 SETACL ("/addressbook/~/public/") "anyone" "r"
S: A123 OK "Setacl complete"
C: A124 SETACL ("/folder/site/") "B1FF" "rwa"
S: A124 NO (PERMISSION ("/folder/site/")) "'B1FF' not
                    permitted to modify access rights
                    for '/folder/site/'"

6.7.2. DELETEACL Command ๐Ÿงน

Arguments:

  • acl object
  • optional authentication identifier

Data: no specific data for this command

Result:

  • OK - deleteacl completed
  • NO - deleteacl failure: can't delete acl
  • BAD - command unknown or arguments invalid

If you give the optional identifier argument, the DELETEACL command removes any part of the access control list on the specified object for that identifier. ๐ŸŽฏ

If you leave out the optional identifier argument, the DELETEACL command removes the ACL from the object entirely, so access gets controlled by a higher-level default ACL instead. This form of the DELETEACL command is not permitted on the default ACL for a dataset, and servers MUST return a BAD in that case. ๐Ÿšท

Example:

C: A223 DELETEACL ("/addressbook/~/public") "anyone"
S: A223 OK "Deleteacl complete"
C: A224 DELETEACL ("/folder/site")
S: A224 BAD "Can't delete ACL from dataset"
C: A225 DELETEACL ("/addressbook/user/fred"
                    "addressbook.Email" "barney")
S: A225 OK "Deleteacl complete"

6.7.3. MYRIGHTS Command ๐Ÿ™‹

Arguments: acl object

Data: intermediate responses: MYRIGHTS

Result:

  • OK - myrights completed
  • NO - myrights failure: can't get rights
  • BAD - command unknown or arguments invalid

The MYRIGHTS command returns the set of rights the client has for the given dataset or dataset attribute. Checking your own vibes, basically. ๐Ÿชž

Example:

C: A003 MYRIGHTS ("/folder/site")
S: A003 MYRIGHTS "r"
S: A003 OK "Myrights complete"

6.7.4. MYRIGHTS Intermediate Response ๐Ÿ“จ

Data: rights

The MYRIGHTS response shows up as a result of a MYRIGHTS command. Its argument is the set of rights the client has for the object referred to in that command. ๐Ÿ’œ

6.7.5. LISTRIGHTS Command ๐Ÿ“œ

Arguments:

  • acl object
  • authentication identifier

Data: untagged responses: LISTRIGHTS

Result:

  • OK - listrights completed
  • NO - listrights failure: can't get rights list
  • BAD - command unknown or arguments invalid

The LISTRIGHTS command takes an object and an identifier, and returns info about which rights the current user may revoke or grant to that identifier in the ACL for that object. Power moves only! ๐Ÿ‘‘

   Example:    C: a001 LISTRIGHTS ("/folder/~/") "smith"
               S: a001 LISTRIGHTS "xra" "w" "i"
               S: a001 OK Listrights completed
               C: a005 LISTRIGHTS ("/folder/site/archive/imap") "anyone"
               S: a005 LISTRIGHTS "" "x" "r" "w" "i"
               S: a005 OK Listrights completed

6.7.6. LISTRIGHTS Intermediate Response ๐Ÿฆ‹

Data:

  • required rights
  • list of optional rights

okay so the LISTRIGHTS response shows up because of a LISTRIGHTS command ๐Ÿ’… The first argument is a string holding the set of rights the identifier will always be granted on the dataset or attribute. That set can be empty, so don't panic if it's "" ๐Ÿซถ

After that come zero or more strings, and each one has a single right that the current user is allowed to revoke or grant to the identifier in that dataset or attribute โœจ

The same right MUST NOT be listed more than once in the LISTRIGHTS response. no doubles, bestie ๐Ÿ™ˆ


6.8. Quotas ๐ŸŒธ

This section defines the commands and responses that relate to quotas. it's giving storage limits, lowkey ๐Ÿ’œ

6.8.1. GETQUOTA Command ๐ŸŽ€

Arguments: dataset

Data: untagged responses: QUOTA

Result:

  • OK - Quota information returned
  • NO - Quota failure: can't access resource limit, or no resource limit
  • BAD - command unknown or arguments invalid

the GETQUOTA command takes the name of a dataset and gives you back an untagged QUOTA response ๐Ÿ“ฌ That response has the dataset name, the quota limit in bytes that applies to that dataset, and the quota usage within that limit. The scope of a quota limit is implementation dependent, so it can look different depending on who built it ๐Ÿคทโ€โ™€๏ธ

   Example:    C: A043 GETQUOTA "/option/user/fred/common"
               S: * QUOTA "/option/user/fred/common" 1048576 2475
               S: A043 OK "Getquota completed"

6.8.3. QUOTA Untagged Response ๐Ÿงš

Data:

  • dataset
  • quota limit in bytes
  • amount of quota limit used
  • extension data

the QUOTA untagged response is generated as a result of a GETQUOTA command. It MAY be generated by the server in response to a SEARCH or STORE command too, to warn you about high usage of a quota โš ๏ธ It includes the name of the applicable dataset, the quota limit in bytes, the quota usage, and some optional extension data.

Clients MUST tolerate the extension data, because its use is reserved for a future extension ๐Ÿ”ฎ

6.9. Extensions ๐ŸŒˆ

so the protocol can grow without breaking everything, clients MUST tolerate unknown server responses that meet the syntax of response-extend. Clients MUST also tolerate unknown server response codes that meet the syntax of resp-code-ext. New commands MUST be announced through a capability on the initial greeting line, and those commands SHOULD meet the syntax of command-extend ๐ŸŽ€

Servers MUST respond to unknown commands with a BAD command completion result. Servers MUST also skip over non-synchronizing literals contained in an unknown command. A server can do this by assuming the unknown command matches the command-extend syntax, or by reading a line at a time and checking for the non-synchronizing literal syntax at the end of the line ๐Ÿ’…

7. Registration Procedures ๐Ÿ“

ACAP's whole vibe is providing a structured storage model for all sorts of configuration data ๐Ÿ’– For that potential to actually happen, the Internet community needs to work toward these goals:

  • (1) Standardization. It is very important to standardize dataset classes. The authors hope ACAP gets the same success SNMP has seen with the definition of numerous standards track MIBs ๐Ÿ‘‘
  • (2) Community Review. In the absence of standardization, it's important to get community review on a proposal so its engineering quality improves ๐Ÿ” Community review is strongly recommended prior to registration. The ACAP implementors mailing list <ietf-acap@andrew.cmu.edu> should be used for this purpose ๐Ÿ“ฎ
  • (3) Registration. Registration serves a two-fold purpose. First, it prevents use of the same name for different purposes. Second, it provides a one-stop list that can be used to locate existing extensions or dataset classes, so nobody duplicates work ๐Ÿฆ‹

The following registration templates may be used to register ACAP protocol elements with the Internet Assigned Numbers Authority (IANA) ๐Ÿงพ

7.1. ACAP Capabilities ๐Ÿ“

New ACAP capabilities MUST be registered prior to use. no skipping this step, bestie ๐Ÿ™…โ€โ™€๏ธ Careful consideration should be made before extending the protocol, because it can lead to complexity or interoperability problems. Review of proposals on the acap implementors mailing list is strongly encouraged prior to registration.

To: iana@iana.org
Subject: Registration of ACAP capability

Capability name:

Capability keyword:

Capability arguments:

Published Specification(s):

(Optional, but strongly encouraged)

Person and email address to contact for further information:

7.2. ACAP Response Codes ๐ŸŒŸ

ACAP response codes are registered on a first come, first served basis. Review of proposals on the acap implementors mailing list is strongly encouraged prior to registration ๐Ÿ’œ

To: iana@iana.org
Subject: Registration of ACAP response code

Response Code:

Arguments (use ABNF to specify syntax):

Purpose:

Published Specification(s):

(Optional, but strongly encouraged)

Person and email address to contact for further information:

7.3. Dataset Classes ๐ŸŽ€

A dataset class provides a core set of attributes for use in a specified hierarchy. It may also define rules for the dataset hierarchy underneath that class. Dataset class specifications must be standards track or IESG approved experimental RFCs ๐Ÿ“œ

To: iana@iana.org
Subject: Registration of ACAP dataset class

Dataset class name/attribute prefix:

Purpose:

Published Specification(s):

(Standards track or IESG approved experimental RFC)

Person and email address to contact for further information:

7.4. Vendor Subtree ๐Ÿข

Vendors may reserve a portion of the ACAP namespace for private use. Dataset class names beginning with "vendor.<company/product name>." are reserved for use by that company or product. Also, all attribute names beginning with "vendor.<company/product name>." are reserved for use by that company or product once registered. Registration is first come, first served. Whenever possible, private attributes and dataset classes should be avoided in favor of improving interoperable dataset class definitions ๐Ÿซถ

To: iana@iana.org
Subject: Registration of ACAP vendor subtree

Private Prefix: vendor.<company/product name>.

Person and email address to contact for further information:

(company names and addresses should be included when appropriate)

8. Formal Syntax ๐Ÿง 

The following syntax specification uses the augmented Backus-Naur Form (BNF) notation as specified in [ABNF]. It uses the ABNF core rules as specified in Appendix A of the ABNF specification [ABNF] โœจ

Except as noted otherwise, all alphabetic characters are case-insensitive. Using upper or lower case characters to define token strings is only for editorial clarity. Implementations MUST accept these strings in a case-insensitive fashion ๐Ÿ’…

The initial-greeting rule defines the initial ACAP greeting from the server. The command rule defines the syntax for commands sent by the client. The response rule defines the syntax for responses sent by the server ๐ŸŽ€

   ATOM-CHAR          = "!" / %x23-27 / %x2A-5B / %x5D-7A / %x7C-7E
                        ;; Any CHAR except ATOM-SPECIALS

   ATOM-SPECIALS      = "(" / ")" / "{" / SP / CTL / QUOTED-SPECIALS

   CHAR               = %x01-7F

   DIGIT-NZ           = %x31-39
                        ; non-zero digits ("1" - "9")

   QUOTED-CHAR        = SAFE-UTF8-CHAR / "\" QUOTED-SPECIALS

   QUOTED-SPECIALS    = <"> / "\"

   SAFE-CHAR          = %x01-09 / %x0B-0C / %x0E-21 /
                        %x23-5B / %x5D-7F
                        ;; any TEXT-CHAR except QUOTED-SPECIALS

   SAFE-UTF8-CHAR     = SAFE-CHAR / UTF8-2 / UTF8-3 / UTF8-4 /
                        UTF8-5 / UTF8-6

   TAG-CHAR           = %x21 / %x23-27 / %x2C-5B / %x5D-7A / %x7C-7E
                        ;; Any ATOM-CHAR except "*" or "+"

   TEXT-CHAR          = %x01-09 / %x0B-0C / %x0E-7F
                        ;; any CHAR except CR and LF

   TEXT-UTF8-CHAR     = SAFE-UTF8-CHAR / QUOTED-SPECIALS

   UTF8-1             = %x80-BF

   UTF8-2             = %xC0-DF UTF8-1

   UTF8-3             = %xE0-EF 2UTF8-1

   UTF8-4             = %xF0-F7 3UTF8-1

   UTF8-5             = %xF8-FB 4UTF8-1

   UTF8-6             = %xFC-FD 5UTF8-1

   UTF8-CHAR          = TEXT-UTF8-CHAR / CR / LF

   acl                = "(" [acl-identrights *(SP acl-identrights)] ")"
                        *(SPACE acl-identrights)] ")"

   acl-identifier     = string-utf8
                        ;; MUST NOT contain HTAB

   acl-identrights    = string-utf8
                        ;; The identifier followed by a HTAB,
                        ;; followed by the rights.

   acl-delobject      = "(" dataset SP attribute [SP entry-name] ")"

   acl-object         = "(" dataset [SP attribute [SP entry-name]] ")"

   acl-rights         = quoted

   atom               = ALPHA *1023ATOM-CHAR

   attribute          = string-utf8
                        ;; dot-separated attribute name
                        ;; MUST NOT contain "*" or "%"

   attribute-store    = attribute SP (value-nildef /
                        "(" 1*(metadata-write-q SP value-store) ")")
                        ;; MUST NOT include the same metadata twice

   auth-type          = <"> auth-type-name <">
   auth-type-name     = iana-token
                        ;; as defined in SASL [SASL]

   command            = tag SP (command-any / command-auth /
                        command-nonauth) CRLF
                        ;; Modal based on state

   command-authent    = "AUTHENTICATE" SP auth-type
                        [SP string] *(CRLF string)

   command-any        = "NOOP" / command-lang / "LOGOUT" /
                        command-extend

   command-auth       = command-delacl / command-dsince /
                        command-freectx / command-getquota /
                        command-lrights / command-myrights /
                        command-search / command-setacl /
                        command-store
                        ;; only valid in authenticated state

   command-delacl     = "DELETEACL" SP acl-delobject [SP acl-identifier]

   command-dsince     = "DELETEDSINCE" SP dataset SP time

   command-extend     = extend-token [SP extension-data]

   command-freectx    = "FREECONTEXT" SP context

   command-getquota   = "GETQUOTA" SP dataset

   command-lang       = "LANG" *(SP lang-tag)

   command-lrights    = "LISTRIGHTS" SP acl-object

   command-myrights   = "MYRIGHTS" SP acl-object

   command-nonauth    = command-authent
                        ;; only valid in non-authenticated state

   command-search     = "SEARCH" SP (dataset / context)
                        *(SP search-modifier) SP search-criteria
                        ;; MUST NOT include same search-modifier twice

   command-setacl     = "SETACL" SP acl-object SP acl-identifier
                        SP acl-rights

   command-store      = "STORE" SP store-entry-list
   comparator         = <"> comparator-name <">

   comparator-name    = ["+" / "-"] iana-token

   context            = string-utf8
                        ;; MUST NOT begin with slash ("/")

   dataset            = string-utf8
                        ;; slash-separated dataset name
                        ;; begins with slash
   entry              = entry-name / entry-path

   entry-name         = string-utf8
                        ;; entry name MUST NOT contain slash
                        ;; MUST NOT begin with "."

   entry-path         = string-utf8
                        ;; slash-separated path to entry
                        ;; begins with slash

   entry-relative     = string-utf8
                        ;; potentially relative path to entry

   extend-token       = atom
                        ;; MUST be defined by a standards track or
                        ;; IESG approved experimental protocol extension

   extension-data     = extension-item *(SP extension-item)

   extension-item     = extend-token / string / number /
                        "(" [extension-data] ")"

   iana-token         = atom
                        ;; MUST be registered with IANA

   initial-greeting   = "*" SP "ACAP" *(SP "(" init-capability ")") CRLF

   init-capability    = init-cap-context / init-cap-extend /
                        init-cap-implem / init-cap-sasl

   init-cap-context   = "CONTEXTLIMIT" SP string

   init-cap-extend    = iana-token [SP string-list]

   init-cap-implem    = "IMPLEMENTATION" SP string

   init-cap-sasl      = "SASL" SP string-list
   lang-tag           = <"> Language-Tag <">
                        ;; Language-Tag rule is defined in [LANG-TAGS]

   literal            = "{" number [ "+" ] "}" CRLF *OCTET
                        ;; The number represents the number of octets
                        ;; MUST be literal-utf8 except for values

   literal-utf8       = "{" number [ "+" ] "}" CRLF *UTF8-CHAR
                        ;; The number represents the number of octets
                        ;; not the number of characters

   metadata           = attribute [ "(" metadata-type-list ")" ]
                        ;; attribute MAY end in "*" as wildcard.

   metadata-list      = metadata *(SP metadata)

   metadata-type      = "attribute" / "myrights" / "size" /
                        "count" / metadata-write

   metadata-type-q    = <"> metadata-type <">

   metadata-type-list = metadata-type-q *(SP metadata-type-q)

   metadata-write     = "value" / "acl"

   metadata-write-q   = <"> metadata-write <">

   nil                = "NIL"

   number             = *DIGIT
                        ;; A 32-bit unsigned number.
                        ;; (0 <= n < 4,294,967,296)

   nz-number          = DIGIT-NZ *DIGIT
                        ;; A 32-bit unsigned non-zero number.
                        ;; (0 < n < 4,294,967,296)

   position           = number
                        ;; "0" if context is not enumerated
                        ;; otherwise this is non-zero

   quota-limit        = number

   quota-usage        = number

   quoted             = <"> *QUOTED-CHAR <">
                        ;; limited to 1024 octets between the <">s

   response           = response-addto / response-alert / response-bye /
                        response-change / response-cont /
                        response-deleted / response-done /
                        response-entry / response-extend /
                        response-listr / response-lang /
                        response-mtimei / response-mtimeu /
                        response-myright / response-quota /
                        response-refer / response-remove / response-stat

   response-addto     = "*" SP "ADDTO" SP context SP entry-name
                        SP position SP return-data-list

   response-alert     = "*" SP "ALERT" SP resp-body CRLF
                       ;; Client MUST display alert text to user

   response-bye       = "*" SP "BYE" SP resp-body CRLF
                       ;; Server will disconnect condition

   response-change    = "*" SP "CHANGE" SP context SP entry-name
                        SP position SP position SP return-data-list

   response-cont      = "+" SP string

   response-deleted   = tag SP "DELETED" SP entry-name

   response-done      = tag SP resp-cond-state CRLF

   response-entry     = tag SP "ENTRY" SP entry SP return-data-list

   response-extend    = (tag / "*") SP extend-token [SP extension-data]

   response-lang      = "*" SP "LANG" SP lang-tag 1*(SP comparator)

   response-listr     = tag SP "LISTRIGHTS" SP acl-rights
                        *(SP acl-rights)

   response-mtimei    = tag SP "MODTIME" SP time

   response-mtimeu    = "*" SP "MODTIME" SP context SP time

   response-myright   = tag SP "MYRIGHTS" SP acl-rights

   response-quota     = "*" SP "QUOTA" SP dataset SP quota-limit
                        SP quota-usage [SP extension-data]

   response-refer     = tag SP "REFER" SP dataset
                        1*(SP <"> url-relative <">)

   response-remove    = "*" SP "REMOVEFROM" SP context SP
                        entry-name SP position

   response-stat      = "*" SP resp-cond-state CRLF

   resp-body          = ["(" resp-code ")" SP] quoted

   resp-code          = "AUTH-TOO-WEAK" / "ENCRYPT-NEEDED" /
                        resp-code-inval / resp-code-mod /
                        resp-code-noexist / resp-code-perm / "QUOTA" /
                        resp-code-refer / resp-code-sasl /
                        resp-code-toomany / "TOOOLD" /
                        "TRANSITION-NEEDED" / "TRYFREECONTEXT" /
                        "TRYLATER" / "WAYTOOMANY" / resp-code-ext

   resp-code-ext      = iana-token [SP extension-data]
                        ;; unknown codes MUST be tolerated by the client

   resp-code-inval    = "INVALID" 1*(SP entry-path SP attribute)

   resp-code-mod      = "MODIFIED" SP entry-path

   resp-code-noexist  = "NOEXIST" SP dataset

   resp-code-perm     = "PERMISSION" SP acl-object

   resp-code-refer    = "REFER" 1*(SP <"> url-relative <">)

   resp-code-sasl     = "SASL" SP string

   resp-code-toomany  = "TOOMANY" SP nz-number

   resp-cond-state    = ("OK" / "NO" / "BAD") SP resp-body
                        ;; Status condition

   return-attr-list   = "(" return-metalist *(SP return-metalist) ")"
                        ;; occurs when "*" in RETURN pattern on SEARCH

   return-data        = return-metadata / return-metalist /
                        return-attr-list

   return-data-list   = return-data *(SP return-data)

   return-metalist    = "(" return-metadata *(SP return-metadata) ")"
                        ;; occurs when multiple metadata items requested

   return-metadata    = nil / string / value-list / acl
   searchkey-equal    = "EQUAL" SP attribute SP comparator SP value-nil

   searchkey-comp     = "COMPARE" SP attribute SP comparator SP value

   searchkey-prefix   = "PREFIX" SP attribute SP comparator SP value

   searchkey-range    = "RANGE" SP nz-number SP nz-number SP time

   searchkey-strict   = "COMPARESTRICT" SP attribute SP comparator
                        SP value

   searchkey-substr   = "SUBSTRING" SP attribute SP comparator SP value

   searchmod-depth    = "DEPTH" SP number

   searchmod-hard     = "HARDLIMIT" SP nz-number

   searchmod-limit    = "LIMIT" SP number SP number

   searchmod-make     = "MAKECONTEXT" [SP "ENUMERATE"]
                        [SP "NOTIFY"] SP context

   searchmod-ninh     = "NOINHERIT"

   searchmod-return   = "RETURN" SP "(" [metadata-list] ")"

   searchmod-sort     = "SORT" SP "(" sort-list ")"

   search-criteria    = "ALL" / searchkey-equal / searchkey-comp /
                        searchkey-strict / searchkey-range /
                        searchkey-prefix / searchkey-substr /
                        "NOT" SP search-criteria /
                        "OR" SP search-criteria SP search-criteria /
                        "AND" SP search-criteria SP search-criteria

   search-modifier    = searchmod-depth / searchmod-hard /
                        searchmod-limit / searchmod-make /
                        searchmod-ninh / searchmod-return /
                        searchmod-sort

   sort-list          = sort-item *(SP sort-item)

   sort-item          = attribute SP comparator

   store-entry        = "(" entry-path *(SP store-modifier)
                            *(SP attribute-store) ")"
                        ;; MUST NOT include same store-modifier twice
                        ;; MUST NOT include same attribute twice

   store-entry-list   = store-entry *(SP store-entry)
                        ;; MUST NOT include same entry twice

   store-modifier     = store-mod-unchang / store-mod-nocreate

   store-mod-nocreate = "NOCREATE"

   store-mod-unchang  = "UNCHANGEDSINCE" SP time

   string             = quoted / literal

   string-list        = string *(SP string)

   string-utf8        = quoted / literal-utf8

   tag                = 1*32TAG-CHAR

   time               = <"> time-year time-month time-day time-hour
                        time-minute time-second time-subsecond <">
                        ;; Timestamp in UTC

   time-day           = 2DIGIT ;; 01-31

   time-hour          = 2DIGIT ;; 00-23

   time-minute        = 2DIGIT ;; 00-59

   time-month         = 2DIGIT ;; 01-12

   time-second        = 2DIGIT ;; 00-60

   time-subsecond     = *DIGIT

   time-year          = 4DIGIT

   value              = string

   value-list         = "(" [value *(SP value)] ")"

   value-nil          = value / nil

   value-nildef       = value-nil / "DEFAULT"

   value-store        = value-nildef / value-list / acl

   url-acap           = "acap://" url-server "/" url-enc-entry
                        [url-filter] [url-extension]
                        ;; url-enc-entry interpreted relative to "/"

   url-attr-list      = url-enc-attr *("&" url-enc-attr)

   url-auth           = ";AUTH=" ("*" / url-enc-auth)

   url-achar          = uchar / "&" / "=" / "~"
                        ;; See RFC 1738 for definition of "uchar"

   url-char           = uchar / "=" / "~" / ":" / "@" / "/"
                        ;; See RFC 1738 for definition of "uchar"

   url-enc-attr       = 1*url-char
                        ;; encoded version of attribute name

   url-enc-auth       = 1*url-achar
                        ;; encoded version of auth-type-name above

   url-enc-entry      = 1*url-char
                        ;; encoded version of entry-relative above

   url-enc-user       = *url-achar
                        ;; encoded version of login userid

   url-extension      = *("?" 1*url-char)

   url-filter         = "?" url-attr-list

   url-relative       = url-acap / [url-enc-entry] [url-filter]
                        ;; url-enc-entry is relative to base URL

   url-server         = [url-enc-user [url-auth] "@"] hostport
                        ;; See RFC 1738 for definition of "hostport"

9. Multi-lingual Considerations โœจ

Okay so this bit is about languages ๐ŸŒธ The IAB charset workshop [IAB-CHARSET] reached a bunch of conclusions that shaped how ACAP got designed ๐Ÿ’…. The big one is that UTF-8 was picked as the character encoding, and that choice came straight out of that workshop work ๐Ÿ’–. There's also the LANG command, which lets you negotiate a language for error messages ๐Ÿซถ.

Now here's the tea ๐Ÿต Section 3.4.5 of the IAB charset workshop report says there should be a way to identify the natural language of human readable strings ๐Ÿงš. The thing is, ACAP has several promising proposals on the table, but right now nobody has landed on one clear winner ๐Ÿ˜ญ. So the spec isn't locking anything in yet โœจ.

That said, the plan is that these rules will probably let multi-lingual support get added later ๐Ÿฆ‹:

okay so bestie, these notes are basically "heads up for the future" vibes ๐Ÿ”ฎ

(1) there's this work in progress called Multi-Lingual String Format (MLSF) ๐ŸŒˆ and it wants to sit on top of UTF-8 and use byte sequences that are normally illegal to stash language tags ๐Ÿณ๏ธโ€๐ŸŒˆ. So that it can be added to a future version of this standard, client-side UTF-8 interpreters MUST be able to silently ignore illegal multi-byte UTF-8 characters, and treat illegal single-byte UTF-8 characters as end of string markers ๐Ÿ™ˆ. Servers, for now, MUST be able to silently accept illegal UTF-8 characters, except in attribute names and entry names ๐Ÿ’–. Clients MUST NOT send illegal UTF-8 characters to the server unless a future standard changes this rule ๐Ÿšซ.

(2) there's a proposal to add language tags to Unicode ๐ŸŒ. To make that work, servers MUST be able to store UTF-8 characters of up to 20 bits of data ๐Ÿ’พ.

(3) the metadata item "language" is reserved for future use ๐Ÿงš.

10. Security Considerations ๐Ÿ”

okay this section is serious, so read it with your whole brain, no cap ๐Ÿ˜ญ

The AUTHENTICATE command uses SASL [SASL] to give you basic authentication, authorization, integrity and privacy services. This is described in section 6.3.1 ๐Ÿ›ก๏ธ.

When the CRAM-MD5 mechanism is used, the security considerations for the CRAM-MD5 SASL mechanism [CRAM-MD5] apply. CRAM-MD5 is also susceptible to passive dictionary attacks ๐Ÿ’€. That means if a passive observer records an authentication session, they can try common passwords through the CRAM-MD5 mechanism and see if the results match. Hard-to-guess passwords make this attack weaker ๐Ÿ”’. Sites are encouraged to educate users and to have the password change service test candidate passwords against a dictionary ๐Ÿ“š. ACAP implementations of CRAM-MD5 SHOULD permit passwords of at least 64 characters in length ๐ŸŽ€.

ACAP protocol transactions are open to passive observers or man in the middle attacks that alter the data ๐Ÿ˜ฑ, unless the optional encryption and integrity services of the AUTHENTICATE command are enabled, or an external security mechanism is used for protection. It may be useful to let both clients and servers be configured to refuse to transfer sensitive information when strong encryption is absent ๐Ÿ”.

ACAP access control lists give fine grained authorization for access to attributes ๐Ÿ‘‘. A number of related security issues are described in section 3.5 ๐Ÿง.

ACAP URLs have the same security considerations as IMAP URLs [IMAP-URL] ๐Ÿ”—.

ACAP clients are encouraged to think about the security problems of a shared lab computer situation ๐Ÿ–ฅ๏ธ. Specifically, a client cache of ACAP configuration information MUST NOT allow access by an unauthorized user. One way to make sure of this is for an ACAP client to be able to completely flush any non-public cached configuration data when a user leaves ๐Ÿงน.

Laptops can be easily stolen, and a cache of configuration data may contain sensitive information ๐Ÿ’ป. So a disconnected mode ACAP client may wish to encrypt and password protect cached configuration information ๐Ÿ”‘.


11. Acknowledgments ๐Ÿ™Œ

Many thanks to the following people who have contributed to ACAP over the past four years ๐Ÿซถ: Wallace Colyer, Mark Crispin, Jack DeWinter, Rob Earhart, Ned Freed, Randy Gellens, Terry Gray, J. S. Greenfield, Steve Dorner, Steve Hole, Steve Hubert, Dave Roberts, Bart Schaefer, Matt Wall and other participants of the IETF ACAP working group โœจ.

12. Authors' Addresses ๐Ÿ’Œ

here are the brilliant minds behind it ๐Ÿง 

Chris Newman
Innosoft International, Inc.
1050 Lakes Drive
West Covina, CA 91790 USA

Email: chris.newman@innosoft.com


John Gardiner Myers
Netscape Communications
501 East Middlefield Road
Mail Stop MV-029
Mountain View, CA 94043

Email: jgmyers@netscape.com

A. References โœจ

okay bestie, the references are where all the good stuff lives ๐Ÿ“š๐Ÿซถ every single one is kept exactly as written, so you can chase down any source you need.

  • [ABNF] Crocker, Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, Internet Mail Consortium, Demon Internet Ltd, November 1997.
    • ftp://ds.internic.net/rfc/rfc2234.txt
  • [BASIC-URL] Berners-Lee, Masinter, McCahill, "Uniform Resource Locators (URL)", RFC 1738, CERN, Xerox Coproration, University of Minnesota, December 1994.
    • ftp://ds.internic.net/rfc/rfc1738.txt
  • [CHARSET-LANG-POLICY] Alvestrand, "IETF Policy on Character Sets and Languages", work in progress.
  • [CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension for Simple Challenge/Response", RFC 2195, MCI, September 1997.
    • ftp://ds.internic.net/rfc/rfc2195.txt
  • [IAB-CHARSET] Weider, Preston, Simonsen, Alvestrand, Atkinson, Crispin, Svanberg, "The Report of the IAB Character Set Workshop held 29 February - 1 March, 1996", RFC 2130, April 1997.
    • ftp://ds.internic.net/rfc/rfc2130.txt
  • [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 4rev1", RFC 2060, University of Washington, December 1996.
    • ftp://ds.internic.net/rfc/rfc2060.txt
  • [IMAP-ACL] Myers, J., "IMAP4 ACL extension", RFC 2086, Carnegie Mellon, January 1997.
    • ftp://ds.internic.net/rfc/rfc2086.txt
  • [IMAP-URL] Newman, "IMAP URL Scheme", RFC 2192, Innosoft, July 1997.
    • ftp://ds.internic.net/rfc/rfc2192.txt
  • [ISO-10646] ISO/IEC 10646-1:1993(E) "Information Technology-- Universal Multiple-octet Coded Character Set (UCS)." See also amendments 1 through 7, plus editorial corrections.
  • [ISO-C] "Programming languages -- C", ISO/IEC 9899:1990, International Organization for Standardization. This is effectively the same as ANSI C standard X3.159-1989.
  • [KEYWORDS] Bradner, "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, Harvard University, March 1997.
    • ftp://ds.internic.net/rfc/rfc2119.txt
  • [LANG-TAGS] Alvestrand, H., "Tags for the Identification of Languages", RFC 1766.
    • ftp://ds.internic.net/rfc/rfc1766.txt
  • [REL-URL] Fielding, "Relative Uniform Resource Locators", RFC 1808, UC Irvine, June 1995.
    • ftp://ds.internic.net/rfc/rfc1808.txt
  • [SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, Netscape Communications, October 1997.
    • ftp://ds.internic.net/rfc/rfc2222.txt
  • [SASL-ANON] Newman, C., "Anonymous SASL Mechanism", RFC 2245, November 1997.
  • [UNICODE-2] The Unicode Consortium, "The Unicode Standard, Version 2.0", Addison-Wesley, 1996. ISBN 0-201-48345-9.
  • [US-ASCII] "USA Standard Code for Information Interchange," X3.4. American National Standards Institute: New York (1968).
  • [UTF8] Yergeau, F. "UTF-8, a transformation format of Unicode and ISO 10646", RFC 2044, Alis Technologies, October 1996.
    • ftp://ds.internic.net/rfc/rfc2044.txt

B. ACAP Keyword Index ๐Ÿ—‚๏ธ

this index is basically your cheat sheet for finding every ACAP keyword, command, response and attribute, with the page where each one shows up ๐Ÿ“ every entry is copied exactly as it appears.

       ACAP (untagged response) ...................................   26
       ADDTO (untagged response) ..................................   40
       ALERT (untagged response) ..................................   31
       ALL (search keyword) .......................................   36
       AND (search keyword) .......................................   36
       AUTH-TOO-WEAK (response code) ..............................   19
       AUTHENTICATE (command) .....................................   31
       BAD (response) .............................................   30
       BYE (untagged response) ....................................   30
       CHANGE (untagged response) .................................   41
       COMPARE (search keyword) ...................................   36
       COMPARESTRICT (search keyword) .............................   36
       CONTEXTLIMIT (ACAP capability) .............................   27
       DELETEACL (command) ........................................   46
       DELETED (intermediate response) ............................   45
       DELETEDSINCE (command) .....................................   45
       DEPTH (search modifier) ....................................   34
       ENCRYPT-NEEDED (response code) .............................   19
       ENTRY (intermediate response) ..............................   37
       EQUAL (search keyword) .....................................   37
       FREECONTEXT (command) ......................................   39
       GETQUOTA (command) .........................................   48
       HARDLIMIT (search modifier) ................................   34
       IMPLEMENTATION (ACAP capability) ...........................   27
       INVALID (response code) ....................................   19
       LANG (command) .............................................   28
       LANG (intermediate response) ...............................   28
       LIMIT (search modifier) ....................................   34
       LISTRIGHTS (command) .......................................   47
       LISTRIGHTS (intermediate response) .........................   48
       LOGOUT (command) ...........................................   29
       MAKECONTEXT (search modifier) ..............................   34
       MODIFIED (response code) ...................................   19
       MODTIME (intermediate response) ............................   38
       MODTIME (untagged response) ................................   42
       MYRIGHTS (command) .........................................   47
       MYRIGHTS (intermediate response) ...........................   47
       NO (response) ..............................................   29
       NOCREATE (store modifier) ..................................   44
       NOEXIST (response code) ....................................   19
       NOINHERIT (search modifier) ................................   35
       NOOP (command) .............................................   27
       NOT (search keyword) .......................................   37
       OK (response) ..............................................   29
       OR (search keyword) ........................................   37
       PERMISSION (response code) .................................   19
       PREFIX (search keyword) ....................................   37
       QUOTA (response code) ......................................   19
       QUOTA (untagged response) ..................................   49
       RANGE (search keyword) .....................................   37
       REFER (intermediate response) ..............................   38
       REFER (response code) ......................................   19
       REMOVEFROM (untagged response) .............................   41
       RETURN (search modifier) ...................................   35
       SASL (ACAP capability) .....................................   27
       SASL (response code) .......................................   20
       SEARCH (command) ...........................................   33
       SETACL (command) ...........................................   46
       SORT (search modifier) .....................................   36
       STORE (command) ............................................   42
       SUBSTRING (search keyword) .................................   37
       TOOMANY (response code) ....................................   20
       TOOOLD (response code) .....................................   20
       TRANSITION-NEEDED (response code) ..........................   20
       TRYFREECONTEXT (response code) .............................   20
       TRYLATER (response code) ...................................   20
       UNCHANGEDSINCE (store modifier) ............................   44
       UPDATECONTEXT (command) ....................................   40
       WAYTOOMANY (response code) .................................   20
       acl (attribute metadata) ...................................   12
       anyone (ACL identifier) ....................................   17
       attribute (attribute metadata) .............................   12
       dataset.acl (dataset attribute) ............................   24
       dataset.acl.<attribute> (dataset attribute) ................   24
       dataset.inherit (dataset attribute) ........................   24
       entry (predefined attribute) ...............................   11
       i;ascii-casemap (comparator) ...............................   16
       i;ascii-numeric (comparator) ...............................   16
       i;octet (comparator) .......................................   16
       modtime (predefined attribute) .............................   11
       myrights (attribute metadata) ..............................   12
       size (attribute metadata) ..................................   13
       subdataset (predefined attribute) ..........................   11
       value (attribute metadata) .................................   13

okay this is the legal bit, and I'm keeping every word so nothing gets lost ๐Ÿ’…

Copyright (C) The Internet Society 1997. All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implmentation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

๐Ÿ“ฆ where this page comes from