IMAP in OCaml

Add IMAP RFC specs and implementation plans

Fetch 8 RFCs for IMAP extensions:
- RFC 3691 (UNSELECT)
- RFC 4731 (ESEARCH)
- RFC 5256 (SORT/THREAD)
- RFC 5258 (LIST Extensions)
- RFC 5530 (Response Codes)
- RFC 6154 (Special-Use Mailboxes)
- RFC 6855 (UTF-8 Support)
- RFC 9208 (QUOTA)

Also fetch draft-ietf-mailmaint-messageflag-mailboxattribute-13
for unified IMAP/JMAP keyword and mailbox attribute handling.

Each RFC has a corresponding PLAN-*.md with implementation
analysis comparing spec to current codebase, prioritized tasks,
and OCamldoc citation templates.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+12832
+265
spec/PLAN-rfc3691.md
··· 1 + # RFC 3691 UNSELECT Command Implementation Plan 2 + 3 + ## RFC Summary 4 + 5 + **RFC 3691** (February 2004) defines the IMAP UNSELECT command extension. 6 + 7 + ### Purpose 8 + 9 + The UNSELECT command provides a clean way to close the currently selected mailbox 10 + without expunging messages marked for deletion. This addresses a gap in RFC 3501 11 + (IMAP4rev1) where CLOSE always performs an implicit expunge. 12 + 13 + ### UNSELECT vs CLOSE Comparison 14 + 15 + | Aspect | CLOSE (RFC 3501) | UNSELECT (RFC 3691) | 16 + |--------|------------------|---------------------| 17 + | Closes mailbox | Yes | Yes | 18 + | Returns to authenticated state | Yes | Yes | 19 + | Expunges \Deleted messages | Yes (if read-write) | No | 20 + | Frees server resources | Yes | Yes | 21 + | Arguments | None | None | 22 + | Responses | OK/BAD | OK/BAD | 23 + 24 + ### RFC Requirements 25 + 26 + 1. **Capability advertisement**: Server MUST advertise "UNSELECT" capability 27 + 2. **No arguments**: Command takes no arguments 28 + 3. **Result codes**: 29 + - `OK` - unselect completed, now in authenticated state 30 + - `BAD` - no mailbox selected, or argument supplied but none permitted 31 + 4. **Behavior**: Same as CLOSE except no messages are permanently removed 32 + 5. **State transition**: Selected state -> Authenticated state 33 + 34 + ### Formal Syntax (ABNF) 35 + 36 + ```abnf 37 + command-select /= "UNSELECT" 38 + ``` 39 + 40 + ### Example Exchange 41 + 42 + ``` 43 + C: A341 UNSELECT 44 + S: A341 OK Unselect completed 45 + ``` 46 + 47 + ## Current Implementation Status 48 + 49 + ### Server (`lib/imapd/`) 50 + 51 + | Component | Status | Location | 52 + |-----------|--------|----------| 53 + | Lexer token | Done | `lexer.mll:56` - UNSELECT keyword defined | 54 + | Grammar rule | Done | `grammar.mly:416` - UNSELECT command parsed | 55 + | Protocol type | Done | `protocol.ml:360` - `Unselect` command variant | 56 + | Command handler | Done | `server.ml:393-405` - `handle_unselect` function | 57 + | Command dispatch | Done | `server.ml:788` - dispatches to handler | 58 + | Capability | **Missing** | Not advertised in `base_capabilities_*` | 59 + 60 + ### Client (`lib/imap/`) 61 + 62 + | Component | Status | Location | 63 + |-----------|--------|----------| 64 + | Command type | Done | `command.ml:36` - `Unselect` variant | 65 + | Command printer | Done | `command.ml:94` - pretty-prints "UNSELECT" | 66 + | Writer | Done | `write.ml:404` - serializes command | 67 + | Client function | Done | `client.ml:430-436` - `unselect` function | 68 + | Interface | Done | `client.mli:163` - exported | 69 + 70 + ### Client (`lib/imapd/` - server-side client) 71 + 72 + | Component | Status | Location | 73 + |-----------|--------|----------| 74 + | Client function | Done | `client.ml:591-598` - `unselect` function | 75 + | Interface | Done | `client.mli:305-306` - exported | 76 + | Capability check | Done | `client.ml:593` - requires UNSELECT capability | 77 + 78 + ### Tests 79 + 80 + | Component | Status | Location | 81 + |-----------|--------|----------| 82 + | Integration test | Done | `test/integration/imaptest_scripted.ml:806-819` | 83 + 84 + ## Implementation Tasks 85 + 86 + ### Priority 1: Capability Advertisement (Required for Compliance) 87 + 88 + **Task**: Add UNSELECT to server capability list 89 + 90 + **File**: `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 91 + 92 + **Change**: Add "UNSELECT" to both `base_capabilities_pre_tls` and `base_capabilities_post_tls`: 93 + 94 + ```ocaml 95 + let base_capabilities_pre_tls = [ 96 + "IMAP4rev2"; 97 + "IMAP4rev1"; 98 + "AUTH=PLAIN"; 99 + "STARTTLS"; 100 + "IDLE"; 101 + "NAMESPACE"; 102 + "UIDPLUS"; 103 + "MOVE"; 104 + "ENABLE"; 105 + "LITERAL+"; 106 + "ID"; 107 + "UNSELECT"; (* RFC 3691 *) 108 + ] 109 + ``` 110 + 111 + ### Priority 2: Documentation (OCamldoc Updates) 112 + 113 + **Task**: Add RFC 3691 citations to relevant code 114 + 115 + #### Server handler (`server.ml`) 116 + 117 + ```ocaml 118 + (** Process UNSELECT command. 119 + 120 + Closes the selected mailbox and returns to authenticated state 121 + without expunging messages marked as \Deleted. 122 + 123 + {b RFC Reference:} {{:https://datatracker.ietf.org/doc/html/rfc3691}RFC 3691} 124 + Section 2 - UNSELECT Command 125 + 126 + @param flow The client connection 127 + @param tag The command tag for the response 128 + @param state Current connection state (must be Selected) 129 + @return New state (Authenticated) or same state on error *) 130 + let handle_unselect flow tag state = 131 + ``` 132 + 133 + #### Client function (`lib/imap/client.ml`) 134 + 135 + ```ocaml 136 + (** [unselect t] closes the selected mailbox without expunging. 137 + 138 + Unlike {!close}, which permanently removes messages marked as \Deleted, 139 + this command preserves all messages and simply returns to the 140 + authenticated state. 141 + 142 + {b RFC Reference:} {{:https://datatracker.ietf.org/doc/html/rfc3691}RFC 3691} 143 + 144 + @raise Error.State_error if not in selected state *) 145 + let unselect t = 146 + ``` 147 + 148 + #### Client function (`lib/imapd/client.ml`) 149 + 150 + ```ocaml 151 + (** [unselect t] closes the selected mailbox without expunging. 152 + 153 + This command returns the connection to the authenticated state 154 + without removing messages marked as \Deleted. Use {!close} if 155 + you want to expunge deleted messages. 156 + 157 + {b RFC Reference:} {{:https://datatracker.ietf.org/doc/html/rfc3691}RFC 3691 158 + 159 + @raise Client_error.State_error if not in selected state 160 + @raise Client_error.Capability_missing if UNSELECT not supported *) 161 + let unselect t = 162 + ``` 163 + 164 + #### Client interface (`lib/imap/client.mli`) 165 + 166 + ```ocaml 167 + val unselect : t -> unit 168 + (** [unselect client] closes the selected mailbox without expunging. 169 + 170 + This is the RFC 3691 UNSELECT command. Unlike {!close}, deleted 171 + messages are preserved. 172 + 173 + @raise Error.State_error if not in selected state *) 174 + ``` 175 + 176 + #### Client interface (`lib/imapd/client.mli`) 177 + 178 + ```ocaml 179 + val unselect : t -> unit 180 + (** [unselect client] closes the selected mailbox without expunging. 181 + 182 + See {{:https://datatracker.ietf.org/doc/html/rfc3691}RFC 3691}. *) 183 + ``` 184 + 185 + ### Priority 3: Enhanced Testing 186 + 187 + **Task**: Verify UNSELECT does not expunge messages 188 + 189 + The existing test at `test/integration/imaptest_scripted.ml:806-819` checks state 190 + transitions but does not verify that messages are preserved. Consider adding: 191 + 192 + ```ocaml 193 + let test_unselect_preserves_deleted ~sw ~env ~config () = 194 + with_test_setup ~sw ~env ~config (fun client -> 195 + if not (has_capability client "UNSELECT") then 196 + raise (Failure "SKIP: Server does not support UNSELECT"); 197 + let mailbox = create_test_mailbox client ~config ~suffix:"unsel_del" in 198 + Fun.protect 199 + ~finally:(fun () -> delete_mailbox_safe client mailbox) 200 + (fun () -> 201 + (* Append a message *) 202 + let _ = Imap.Client.append client ~mailbox ~message:simple_message () in 203 + let _ = Imap.Client.select client mailbox in 204 + (* Mark message as deleted *) 205 + let _ = Imap.Client.store client 206 + ~sequence:[Imap.Seq.Single 1] 207 + ~action:Imap.Store.Add 208 + ~flags:[Imap.Flag.System Imap.Flag.Deleted] () in 209 + (* UNSELECT should preserve the deleted message *) 210 + Imap.Client.unselect client; 211 + (* Re-select and verify message still exists *) 212 + let info = Imap.Client.select client mailbox in 213 + if info.exists <> 1 then 214 + raise (Failure "UNSELECT should not expunge deleted messages"))) 215 + ``` 216 + 217 + ## OCamldoc Citation Templates 218 + 219 + ### For implementation files 220 + 221 + ```ocaml 222 + (** ... description ... 223 + 224 + {b RFC Reference:} {{:https://datatracker.ietf.org/doc/html/rfc3691}RFC 3691} 225 + Section 2 - UNSELECT Command *) 226 + ``` 227 + 228 + ### For interface files 229 + 230 + ```ocaml 231 + (** ... description ... 232 + 233 + See {{:https://datatracker.ietf.org/doc/html/rfc3691}RFC 3691}. *) 234 + ``` 235 + 236 + ### For types/variants 237 + 238 + ```ocaml 239 + | Unselect 240 + (** Close mailbox without expunging ({{:https://datatracker.ietf.org/doc/html/rfc3691}RFC 3691}). *) 241 + ``` 242 + 243 + ## Summary 244 + 245 + The UNSELECT command is **fully implemented** in both server and client code. 246 + The only missing piece is the capability advertisement in the server, which is 247 + a one-line fix. Documentation improvements are recommended but not required 248 + for correctness. 249 + 250 + ### Implementation Checklist 251 + 252 + - [ ] Add "UNSELECT" to `base_capabilities_pre_tls` in `server.ml` 253 + - [ ] Add "UNSELECT" to `base_capabilities_post_tls` in `server.ml` 254 + - [ ] Add OCamldoc citation to `handle_unselect` in `server.ml` 255 + - [ ] Add OCamldoc citation to `unselect` in `lib/imap/client.ml` 256 + - [ ] Add OCamldoc citation to `unselect` in `lib/imap/client.mli` 257 + - [ ] Add OCamldoc citation to `unselect` in `lib/imapd/client.ml` 258 + - [ ] Add OCamldoc citation to `unselect` in `lib/imapd/client.mli` 259 + - [ ] (Optional) Add test for message preservation after UNSELECT 260 + 261 + ## References 262 + 263 + - [RFC 3691](https://datatracker.ietf.org/doc/html/rfc3691) - Internet Message Access Protocol (IMAP) UNSELECT command 264 + - [RFC 9051](https://datatracker.ietf.org/doc/html/rfc9051) - Internet Message Access Protocol (IMAP) - Version 4rev2 265 + - [RFC 3501](https://datatracker.ietf.org/doc/html/rfc3501) - Internet Message Access Protocol - Version 4rev1 (CLOSE command)
+581
spec/PLAN-rfc4731.md
··· 1 + # RFC 4731 Implementation Plan: ESEARCH Extension 2 + 3 + **RFC:** [4731 - IMAP4 Extension to SEARCH Command for Controlling What Kind of Information Is Returned](https://datatracker.ietf.org/doc/html/rfc4731) 4 + 5 + **Status:** Partially Implemented 6 + 7 + **Spec Location:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/spec/rfc4731.txt` 8 + 9 + --- 10 + 11 + ## 1. RFC Summary 12 + 13 + RFC 4731 extends the IMAP SEARCH and UID SEARCH commands with result options that control what information is returned. A server advertising the `ESEARCH` capability supports: 14 + 15 + ### 1.1 Result Options 16 + 17 + | Option | Description | Response Format | 18 + |--------|-------------|-----------------| 19 + | `MIN` | Lowest message number/UID matching criteria | `MIN <nz-number>` | 20 + | `MAX` | Highest message number/UID matching criteria | `MAX <nz-number>` | 21 + | `ALL` | All matching message numbers/UIDs as sequence-set | `ALL <sequence-set>` | 22 + | `COUNT` | Count of matching messages | `COUNT <number>` | 23 + 24 + ### 1.2 Key Requirements 25 + 26 + 1. When result options are specified, server MUST return `ESEARCH` response instead of `SEARCH` response 27 + 2. Empty result option list `RETURN ()` is equivalent to `RETURN (ALL)` 28 + 3. For `UID SEARCH`, the ESEARCH response MUST include the `UID` indicator 29 + 4. If no matches found, MIN/MAX/ALL MUST NOT be included, but ESEARCH response MUST still be sent 30 + 5. COUNT MUST always be included when requested (even if zero) 31 + 6. ESEARCH response includes `(TAG "tag")` to correlate with command 32 + 33 + ### 1.3 Command Syntax 34 + 35 + ``` 36 + search-return-opts = "RETURN" SP "(" [search-return-opt *(SP search-return-opt)] ")" 37 + search-return-opt = "MIN" / "MAX" / "ALL" / "COUNT" 38 + ``` 39 + 40 + Example commands: 41 + ``` 42 + C: A282 SEARCH RETURN (MIN COUNT) FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith" 43 + C: A283 SEARCH RETURN () FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith" 44 + C: A284 SEARCH RETURN (MIN) UNSEEN 45 + C: A285 UID SEARCH RETURN (MIN MAX) 1:5000 46 + ``` 47 + 48 + ### 1.4 Response Syntax 49 + 50 + ``` 51 + esearch-response = "* ESEARCH" [search-correlator] [SP "UID"] *(SP search-return-data) 52 + search-correlator = SP "(" "TAG" SP tag-string ")" 53 + search-return-data = "MIN" SP nz-number / 54 + "MAX" SP nz-number / 55 + "ALL" SP sequence-set / 56 + "COUNT" SP number 57 + ``` 58 + 59 + Example responses: 60 + ``` 61 + S: * ESEARCH (TAG "A282") MIN 2 COUNT 3 62 + S: * ESEARCH (TAG "A283") ALL 2,10:11 63 + S: * ESEARCH (TAG "A284") MIN 4 64 + S: * ESEARCH (TAG "A285") UID MIN 7 MAX 3800 65 + S: * ESEARCH (TAG "A286") COUNT 15 66 + ``` 67 + 68 + ### 1.5 CONDSTORE Interaction (RFC 4551) 69 + 70 + When both ESEARCH and CONDSTORE are supported and MODSEQ criterion is used: 71 + - Server returns ESEARCH response with `MODSEQ` result option 72 + - MODSEQ value depends on which result options were requested 73 + 74 + --- 75 + 76 + ## 2. Current Implementation Status 77 + 78 + ### 2.1 Already Implemented 79 + 80 + | Component | File | Status | 81 + |-----------|------|--------| 82 + | `Response.esearch_result` type | `lib/imap/response.ml:22-26` | Complete | 83 + | `Response.Esearch` variant | `lib/imap/response.ml:45` | Complete | 84 + | `Response.mli` exports | `lib/imap/response.mli:22-27,45` | Complete | 85 + | Server-side ESEARCH generation | `lib/imapd/server.ml:616-623` | Basic | 86 + | Server-side ESEARCH serialization | `lib/imapd/parser.ml:296-307` | Basic | 87 + | Server-side `esearch_result` type | `lib/imapd/protocol.ml:396-400` | Complete | 88 + 89 + ### 2.2 Missing/Incomplete 90 + 91 + | Component | File | Issue | 92 + |-----------|------|-------| 93 + | ESEARCH response parsing | `lib/imap/read.ml` | Not implemented | 94 + | Search return options in Command type | `lib/imap/command.ml` | Missing `return_opts` field | 95 + | Search return options serialization | `lib/imap/write.ml` | Missing `RETURN (...)` syntax | 96 + | Client API for ESEARCH | `lib/imap/client.ml` | Uses basic SEARCH only | 97 + | MODSEQ result option | All files | Not implemented | 98 + 99 + --- 100 + 101 + ## 3. Implementation Tasks 102 + 103 + ### 3.1 Phase 1: Response Parsing (Priority: High) 104 + 105 + #### Task 1.1: Add ESEARCH Response Parsing to read.ml 106 + 107 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/read.ml` 108 + 109 + **Location:** Add after `SEARCH` case around line 616-624 110 + 111 + **Implementation:** 112 + 113 + ```ocaml 114 + (** Parse ESEARCH response per {{:https://datatracker.ietf.org/doc/html/rfc4731#section-4}RFC 4731 Section 4}. *) 115 + | "ESEARCH" -> 116 + (* Parse optional (TAG "xxx") correlator *) 117 + let tag = 118 + if R.peek_char r = Some ' ' then begin 119 + sp r; 120 + if R.peek_char r = Some '(' then begin 121 + R.char '(' r; 122 + let _ = atom r in (* "TAG" *) 123 + sp r; 124 + let t = quoted_string r in 125 + R.char ')' r; 126 + Some t 127 + end else None 128 + end else None 129 + in 130 + (* Parse optional UID indicator *) 131 + let uid = 132 + if R.peek_char r = Some ' ' then begin 133 + R.ensure r 4; 134 + let buf = R.peek r in 135 + if Cstruct.length buf >= 4 && 136 + Char.uppercase_ascii (Cstruct.get_char buf 1) = 'U' && 137 + Char.uppercase_ascii (Cstruct.get_char buf 2) = 'I' && 138 + Char.uppercase_ascii (Cstruct.get_char buf 3) = 'D' then begin 139 + sp r; 140 + let _ = atom r in (* "UID" *) 141 + true 142 + end else false 143 + end else false 144 + in 145 + (* Parse result data items *) 146 + let results = ref [] in 147 + while R.peek_char r = Some ' ' do 148 + sp r; 149 + let name = atom r in 150 + sp r; 151 + let result = match String.uppercase_ascii name with 152 + | "MIN" -> Response.Esearch_min (number r) 153 + | "MAX" -> Response.Esearch_max (number r) 154 + | "COUNT" -> Response.Esearch_count (number r) 155 + | "ALL" -> Response.Esearch_all (parse_sequence_set r) 156 + | _ -> Response.Esearch_count 0 (* fallback *) 157 + in 158 + results := result :: !results 159 + done; 160 + crlf r; 161 + Response.Esearch { tag; uid; results = List.rev !results } 162 + ``` 163 + 164 + #### Task 1.2: Add Sequence-Set Parser to read.ml 165 + 166 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/read.ml` 167 + 168 + **Location:** Add in parser helpers section around line 89-108 169 + 170 + **Implementation:** 171 + 172 + ```ocaml 173 + (** Parse sequence-set per {{:https://datatracker.ietf.org/doc/html/rfc9051#section-9}RFC 9051 Section 9}. 174 + 175 + Used for ESEARCH ALL result option per {{:https://datatracker.ietf.org/doc/html/rfc4731#section-4}RFC 4731}. *) 176 + let parse_sequence_range r = 177 + let first = 178 + match R.peek_char r with 179 + | Some '*' -> R.char '*' r; None 180 + | _ -> Some (number r) 181 + in 182 + if R.peek_char r = Some ':' then begin 183 + R.char ':' r; 184 + let last = 185 + match R.peek_char r with 186 + | Some '*' -> R.char '*' r; None 187 + | _ -> Some (number r) 188 + in 189 + match first, last with 190 + | Some a, Some b -> Seq.Range (a, b) 191 + | Some a, None -> Seq.From a 192 + | None, _ -> Seq.All 193 + end else 194 + match first with 195 + | Some n -> Seq.Single n 196 + | None -> Seq.All 197 + 198 + let parse_sequence_set r = 199 + let rec loop acc = 200 + let range = parse_sequence_range r in 201 + match R.peek_char r with 202 + | Some ',' -> R.char ',' r; loop (range :: acc) 203 + | _ -> List.rev (range :: acc) 204 + in 205 + loop [] 206 + ``` 207 + 208 + --- 209 + 210 + ### 3.2 Phase 2: Command Extensions (Priority: High) 211 + 212 + #### Task 2.1: Add Search Return Options to Command Type 213 + 214 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/command.ml` 215 + 216 + **Location:** Line 38 and 64 217 + 218 + **Changes:** 219 + 220 + ```ocaml 221 + (** Search return options per {{:https://datatracker.ietf.org/doc/html/rfc4731#section-3.1}RFC 4731 Section 3.1}. *) 222 + type search_return_opt = 223 + | Return_min 224 + | Return_max 225 + | Return_all 226 + | Return_count 227 + 228 + (* Modify Search command *) 229 + | Search of { 230 + charset : string option; 231 + criteria : Search.t; 232 + return_opts : search_return_opt list option (* NEW *) 233 + } 234 + 235 + (* Modify Uid_search command *) 236 + | Uid_search of { 237 + charset : string option; 238 + criteria : Search.t; 239 + return_opts : search_return_opt list option (* NEW *) 240 + } 241 + ``` 242 + 243 + #### Task 2.2: Add Search Return Options Serialization 244 + 245 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/write.ml` 246 + 247 + **Location:** Around line 327-331 in `write_search` function 248 + 249 + **Changes:** 250 + 251 + ```ocaml 252 + (** Serialize search return options per {{:https://datatracker.ietf.org/doc/html/rfc4731#section-4}RFC 4731}. *) 253 + let search_return_opt w = function 254 + | Command.Return_min -> W.string w "MIN" 255 + | Command.Return_max -> W.string w "MAX" 256 + | Command.Return_all -> W.string w "ALL" 257 + | Command.Return_count -> W.string w "COUNT" 258 + 259 + let search_return_opts w opts = 260 + W.string w "RETURN ("; 261 + List.iteri (fun i opt -> 262 + if i > 0 then sp w; 263 + search_return_opt w opt 264 + ) opts; 265 + W.char w ')' 266 + 267 + let write_search w charset return_opts criteria = 268 + W.string w "SEARCH"; 269 + (* Return options come before CHARSET per RFC 4731 *) 270 + Option.iter (fun opts -> sp w; search_return_opts w opts) return_opts; 271 + Option.iter (fun cs -> W.string w " CHARSET "; astring w cs) charset; 272 + sp w; 273 + search_key w criteria 274 + ``` 275 + 276 + --- 277 + 278 + ### 3.3 Phase 3: Client API (Priority: Medium) 279 + 280 + #### Task 3.1: Add ESEARCH-Aware Search Functions 281 + 282 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/client.ml` 283 + 284 + **Location:** Around line 571-593 285 + 286 + **Changes:** 287 + 288 + ```ocaml 289 + (** ESEARCH result type *) 290 + type esearch_result = { 291 + min : int option; 292 + max : int option; 293 + count : int option; 294 + all : Seq.t option; 295 + } 296 + 297 + (** Search with ESEARCH return options per {{:https://datatracker.ietf.org/doc/html/rfc4731}RFC 4731}. 298 + 299 + Returns structured results when server supports ESEARCH capability. *) 300 + let esearch t ?charset ?(return_opts=[Command.Return_all]) criteria = 301 + require_selected t; 302 + let tag = send_command t (Command.Search { charset; criteria; return_opts = Some return_opts }) in 303 + let untagged, final = receive_responses t tag in 304 + check_ok tag untagged final; 305 + (* Extract ESEARCH results *) 306 + let result = ref { min = None; max = None; count = None; all = None } in 307 + List.iter (function 308 + | Response.Esearch { results; _ } -> 309 + List.iter (function 310 + | Response.Esearch_min n -> result := { !result with min = Some n } 311 + | Response.Esearch_max n -> result := { !result with max = Some n } 312 + | Response.Esearch_count n -> result := { !result with count = Some n } 313 + | Response.Esearch_all seq -> result := { !result with all = Some seq } 314 + ) results 315 + | Response.Search seqs -> 316 + (* Fallback for servers without ESEARCH *) 317 + result := { !result with all = Some (List.map (fun n -> Seq.Single n) seqs) } 318 + | _ -> () 319 + ) untagged; 320 + !result 321 + 322 + (** UID search with ESEARCH return options. *) 323 + let uid_esearch t ?charset ?(return_opts=[Command.Return_all]) criteria = 324 + require_selected t; 325 + let tag = send_command t (Command.Uid (Uid_search { charset; criteria; return_opts = Some return_opts })) in 326 + let untagged, final = receive_responses t tag in 327 + check_ok tag untagged final; 328 + (* Extract ESEARCH results - same as esearch but UIDs *) 329 + let result = ref { min = None; max = None; count = None; all = None } in 330 + List.iter (function 331 + | Response.Esearch { results; uid = true; _ } -> 332 + List.iter (function 333 + | Response.Esearch_min n -> result := { !result with min = Some n } 334 + | Response.Esearch_max n -> result := { !result with max = Some n } 335 + | Response.Esearch_count n -> result := { !result with count = Some n } 336 + | Response.Esearch_all seq -> result := { !result with all = Some seq } 337 + ) results 338 + | _ -> () 339 + ) untagged; 340 + !result 341 + ``` 342 + 343 + #### Task 3.2: Add Convenience Functions 344 + 345 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/client.ml` 346 + 347 + ```ocaml 348 + (** Find first unseen message using ESEARCH MIN. 349 + 350 + Example from {{:https://datatracker.ietf.org/doc/html/rfc4731#section-3.1}RFC 4731 Section 3.1}. *) 351 + let first_unseen t = 352 + let result = esearch t ~return_opts:[Command.Return_min] Search.Unseen in 353 + result.min 354 + 355 + (** Count messages matching criteria using ESEARCH COUNT. *) 356 + let count_messages t criteria = 357 + let result = esearch t ~return_opts:[Command.Return_count] criteria in 358 + Option.value ~default:0 result.count 359 + 360 + (** Count deleted messages. *) 361 + let count_deleted t = 362 + count_messages t Search.Deleted 363 + ``` 364 + 365 + --- 366 + 367 + ### 3.4 Phase 4: Server Implementation Improvements (Priority: Low) 368 + 369 + #### Task 4.1: Parse Search Return Options in Server 370 + 371 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/protocol.ml` 372 + 373 + **Changes:** Add `search_return_opt` type and update `search_key` commands 374 + 375 + #### Task 4.2: Generate Correct ESEARCH Based on Options 376 + 377 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 378 + 379 + **Location:** Line 608-631 380 + 381 + **Changes:** Honor requested return options instead of always returning COUNT and ALL 382 + 383 + --- 384 + 385 + ### 3.5 Phase 5: CONDSTORE Integration (Priority: Low) 386 + 387 + #### Task 5.1: Add MODSEQ Result Option 388 + 389 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/response.ml` 390 + 391 + ```ocaml 392 + type esearch_result = 393 + | Esearch_min of int 394 + | Esearch_max of int 395 + | Esearch_count of int 396 + | Esearch_all of Seq.t 397 + | Esearch_modseq of int64 (* NEW - per RFC 4731 Section 3.2 *) 398 + ``` 399 + 400 + --- 401 + 402 + ## 4. OCamldoc Citation Templates 403 + 404 + ### 4.1 Module-Level Documentation 405 + 406 + ```ocaml 407 + (** IMAP ESEARCH Extension 408 + 409 + Implements {{:https://datatracker.ietf.org/doc/html/rfc4731}RFC 4731} - 410 + IMAP4 Extension to SEARCH Command for Controlling What Kind of Information 411 + Is Returned. 412 + 413 + The ESEARCH extension provides result options for SEARCH commands: 414 + - {b MIN}: Lowest matching message number/UID 415 + - {b MAX}: Highest matching message number/UID 416 + - {b ALL}: All matching numbers as a sequence-set 417 + - {b COUNT}: Total count of matches 418 + 419 + @see <https://datatracker.ietf.org/doc/html/rfc4731#section-3.1> Result Options 420 + @see <https://datatracker.ietf.org/doc/html/rfc4731#section-4> Formal Syntax *) 421 + ``` 422 + 423 + ### 4.2 Type Documentation 424 + 425 + ```ocaml 426 + (** Search return options per {{:https://datatracker.ietf.org/doc/html/rfc4731#section-3.1}RFC 4731 Section 3.1}. 427 + 428 + These options control what information the server returns from a SEARCH command. 429 + When any option is specified, the server returns an ESEARCH response instead 430 + of the traditional SEARCH response. *) 431 + type search_return_opt = 432 + | Return_min (** Return lowest matching message number/UID *) 433 + | Return_max (** Return highest matching message number/UID *) 434 + | Return_all (** Return all matching numbers as sequence-set *) 435 + | Return_count (** Return count of matching messages *) 436 + ``` 437 + 438 + ### 4.3 Function Documentation 439 + 440 + ```ocaml 441 + (** [esearch t ?charset ?return_opts criteria] performs a SEARCH with ESEARCH 442 + result options per {{:https://datatracker.ietf.org/doc/html/rfc4731}RFC 4731}. 443 + 444 + When [return_opts] is provided, the server returns structured results 445 + containing only the requested information. This is more efficient than 446 + returning all matching message numbers. 447 + 448 + {b Examples} from RFC 4731: 449 + {[ 450 + (* Find first unseen message *) 451 + let result = esearch t ~return_opts:[Return_min] Search.Unseen in 452 + result.min (* Some 4 *) 453 + 454 + (* Count deleted messages *) 455 + let result = esearch t ~return_opts:[Return_count] Search.Deleted in 456 + result.count (* Some 15 *) 457 + 458 + (* Get min, max and count *) 459 + let result = esearch t ~return_opts:[Return_min; Return_max; Return_count] 460 + (Search.And [Search.Flagged; Search.Since "1-Feb-1994"]) in 461 + (* result.min = Some 2, result.max = Some 11, result.count = Some 3 *) 462 + ]} 463 + 464 + @param charset Optional character set for string searches 465 + @param return_opts List of result options (default: [Return_all]) 466 + @param criteria Search criteria 467 + @return Structured search results 468 + @raise Error.Protocol_error if server returns error response 469 + @see <https://datatracker.ietf.org/doc/html/rfc4731#section-3.1> RFC 4731 Result Options *) 470 + val esearch : t -> ?charset:string -> ?return_opts:search_return_opt list -> 471 + Search.t -> esearch_result 472 + ``` 473 + 474 + --- 475 + 476 + ## 5. Testing Requirements 477 + 478 + ### 5.1 Unit Tests 479 + 480 + **File:** `test/test_read.ml` 481 + 482 + ```ocaml 483 + let test_esearch_parsing () = 484 + (* Test MIN result *) 485 + let resp = parse "* ESEARCH (TAG \"A282\") MIN 2 COUNT 3\r\n" in 486 + assert (resp = Response.Esearch { 487 + tag = Some "A282"; 488 + uid = false; 489 + results = [Esearch_min 2; Esearch_count 3] 490 + }); 491 + 492 + (* Test UID indicator *) 493 + let resp = parse "* ESEARCH (TAG \"A285\") UID MIN 7 MAX 3800\r\n" in 494 + assert (resp = Response.Esearch { 495 + tag = Some "A285"; 496 + uid = true; 497 + results = [Esearch_min 7; Esearch_max 3800] 498 + }); 499 + 500 + (* Test ALL with sequence-set *) 501 + let resp = parse "* ESEARCH (TAG \"A283\") ALL 2,10:11\r\n" in 502 + assert (resp = Response.Esearch { 503 + tag = Some "A283"; 504 + uid = false; 505 + results = [Esearch_all [Single 2; Range (10, 11)]] 506 + }); 507 + 508 + (* Test empty result (no matches) *) 509 + let resp = parse "* ESEARCH (TAG \"A287\") COUNT 0\r\n" in 510 + assert (resp = Response.Esearch { 511 + tag = Some "A287"; 512 + uid = false; 513 + results = [Esearch_count 0] 514 + }) 515 + ``` 516 + 517 + **File:** `test/test_write.ml` 518 + 519 + ```ocaml 520 + let test_search_return_opts () = 521 + (* Test RETURN (MIN COUNT) *) 522 + let cmd = Command.Search { 523 + charset = None; 524 + criteria = Search.Flagged; 525 + return_opts = Some [Return_min; Return_count] 526 + } in 527 + assert (serialize cmd = "SEARCH RETURN (MIN COUNT) FLAGGED"); 528 + 529 + (* Test empty RETURN () *) 530 + let cmd = Command.Search { 531 + charset = None; 532 + criteria = Search.Flagged; 533 + return_opts = Some [] 534 + } in 535 + assert (serialize cmd = "SEARCH RETURN () FLAGGED") 536 + ``` 537 + 538 + ### 5.2 Integration Tests 539 + 540 + - Test against real IMAP server with ESEARCH capability 541 + - Verify fallback behavior for servers without ESEARCH 542 + - Test UID SEARCH with return options 543 + 544 + --- 545 + 546 + ## 6. Priority Order 547 + 548 + | Priority | Task | Complexity | Impact | 549 + |----------|------|------------|--------| 550 + | P0 | Task 1.1: ESEARCH Response Parsing | Medium | High - enables reading ESEARCH | 551 + | P0 | Task 1.2: Sequence-Set Parser | Low | High - required by Task 1.1 | 552 + | P1 | Task 2.1: Command Type Changes | Low | High - enables sending ESEARCH | 553 + | P1 | Task 2.2: Write Serialization | Low | High - completes sending | 554 + | P2 | Task 3.1: Client API | Medium | Medium - user-facing API | 555 + | P2 | Task 3.2: Convenience Functions | Low | Medium - usability | 556 + | P3 | Task 4.1-4.2: Server Improvements | Medium | Low - server already works | 557 + | P3 | Task 5.1: CONDSTORE Integration | Low | Low - extension support | 558 + 559 + --- 560 + 561 + ## 7. Dependencies 562 + 563 + ### 7.1 This RFC Depends On 564 + 565 + - RFC 9051 (IMAP4rev2) - Base SEARCH command 566 + - RFC 4466 (IMAPABNF) - Search return option grammar 567 + 568 + ### 7.2 Other RFCs That Depend On This 569 + 570 + - RFC 4551/7162 (CONDSTORE/QRESYNC) - Uses ESEARCH for MODSEQ results 571 + - RFC 5267 (CONTEXT=SEARCH) - Extends ESEARCH with CONTEXT 572 + - RFC 6237 (MULTISEARCH) - Multiple mailbox search uses ESEARCH 573 + 574 + --- 575 + 576 + ## 8. References 577 + 578 + - [RFC 4731](https://datatracker.ietf.org/doc/html/rfc4731) - ESEARCH Extension 579 + - [RFC 4466](https://datatracker.ietf.org/doc/html/rfc4466) - IMAP4 ABNF Extensions 580 + - [RFC 9051](https://datatracker.ietf.org/doc/html/rfc9051) - IMAP4rev2 581 + - [RFC 4551](https://datatracker.ietf.org/doc/html/rfc4551) - CONDSTORE Extension
+679
spec/PLAN-rfc5256.md
··· 1 + # RFC 5256: IMAP SORT and THREAD Extensions - Implementation Plan 2 + 3 + This document provides a detailed analysis of RFC 5256 against the ocaml-imap 4 + implementation and outlines the tasks needed for full compliance. 5 + 6 + ## RFC 5256 Summary 7 + 8 + RFC 5256 defines two IMAP extensions: 9 + 10 + 1. **SORT Extension**: Server-side sorting of search results by various criteria 11 + 2. **THREAD Extension**: Server-side threading of messages using algorithms like 12 + ORDEREDSUBJECT and REFERENCES 13 + 14 + ### Key RFC Requirements 15 + 16 + #### SORT Command (Section 3, BASE.6.4.SORT) 17 + 18 + - Arguments: sort program, charset specification, searching criteria 19 + - Returns: `* SORT` response with message sequence numbers (or UIDs for UID SORT) 20 + - Required charsets: US-ASCII, UTF-8 (MUST implement) 21 + - Sort criteria: ARRIVAL, CC, DATE, FROM, REVERSE, SIZE, SUBJECT, TO 22 + - Capability: `SORT` 23 + 24 + #### THREAD Command (Section 3, BASE.6.4.THREAD) 25 + 26 + - Arguments: threading algorithm, charset specification, searching criteria 27 + - Returns: `* THREAD` response with nested parenthesized structure 28 + - Required algorithms: 29 + - `ORDEREDSUBJECT`: Simple subject-based threading ("poor man's threading") 30 + - `REFERENCES`: Full References/In-Reply-To based threading (JWZ algorithm) 31 + - Capabilities: `THREAD=ORDEREDSUBJECT`, `THREAD=REFERENCES` 32 + 33 + #### Base Subject Extraction (Section 2.1) 34 + 35 + A critical algorithm for both SORT by SUBJECT and threading: 36 + 37 + 1. Convert RFC 2047 encoded-words to UTF-8 38 + 2. Normalize whitespace (tabs, continuations, multiple spaces -> single space) 39 + 3. Remove trailing `(fwd)` and whitespace (subj-trailer) 40 + 4. Remove leading `Re:`, `Fw:`, `Fwd:` with optional `[blob]` (subj-leader) 41 + 5. Remove leading `[blob]` if non-empty base remains 42 + 6. Handle `[fwd: ... ]` wrapper pattern 43 + 7. Result is the "base subject" for sorting/threading 44 + 45 + #### Sent Date (Section 2.2) 46 + 47 + - Extracted from Date: header, normalized to UTC 48 + - Invalid timezone treated as UTC 49 + - Invalid time treated as 00:00:00 50 + - Missing/unparseable date uses INTERNALDATE as fallback 51 + - Tie-breaker: message sequence number 52 + 53 + --- 54 + 55 + ## Current Implementation Status 56 + 57 + ### SORT Extension - Partially Implemented 58 + 59 + | Component | Status | Location | 60 + |-----------|--------|----------| 61 + | Sort criteria types | Done | `lib/imap/sort.ml`, `lib/imap/sort.mli` | 62 + | Sort keys (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO) | Done | `lib/imap/sort.ml` | 63 + | REVERSE modifier | Done | `lib/imap/sort.ml` | 64 + | SORT command (client) | Done | `lib/imap/command.ml` | 65 + | UID SORT command | Done | `lib/imap/command.ml` | 66 + | SORT command serialization | Done | `lib/imap/write.ml` | 67 + | SORT response parsing | Done | `lib/imap/read.ml` | 68 + | Client API (sort, uid_sort) | Done | `lib/imap/client.ml` | 69 + | **Base subject extraction** | **Missing** | - | 70 + | **Sent date normalization** | **Missing** | - | 71 + | **Server-side SORT handler** | **Missing** | `lib/imapd/` | 72 + | **I18NLEVEL=1 collation** | **Missing** | - | 73 + 74 + ### THREAD Extension - Not Implemented 75 + 76 + | Component | Status | Location | 77 + |-----------|--------|----------| 78 + | Thread algorithm types | **Missing** | - | 79 + | THREAD command type | **Missing** | - | 80 + | Thread response type | **Missing** | - | 81 + | ORDEREDSUBJECT algorithm | **Missing** | - | 82 + | REFERENCES algorithm | **Missing** | - | 83 + | Thread response serialization | **Missing** | - | 84 + | Thread response parsing | **Missing** | - | 85 + | Client API | **Missing** | - | 86 + | Server-side handler | **Missing** | - | 87 + 88 + ### Supporting Infrastructure 89 + 90 + | Component | Status | Notes | 91 + |-----------|--------|-------| 92 + | Message-ID extraction | Partial | Envelope has `message_id` field | 93 + | References header access | **Missing** | Not in Envelope type | 94 + | In-Reply-To access | Partial | Envelope has `in_reply_to` field | 95 + | RFC 2047 decoding | **Missing** | Needed for base subject | 96 + | Unicode case-folding | **Missing** | Required for i;unicode-casemap | 97 + 98 + --- 99 + 100 + ## Implementation Tasks 101 + 102 + ### Priority 1: Core THREAD Infrastructure 103 + 104 + #### Task 1.1: Create Thread Module Types 105 + 106 + **File:** `lib/imap/thread.ml` (new) 107 + 108 + ```ocaml 109 + (** {0 RFC 5256 THREAD Extension} 110 + 111 + Message threading algorithms as specified in 112 + {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256 Section 3}. 113 + 114 + {1 Threading Algorithms} 115 + 116 + {2 ORDEREDSUBJECT} 117 + 118 + The ORDEREDSUBJECT algorithm ({{:https://datatracker.ietf.org/doc/html/rfc5256#section-3}RFC 5256 BASE.6.4.THREAD}) 119 + groups messages by base subject and sorts by sent date. Also known as 120 + "poor man's threading". 121 + 122 + {2 REFERENCES} 123 + 124 + The REFERENCES algorithm uses the References and In-Reply-To headers 125 + to build parent/child relationships. Based on the JWZ threading algorithm 126 + ({{:http://www.jwz.org/doc/threading.html}jwz.org/doc/threading.html}). 127 + *) 128 + 129 + (** Threading algorithm *) 130 + type algorithm = 131 + | Orderedsubject 132 + (** {{:https://datatracker.ietf.org/doc/html/rfc5256#section-3}RFC 5256} 133 + ORDEREDSUBJECT - group by base subject, sort by sent date *) 134 + | References 135 + (** {{:https://datatracker.ietf.org/doc/html/rfc5256#section-3}RFC 5256} 136 + REFERENCES - full parent/child threading via References header *) 137 + | Extension of string 138 + (** Future algorithm extensions *) 139 + 140 + (** A thread node in the result tree *) 141 + type 'a node = 142 + | Message of 'a * 'a node list (** Message with children *) 143 + | Dummy of 'a node list (** Placeholder for missing parent *) 144 + 145 + (** Thread result: list of root-level threads *) 146 + type 'a t = 'a node list 147 + 148 + val pp_algorithm : Format.formatter -> algorithm -> unit 149 + val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit 150 + ``` 151 + 152 + **File:** `lib/imap/thread.mli` (new) 153 + 154 + ```ocaml 155 + (** {0 RFC 5256 THREAD Extension} 156 + 157 + @see <https://datatracker.ietf.org/doc/html/rfc5256> RFC 5256 *) 158 + 159 + type algorithm = 160 + | Orderedsubject 161 + | References 162 + | Extension of string 163 + 164 + type 'a node = 165 + | Message of 'a * 'a node list 166 + | Dummy of 'a node list 167 + 168 + type 'a t = 'a node list 169 + 170 + val pp_algorithm : Format.formatter -> algorithm -> unit 171 + val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit 172 + ``` 173 + 174 + #### Task 1.2: Add THREAD to Command Types 175 + 176 + **File:** `lib/imap/command.ml` 177 + 178 + Add to type `t`: 179 + ```ocaml 180 + | Thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 181 + ``` 182 + 183 + Add to type `uid_command`: 184 + ```ocaml 185 + | Uid_thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 186 + ``` 187 + 188 + #### Task 1.3: Add THREAD Response Type 189 + 190 + **File:** `lib/imap/response.ml` 191 + 192 + Add to type `t`: 193 + ```ocaml 194 + | Thread of int64 Thread.t (** THREAD response with message numbers/UIDs *) 195 + ``` 196 + 197 + #### Task 1.4: Implement THREAD Serialization 198 + 199 + **File:** `lib/imap/write.ml` 200 + 201 + ```ocaml 202 + let thread_algorithm w = function 203 + | Thread.Orderedsubject -> W.string w "ORDEREDSUBJECT" 204 + | Thread.References -> W.string w "REFERENCES" 205 + | Thread.Extension s -> W.string w s 206 + 207 + let write_thread w charset algorithm search = 208 + W.string w "THREAD "; 209 + thread_algorithm w algorithm; 210 + sp w; 211 + astring w charset; 212 + sp w; 213 + search_key w search 214 + ``` 215 + 216 + #### Task 1.5: Implement THREAD Response Parsing 217 + 218 + **File:** `lib/imap/read.ml` 219 + 220 + ```ocaml 221 + (** Parse thread-list per RFC 5256 Section 5 formal syntax: 222 + thread-list = "(" (thread-members / thread-nested) ")" 223 + thread-members = nz-number *(SP nz-number) [SP thread-nested] 224 + thread-nested = 2*thread-list *) 225 + let rec thread_list r = 226 + R.char '(' r; 227 + let rec parse_members acc = 228 + match R.peek_char r with 229 + | Some ')' -> R.char ')' r; (List.rev acc, []) 230 + | Some ' ' -> 231 + sp r; 232 + (match R.peek_char r with 233 + | Some '(' -> (List.rev acc, thread_nested r) 234 + | Some c when c >= '0' && c <= '9' -> 235 + parse_members (number64 r :: acc) 236 + | _ -> (List.rev acc, [])) 237 + | Some c when c >= '0' && c <= '9' -> 238 + parse_members (number64 r :: acc) 239 + | _ -> (List.rev acc, []) 240 + in 241 + parse_members [] 242 + 243 + and thread_nested r = 244 + (* 2*thread-list *) 245 + let rec loop acc = 246 + match R.peek_char r with 247 + | Some '(' -> loop (thread_list r :: acc) 248 + | Some ' ' -> sp r; loop acc 249 + | _ -> List.rev acc 250 + in 251 + loop [] 252 + ``` 253 + 254 + ### Priority 2: Base Subject Extraction 255 + 256 + #### Task 2.1: Create Subject Module 257 + 258 + **File:** `lib/imap/subject.ml` (new) 259 + 260 + ```ocaml 261 + (** {0 Base Subject Extraction} 262 + 263 + Implements the base subject algorithm from 264 + {{:https://datatracker.ietf.org/doc/html/rfc5256#section-2.1}RFC 5256 Section 2.1}. 265 + 266 + The base subject is used for: 267 + - SORT by SUBJECT criterion 268 + - ORDEREDSUBJECT threading algorithm 269 + - REFERENCES threading subject grouping (step 5) 270 + 271 + {1 Algorithm Steps} 272 + 273 + Per RFC 5256 Section 2.1: 274 + 275 + {ol 276 + {- Convert RFC 2047 encoded-words to UTF-8, normalize whitespace} 277 + {- Remove trailing subj-trailer (e.g., "(fwd)")} 278 + {- Remove leading subj-leader (e.g., "Re:", "Fw: [list]")} 279 + {- Remove leading subj-blob if non-empty base remains} 280 + {- Repeat steps 3-4} 281 + {- Unwrap [fwd: ... ] wrapper} 282 + {- Result is the base subject}} 283 + *) 284 + 285 + (** Extract base subject from a subject line. 286 + 287 + @param subject The original subject string (may contain RFC 2047 encoding) 288 + @return The normalized base subject for sorting/threading 289 + 290 + Example: 291 + {[ 292 + base_subject "Re: [ocaml] Fwd: Meeting notes" 293 + (* Returns: "Meeting notes" *) 294 + ]} *) 295 + val base_subject : string -> string 296 + 297 + (** Check if a subject indicates a reply or forward. 298 + 299 + Per RFC 5256, a message is a reply/forward if base_subject extraction 300 + removed any of: 301 + - A subj-refwd (re:, fw:, fwd:) 302 + - A "(fwd)" trailer 303 + - A [fwd: ... ] wrapper 304 + 305 + This is used in REFERENCES threading step 5.C.iv. *) 306 + val is_reply_or_forward : string -> bool 307 + ``` 308 + 309 + Implementation notes: 310 + - ABNF from RFC 5256 Section 5: 311 + - `subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":"` 312 + - `subj-blob = "[" *BLOBCHAR "]" *WSP` 313 + - `subj-trailer = "(fwd)" / WSP` 314 + - `subj-fwd-hdr = "[fwd:"` 315 + - `subj-fwd-trl = "]"` 316 + 317 + #### Task 2.2: Add RFC 2047 Decoding Support 318 + 319 + **File:** `lib/imap/mime.ml` (new) 320 + 321 + ```ocaml 322 + (** {0 MIME Utilities} 323 + 324 + RFC 2047 encoded-word decoding for internationalized headers. 325 + 326 + @see <https://datatracker.ietf.org/doc/html/rfc2047> RFC 2047 *) 327 + 328 + (** Decode RFC 2047 encoded-words in a header value. 329 + 330 + Handles patterns like: 331 + - =?UTF-8?B?base64data?= 332 + - =?ISO-8859-1?Q?quoted=20printable?= 333 + 334 + @param value Header value potentially containing encoded-words 335 + @return Decoded UTF-8 string *) 336 + val decode_header : string -> string 337 + ``` 338 + 339 + ### Priority 3: Sent Date Handling 340 + 341 + #### Task 3.1: Create Date Normalization Module 342 + 343 + **File:** `lib/imap/date.ml` (new) 344 + 345 + ```ocaml 346 + (** {0 IMAP Date Handling} 347 + 348 + Date parsing and normalization as specified in 349 + {{:https://datatracker.ietf.org/doc/html/rfc5256#section-2.2}RFC 5256 Section 2.2}. 350 + 351 + {1 Sent Date} 352 + 353 + The "sent date" is the Date: header value normalized to UTC: 354 + - Valid date with timezone: normalize to UTC 355 + - Invalid timezone: treat as UTC 356 + - Invalid time: treat as 00:00:00 357 + - Missing/unparseable: use INTERNALDATE 358 + 359 + {1 Comparison} 360 + 361 + When comparing sent dates that match exactly, the message sequence 362 + number is used as a tie-breaker (per RFC 5256 Section 2.2). *) 363 + 364 + (** Parsed date with optional timezone offset *) 365 + type t 366 + 367 + (** Parse a Date: header value. 368 + 369 + @param date_header The raw Date: header content 370 + @return Parsed date or None if unparseable *) 371 + val of_header : string -> t option 372 + 373 + (** Parse an INTERNALDATE string (IMAP format). 374 + 375 + @param internaldate The INTERNALDATE value from server 376 + @return Parsed date *) 377 + val of_internaldate : string -> t 378 + 379 + (** Get sent date for a message. 380 + 381 + Per RFC 5256: uses Date: header if valid, falls back to INTERNALDATE. 382 + 383 + @param date_header Optional Date: header value 384 + @param internaldate INTERNALDATE value 385 + @return Normalized sent date *) 386 + val sent_date : date_header:string option -> internaldate:string -> t 387 + 388 + (** Compare two dates. 389 + 390 + @return negative if a < b, 0 if equal, positive if a > b *) 391 + val compare : t -> t -> int 392 + ``` 393 + 394 + ### Priority 4: Unicode Collation 395 + 396 + #### Task 4.1: Implement i;unicode-casemap 397 + 398 + **File:** `lib/imap/collation.ml` (new) 399 + 400 + ```ocaml 401 + (** {0 String Collation} 402 + 403 + Collation algorithms for IMAP SORT/THREAD as specified in 404 + {{:https://datatracker.ietf.org/doc/html/rfc5256#section-7}RFC 5256 Section 7}. 405 + 406 + Servers MUST implement i;unicode-casemap collation per 407 + {{:https://datatracker.ietf.org/doc/html/rfc5051}RFC 5051}. 408 + 409 + {1 i;unicode-casemap} 410 + 411 + Simple Unicode case-insensitive comparison: 412 + - Apply Unicode Simple Case Folding 413 + - Compare resulting strings as binary 414 + 415 + This is required for I18NLEVEL=1 compliance. *) 416 + 417 + (** Case-insensitive Unicode comparison. 418 + 419 + @return negative if a < b, 0 if equal, positive if a > b *) 420 + val compare_unicode_casemap : string -> string -> int 421 + 422 + (** Case-fold a string for comparison. 423 + 424 + Applies Unicode Simple Case Folding. *) 425 + val casefold : string -> string 426 + ``` 427 + 428 + ### Priority 5: Server-Side Implementation 429 + 430 + #### Task 5.1: Add SORT/THREAD to Server Protocol 431 + 432 + **File:** `lib/imapd/protocol.ml` 433 + 434 + Add Sort and Thread to the command type: 435 + ```ocaml 436 + | Sort of { charset : string; criteria : sort_criterion list; search : search_key } 437 + | Thread of { algorithm : thread_algorithm; charset : string; search : search_key } 438 + ``` 439 + 440 + #### Task 5.2: Implement Server SORT Handler 441 + 442 + **File:** `lib/imapd/client.ml` 443 + 444 + ```ocaml 445 + (** Handle SORT command per RFC 5256. *) 446 + let handle_sort state ~charset ~criteria ~search ~uid = 447 + (* 1. Search for matching messages *) 448 + let matches = search_messages state.storage state.mailbox search in 449 + 450 + (* 2. Fetch sort keys for each message *) 451 + let keyed = List.map (fun msg -> 452 + let keys = List.map (extract_sort_key msg) criteria in 453 + (msg, keys) 454 + ) matches in 455 + 456 + (* 3. Sort by criteria *) 457 + let sorted = List.sort (compare_by_criteria criteria) keyed in 458 + 459 + (* 4. Return sequence numbers or UIDs *) 460 + let ids = List.map (fun (msg, _) -> 461 + if uid then msg.uid else Int64.of_int msg.seq 462 + ) sorted in 463 + 464 + (* 5. Send SORT response *) 465 + send_response (Sort_response ids) 466 + ``` 467 + 468 + #### Task 5.3: Implement ORDEREDSUBJECT Algorithm 469 + 470 + **File:** `lib/imapd/thread.ml` (new) 471 + 472 + ```ocaml 473 + (** ORDEREDSUBJECT threading per RFC 5256. 474 + 475 + Algorithm: 476 + 1. Sort messages by (base_subject, sent_date) 477 + 2. Group by base_subject 478 + 3. First message of each group is root 479 + 4. Subsequent messages are children of root 480 + 5. Sort groups by sent_date of first message *) 481 + let orderedsubject messages = 482 + (* ... *) 483 + ``` 484 + 485 + #### Task 5.4: Implement REFERENCES Algorithm 486 + 487 + **File:** `lib/imapd/thread.ml` 488 + 489 + ```ocaml 490 + (** REFERENCES threading per RFC 5256. 491 + 492 + This is the JWZ threading algorithm with 6 main steps: 493 + 494 + 1. Build References relationships 495 + 2. Gather parentless messages under root 496 + 3. Prune dummy messages 497 + 4. Sort root children by sent date 498 + 5. Group by base subject 499 + 6. Sort all sibling sets by sent date *) 500 + let references messages = 501 + (* Step 1: Build id_table and parent/child links *) 502 + let id_table = Hashtbl.create (List.length messages) in 503 + (* ... 6 steps per RFC 5256 ... *) 504 + ``` 505 + 506 + ### Priority 6: Client API 507 + 508 + #### Task 6.1: Add Thread Methods to Client 509 + 510 + **File:** `lib/imap/client.ml` 511 + 512 + ```ocaml 513 + val thread : t -> algorithm:Thread.algorithm -> charset:string -> Search.t -> int64 Thread.t 514 + (** [thread client ~algorithm ~charset search] threads matching messages. 515 + Requires THREAD=algorithm capability. *) 516 + 517 + val uid_thread : t -> algorithm:Thread.algorithm -> charset:string -> Search.t -> int64 Thread.t 518 + (** [uid_thread client ~algorithm ~charset search] like {!thread} but returns UIDs. *) 519 + ``` 520 + 521 + ### Priority 7: Capability Advertisement 522 + 523 + #### Task 7.1: Update Server Capabilities 524 + 525 + **File:** `lib/imapd/client.ml` 526 + 527 + Add to capability list: 528 + ```ocaml 529 + let capabilities = [ 530 + (* ... existing ... *) 531 + "SORT"; 532 + "THREAD=ORDEREDSUBJECT"; 533 + "THREAD=REFERENCES"; 534 + ] 535 + ``` 536 + 537 + --- 538 + 539 + ## OCamldoc Citation Templates 540 + 541 + ### For thread.ml/thread.mli 542 + 543 + ```ocaml 544 + (** {0 RFC 5256 THREAD Extension} 545 + 546 + Message threading algorithms as specified in 547 + {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256}. 548 + 549 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-3> THREAD Command 550 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-5> Formal Syntax *) 551 + ``` 552 + 553 + ### For subject.ml/subject.mli 554 + 555 + ```ocaml 556 + (** {0 Base Subject Extraction} 557 + 558 + Implements {{:https://datatracker.ietf.org/doc/html/rfc5256#section-2.1}RFC 5256 Section 2.1}. 559 + 560 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-2.1> Base Subject Algorithm 561 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-5> ABNF for subj-* rules *) 562 + ``` 563 + 564 + ### For sort.ml/sort.mli (enhancement) 565 + 566 + ```ocaml 567 + (** {0 SORT Criteria} 568 + 569 + Sort keys for the SORT command as specified in 570 + {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256}. 571 + 572 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-3> SORT Command 573 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-2.1> Base Subject (for SUBJECT key) 574 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-2.2> Sent Date (for DATE key) *) 575 + ``` 576 + 577 + ### For date.ml/date.mli 578 + 579 + ```ocaml 580 + (** {0 IMAP Date Handling} 581 + 582 + Date parsing for SORT/THREAD as specified in 583 + {{:https://datatracker.ietf.org/doc/html/rfc5256#section-2.2}RFC 5256 Section 2.2}. 584 + 585 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-2.2> Sent Date definition 586 + @see <https://datatracker.ietf.org/doc/html/rfc2822#section-3.3> Date-Time format *) 587 + ``` 588 + 589 + ### For collation.ml/collation.mli 590 + 591 + ```ocaml 592 + (** {0 String Collation} 593 + 594 + Implements i;unicode-casemap collation per 595 + {{:https://datatracker.ietf.org/doc/html/rfc5051}RFC 5051}. 596 + 597 + Required for {{:https://datatracker.ietf.org/doc/html/rfc5256#section-7}RFC 5256 Section 7} 598 + (Internationalization Considerations). 599 + 600 + @see <https://datatracker.ietf.org/doc/html/rfc5051> i;unicode-casemap 601 + @see <https://datatracker.ietf.org/doc/html/rfc5255> IMAP I18N (I18NLEVEL=1) *) 602 + ``` 603 + 604 + --- 605 + 606 + ## Priority Summary 607 + 608 + | Priority | Task | Effort | Dependencies | 609 + |----------|------|--------|--------------| 610 + | P1 | Thread module types | Low | None | 611 + | P1 | THREAD command/response types | Low | Thread types | 612 + | P1 | THREAD serialization/parsing | Medium | Command types | 613 + | P2 | Base subject extraction | Medium | None | 614 + | P2 | RFC 2047 decoding | Medium | None | 615 + | P3 | Sent date normalization | Medium | None | 616 + | P4 | Unicode collation | Medium | None | 617 + | P5 | Server SORT handler | High | P2, P3, P4 | 618 + | P5 | Server ORDEREDSUBJECT | Medium | P2, P3 | 619 + | P5 | Server REFERENCES | High | P2, P3, P5.1 | 620 + | P6 | Client thread API | Low | P1 | 621 + | P7 | Capability advertisement | Low | P5 | 622 + 623 + --- 624 + 625 + ## Testing Requirements 626 + 627 + ### Unit Tests 628 + 629 + ```ocaml 630 + (* test/test_subject.ml *) 631 + let test_base_subject () = 632 + (* RFC 5256 examples *) 633 + assert (Subject.base_subject "Re: test" = "test"); 634 + assert (Subject.base_subject "Re: Re: test" = "test"); 635 + assert (Subject.base_subject "[PATCH] Re: [ocaml] test" = "test"); 636 + assert (Subject.base_subject "Fwd: [Fwd: test]" = "test"); 637 + assert (Subject.base_subject "[fwd: wrapped]" = "wrapped"); 638 + assert (Subject.base_subject " spaced " = "spaced") 639 + 640 + (* test/test_thread.ml *) 641 + let test_orderedsubject () = 642 + (* Test grouping by base subject *) 643 + (* Test sent date ordering within groups *) 644 + (* Test group ordering by first message date *) 645 + 646 + let test_references () = 647 + (* Test parent/child from References header *) 648 + (* Test In-Reply-To fallback *) 649 + (* Test duplicate Message-ID handling *) 650 + (* Test loop prevention *) 651 + (* Test dummy message pruning *) 652 + (* Test subject grouping (step 5) *) 653 + ``` 654 + 655 + ### Integration Tests 656 + 657 + ```ocaml 658 + (* test/integration/test_sort_thread.ml *) 659 + let test_sort_command () = 660 + (* SORT (SUBJECT) UTF-8 ALL *) 661 + (* SORT (DATE REVERSE SUBJECT) UTF-8 SINCE 1-Jan-2020 *) 662 + (* UID SORT (FROM) UTF-8 ALL *) 663 + 664 + let test_thread_command () = 665 + (* THREAD ORDEREDSUBJECT UTF-8 ALL *) 666 + (* THREAD REFERENCES UTF-8 SINCE 1-Jan-2020 *) 667 + (* UID THREAD REFERENCES UTF-8 ALL *) 668 + ``` 669 + 670 + --- 671 + 672 + ## References 673 + 674 + - {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256} - IMAP SORT and THREAD Extensions 675 + - {{:https://datatracker.ietf.org/doc/html/rfc5051}RFC 5051} - i;unicode-casemap Collation 676 + - {{:https://datatracker.ietf.org/doc/html/rfc5255}RFC 5255} - IMAP Internationalization 677 + - {{:https://datatracker.ietf.org/doc/html/rfc2047}RFC 2047} - MIME Encoded-Words 678 + - {{:https://datatracker.ietf.org/doc/html/rfc2822}RFC 2822} - Internet Message Format 679 + - {{:http://www.jwz.org/doc/threading.html}JWZ Threading} - Original REFERENCES algorithm
+723
spec/PLAN-rfc5258.md
··· 1 + # RFC 5258 Implementation Plan: IMAP4 LIST Command Extensions 2 + 3 + ## Overview 4 + 5 + This document provides a detailed implementation plan for adding RFC 5258 (LIST-EXTENDED) 6 + support to the ocaml-imap server implementation. 7 + 8 + **RFC**: [RFC 5258 - IMAP4 LIST Command Extensions](https://datatracker.ietf.org/doc/html/rfc5258) 9 + **Status**: Standards Track 10 + **Obsoletes**: RFC 3348 11 + **Updates**: RFC 2193 12 + 13 + ## 1. RFC 5258 Requirements Summary 14 + 15 + ### 1.1 Extended LIST Syntax 16 + 17 + The RFC extends the LIST command with three new syntactic forms: 18 + 19 + ```abnf 20 + list = "LIST" [SP list-select-opts] SP mailbox SP mbox-or-pat 21 + [SP list-return-opts] 22 + ``` 23 + 24 + The extended syntax is detected when: 25 + 1. First word after LIST begins with parenthesis (selection options) 26 + 2. Second word after LIST begins with parenthesis (multiple patterns) 27 + 3. LIST command has more than 2 parameters (return options) 28 + 29 + ### 1.2 Selection Options 30 + 31 + Selection options filter which mailboxes are returned: 32 + 33 + | Option | Description | RFC Section | 34 + |--------|-------------|-------------| 35 + | `SUBSCRIBED` | List subscribed names rather than existing mailboxes | 3.1 | 36 + | `REMOTE` | Include remote mailboxes (per RFC 2193) | 3.1 | 37 + | `RECURSIVEMATCH` | Return parent mailboxes with matching children | 3.1 | 38 + 39 + **Constraints**: 40 + - `RECURSIVEMATCH` cannot be used alone or only with `REMOTE` 41 + - Server MUST return BAD if `RECURSIVEMATCH` is the only selection option 42 + 43 + ### 1.3 Return Options 44 + 45 + Return options control what information is returned: 46 + 47 + | Option | Description | RFC Section | 48 + |--------|-------------|-------------| 49 + | `SUBSCRIBED` | Return subscription state for all matching mailboxes | 3.2 | 50 + | `CHILDREN` | Return `\HasChildren` or `\HasNoChildren` attributes | 4 | 51 + 52 + **Note**: The `CHILDREN` return option MUST be supported by all servers implementing RFC 5258. 53 + 54 + ### 1.4 New Mailbox Attributes 55 + 56 + | Attribute | Description | RFC Section | 57 + |-----------|-------------|-------------| 58 + | `\NonExistent` | Mailbox name does not refer to existing mailbox | 3 | 59 + | `\Subscribed` | Mailbox name is subscribed | 3.1 | 60 + | `\Remote` | Mailbox is on a remote server | 3.1 | 61 + | `\HasChildren` | Mailbox has child mailboxes | 4 | 62 + | `\HasNoChildren` | Mailbox has no accessible child mailboxes | 4 | 63 + 64 + **Attribute Implications** (Section 3.4): 65 + - `\NoInferiors` implies `\HasNoChildren` 66 + - `\NonExistent` implies `\NoSelect` 67 + 68 + ### 1.5 CHILDINFO Extended Data Item 69 + 70 + The `CHILDINFO` extended data item is returned when `RECURSIVEMATCH` is specified: 71 + 72 + ``` 73 + * LIST () "/" "Foo" ("CHILDINFO" ("SUBSCRIBED")) 74 + ``` 75 + 76 + This indicates that mailbox "Foo" has a descendant that matches the selection criteria. 77 + 78 + ### 1.6 Capability String 79 + 80 + Servers implementing RFC 5258 MUST advertise the `LIST-EXTENDED` capability. 81 + 82 + ## 2. Current Implementation Status 83 + 84 + ### 2.1 Supported Features 85 + 86 + | Feature | Status | File Location | 87 + |---------|--------|---------------| 88 + | Basic LIST command | Implemented | `lib/imapd/grammar.mly:385` | 89 + | `\Noinferiors` attribute | Implemented | `lib/imapd/protocol.ml:188` | 90 + | `\Noselect` attribute | Implemented | `lib/imapd/protocol.ml:189` | 91 + | `\Marked` attribute | Implemented | `lib/imapd/protocol.ml:190` | 92 + | `\Unmarked` attribute | Implemented | `lib/imapd/protocol.ml:191` | 93 + | `\Subscribed` attribute | Implemented | `lib/imapd/protocol.ml:192` | 94 + | `\HasChildren` attribute | Implemented | `lib/imapd/protocol.ml:193` | 95 + | `\HasNoChildren` attribute | Implemented | `lib/imapd/protocol.ml:194` | 96 + | Lexer tokens for options | Implemented | `lib/imapd/lexer.mll:121-124` | 97 + 98 + ### 2.2 Missing Features 99 + 100 + | Feature | Status | Priority | 101 + |---------|--------|----------| 102 + | Extended LIST syntax parsing | Not implemented | P0 | 103 + | Selection options support | Not implemented | P0 | 104 + | Return options support | Not implemented | P0 | 105 + | `\NonExistent` attribute | Not implemented | P1 | 106 + | `\Remote` attribute | Not implemented | P2 | 107 + | `CHILDINFO` extended data | Not implemented | P1 | 108 + | Multiple mailbox patterns | Not implemented | P1 | 109 + | Subscription tracking in storage | Partial | P1 | 110 + | `LIST-EXTENDED` capability | Not implemented | P0 | 111 + 112 + ### 2.3 Current LIST Command Structure 113 + 114 + The current implementation uses a simple record: 115 + 116 + ```ocaml 117 + (* lib/imapd/protocol.ml:354 *) 118 + | List of { reference : string; pattern : string } 119 + ``` 120 + 121 + This needs to be extended to support selection and return options. 122 + 123 + ## 3. Detailed Implementation Tasks 124 + 125 + ### Phase 1: Core Types and Capability (Priority P0) 126 + 127 + #### Task 1.1: Add LIST-EXTENDED Types to Protocol 128 + 129 + **File**: `lib/imapd/protocol.ml` 130 + 131 + Add new types for selection and return options: 132 + 133 + ```ocaml 134 + (** LIST selection options per 135 + {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.1}RFC 5258 Section 3.1}. *) 136 + type list_select_option = 137 + | List_select_subscribed (** SUBSCRIBED - list subscribed names *) 138 + | List_select_remote (** REMOTE - include remote mailboxes *) 139 + | List_select_recursivematch (** RECURSIVEMATCH - return matching parents *) 140 + 141 + (** LIST return options per 142 + {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.2}RFC 5258 Section 3.2}. *) 143 + type list_return_option = 144 + | List_return_subscribed (** SUBSCRIBED - return subscription state *) 145 + | List_return_children (** CHILDREN - return child info *) 146 + 147 + (** Extended LIST command per 148 + {{:https://datatracker.ietf.org/doc/html/rfc5258}RFC 5258}. *) 149 + type list_command = 150 + | List_basic of { reference : string; pattern : string } 151 + | List_extended of { 152 + selection : list_select_option list; 153 + reference : string; 154 + patterns : string list; 155 + return_opts : list_return_option list; 156 + } 157 + ``` 158 + 159 + Update the command type: 160 + 161 + ```ocaml 162 + | List of list_command 163 + ``` 164 + 165 + #### Task 1.2: Add \NonExistent Attribute 166 + 167 + **File**: `lib/imapd/protocol.ml` 168 + 169 + Add to `list_flag` type: 170 + 171 + ```ocaml 172 + (** LIST flags per 173 + {{:https://datatracker.ietf.org/doc/html/rfc9051#section-7.3.1}RFC 9051 Section 7.3.1} 174 + and {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3}RFC 5258 Section 3}. *) 175 + type list_flag = 176 + | List_noinferiors 177 + | List_noselect 178 + | List_marked 179 + | List_unmarked 180 + | List_subscribed 181 + | List_haschildren 182 + | List_hasnochildren 183 + | List_nonexistent (** \NonExistent - RFC 5258 Section 3 *) 184 + | List_remote (** \Remote - RFC 5258 Section 3.1 *) 185 + (* ... existing special-use flags ... *) 186 + ``` 187 + 188 + #### Task 1.3: Add CHILDINFO Extended Data 189 + 190 + **File**: `lib/imapd/protocol.ml` 191 + 192 + Add type for extended response data: 193 + 194 + ```ocaml 195 + (** LIST extended data item per 196 + {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.5}RFC 5258 Section 3.5}. *) 197 + type list_extended_item = 198 + | Childinfo of string list (** CHILDINFO with selection options that matched *) 199 + 200 + (** Extended LIST response per 201 + {{:https://datatracker.ietf.org/doc/html/rfc5258}RFC 5258}. *) 202 + type list_response = { 203 + flags : list_flag list; 204 + delimiter : char option; 205 + name : mailbox_name; 206 + extended : list_extended_item list; 207 + } 208 + ``` 209 + 210 + Update response type: 211 + 212 + ```ocaml 213 + | List_response of list_response 214 + ``` 215 + 216 + #### Task 1.4: Add LIST-EXTENDED Capability 217 + 218 + **File**: `lib/imapd/server.ml` 219 + 220 + Add to capabilities list: 221 + 222 + ```ocaml 223 + let base_capabilities_pre_tls = [ 224 + "IMAP4rev2"; 225 + "IMAP4rev1"; 226 + "LIST-EXTENDED"; (* RFC 5258 *) 227 + (* ... rest ... *) 228 + ] 229 + ``` 230 + 231 + ### Phase 2: Parser Updates (Priority P0) 232 + 233 + #### Task 2.1: Update Grammar for Extended LIST 234 + 235 + **File**: `lib/imapd/grammar.mly` 236 + 237 + Add new grammar rules: 238 + 239 + ```ocaml 240 + (* LIST selection options - RFC 5258 Section 3.1 *) 241 + list_select_opt: 242 + | SUBSCRIBED { List_select_subscribed } 243 + | REMOTE { List_select_remote } 244 + | RECURSIVEMATCH { List_select_recursivematch } 245 + ; 246 + 247 + list_select_opts: 248 + | { [] } 249 + | o = list_select_opt { [o] } 250 + | o = list_select_opt SP os = list_select_opts { o :: os } 251 + ; 252 + 253 + (* LIST return options - RFC 5258 Section 3.2 *) 254 + list_return_opt: 255 + | SUBSCRIBED { List_return_subscribed } 256 + | CHILDREN { List_return_children } 257 + ; 258 + 259 + list_return_opts: 260 + | { [] } 261 + | o = list_return_opt { [o] } 262 + | o = list_return_opt SP os = list_return_opts { o :: os } 263 + ; 264 + 265 + (* Multiple mailbox patterns *) 266 + list_patterns: 267 + | p = list_mailbox { [p] } 268 + | p = list_mailbox SP ps = list_patterns { p :: ps } 269 + ; 270 + 271 + mbox_or_pat: 272 + | p = list_mailbox { [p] } 273 + | LPAREN ps = list_patterns RPAREN { ps } 274 + ; 275 + 276 + (* Extended LIST command - RFC 5258 *) 277 + command_auth: 278 + (* Basic LIST - backward compatible *) 279 + | LIST SP ref = astring SP pat = list_mailbox 280 + { List (List_basic { reference = ref; pattern = pat }) } 281 + (* Extended LIST with selection options *) 282 + | LIST SP LPAREN sel = list_select_opts RPAREN SP ref = astring SP pats = mbox_or_pat 283 + { List (List_extended { selection = sel; reference = ref; patterns = pats; return_opts = [] }) } 284 + (* Extended LIST with return options *) 285 + | LIST SP LPAREN sel = list_select_opts RPAREN SP ref = astring SP pats = mbox_or_pat 286 + SP RETURN SP LPAREN ret = list_return_opts RPAREN 287 + { List (List_extended { selection = sel; reference = ref; patterns = pats; return_opts = ret }) } 288 + (* Basic LIST with return options only *) 289 + | LIST SP ref = astring SP pats = mbox_or_pat SP RETURN SP LPAREN ret = list_return_opts RPAREN 290 + { List (List_extended { selection = []; reference = ref; patterns = pats; return_opts = ret }) } 291 + ; 292 + ``` 293 + 294 + ### Phase 3: Storage Backend Updates (Priority P1) 295 + 296 + #### Task 3.1: Add Subscription Tracking 297 + 298 + **File**: `lib/imapd/storage.ml` 299 + 300 + Update `STORAGE` signature: 301 + 302 + ```ocaml 303 + (** List mailboxes with extended options per 304 + {{:https://datatracker.ietf.org/doc/html/rfc5258}RFC 5258}. *) 305 + val list_mailboxes_extended : 306 + t -> 307 + username:string -> 308 + reference:string -> 309 + patterns:string list -> 310 + selection:list_select_option list -> 311 + return_opts:list_return_option list -> 312 + list_response list 313 + 314 + (** Subscribe to a mailbox per 315 + {{:https://datatracker.ietf.org/doc/html/rfc9051#section-6.3.6}RFC 9051 Section 6.3.6}. *) 316 + val subscribe : t -> username:string -> mailbox_name -> (unit, error) result 317 + 318 + (** Unsubscribe from a mailbox. *) 319 + val unsubscribe : t -> username:string -> mailbox_name -> (unit, error) result 320 + 321 + (** Check if mailbox is subscribed. *) 322 + val is_subscribed : t -> username:string -> mailbox_name -> bool 323 + ``` 324 + 325 + #### Task 3.2: Implement Subscription Storage 326 + 327 + **File**: `lib/imapd/storage.ml` 328 + 329 + For `Memory_storage`: 330 + 331 + ```ocaml 332 + type user_data = { 333 + mailboxes : (mailbox_name, mailbox) Hashtbl.t; 334 + subscriptions : (mailbox_name, unit) Hashtbl.t; (* Set of subscribed names *) 335 + } 336 + 337 + let subscribe t ~username mailbox = 338 + let user = get_user t ~username in 339 + Hashtbl.replace user.subscriptions mailbox (); 340 + Result.Ok () 341 + 342 + let unsubscribe t ~username mailbox = 343 + let user = get_user t ~username in 344 + Hashtbl.remove user.subscriptions mailbox; 345 + Result.Ok () 346 + 347 + let is_subscribed t ~username mailbox = 348 + let user = get_user t ~username in 349 + Hashtbl.mem user.subscriptions mailbox 350 + ``` 351 + 352 + For `Maildir_storage`: 353 + 354 + ```ocaml 355 + (* Store subscriptions in .subscriptions file *) 356 + let subscriptions_file path = Filename.concat path ".subscriptions" 357 + 358 + let load_subscriptions path = 359 + let file = subscriptions_file path in 360 + if Sys.file_exists file then begin 361 + let ic = open_in file in 362 + let subs = Hashtbl.create 16 in 363 + (try 364 + while true do 365 + Hashtbl.add subs (input_line ic) () 366 + done 367 + with End_of_file -> ()); 368 + close_in ic; 369 + subs 370 + end else 371 + Hashtbl.create 16 372 + 373 + let save_subscriptions path subs = 374 + let file = subscriptions_file path in 375 + let oc = open_out file in 376 + Hashtbl.iter (fun name () -> output_string oc (name ^ "\n")) subs; 377 + close_out oc 378 + ``` 379 + 380 + #### Task 3.3: Implement Extended LIST Logic 381 + 382 + **File**: `lib/imapd/storage.ml` 383 + 384 + ```ocaml 385 + let list_mailboxes_extended t ~username ~reference ~patterns ~selection ~return_opts = 386 + let all_mailboxes = list_all_mailboxes t ~username ~reference in 387 + 388 + (* Apply pattern matching *) 389 + let pattern_matches name = 390 + List.exists (fun pat -> matches_pattern ~pattern:pat name) patterns 391 + in 392 + 393 + (* Check selection criteria *) 394 + let meets_selection mb_name = 395 + if List.mem List_select_subscribed selection then 396 + is_subscribed t ~username mb_name 397 + else 398 + mailbox_exists t ~username mb_name 399 + in 400 + 401 + (* Build response with appropriate flags *) 402 + let build_response mb_name = 403 + let flags = ref [] in 404 + let extended = ref [] in 405 + 406 + (* Check existence *) 407 + if not (mailbox_exists t ~username mb_name) then 408 + flags := List_nonexistent :: !flags; 409 + 410 + (* Check subscription if requested *) 411 + if List.mem List_return_subscribed return_opts || 412 + List.mem List_select_subscribed selection then 413 + if is_subscribed t ~username mb_name then 414 + flags := List_subscribed :: !flags; 415 + 416 + (* Check children if requested *) 417 + if List.mem List_return_children return_opts then begin 418 + if has_children t ~username mb_name then 419 + flags := List_haschildren :: !flags 420 + else 421 + flags := List_hasnochildren :: !flags 422 + end; 423 + 424 + (* Handle RECURSIVEMATCH *) 425 + if List.mem List_select_recursivematch selection then begin 426 + let child_matches = has_matching_descendants t ~username mb_name ~selection in 427 + if child_matches && not (meets_selection mb_name) then 428 + extended := Childinfo ["SUBSCRIBED"] :: !extended 429 + end; 430 + 431 + { flags = !flags; delimiter = Some '/'; name = mb_name; extended = !extended } 432 + in 433 + 434 + (* Filter and map *) 435 + all_mailboxes 436 + |> List.filter pattern_matches 437 + |> List.filter_map (fun mb_name -> 438 + if meets_selection mb_name then Some (build_response mb_name) 439 + else if List.mem List_select_recursivematch selection && 440 + has_matching_descendants t ~username mb_name ~selection then 441 + Some (build_response mb_name) 442 + else None) 443 + ``` 444 + 445 + ### Phase 4: Response Serialization (Priority P1) 446 + 447 + #### Task 4.1: Update LIST Response Serialization 448 + 449 + **File**: `lib/imapd/parser.ml` 450 + 451 + ```ocaml 452 + let serialize_list_response f resp = 453 + write_string f "* LIST ("; 454 + List.iteri (fun i flag -> 455 + if i > 0 then write_sp f; 456 + match flag with 457 + | List_noinferiors -> write_string f "\\Noinferiors" 458 + | List_noselect -> write_string f "\\Noselect" 459 + | List_marked -> write_string f "\\Marked" 460 + | List_unmarked -> write_string f "\\Unmarked" 461 + | List_subscribed -> write_string f "\\Subscribed" 462 + | List_haschildren -> write_string f "\\HasChildren" 463 + | List_hasnochildren -> write_string f "\\HasNoChildren" 464 + | List_nonexistent -> write_string f "\\NonExistent" 465 + | List_remote -> write_string f "\\Remote" 466 + (* ... other flags ... *) 467 + ) resp.flags; 468 + write_string f ") "; 469 + (match resp.delimiter with 470 + | Some d -> write_quoted_string f (String.make 1 d) 471 + | None -> write_string f "NIL"); 472 + write_sp f; 473 + write_quoted_string f resp.name; 474 + 475 + (* Extended data items *) 476 + if resp.extended <> [] then begin 477 + write_string f " ("; 478 + List.iteri (fun i item -> 479 + if i > 0 then write_sp f; 480 + match item with 481 + | Childinfo opts -> 482 + write_string f "\"CHILDINFO\" ("; 483 + List.iteri (fun j opt -> 484 + if j > 0 then write_sp f; 485 + write_quoted_string f opt 486 + ) opts; 487 + write_char f ')' 488 + ) resp.extended; 489 + write_char f ')' 490 + end; 491 + 492 + write_crlf f 493 + ``` 494 + 495 + ### Phase 5: Server Handler Updates (Priority P0) 496 + 497 + #### Task 5.1: Update LIST Command Handler 498 + 499 + **File**: `lib/imapd/server.ml` 500 + 501 + ```ocaml 502 + (** Process LIST command per 503 + {{:https://datatracker.ietf.org/doc/html/rfc5258}RFC 5258}. *) 504 + let handle_list t flow tag cmd state = 505 + let username = match state with 506 + | Authenticated { username } -> Some username 507 + | Selected { username; _ } -> Some username 508 + | _ -> None 509 + in 510 + match username with 511 + | None -> 512 + send_response flow (Bad { 513 + tag = Some tag; 514 + code = None; 515 + text = "Command not valid in this state" 516 + }); 517 + state 518 + | Some username -> 519 + match cmd with 520 + | List_basic { reference; pattern } -> 521 + (* Backward compatible basic LIST *) 522 + let mailboxes = Storage.list_mailboxes t.storage ~username ~reference ~pattern in 523 + List.iter (fun mb -> 524 + send_response flow (List_response { 525 + flags = mb.flags; 526 + delimiter = mb.delimiter; 527 + name = mb.name; 528 + extended = []; 529 + }) 530 + ) mailboxes; 531 + send_response flow (Ok { tag = Some tag; code = None; text = "LIST completed" }); 532 + state 533 + 534 + | List_extended { selection; reference; patterns; return_opts } -> 535 + (* Validate RECURSIVEMATCH usage - RFC 5258 Section 3.1 *) 536 + if List.mem List_select_recursivematch selection then begin 537 + let has_base_opt = List.exists (function 538 + | List_select_subscribed -> true 539 + | _ -> false 540 + ) selection in 541 + if not has_base_opt then begin 542 + send_response flow (Bad { 543 + tag = Some tag; 544 + code = None; 545 + text = "RECURSIVEMATCH requires another selection option" 546 + }); 547 + state 548 + end else 549 + handle_extended_list t flow tag ~username ~selection ~reference ~patterns ~return_opts state 550 + end else 551 + handle_extended_list t flow tag ~username ~selection ~reference ~patterns ~return_opts state 552 + 553 + and handle_extended_list t flow tag ~username ~selection ~reference ~patterns ~return_opts state = 554 + let mailboxes = Storage.list_mailboxes_extended t.storage 555 + ~username ~reference ~patterns ~selection ~return_opts in 556 + List.iter (fun resp -> 557 + send_response flow (List_response resp) 558 + ) mailboxes; 559 + send_response flow (Ok { tag = Some tag; code = None; text = "LIST completed" }); 560 + state 561 + ``` 562 + 563 + ### Phase 6: Client Library Updates (Priority P2) 564 + 565 + #### Task 6.1: Update Client Library Types 566 + 567 + **File**: `lib/imap/list_attr.ml` 568 + 569 + Add missing attributes: 570 + 571 + ```ocaml 572 + (** LIST Command Attributes per 573 + {{:https://datatracker.ietf.org/doc/html/rfc9051#section-7.2.2}RFC 9051 Section 7.2.2} 574 + and {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3}RFC 5258 Section 3}. *) 575 + 576 + type t = 577 + | Noinferiors 578 + | Noselect 579 + | Marked 580 + | Unmarked 581 + | Subscribed 582 + | Haschildren 583 + | Hasnochildren 584 + | Nonexistent (** RFC 5258 *) 585 + | Remote (** RFC 5258 *) 586 + (* ... special-use flags ... *) 587 + ``` 588 + 589 + ## 4. OCamldoc Citation Templates 590 + 591 + Use these templates when documenting RFC 5258 features: 592 + 593 + ### Module-level documentation: 594 + 595 + ```ocaml 596 + (** LIST Command Extensions 597 + 598 + Implements {{:https://datatracker.ietf.org/doc/html/rfc5258}RFC 5258} IMAP4 LIST 599 + Command Extensions. 600 + 601 + {2 Selection Options} 602 + 603 + Selection options per {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.1}RFC 5258 Section 3.1}: 604 + {ul 605 + {- SUBSCRIBED - list subscribed mailboxes} 606 + {- REMOTE - include remote mailboxes} 607 + {- RECURSIVEMATCH - return parents with matching children}} 608 + 609 + {2 Return Options} 610 + 611 + Return options per {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.2}RFC 5258 Section 3.2}: 612 + {ul 613 + {- SUBSCRIBED - include subscription state} 614 + {- CHILDREN - include \HasChildren/\HasNoChildren}} *) 615 + ``` 616 + 617 + ### Type-level documentation: 618 + 619 + ```ocaml 620 + (** Selection option for LIST command per 621 + {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.1}RFC 5258 Section 3.1}. *) 622 + type list_select_option = ... 623 + 624 + (** Return option for LIST command per 625 + {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.2}RFC 5258 Section 3.2}. *) 626 + type list_return_option = ... 627 + 628 + (** Extended data item per 629 + {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.5}RFC 5258 Section 3.5}. *) 630 + type list_extended_item = ... 631 + ``` 632 + 633 + ### Function-level documentation: 634 + 635 + ```ocaml 636 + (** List mailboxes with extended options. 637 + 638 + Implements the LIST-EXTENDED command per 639 + {{:https://datatracker.ietf.org/doc/html/rfc5258}RFC 5258}. 640 + 641 + @param selection Selection options to filter results 642 + @param patterns One or more mailbox patterns to match 643 + @param return_opts Return options controlling response data 644 + @return List of matching mailboxes with requested attributes 645 + 646 + {b Note}: Per {{:https://datatracker.ietf.org/doc/html/rfc5258#section-3.1}RFC 5258 Section 3.1}, 647 + RECURSIVEMATCH cannot be used alone and requires another selection option. *) 648 + val list_mailboxes_extended : ... 649 + ``` 650 + 651 + ## 5. Priority Order 652 + 653 + ### P0 - Required for LIST-EXTENDED capability 654 + 655 + 1. Add `LIST-EXTENDED` to capability string 656 + 2. Add extended types to `protocol.ml` 657 + 3. Update grammar for extended syntax 658 + 4. Update server handler for extended LIST 659 + 5. Update response serialization 660 + 661 + ### P1 - Core functionality 662 + 663 + 1. Add `\NonExistent` and `\Remote` attributes 664 + 2. Implement subscription tracking in storage 665 + 3. Implement `SUBSCRIBED` selection option 666 + 4. Implement `CHILDREN` return option 667 + 5. Implement `CHILDINFO` extended data 668 + 6. Support multiple mailbox patterns 669 + 670 + ### P2 - Full compliance 671 + 672 + 1. Implement `REMOTE` selection option (requires mailbox referrals) 673 + 2. Implement `RECURSIVEMATCH` selection option 674 + 3. Update client library 675 + 4. Add comprehensive tests 676 + 677 + ## 6. Testing Plan 678 + 679 + ### Unit Tests 680 + 681 + ```ocaml 682 + (* Test basic LIST still works *) 683 + let%test "basic_list" = ... 684 + 685 + (* Test extended LIST with selection options *) 686 + let%test "list_subscribed" = ... 687 + let%test "list_recursivematch_requires_base" = ... 688 + 689 + (* Test return options *) 690 + let%test "list_return_children" = ... 691 + let%test "list_return_subscribed" = ... 692 + 693 + (* Test attribute implications *) 694 + let%test "noinferiors_implies_hasnochildren" = ... 695 + let%test "nonexistent_implies_noselect" = ... 696 + ``` 697 + 698 + ### Integration Tests 699 + 700 + - ImapTest compatibility suite 701 + - Dovecot interoperability testing 702 + - Mail client compatibility (Thunderbird, Apple Mail) 703 + 704 + ## 7. File Summary 705 + 706 + | File | Changes | 707 + |------|---------| 708 + | `lib/imapd/protocol.ml` | Add selection/return option types, update list_flag, update command type | 709 + | `lib/imapd/protocol.mli` | Add new type signatures with documentation | 710 + | `lib/imapd/grammar.mly` | Add extended LIST grammar rules | 711 + | `lib/imapd/lexer.mll` | Already has required tokens | 712 + | `lib/imapd/parser.ml` | Update response serialization | 713 + | `lib/imapd/storage.ml` | Add subscription tracking, extended list logic | 714 + | `lib/imapd/server.ml` | Add LIST-EXTENDED capability, update handler | 715 + | `lib/imap/list_attr.ml` | Add Nonexistent, Remote constructors | 716 + | `lib/imap/list_attr.mli` | Update interface | 717 + 718 + ## 8. References 719 + 720 + - [RFC 5258](https://datatracker.ietf.org/doc/html/rfc5258) - IMAP4 LIST Command Extensions 721 + - [RFC 9051](https://datatracker.ietf.org/doc/html/rfc9051) - IMAP4rev2 (incorporates LIST-EXTENDED) 722 + - [RFC 3348](https://datatracker.ietf.org/doc/html/rfc3348) - Child Mailbox Extension (obsoleted by 5258) 723 + - [RFC 2193](https://datatracker.ietf.org/doc/html/rfc2193) - IMAP4 Mailbox Referrals (updated by 5258)
+339
spec/PLAN-rfc5530.md
··· 1 + # RFC 5530 Implementation Plan: IMAP Response Codes 2 + 3 + ## Overview 4 + 5 + [RFC 5530](https://datatracker.ietf.org/doc/html/rfc5530) defines standard IMAP response codes for better error reporting and interoperability. This document analyzes the current ocaml-imap implementation against RFC 5530 and provides an implementation plan. 6 + 7 + ## RFC 5530 Response Codes Summary 8 + 9 + RFC 5530 defines 16 response codes to supplement RFC 3501: 10 + 11 + | Code | Description | Usage Context | 12 + |------|-------------|---------------| 13 + | `UNAVAILABLE` | Temporary failure, subsystem down | Authentication, any operation | 14 + | `AUTHENTICATIONFAILED` | Auth failed (unknown user, bad password) | LOGIN, AUTHENTICATE | 15 + | `AUTHORIZATIONFAILED` | Auth OK but authorization denied | AUTHENTICATE with different auth/authz IDs | 16 + | `EXPIRED` | Passphrase expired, need new one | LOGIN, AUTHENTICATE | 17 + | `PRIVACYREQUIRED` | Operation needs TLS | LOGIN, SELECT, any operation | 18 + | `CONTACTADMIN` | User should contact support | Any operation | 19 + | `NOPERM` | ACL denies this operation | SELECT, CREATE, etc. | 20 + | `INUSE` | Resource locked by another user | DELETE, exclusive operations | 21 + | `EXPUNGEISSUED` | Another client expunged messages | SEARCH, FETCH, etc. | 22 + | `CORRUPTION` | Server detected data corruption | SELECT, FETCH, etc. | 23 + | `SERVERBUG` | Server internal error | Any operation | 24 + | `CLIENTBUG` | Server detected client bug | Any operation | 25 + | `CANNOT` | Operation violates server invariants | CREATE, RENAME, etc. | 26 + | `LIMIT` | Implementation limit reached | STORE (flags), etc. | 27 + | `OVERQUOTA` | User over quota | COPY, APPEND | 28 + | `ALREADYEXISTS` | Resource already exists | CREATE, RENAME | 29 + | `NONEXISTENT` | Resource does not exist | DELETE, RENAME, SELECT | 30 + 31 + ## Current Implementation Status 32 + 33 + ### Response Code Types 34 + 35 + **Location:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imap/code.ml` and `code.mli` 36 + 37 + The `Code.t` type defines all response codes. Current RFC 5530 status: 38 + 39 + | RFC 5530 Code | OCaml Variant | Status | Notes | 40 + |---------------|---------------|--------|-------| 41 + | `UNAVAILABLE` | `Unavailable` | **Implemented** | Present in type | 42 + | `AUTHENTICATIONFAILED` | `Authenticationfailed` | **Implemented** | Present in type | 43 + | `AUTHORIZATIONFAILED` | `Authorizationfailed` | **Implemented** | Present in type | 44 + | `EXPIRED` | `Expired` | **Implemented** | Present in type | 45 + | `PRIVACYREQUIRED` | `Privacyrequired` | **Implemented** | Present in type | 46 + | `CONTACTADMIN` | `Contactadmin` | **Implemented** | Present in type | 47 + | `NOPERM` | `Noperm` | **Implemented** | Present in type | 48 + | `INUSE` | `Inuse` | **Implemented** | Present in type | 49 + | `EXPUNGEISSUED` | `Expungeissued` | **Implemented** | Present in type | 50 + | `CORRUPTION` | `Corruption` | **Implemented** | Present in type | 51 + | `SERVERBUG` | `Serverbug` | **Implemented** | Present in type | 52 + | `CLIENTBUG` | `Clientbug` | **Implemented** | Present in type | 53 + | `CANNOT` | `Cannot` | **Implemented** | Present in type | 54 + | `LIMIT` | `Limit` | **Implemented** | Present in type | 55 + | `OVERQUOTA` | `Overquota` | **Implemented** | Present in type | 56 + | `ALREADYEXISTS` | `Alreadyexists` | **Implemented** | Present in type | 57 + | `NONEXISTENT` | `Nonexistent` | **Implemented** | Present in type | 58 + 59 + **Result: All 16 RFC 5530 response codes are defined in the type system.** 60 + 61 + ### Server Usage Analysis 62 + 63 + **Location:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 64 + 65 + The server implementation uses these RFC 5530 codes: 66 + 67 + | Code | Server Usage | Context | 68 + |------|--------------|---------| 69 + | `Code_authenticationfailed` | **Used** | LOGIN failure (lines 143, 158, 978, 999, 1005) | 70 + | `Code_nonexistent` | **Used** | SELECT/STATUS/RENAME mailbox not found (lines 201, 284, 507) | 71 + | `Code_alreadyexists` | **Used** | CREATE/RENAME destination exists (lines 435, 514) | 72 + | `Code_cannot` | **Used** | DELETE INBOX forbidden (line 471) | 73 + | `Code_trycreate` | **Used** | COPY/MOVE/APPEND dest not found (lines 536, 578, 658) | 74 + | `Code_unavailable` | **NOT used** | No subsystem failure handling | 75 + | `Code_authorizationfailed` | **NOT used** | No separate authz handling | 76 + | `Code_expired` | **NOT used** | No password expiry support | 77 + | `Code_privacyrequired` | **NOT used** | No TLS requirement enforcement | 78 + | `Code_contactadmin` | **NOT used** | No admin contact scenarios | 79 + | `Code_noperm` | **NOT used** | No ACL system | 80 + | `Code_inuse` | **NOT used** | No lock/exclusive access handling | 81 + | `Code_expungeissued` | **NOT used** | No concurrent expunge notification | 82 + | `Code_corruption` | **NOT used** | No corruption detection | 83 + | `Code_serverbug` | **NOT used** | Generic errors used instead | 84 + | `Code_clientbug` | **NOT used** | No client bug detection | 85 + | `Code_limit` | **NOT used** | No implementation limits checked | 86 + | `Code_overquota` | **NOT used** | No quota system | 87 + 88 + ### Protocol Types 89 + 90 + **Location:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/protocol.ml` 91 + 92 + The `response_code` type in protocol.ml mirrors `Code.t` and includes all RFC 5530 codes. 93 + 94 + ## Implementation Tasks 95 + 96 + ### Priority 1: Documentation (No Code Changes) 97 + 98 + Update OCamldoc comments in `code.ml` and `code.mli` with RFC citations: 99 + 100 + ```ocaml 101 + (** Response Codes 102 + 103 + IMAP response codes as specified in: 104 + - {{:https://datatracker.ietf.org/doc/html/rfc9051#section-7.1}RFC 9051 Section 7.1} (IMAP4rev2) 105 + - {{:https://datatracker.ietf.org/doc/html/rfc5530}RFC 5530} (Extended Response Codes) 106 + 107 + @see <https://datatracker.ietf.org/doc/html/rfc5530> RFC 5530 IMAP Response Codes *) 108 + ``` 109 + 110 + Add per-variant documentation: 111 + 112 + ```ocaml 113 + type t = 114 + | Unavailable 115 + (** Temporary failure because a subsystem is down. 116 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 117 + | Authenticationfailed 118 + (** Authentication failed (unknown user, bad password). 119 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 120 + | Authorizationfailed 121 + (** Authentication succeeded but authorization denied. 122 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 123 + | Expired 124 + (** Passphrase expired, user needs a new one. 125 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 126 + | Privacyrequired 127 + (** Operation requires TLS encryption. 128 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 129 + | Contactadmin 130 + (** User should contact system administrator. 131 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 132 + | Noperm 133 + (** Access control (ACL) denies this operation. 134 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 135 + | Inuse 136 + (** Resource locked or in use by another session. 137 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 138 + | Expungeissued 139 + (** Another client issued EXPUNGE for this mailbox. 140 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 141 + | Corruption 142 + (** Server detected data corruption. 143 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 144 + | Serverbug 145 + (** Server encountered an internal bug. 146 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 147 + | Clientbug 148 + (** Server detected a client protocol bug. 149 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 150 + | Cannot 151 + (** Operation violates server invariants (will never succeed). 152 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 153 + | Limit 154 + (** Implementation limit reached (e.g., max flags). 155 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 156 + | Overquota 157 + (** User would exceed storage quota. 158 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 159 + | Alreadyexists 160 + (** Resource (mailbox) already exists. 161 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 162 + | Nonexistent 163 + (** Resource (mailbox) does not exist. 164 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 165 + ``` 166 + 167 + ### Priority 2: Server Error Handling Enhancement 168 + 169 + #### 2.1 Add SERVERBUG for Internal Errors 170 + 171 + Replace generic error handling with `Code_serverbug`: 172 + 173 + ```ocaml 174 + (* In handle_fetch, handle_store, etc. *) 175 + | Error Storage_types.Internal_error msg -> 176 + send_response flow (No { 177 + tag = Some tag; 178 + code = Some Code_serverbug; 179 + text = "Internal server error" 180 + }) 181 + ``` 182 + 183 + #### 2.2 Add PRIVACYREQUIRED for TLS Enforcement 184 + 185 + When TLS is required but not active: 186 + 187 + ```ocaml 188 + (* In handle_login *) 189 + | Not_authenticated when not tls_active && t.config.require_tls -> 190 + send_response flow (No { 191 + tag = Some tag; 192 + code = Some Code_privacyrequired; 193 + text = "LOGIN requires TLS" 194 + }); 195 + state 196 + ``` 197 + 198 + #### 2.3 Add UNAVAILABLE for Backend Failures 199 + 200 + When storage backend is unavailable: 201 + 202 + ```ocaml 203 + | Error Storage_types.Backend_unavailable -> 204 + send_response flow (No { 205 + tag = Some tag; 206 + code = Some Code_unavailable; 207 + text = "Backend temporarily unavailable" 208 + }) 209 + ``` 210 + 211 + ### Priority 3: Advanced Features (Future Work) 212 + 213 + #### 3.1 Quota Support with OVERQUOTA 214 + 215 + Requires implementing quota tracking in storage: 216 + 217 + ```ocaml 218 + (* In handle_append *) 219 + | Error Storage_types.Quota_exceeded -> 220 + send_response flow (No { 221 + tag = Some tag; 222 + code = Some Code_overquota; 223 + text = "Mailbox quota exceeded" 224 + }) 225 + ``` 226 + 227 + #### 3.2 ACL Support with NOPERM 228 + 229 + Requires implementing access control: 230 + 231 + ```ocaml 232 + (* In handle_select *) 233 + | Error Storage_types.Permission_denied -> 234 + send_response flow (No { 235 + tag = Some tag; 236 + code = Some Code_noperm; 237 + text = "Access denied" 238 + }) 239 + ``` 240 + 241 + #### 3.3 Concurrent Access with INUSE and EXPUNGEISSUED 242 + 243 + Requires implementing locking and notification: 244 + 245 + ```ocaml 246 + (* When another client has exclusive lock *) 247 + | Error Storage_types.Mailbox_locked -> 248 + send_response flow (No { 249 + tag = Some tag; 250 + code = Some Code_inuse; 251 + text = "Mailbox in use by another session" 252 + }) 253 + ``` 254 + 255 + #### 3.4 Implementation Limits with LIMIT 256 + 257 + ```ocaml 258 + (* In handle_store when too many flags *) 259 + | Error Storage_types.Too_many_flags -> 260 + send_response flow (No { 261 + tag = Some tag; 262 + code = Some Code_limit; 263 + text = "Maximum flag count exceeded" 264 + }) 265 + ``` 266 + 267 + ## OCamldoc Citation Templates 268 + 269 + ### Module-Level Citation 270 + 271 + ```ocaml 272 + (** {1 RFC 5530 Response Codes} 273 + 274 + Extended IMAP response codes for improved error reporting. 275 + 276 + {2 References} 277 + 278 + - {{:https://datatracker.ietf.org/doc/html/rfc5530}RFC 5530} - IMAP Response Codes 279 + - {{:https://www.iana.org/assignments/imap-response-codes/imap-response-codes.xhtml}IANA IMAP Response Codes Registry} 280 + 281 + @since RFC 5530 (May 2009) *) 282 + ``` 283 + 284 + ### Variant Citation Pattern 285 + 286 + ```ocaml 287 + | Codename 288 + (** Brief description of when this code is used. 289 + 290 + {b Example:} 291 + {[ 292 + C: a COMMAND arg 293 + S: a NO [CODENAME] Human readable message 294 + ]} 295 + 296 + @see <https://datatracker.ietf.org/doc/html/rfc5530#section-3> RFC 5530 Section 3 *) 297 + ``` 298 + 299 + ## Testing Requirements 300 + 301 + ### Unit Tests 302 + 303 + 1. Verify all RFC 5530 codes serialize correctly to wire format 304 + 2. Verify parsing of server responses with RFC 5530 codes 305 + 3. Test each code with OK, NO, and BAD response types where applicable 306 + 307 + ### Integration Tests 308 + 309 + 1. Test `AUTHENTICATIONFAILED` with invalid credentials 310 + 2. Test `NONEXISTENT` with missing mailbox 311 + 3. Test `ALREADYEXISTS` with duplicate CREATE 312 + 4. Test `CANNOT` with INBOX deletion attempt 313 + 314 + ## Implementation Order 315 + 316 + 1. **Phase 1: Documentation** - Add RFC citations to type definitions 317 + 2. **Phase 2: Server hardening** - Add SERVERBUG, PRIVACYREQUIRED 318 + 3. **Phase 3: Storage errors** - Map storage errors to appropriate codes 319 + 4. **Phase 4: Advanced features** - Quota, ACL, concurrent access 320 + 321 + ## Files to Modify 322 + 323 + | File | Changes | 324 + |------|---------| 325 + | `lib/imap/code.ml` | Add OCamldoc citations | 326 + | `lib/imap/code.mli` | Add OCamldoc citations | 327 + | `lib/imapd/protocol.ml` | Add OCamldoc citations | 328 + | `lib/imapd/server.ml` | Enhance error handling | 329 + | `lib/imapd/storage.ml` | Add new error types | 330 + 331 + ## Compliance Checklist 332 + 333 + - [x] All 16 RFC 5530 codes defined in type system 334 + - [x] Pretty-printer (`pp`) handles all codes 335 + - [x] `to_string` conversion works for all codes 336 + - [ ] All codes documented with RFC citations 337 + - [ ] Server uses appropriate codes for all error conditions 338 + - [ ] Storage layer provides sufficient error granularity 339 + - [ ] Tests cover all RFC 5530 codes
+493
spec/PLAN-rfc6154.md
··· 1 + # RFC 6154 Implementation Plan: IMAP LIST Extension for Special-Use Mailboxes 2 + 3 + **RFC**: [RFC 6154 - IMAP LIST Extension for Special-Use Mailboxes](https://datatracker.ietf.org/doc/html/rfc6154) 4 + **Authors**: B. Leiba (Huawei Technologies), J. Nicolson (Google) 5 + **Status**: Standards Track 6 + **Date**: March 2011 7 + 8 + --- 9 + 10 + ## 1. Summary of RFC Requirements 11 + 12 + RFC 6154 defines special-use mailbox attributes that servers may include in IMAP LIST command responses to identify mailboxes with specific purposes to clients. 13 + 14 + ### 1.1 Special-Use Mailbox Attributes 15 + 16 + The RFC defines the following mailbox attributes (Section 2): 17 + 18 + | Attribute | Description | 19 + |-------------|-------------| 20 + | `\All` | Virtual mailbox presenting all messages in the user's message store | 21 + | `\Archive` | Mailbox used to archive messages | 22 + | `\Drafts` | Mailbox for draft messages (messages being composed) | 23 + | `\Flagged` | Virtual mailbox presenting all messages marked as "important" | 24 + | `\Junk` | Mailbox for spam/junk mail | 25 + | `\Sent` | Mailbox for sent message copies | 26 + | `\Trash` | Mailbox for deleted messages | 27 + 28 + All attributes are OPTIONAL. A mailbox may have none, one, or multiple special-use attributes. 29 + 30 + ### 1.2 SPECIAL-USE Capability 31 + 32 + Servers supporting the extended LIST command (RFC 5258) features MUST advertise: 33 + - `SPECIAL-USE` capability in response to CAPABILITY command 34 + 35 + ### 1.3 SPECIAL-USE Selection Option (Extended LIST) 36 + 37 + When client specifies `SPECIAL-USE` as a selection option: 38 + ``` 39 + C: t1 LIST (SPECIAL-USE) "" "*" 40 + ``` 41 + The server MUST return only mailboxes that have a special-use attribute set. 42 + 43 + ### 1.4 SPECIAL-USE Return Option (Extended LIST) 44 + 45 + When client specifies `SPECIAL-USE` as a return option: 46 + ``` 47 + C: t1 LIST "" "%" RETURN (SPECIAL-USE) 48 + ``` 49 + The server MUST return special-use attributes on mailboxes that have them. 50 + 51 + The return option is implied by the selection option. 52 + 53 + ### 1.5 CREATE-SPECIAL-USE Capability (OPTIONAL) 54 + 55 + Servers MAY support the `CREATE-SPECIAL-USE` capability allowing clients to designate special uses at mailbox creation: 56 + ``` 57 + C: t1 CREATE MyDrafts (USE (\Drafts)) 58 + ``` 59 + 60 + ### 1.6 USEATTR Response Code 61 + 62 + When CREATE with USE parameter fails due to special-use attribute issues, server SHOULD return: 63 + ``` 64 + S: t1 NO [USEATTR] \All not supported 65 + ``` 66 + 67 + ### 1.7 METADATA Integration (OPTIONAL) 68 + 69 + If server supports both this extension and METADATA (RFC 5464), it SHOULD tie special-use attributes to `/private/specialuse` metadata entry. 70 + 71 + --- 72 + 73 + ## 2. Current Implementation Status 74 + 75 + ### 2.1 Fully Implemented 76 + 77 + | Component | File | Status | 78 + |-----------|------|--------| 79 + | LIST attribute types | `lib/imap/list_attr.ml` | Complete - All 7 special-use variants defined | 80 + | LIST attribute parsing (client) | `lib/imap/read.ml` | Complete - Parses all special-use attributes | 81 + | LIST response serialization (server) | `lib/imapd/parser.ml` | Complete - Serializes all special-use attributes | 82 + | Protocol types | `lib/imapd/protocol.ml` | Complete - `list_flag` type includes all special-use variants | 83 + 84 + ### 2.2 Partially Implemented 85 + 86 + | Component | File | Status | Gap | 87 + |-----------|------|--------|-----| 88 + | SPECIAL-USE capability | `lib/imapd/server.ml` | Missing | Not in `base_capabilities` list | 89 + | Storage mailbox info | `lib/imapd/storage.ml` | Partial | `mailbox_info.flags` always empty `[]` | 90 + 91 + ### 2.3 Not Implemented 92 + 93 + | Component | Description | Priority | 94 + |-----------|-------------|----------| 95 + | Extended LIST selection option | `LIST (SPECIAL-USE) "" "*"` filtering | Medium | 96 + | Extended LIST return option | `LIST "" "%" RETURN (SPECIAL-USE)` | Medium | 97 + | CREATE-SPECIAL-USE capability | `CREATE mailbox (USE (\Drafts))` | Low | 98 + | USEATTR response code | `[USEATTR]` in NO response | Low | 99 + | METADATA integration | `/private/specialuse` entry | Low | 100 + | Mailbox special-use persistence | Store/retrieve special-use assignments | High | 101 + 102 + --- 103 + 104 + ## 3. Detailed Implementation Tasks 105 + 106 + ### Phase 1: Core Special-Use Support (Priority: High) 107 + 108 + #### Task 1.1: Add SPECIAL-USE Capability 109 + **File**: `lib/imapd/server.ml` 110 + **Lines**: ~17-42 111 + 112 + Add `SPECIAL-USE` to capability lists: 113 + ```ocaml 114 + let base_capabilities_pre_tls = [ 115 + "IMAP4rev2"; 116 + "IMAP4rev1"; 117 + "AUTH=PLAIN"; 118 + "STARTTLS"; 119 + "IDLE"; 120 + "NAMESPACE"; 121 + "UIDPLUS"; 122 + "MOVE"; 123 + "ENABLE"; 124 + "LITERAL+"; 125 + "ID"; 126 + "SPECIAL-USE"; (* RFC 6154 *) 127 + ] 128 + ``` 129 + 130 + #### Task 1.2: Add Special-Use Storage to Mailbox Metadata 131 + **File**: `lib/imapd/storage.ml` 132 + 133 + Extend `mailbox_info` type to include special-use persistence: 134 + ```ocaml 135 + type mailbox_info = { 136 + name : mailbox_name; 137 + delimiter : char option; 138 + flags : list_flag list; 139 + special_use : list_flag list; (* New: persistent special-use attributes *) 140 + } 141 + ``` 142 + 143 + Add special-use configuration for standard mailboxes: 144 + ```ocaml 145 + let default_special_use_map = [ 146 + ("Drafts", [List_drafts]); 147 + ("Sent", [List_sent]); 148 + ("Trash", [List_trash]); 149 + ("Junk", [List_junk]); 150 + ("Spam", [List_junk]); 151 + ("Archive", [List_archive]); 152 + ] 153 + ``` 154 + 155 + #### Task 1.3: Return Special-Use Flags in LIST Response 156 + **File**: `lib/imapd/storage.ml` 157 + **Function**: `list_mailboxes` 158 + 159 + Update `list_mailboxes` implementations to return special-use flags: 160 + ```ocaml 161 + let list_mailboxes t ~username ~reference:_ ~pattern = 162 + (* ... existing code ... *) 163 + let special_use = get_special_use_for_mailbox name in 164 + { name; delimiter = Some '/'; flags = special_use } :: acc 165 + ``` 166 + 167 + #### Task 1.4: Add USEATTR Response Code 168 + **File**: `lib/imapd/protocol.ml` 169 + **Type**: `response_code` 170 + 171 + ```ocaml 172 + type response_code = 173 + (* ... existing codes ... *) 174 + | Code_useattr (* RFC 6154 - special-use attribute error *) 175 + ``` 176 + 177 + **File**: `lib/imapd/parser.ml` 178 + **Function**: `write_response_code` 179 + 180 + ```ocaml 181 + | Code_useattr -> write_string f "USEATTR" 182 + ``` 183 + 184 + **File**: `lib/imap/code.ml` 185 + 186 + ```ocaml 187 + type t = 188 + (* ... existing codes ... *) 189 + | Useattr (** RFC 6154 - special-use attribute error *) 190 + ``` 191 + 192 + ### Phase 2: Extended LIST Support (Priority: Medium) 193 + 194 + #### Task 2.1: Parse Extended LIST Command 195 + **File**: `lib/imapd/grammar.mly` 196 + 197 + Add extended LIST syntax support: 198 + ``` 199 + list-select-opts = "(" list-select-option *(SP list-select-option) ")" 200 + list-select-option = "SPECIAL-USE" / "SUBSCRIBED" / ... 201 + return-opts = "RETURN" SP "(" return-option *(SP return-option) ")" 202 + return-option = "SPECIAL-USE" / "SUBSCRIBED" / ... 203 + ``` 204 + 205 + #### Task 2.2: Extend LIST Command Type 206 + **File**: `lib/imapd/protocol.ml` 207 + 208 + ```ocaml 209 + type list_options = { 210 + selection : list_selection_option list; 211 + return : list_return_option list; 212 + } 213 + 214 + type list_selection_option = 215 + | Select_special_use 216 + | Select_subscribed 217 + | Select_remote 218 + | Select_recursivematch 219 + 220 + type list_return_option = 221 + | Return_special_use 222 + | Return_subscribed 223 + | Return_children 224 + ``` 225 + 226 + Update LIST command: 227 + ```ocaml 228 + | List of { 229 + reference : string; 230 + pattern : string; 231 + options : list_options option; (* Extended LIST options *) 232 + } 233 + ``` 234 + 235 + #### Task 2.3: Handle SPECIAL-USE Selection Option 236 + **File**: `lib/imapd/server.ml` 237 + **Function**: `handle_list` 238 + 239 + Filter mailboxes when SPECIAL-USE selection option is specified: 240 + ```ocaml 241 + let handle_list t flow tag ~reference ~pattern ~options state = 242 + let mailboxes = Storage.list_mailboxes t.storage ~username ~reference ~pattern in 243 + let filtered = match options with 244 + | Some { selection; _ } when List.mem Select_special_use selection -> 245 + List.filter (fun mb -> mb.flags <> []) mailboxes 246 + | _ -> mailboxes 247 + in 248 + (* ... send responses ... *) 249 + ``` 250 + 251 + ### Phase 3: CREATE-SPECIAL-USE Support (Priority: Low) 252 + 253 + #### Task 3.1: Add CREATE-SPECIAL-USE Capability 254 + **File**: `lib/imapd/server.ml` 255 + 256 + Add to capabilities when feature is enabled: 257 + ```ocaml 258 + let optional_capabilities = [ 259 + "CREATE-SPECIAL-USE"; (* RFC 6154 - optional *) 260 + ] 261 + ``` 262 + 263 + #### Task 3.2: Extend CREATE Command 264 + **File**: `lib/imapd/protocol.ml` 265 + 266 + ```ocaml 267 + | Create of { 268 + mailbox : mailbox_name; 269 + use : list_flag list option; (* RFC 6154 USE parameter *) 270 + } 271 + ``` 272 + 273 + #### Task 3.3: Parse CREATE USE Parameter 274 + **File**: `lib/imapd/grammar.mly` 275 + 276 + ``` 277 + command_auth: 278 + | CREATE SP mb = mailbox { Create { mailbox = mb; use = None } } 279 + | CREATE SP mb = mailbox SP LPAREN USE SP LPAREN attrs = use_attr_list RPAREN RPAREN 280 + { Create { mailbox = mb; use = Some attrs } } 281 + ``` 282 + 283 + #### Task 3.4: Handle CREATE with USE 284 + **File**: `lib/imapd/server.ml` 285 + **Function**: `handle_create` 286 + 287 + ```ocaml 288 + let handle_create t flow tag mailbox ~use state = 289 + match Storage.create_mailbox t.storage ~username mailbox ~special_use:use with 290 + | Ok () -> (* success *) 291 + | Error (Special_use_not_supported attr) -> 292 + send_response flow (No { 293 + tag = Some tag; 294 + code = Some Code_useattr; 295 + text = Printf.sprintf "%s not supported" (List_attr.to_string attr) 296 + }) 297 + ``` 298 + 299 + ### Phase 4: Client Library Enhancements (Priority: Medium) 300 + 301 + #### Task 4.1: Add Special-Use Query Function 302 + **File**: `lib/imap/client.ml` (if exists) or `lib/imapd/client.ml` 303 + 304 + ```ocaml 305 + (** List only special-use mailboxes *) 306 + val list_special_use : t -> reference:string -> pattern:string -> list_entry list 307 + 308 + (** Get special-use mailboxes by type *) 309 + val get_drafts_mailbox : t -> list_entry option 310 + val get_sent_mailbox : t -> list_entry option 311 + val get_trash_mailbox : t -> list_entry option 312 + val get_junk_mailbox : t -> list_entry option 313 + val get_archive_mailbox : t -> list_entry option 314 + ``` 315 + 316 + --- 317 + 318 + ## 4. OCamldoc Citation Templates 319 + 320 + ### 4.1 Module-Level Documentation 321 + 322 + ```ocaml 323 + (** IMAP LIST Extension for Special-Use Mailboxes 324 + 325 + Implements {{:https://datatracker.ietf.org/doc/html/rfc6154}RFC 6154} 326 + which defines mailbox attributes that identify special-use mailboxes. 327 + 328 + {2 Special-Use Attributes} 329 + 330 + {ul 331 + {- [\All] - All messages (virtual)} 332 + {- [\Archive] - Archived messages} 333 + {- [\Drafts] - Draft messages} 334 + {- [\Flagged] - Important messages (virtual)} 335 + {- [\Junk] - Spam/junk mail} 336 + {- [\Sent] - Sent messages} 337 + {- [\Trash] - Deleted messages}} 338 + 339 + {2 References} 340 + {ul 341 + {- {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2} - Special-Use Attributes} 342 + {- {{:https://datatracker.ietf.org/doc/html/rfc6154#section-3}RFC 6154 Section 3} - CREATE Extension} 343 + {- {{:https://datatracker.ietf.org/doc/html/rfc6154#section-6}RFC 6154 Section 6} - Formal Syntax}} *) 344 + ``` 345 + 346 + ### 4.2 Type Documentation 347 + 348 + ```ocaml 349 + type list_flag = 350 + | List_all 351 + (** [\All] - Virtual mailbox presenting all messages. 352 + See {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2}. *) 353 + | List_archive 354 + (** [\Archive] - Mailbox for archived messages. 355 + See {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2}. *) 356 + | List_drafts 357 + (** [\Drafts] - Mailbox for draft messages. 358 + See {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2}. *) 359 + | List_flagged 360 + (** [\Flagged] - Virtual mailbox for flagged/important messages. 361 + See {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2}. *) 362 + | List_junk 363 + (** [\Junk] - Mailbox for spam/junk mail. 364 + See {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2}. *) 365 + | List_sent 366 + (** [\Sent] - Mailbox for sent message copies. 367 + See {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2}. *) 368 + | List_trash 369 + (** [\Trash] - Mailbox for deleted messages. 370 + See {{:https://datatracker.ietf.org/doc/html/rfc6154#section-2}RFC 6154 Section 2}. *) 371 + ``` 372 + 373 + ### 4.3 Function Documentation 374 + 375 + ```ocaml 376 + (** Return special-use mailbox flags for a mailbox name. 377 + 378 + Maps common mailbox names to their RFC 6154 special-use attributes: 379 + - ["Drafts"] -> [[\Drafts]] 380 + - ["Sent"], ["Sent Messages"] -> [[\Sent]] 381 + - ["Trash"] -> [[\Trash]] 382 + - ["Junk"], ["Spam"] -> [[\Junk]] 383 + - ["Archive"] -> [[\Archive]] 384 + 385 + @param name The mailbox name to check 386 + @return List of special-use flags, empty if none apply 387 + @see <https://datatracker.ietf.org/doc/html/rfc6154#section-2> RFC 6154 Section 2 *) 388 + val get_special_use : mailbox_name -> list_flag list 389 + ``` 390 + 391 + --- 392 + 393 + ## 5. Testing Requirements 394 + 395 + ### 5.1 Unit Tests 396 + 397 + **File**: `test/test_special_use.ml` (new) 398 + 399 + ```ocaml 400 + (* Test special-use flag parsing *) 401 + let test_parse_special_use_flags () = 402 + let input = "(\\Drafts \\HasNoChildren)" in 403 + let flags = parse_list_flags input in 404 + assert (List.mem List_drafts flags); 405 + assert (List.mem List_hasnochildren flags) 406 + 407 + (* Test special-use flag serialization *) 408 + let test_serialize_special_use_flags () = 409 + let flags = [List_drafts; List_hasnochildren] in 410 + let output = serialize_list_flags flags in 411 + assert (String.contains output "\\Drafts") 412 + ``` 413 + 414 + ### 5.2 Integration Tests 415 + 416 + **File**: `test/integration/imaptest_scripted.ml` 417 + 418 + Existing test at line 1226 (`test_special_use_list`) should be enhanced to verify: 419 + - SPECIAL-USE capability is advertised 420 + - LIST returns special-use attributes on appropriate mailboxes 421 + - Extended LIST with SPECIAL-USE selection option filters correctly 422 + 423 + ### 5.3 Interoperability Tests 424 + 425 + Test against other IMAP servers: 426 + - Dovecot (full RFC 6154 support) 427 + - Gmail IMAP (partial support) 428 + - Microsoft Exchange (partial support) 429 + 430 + --- 431 + 432 + ## 6. Priority Summary 433 + 434 + | Priority | Task | Complexity | Dependencies | 435 + |----------|------|------------|--------------| 436 + | **High** | Add SPECIAL-USE capability | Low | None | 437 + | **High** | Return special-use flags in LIST | Medium | Task 1.1 | 438 + | **High** | Add USEATTR response code | Low | None | 439 + | **Medium** | Extended LIST selection option | Medium | Grammar changes | 440 + | **Medium** | Extended LIST return option | Medium | Grammar changes | 441 + | **Medium** | Client convenience functions | Low | Core support | 442 + | **Low** | CREATE-SPECIAL-USE support | High | Grammar, storage | 443 + | **Low** | METADATA integration | High | METADATA extension | 444 + 445 + --- 446 + 447 + ## 7. Implementation Order 448 + 449 + 1. **Phase 1** (1-2 days): Core special-use support 450 + - Add capability 451 + - Implement mailbox-to-special-use mapping 452 + - Return attributes in LIST responses 453 + - Add USEATTR response code 454 + 455 + 2. **Phase 2** (2-3 days): Extended LIST 456 + - Grammar changes for selection/return options 457 + - Protocol type updates 458 + - Server handler updates 459 + 460 + 3. **Phase 3** (Optional, 1-2 days): CREATE-SPECIAL-USE 461 + - Only if explicitly requested 462 + - Requires storage layer changes 463 + 464 + 4. **Phase 4** (1 day): Client library 465 + - Convenience functions 466 + - Documentation 467 + 468 + --- 469 + 470 + ## 8. Files to Modify 471 + 472 + | File | Changes | 473 + |------|---------| 474 + | `lib/imapd/server.ml` | Add SPECIAL-USE capability, handle extended LIST | 475 + | `lib/imapd/storage.ml` | Add special-use mapping for mailboxes | 476 + | `lib/imapd/protocol.ml` | Add Code_useattr, extend LIST command type | 477 + | `lib/imapd/protocol.mli` | Update interface | 478 + | `lib/imapd/parser.ml` | Serialize USEATTR code | 479 + | `lib/imapd/grammar.mly` | Parse extended LIST, CREATE USE | 480 + | `lib/imap/code.ml` | Add Useattr variant | 481 + | `lib/imap/code.mli` | Update interface | 482 + | `lib/imap/list_attr.ml` | Add helper functions | 483 + | `lib/imap/list_attr.mli` | Update interface | 484 + | `test/test_special_use.ml` | New test file | 485 + 486 + --- 487 + 488 + ## References 489 + 490 + - [RFC 6154 - IMAP LIST Extension for Special-Use Mailboxes](https://datatracker.ietf.org/doc/html/rfc6154) 491 + - [RFC 5258 - IMAP4 LIST Command Extensions](https://datatracker.ietf.org/doc/html/rfc5258) 492 + - [RFC 5464 - The IMAP METADATA Extension](https://datatracker.ietf.org/doc/html/rfc5464) 493 + - [RFC 9051 - IMAP4rev2](https://datatracker.ietf.org/doc/html/rfc9051) (incorporates special-use)
+510
spec/PLAN-rfc6855.md
··· 1 + # RFC 6855 Implementation Plan - IMAP Support for UTF-8 2 + 3 + This document provides a detailed implementation plan for RFC 6855 (IMAP Support for UTF-8) 4 + in the ocaml-imap library. 5 + 6 + ## RFC Summary 7 + 8 + [RFC 6855](https://datatracker.ietf.org/doc/html/rfc6855) extends IMAP to support UTF-8 9 + encoded international characters in: 10 + - User names (via AUTHENTICATE, not LOGIN) 11 + - Mail addresses 12 + - Message headers 13 + - Mailbox names 14 + 15 + This RFC replaces the experimental RFC 5738. 16 + 17 + ## Capability Overview 18 + 19 + ### UTF8=ACCEPT Capability 20 + 21 + The `UTF8=ACCEPT` capability indicates that the server: 22 + 1. Supports opening mailboxes containing internationalized messages 23 + 2. Can provide UTF-8 responses to LIST and LSUB commands 24 + 3. Accepts UTF-8 in quoted-strings after client issues `ENABLE UTF8=ACCEPT` 25 + 4. Accepts UTF-8 headers in APPEND command (with UTF8 data extension) 26 + 5. Accepts UTF-8 mailbox names 27 + 28 + ### UTF8=ONLY Capability 29 + 30 + The `UTF8=ONLY` capability indicates that the server: 31 + 1. Supports everything in `UTF8=ACCEPT` 32 + 2. **Requires** UTF-8 support from clients 33 + 3. Will send UTF-8 in quoted-strings 34 + 4. Will NOT accept modified UTF-7 mailbox names 35 + 5. Will reject commands requiring UTF-8 without prior `ENABLE UTF8=ACCEPT` with `NO [CANNOT]` 36 + 37 + Note: A server advertises either `UTF8=ACCEPT` or `UTF8=ONLY`, never both. 38 + 39 + ## Current Implementation Status 40 + 41 + ### Already Implemented 42 + 43 + | Feature | Status | Location | 44 + |---------|--------|----------| 45 + | ENABLE command | Done | `lib/imapd/server.ml:697` | 46 + | UTF8=ACCEPT in ENABLE response | Partial | `lib/imapd/server.ml:704` | 47 + | Basic capabilities list | Done | `lib/imapd/server.ml:17-42` | 48 + 49 + ### Not Implemented 50 + 51 + | Feature | Status | RFC Section | 52 + |---------|--------|-------------| 53 + | UTF8=ACCEPT capability advertisement | Missing | Section 3 | 54 + | UTF8=ONLY capability advertisement | Missing | Section 6 | 55 + | UTF-8 in quoted-strings | Missing | Section 3 | 56 + | UTF8 APPEND data extension | Missing | Section 4 | 57 + | UTF-8 validation in parser | Missing | Section 3 | 58 + | SEARCH charset restriction | Missing | Section 3 | 59 + | Mailbox name UTF-8 support | Partial | Section 3 | 60 + | Session UTF-8 mode tracking | Missing | Section 3 | 61 + 62 + ## Detailed Requirements 63 + 64 + ### 1. UTF-8 in Quoted Strings (Section 3) 65 + 66 + After `ENABLE UTF8=ACCEPT`, the server MUST: 67 + - Accept UTF-8 characters in quoted-strings 68 + - Reject invalid UTF-8 sequences with `BAD` response 69 + - NOT send UTF-8 in quoted-strings until client enables it 70 + 71 + **ABNF Extension:** 72 + ```abnf 73 + quoted =/ DQUOTE *uQUOTED-CHAR DQUOTE 74 + uQUOTED-CHAR = QUOTED-CHAR / UTF8-2 / UTF8-3 / UTF8-4 75 + UTF8-2 = <Defined in Section 4 of RFC 3629> 76 + UTF8-3 = <Defined in Section 4 of RFC 3629> 77 + UTF8-4 = <Defined in Section 4 of RFC 3629> 78 + ``` 79 + 80 + ### 2. APPEND UTF8 Data Extension (Section 4) 81 + 82 + For appending messages with UTF-8 headers: 83 + 84 + **ABNF:** 85 + ```abnf 86 + utf8-literal = "UTF8" SP "(" literal8 ")" 87 + literal8 = <Defined in RFC 4466> 88 + append-data =/ utf8-literal 89 + ``` 90 + 91 + **Requirements:** 92 + - If client has NOT issued `ENABLE UTF8=ACCEPT`, server MUST reject APPEND with 8-bit headers with `NO` 93 + - If client uses `UTF8 (...)` syntax, server accepts UTF-8 headers 94 + 95 + ### 3. LOGIN Command (Section 5) 96 + 97 + RFC 6855 explicitly does NOT extend LOGIN for UTF-8: 98 + - UTF-8 usernames/passwords MUST use AUTHENTICATE command 99 + - No changes needed to LOGIN implementation 100 + 101 + ### 4. SEARCH Charset Restriction (Section 3) 102 + 103 + After `ENABLE UTF8=ACCEPT`: 104 + - Client MUST NOT issue SEARCH with a CHARSET specification 105 + - Server SHOULD reject such SEARCH with `BAD` response 106 + 107 + ### 5. Mailbox Names (Section 3) 108 + 109 + All `UTF8=ACCEPT` servers SHOULD: 110 + - Accept UTF-8 mailbox names 111 + - Convert UTF-8 to modified UTF-7 internally (if using RFC 3501 naming) 112 + - Mailbox names MUST comply with Net-Unicode (RFC 5198 Section 2) 113 + - MUST NOT contain: U+0000-U+001F, U+0080-U+009F, U+007F, U+2028, U+2029 114 + 115 + ## Implementation Tasks 116 + 117 + ### Priority 1: Core Infrastructure 118 + 119 + #### Task 1.1: Add Session UTF-8 State Tracking 120 + **Files:** `lib/imapd/server.ml`, `lib/imapd/protocol.ml` 121 + 122 + Add tracking for whether UTF-8 has been enabled for the session: 123 + 124 + ```ocaml 125 + (** Session state including UTF-8 mode. 126 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 127 + type session_state = { 128 + utf8_enabled : bool; (** True after ENABLE UTF8=ACCEPT *) 129 + (* ... other session state ... *) 130 + } 131 + ``` 132 + 133 + **Implementation:** 134 + 1. Add `utf8_enabled` field to connection state 135 + 2. Update `handle_enable` to set this flag when UTF8=ACCEPT is enabled 136 + 3. Pass this state through command handlers 137 + 138 + #### Task 1.2: Add UTF8=ACCEPT to Capabilities 139 + **Files:** `lib/imapd/server.ml` 140 + 141 + ```ocaml 142 + (** Base capabilities per RFC 9051 with UTF-8 support per RFC 6855. 143 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 144 + let base_capabilities_post_tls = [ 145 + "IMAP4rev2"; 146 + "IMAP4rev1"; 147 + "AUTH=PLAIN"; 148 + "IDLE"; 149 + "NAMESPACE"; 150 + "UIDPLUS"; 151 + "MOVE"; 152 + "ENABLE"; 153 + "LITERAL+"; 154 + "ID"; 155 + "UTF8=ACCEPT"; (* RFC 6855 *) 156 + ] 157 + ``` 158 + 159 + ### Priority 2: Lexer/Parser Changes 160 + 161 + #### Task 2.1: Add UTF-8 Validation Function 162 + **Files:** `lib/imapd/protocol.ml` (new), or `lib/imapd/utf8.ml` (new file) 163 + 164 + ```ocaml 165 + (** UTF-8 validation per RFC 3629. 166 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 167 + 168 + (** Check if a string contains only valid UTF-8 sequences. *) 169 + val is_valid_utf8 : string -> bool 170 + 171 + (** Check if a string contains any non-ASCII characters. *) 172 + val has_non_ascii : string -> bool 173 + 174 + (** Validate a mailbox name for UTF-8 compliance per RFC 6855. 175 + Rejects control characters U+0000-U+001F, U+0080-U+009F, 176 + delete U+007F, line separator U+2028, paragraph separator U+2029. 177 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 178 + val is_valid_utf8_mailbox_name : string -> bool 179 + ``` 180 + 181 + #### Task 2.2: Update Lexer for UTF-8 Quoted Strings 182 + **Files:** `lib/imapd/lexer.mll` 183 + 184 + Current lexer rejects 8-bit characters in quoted strings. Add UTF-8 support: 185 + 186 + ```ocaml 187 + (* In quoted_string rule, currently: *) 188 + | [^ '"' '\\' '\r' '\n']+ as s 189 + 190 + (* Change to allow UTF-8 when enabled. Need to track session state. *) 191 + (* Option 1: Always accept UTF-8, validate later *) 192 + | [^ '"' '\\' '\r' '\n']+ as s 193 + { Buffer.add_string string_buffer s; quoted_string lexbuf } 194 + 195 + (* The validation happens at command processing time based on session state *) 196 + ``` 197 + 198 + Note: The lexer is stateless, so UTF-8 validation should happen in the command handlers 199 + based on the session's `utf8_enabled` flag. 200 + 201 + #### Task 2.3: Add UTF8 APPEND Data Extension Parser 202 + **Files:** `lib/imapd/grammar.mly`, `lib/imapd/lexer.mll` 203 + 204 + Add new token and grammar rule: 205 + 206 + ```ocaml 207 + (* In lexer.mll keyword_table *) 208 + ("UTF8", UTF8); 209 + 210 + (* In grammar.mly *) 211 + %token UTF8 212 + 213 + append_message: 214 + | s = QUOTED_STRING { (s, false) } (* (message, is_utf8) *) 215 + | LITERAL_START { ("", false) } 216 + | LITERAL_START_PLUS { ("", false) } 217 + | UTF8 SP LPAREN n = LITERAL_START RPAREN { ("", true) } 218 + | UTF8 SP LPAREN n = LITERAL_START_PLUS RPAREN { ("", true) } 219 + ; 220 + ``` 221 + 222 + **Update protocol types:** 223 + ```ocaml 224 + (** APPEND command with UTF8 support. 225 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-4> RFC 6855 Section 4 *) 226 + | Append of { 227 + mailbox : mailbox_name; 228 + flags : flag list; 229 + date : string option; 230 + message : string; 231 + utf8 : bool; (** True if UTF8 data extension used *) 232 + } 233 + ``` 234 + 235 + ### Priority 3: Command Handler Updates 236 + 237 + #### Task 3.1: Update ENABLE Handler 238 + **Files:** `lib/imapd/server.ml` 239 + 240 + ```ocaml 241 + (** Process ENABLE command - RFC 5161, RFC 6855. 242 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 243 + let handle_enable flow tag ~capabilities state = 244 + match state with 245 + | Authenticated { username; utf8_enabled = _ } -> 246 + (* Filter to capabilities we actually support *) 247 + let enabled = List.filter (fun cap -> 248 + let cap_upper = String.uppercase_ascii cap in 249 + cap_upper = "IMAP4REV2" || cap_upper = "UTF8=ACCEPT" 250 + ) capabilities in 251 + let utf8_enabled = List.exists (fun cap -> 252 + String.uppercase_ascii cap = "UTF8=ACCEPT" 253 + ) enabled in 254 + if List.length enabled > 0 then 255 + send_response flow (Enabled enabled); 256 + send_response flow (Ok { tag = Some tag; code = None; text = "ENABLE completed" }); 257 + Authenticated { username; utf8_enabled } 258 + (* ... *) 259 + ``` 260 + 261 + #### Task 3.2: Update SEARCH Handler 262 + **Files:** `lib/imapd/server.ml` 263 + 264 + ```ocaml 265 + (** Process SEARCH command. 266 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 267 + - After ENABLE UTF8=ACCEPT, SEARCH with CHARSET is rejected *) 268 + let handle_search t flow tag ~charset ~criteria state = 269 + match state with 270 + | Selected { username; mailbox; utf8_enabled; _ } -> 271 + (* RFC 6855: After ENABLE UTF8=ACCEPT, reject CHARSET in SEARCH *) 272 + if utf8_enabled && Option.is_some charset then begin 273 + send_response flow (Bad { 274 + tag = Some tag; 275 + code = None; 276 + text = "CHARSET not allowed after ENABLE UTF8=ACCEPT" 277 + }); 278 + state 279 + end else 280 + (* ... existing search logic ... *) 281 + ``` 282 + 283 + #### Task 3.3: Update APPEND Handler 284 + **Files:** `lib/imapd/server.ml` 285 + 286 + ```ocaml 287 + (** Process APPEND command with UTF-8 support. 288 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-4> RFC 6855 Section 4 *) 289 + let handle_append t flow tag ~mailbox ~flags ~date ~message ~utf8 state = 290 + let username, utf8_enabled = match state with 291 + | Authenticated { username; utf8_enabled } -> Some username, utf8_enabled 292 + | Selected { username; utf8_enabled; _ } -> Some username, utf8_enabled 293 + | _ -> None, false 294 + in 295 + match username with 296 + | None -> (* ... error handling ... *) 297 + | Some username -> 298 + (* RFC 6855 Section 4: If UTF8=ACCEPT and client has NOT enabled it, 299 + reject APPEND with 8-bit characters in headers *) 300 + if has_non_ascii message && not utf8_enabled && not utf8 then begin 301 + send_response flow (No { 302 + tag = Some tag; 303 + code = None; 304 + text = "8-bit characters require ENABLE UTF8=ACCEPT or UTF8 data extension" 305 + }); 306 + state 307 + end else 308 + (* ... existing append logic ... *) 309 + ``` 310 + 311 + ### Priority 4: Response Generation Updates 312 + 313 + #### Task 4.1: UTF-8 in LIST/LSUB Responses 314 + **Files:** `lib/imapd/parser.ml` 315 + 316 + Mailbox names in LIST responses should use UTF-8 if the session has enabled it: 317 + 318 + ```ocaml 319 + (** Write LIST response with UTF-8 mailbox names if enabled. 320 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 321 + let write_list_response f ~utf8_enabled { flags; delimiter; name } = 322 + (* ... existing code ... *) 323 + (* If UTF-8 not enabled and name has non-ASCII, use modified UTF-7 *) 324 + let encoded_name = 325 + if utf8_enabled then name 326 + else encode_modified_utf7 name 327 + in 328 + write_quoted_string f encoded_name; 329 + (* ... *) 330 + ``` 331 + 332 + ### Priority 5: Client Library Updates 333 + 334 + #### Task 5.1: Add UTF-8 Support to Client 335 + **Files:** `lib/imap/client.ml`, `lib/imap/client.mli` 336 + 337 + ```ocaml 338 + (** Enable UTF-8 support per RFC 6855. 339 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 340 + val enable_utf8 : t -> bool 341 + (** [enable_utf8 client] enables UTF8=ACCEPT if supported. 342 + Returns [true] if successfully enabled. *) 343 + 344 + (** Append a message with UTF-8 headers. 345 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-4> RFC 6855 Section 4 *) 346 + val append_utf8 : t -> mailbox:string -> ?flags:Flag.t list -> ?date:string -> string -> int32 347 + (** [append_utf8 client ~mailbox message] appends [message] using the UTF8 data extension. 348 + Requires UTF8=ACCEPT capability. *) 349 + ``` 350 + 351 + ## OCamldoc Citation Templates 352 + 353 + Use these templates for RFC 6855 citations in the codebase: 354 + 355 + ### General UTF-8 Support 356 + ```ocaml 357 + (** ... description ... 358 + @see <https://datatracker.ietf.org/doc/html/rfc6855> RFC 6855: IMAP Support for UTF-8 *) 359 + ``` 360 + 361 + ### UTF8=ACCEPT Capability 362 + ```ocaml 363 + (** ... description ... 364 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3: UTF8=ACCEPT Capability *) 365 + ``` 366 + 367 + ### UTF8 APPEND Extension 368 + ```ocaml 369 + (** ... description ... 370 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-4> RFC 6855 Section 4: UTF8 APPEND Data Extension *) 371 + ``` 372 + 373 + ### UTF8=ONLY Capability 374 + ```ocaml 375 + (** ... description ... 376 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-6> RFC 6855 Section 6: UTF8=ONLY Capability *) 377 + ``` 378 + 379 + ### Mailbox Name Validation 380 + ```ocaml 381 + (** ... description ... 382 + Mailbox names MUST comply with Net-Unicode (RFC 5198 Section 2) excluding 383 + control characters U+0000-U+001F, U+0080-U+009F, U+007F, U+2028, U+2029. 384 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 385 + ``` 386 + 387 + ## Testing Plan 388 + 389 + ### Unit Tests 390 + 391 + ```ocaml 392 + (* test/test_utf8.ml *) 393 + 394 + let test_utf8_validation () = 395 + (* Valid UTF-8 *) 396 + assert (Utf8.is_valid_utf8 "Hello"); 397 + assert (Utf8.is_valid_utf8 "Cafe\xcc\x81"); (* Cafe with combining acute *) 398 + assert (Utf8.is_valid_utf8 "\xe4\xb8\xad\xe6\x96\x87"); (* Chinese characters *) 399 + 400 + (* Invalid UTF-8 *) 401 + assert (not (Utf8.is_valid_utf8 "\xff\xfe")); (* Invalid sequence *) 402 + assert (not (Utf8.is_valid_utf8 "\xc0\x80")); (* Overlong encoding *) 403 + 404 + let test_mailbox_name_validation () = 405 + assert (Utf8.is_valid_utf8_mailbox_name "INBOX"); 406 + assert (Utf8.is_valid_utf8_mailbox_name "Sent/2024"); 407 + assert (Utf8.is_valid_utf8_mailbox_name "\xe5\x8f\x91\xe4\xbb\xb6\xe7\xae\xb1"); (* Chinese "Sent" *) 408 + 409 + (* Invalid: control characters *) 410 + assert (not (Utf8.is_valid_utf8_mailbox_name "INBOX\x00")); 411 + assert (not (Utf8.is_valid_utf8_mailbox_name "Test\x1f")); 412 + 413 + (* Invalid: line/paragraph separators *) 414 + assert (not (Utf8.is_valid_utf8_mailbox_name "Test\xe2\x80\xa8Name")); (* U+2028 *) 415 + assert (not (Utf8.is_valid_utf8_mailbox_name "Test\xe2\x80\xa9Name")); (* U+2029 *) 416 + ``` 417 + 418 + ### Integration Tests 419 + 420 + ```ocaml 421 + (* test/integration/test_utf8_integration.ml *) 422 + 423 + let test_enable_utf8 ~sw ~env ~config () = 424 + with_client ~sw ~env ~config (fun client -> 425 + let caps = Imap.Client.capability client in 426 + if List.mem "UTF8=ACCEPT" caps then begin 427 + let enabled = Imap.Client.enable client ["UTF8=ACCEPT"] in 428 + assert (List.mem "UTF8=ACCEPT" enabled) 429 + end) 430 + 431 + let test_append_utf8_message ~sw ~env ~config () = 432 + with_test_mailbox ~sw ~env ~config (fun client mailbox -> 433 + if has_capability client "UTF8=ACCEPT" then begin 434 + let _ = Imap.Client.enable client ["UTF8=ACCEPT"] in 435 + (* Message with UTF-8 Subject header *) 436 + let message = 437 + "Subject: =?UTF-8?B?VGVzdCDwn46J?=\r\n" ^ 438 + "From: test@example.com\r\n" ^ 439 + "\r\n" ^ 440 + "Test body\r\n" 441 + in 442 + let uid = Imap.Client.append client ~mailbox message in 443 + assert (uid > 0l) 444 + end) 445 + 446 + let test_search_charset_rejected_after_utf8 ~sw ~env ~config () = 447 + with_test_mailbox ~sw ~env ~config (fun client mailbox -> 448 + if has_capability client "UTF8=ACCEPT" then begin 449 + let _ = Imap.Client.enable client ["UTF8=ACCEPT"] in 450 + (* SEARCH with CHARSET should be rejected *) 451 + try 452 + let _ = Imap.Client.search client ~charset:"UTF-8" Search.All in 453 + assert false (* Should have raised *) 454 + with Imap.Error.Bad _ -> () 455 + end) 456 + ``` 457 + 458 + ## Implementation Priority Summary 459 + 460 + | Priority | Task | Effort | Files | 461 + |----------|------|--------|-------| 462 + | P1 | Session UTF-8 state tracking | Low | server.ml, protocol.ml | 463 + | P1 | Add UTF8=ACCEPT to capabilities | Low | server.ml | 464 + | P2 | UTF-8 validation functions | Medium | utf8.ml (new) | 465 + | P2 | Lexer UTF-8 in quoted strings | Medium | lexer.mll | 466 + | P2 | UTF8 APPEND grammar | Medium | grammar.mly, lexer.mll | 467 + | P3 | ENABLE handler update | Low | server.ml | 468 + | P3 | SEARCH charset restriction | Low | server.ml | 469 + | P3 | APPEND 8-bit rejection | Low | server.ml | 470 + | P4 | LIST/LSUB UTF-8 responses | Medium | parser.ml | 471 + | P5 | Client library UTF-8 support | Medium | client.ml, client.mli | 472 + 473 + ## Dependencies 474 + 475 + ### External Dependencies 476 + 477 + None required. UTF-8 validation can be implemented using standard OCaml string operations 478 + or the `uutf` library if more sophisticated Unicode handling is needed. 479 + 480 + ### Internal Dependencies 481 + 482 + - Task 2.2 (lexer) depends on Task 2.1 (validation) 483 + - Tasks 3.1-3.3 (handlers) depend on Task 1.1 (state tracking) 484 + - Task 4.1 (responses) depends on Task 1.1 (state tracking) 485 + - Task 5.1 (client) depends on Tasks 2.2-2.3 (parser changes) 486 + 487 + ## Related RFCs 488 + 489 + | RFC | Title | Relevance | 490 + |-----|-------|-----------| 491 + | RFC 6855 | IMAP Support for UTF-8 | Primary specification | 492 + | RFC 3629 | UTF-8, a transformation format of ISO 10646 | UTF-8 encoding rules | 493 + | RFC 5198 | Unicode Format for Network Interchange | Net-Unicode requirements | 494 + | RFC 5161 | The IMAP ENABLE Extension | ENABLE command | 495 + | RFC 4466 | Collected Extensions to IMAP4 ABNF | literal8 definition | 496 + | RFC 9051 | IMAP4rev2 | Base protocol (already uses UTF-8) | 497 + 498 + ## Notes 499 + 500 + 1. **RFC 9051 Compatibility**: IMAP4rev2 (RFC 9051) already mandates UTF-8 support in many places. 501 + This plan focuses on the explicit `UTF8=ACCEPT` capability and related features. 502 + 503 + 2. **Downgrading**: RFC 6855 Section 7 discusses dealing with legacy clients. This is optional 504 + and not included in this initial implementation plan. 505 + 506 + 3. **UTF8=ONLY**: The `UTF8=ONLY` capability is more aggressive and could be implemented as a 507 + follow-on after `UTF8=ACCEPT` is stable. 508 + 509 + 4. **SORT/THREAD**: RFC 5256 (SORT/THREAD) requires UTF-8 charset support. The existing SORT 510 + implementation should work correctly once UTF8=ACCEPT is enabled.
+718
spec/PLAN-rfc9208.md
··· 1 + # RFC 9208 - IMAP QUOTA Extension Implementation Plan 2 + 3 + This document provides a detailed implementation plan for adding RFC 9208 (IMAP QUOTA Extension) support to the ocaml-imap library. 4 + 5 + ## RFC Summary 6 + 7 + **RFC 9208** (March 2022) defines the IMAP QUOTA extension, which permits administrative limits on resource usage to be manipulated through the IMAP protocol. It obsoletes RFC 2087 while maintaining backward compatibility. 8 + 9 + ### Key RFC References 10 + 11 + - Full specification: [RFC 9208](https://datatracker.ietf.org/doc/html/rfc9208) 12 + - Section 4.1 - Commands (GETQUOTA, GETQUOTAROOT, SETQUOTA) 13 + - Section 4.2 - Responses (QUOTA, QUOTAROOT) 14 + - Section 4.3 - Response Codes (OVERQUOTA) 15 + - Section 5 - Resource Type Definitions 16 + - Section 7 - Formal Syntax 17 + 18 + ## RFC Requirements 19 + 20 + ### Commands 21 + 22 + #### GETQUOTA (Section 4.1.1) 23 + ``` 24 + Arguments: quota root 25 + 26 + Responses: REQUIRED untagged responses: QUOTA 27 + 28 + Result: OK - getquota completed 29 + NO - getquota error: no such quota root, permission denied 30 + BAD - command unknown or arguments invalid 31 + ``` 32 + 33 + Example: 34 + ``` 35 + C: G0001 GETQUOTA "!partition/sda4" 36 + S: * QUOTA "!partition/sda4" (STORAGE 104 10923847) 37 + S: G0001 OK Getquota complete 38 + ``` 39 + 40 + #### GETQUOTAROOT (Section 4.1.2) 41 + ``` 42 + Arguments: mailbox name 43 + 44 + Responses: REQUIRED untagged responses: QUOTAROOT, QUOTA 45 + 46 + Result: OK - getquotaroot completed 47 + NO - getquotaroot error: permission denied 48 + BAD - command unknown or arguments invalid 49 + ``` 50 + 51 + Example: 52 + ``` 53 + C: G0002 GETQUOTAROOT INBOX 54 + S: * QUOTAROOT INBOX "#user/alice" "!partition/sda4" 55 + S: * QUOTA "#user/alice" (MESSAGE 42 1000) 56 + S: * QUOTA "!partition/sda4" (STORAGE 104 10923847) 57 + S: G0002 OK Getquotaroot complete 58 + ``` 59 + 60 + #### SETQUOTA (Section 4.1.3) 61 + ``` 62 + Arguments: quota root, list of resource limits 63 + 64 + Responses: untagged responses: QUOTA 65 + 66 + Result: OK - setquota completed 67 + NO - setquota error: can't set that data 68 + BAD - command unknown or arguments invalid 69 + ``` 70 + 71 + **Note:** Requires "QUOTASET" capability to be advertised. 72 + 73 + Example: 74 + ``` 75 + C: S0001 SETQUOTA "#user/alice" (STORAGE 510) 76 + S: * QUOTA "#user/alice" (STORAGE 58 512) 77 + S: S0001 OK Rounded quota 78 + ``` 79 + 80 + ### New STATUS Attributes (Section 4.1.4) 81 + 82 + | Attribute | Description | Required When | 83 + |-----------|-------------|---------------| 84 + | `DELETED` | Number of messages with \Deleted flag | QUOTA=RES-MESSAGE capability | 85 + | `DELETED-STORAGE` | Storage reclaimable by EXPUNGE | QUOTA=RES-STORAGE capability | 86 + 87 + ### Responses 88 + 89 + #### QUOTA Response (Section 4.2.1) 90 + ``` 91 + Data: quota root name 92 + list of resource names, usages, and limits 93 + ``` 94 + 95 + Format: `* QUOTA <quota-root> (<resource> <usage> <limit> ...)` 96 + 97 + #### QUOTAROOT Response (Section 4.2.2) 98 + ``` 99 + Data: mailbox name 100 + zero or more quota root names 101 + ``` 102 + 103 + Format: `* QUOTAROOT <mailbox> [<quota-root> ...]` 104 + 105 + ### Response Codes 106 + 107 + #### OVERQUOTA (Section 4.3.1) 108 + 109 + The OVERQUOTA response code SHOULD be returned in: 110 + - Tagged NO response to APPEND/COPY/MOVE when quota exceeded 111 + - Untagged NO response when soft quota exceeded 112 + 113 + **Note:** `Code_overquota` already exists in `protocol.ml` (line 257). 114 + 115 + ### Resource Types (Section 5) 116 + 117 + | Resource | Capability | Description | Unit | 118 + |----------|------------|-------------|------| 119 + | STORAGE | QUOTA=RES-STORAGE | Physical space estimate | 1024 octets (KB) | 120 + | MESSAGE | QUOTA=RES-MESSAGE | Number of messages | Count | 121 + | MAILBOX | QUOTA=RES-MAILBOX | Number of mailboxes | Count | 122 + | ANNOTATION-STORAGE | QUOTA=RES-ANNOTATION-STORAGE | Annotation size | 1024 octets (KB) | 123 + 124 + ### Capability Strings 125 + 126 + - `QUOTA` - Basic quota support (RFC 2087 compatible) 127 + - `QUOTA=RES-STORAGE` - STORAGE resource type support 128 + - `QUOTA=RES-MESSAGE` - MESSAGE resource type support 129 + - `QUOTA=RES-MAILBOX` - MAILBOX resource type support 130 + - `QUOTA=RES-ANNOTATION-STORAGE` - ANNOTATION-STORAGE resource type support 131 + - `QUOTASET` - SETQUOTA command support 132 + 133 + ## Current Implementation Status 134 + 135 + ### Already Implemented 136 + - `Code_overquota` response code in `protocol.ml` (line 257) 137 + - `Storage.Quota_exceeded` error variant in `storage.ml` (line 19) 138 + - OVERQUOTA serialization in `parser.ml` (line 159) 139 + 140 + ### Not Implemented 141 + - GETQUOTA command 142 + - GETQUOTAROOT command 143 + - SETQUOTA command 144 + - QUOTA response 145 + - QUOTAROOT response 146 + - Resource type definitions 147 + - Quota tracking in storage backends 148 + - DELETED and DELETED-STORAGE STATUS attributes 149 + - QUOTA capabilities 150 + 151 + ## Implementation Tasks 152 + 153 + ### Priority 1: Core Types and Protocol (Effort: Low) 154 + 155 + #### Task 1.1: Add Quota Types to Protocol 156 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/protocol.ml` 157 + 158 + ```ocaml 159 + (** {1 QUOTA Types} 160 + 161 + See {{:https://datatracker.ietf.org/doc/html/rfc9208}RFC 9208}. *) 162 + 163 + (** Quota resource types. 164 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5}RFC 9208 Section 5}. *) 165 + type quota_resource = 166 + | Quota_storage (** STORAGE - physical space in KB *) 167 + | Quota_message (** MESSAGE - number of messages *) 168 + | Quota_mailbox (** MAILBOX - number of mailboxes *) 169 + | Quota_annotation_storage (** ANNOTATION-STORAGE - annotation size in KB *) 170 + 171 + (** A single quota resource with usage and limit. 172 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.2.1}RFC 9208 Section 4.2.1}. *) 173 + type quota_resource_info = { 174 + resource : quota_resource; 175 + usage : int64; (** Current usage (63-bit unsigned) *) 176 + limit : int64; (** Resource limit (63-bit unsigned) *) 177 + } 178 + 179 + (** Quota root information. 180 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-3.2}RFC 9208 Section 3.2}. *) 181 + type quota_root = string 182 + ``` 183 + 184 + #### Task 1.2: Add Quota Commands to Protocol 185 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/protocol.ml` 186 + 187 + Add to the `command` type: 188 + ```ocaml 189 + | Getquota of quota_root 190 + (** {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.1}RFC 9208 Section 4.1.1} *) 191 + | Getquotaroot of mailbox_name 192 + (** {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.2}RFC 9208 Section 4.1.2} *) 193 + | Setquota of { root : quota_root; limits : (quota_resource * int64) list } 194 + (** {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.3}RFC 9208 Section 4.1.3} *) 195 + ``` 196 + 197 + #### Task 1.3: Add Quota Responses to Protocol 198 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/protocol.ml` 199 + 200 + Add to the `response` type: 201 + ```ocaml 202 + | Quota_response of { root : quota_root; resources : quota_resource_info list } 203 + (** {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.2.1}RFC 9208 Section 4.2.1} *) 204 + | Quotaroot_response of { mailbox : mailbox_name; roots : quota_root list } 205 + (** {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.2.2}RFC 9208 Section 4.2.2} *) 206 + ``` 207 + 208 + #### Task 1.4: Add New STATUS Items 209 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/protocol.ml` 210 + 211 + Add to the `status_item` type: 212 + ```ocaml 213 + | Status_deleted_storage 214 + (** DELETED-STORAGE - storage reclaimable by EXPUNGE. 215 + {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.4}RFC 9208 Section 4.1.4} *) 216 + ``` 217 + 218 + **Note:** `Status_deleted` already exists for RFC 9051 compliance. 219 + 220 + ### Priority 2: Storage Backend Interface (Effort: Medium) 221 + 222 + #### Task 2.1: Add Quota Operations to Storage Signature 223 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/storage.mli` 224 + 225 + Add to `module type STORAGE`: 226 + ```ocaml 227 + (** {2 Quota Operations} 228 + 229 + See {{:https://datatracker.ietf.org/doc/html/rfc9208}RFC 9208}. *) 230 + 231 + val get_quota_roots : t -> username:string -> mailbox_name -> quota_root list 232 + (** Get quota roots for a mailbox. 233 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.2}RFC 9208 Section 4.1.2}. *) 234 + 235 + val get_quota : t -> username:string -> quota_root -> (quota_resource_info list, error) result 236 + (** Get quota information for a quota root. 237 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.1}RFC 9208 Section 4.1.1}. *) 238 + 239 + val set_quota : t -> username:string -> quota_root -> (quota_resource * int64) list -> (quota_resource_info list, error) result 240 + (** Set quota limits for a quota root. 241 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.3}RFC 9208 Section 4.1.3}. 242 + Returns the actual limits after any server-side rounding. *) 243 + 244 + val check_quota : t -> username:string -> mailbox_name -> additional_size:int64 -> bool 245 + (** Check if an operation would exceed quota. 246 + Used before APPEND/COPY/MOVE operations. *) 247 + ``` 248 + 249 + #### Task 2.2: Add Quota Error Variants 250 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/storage.ml` 251 + 252 + Add to `type error`: 253 + ```ocaml 254 + | Quota_root_not_found 255 + | Quota_cannot_set (** Cannot modify this quota (system limit) *) 256 + ``` 257 + 258 + #### Task 2.3: Implement Memory Storage Quota 259 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/storage.ml` 260 + 261 + Add to `Memory_storage`: 262 + ```ocaml 263 + (* Quota state per user *) 264 + type user_quota = { 265 + mutable storage_limit : int64 option; (* KB *) 266 + mutable message_limit : int64 option; 267 + mutable mailbox_limit : int64 option; 268 + } 269 + 270 + (* In user_data type *) 271 + type user_data = { 272 + mailboxes : (mailbox_name, mailbox) Hashtbl.t; 273 + subscriptions : mailbox_name list; 274 + quota : user_quota; 275 + } 276 + 277 + (* Quota root is "#user/<username>" for per-user quotas *) 278 + let get_quota_roots _t ~username mailbox = 279 + if Hashtbl.mem (get_user t ~username).mailboxes mailbox then 280 + ["#user/" ^ username] 281 + else 282 + [] 283 + 284 + let calculate_storage_usage t ~username = 285 + let user = get_user t ~username in 286 + Hashtbl.fold (fun _ mb acc -> 287 + List.fold_left (fun acc (m : message) -> 288 + Int64.add acc (Int64.div (Int64.add m.size 1023L) 1024L) 289 + ) acc mb.messages 290 + ) user.mailboxes 0L 291 + 292 + let calculate_message_count t ~username = 293 + let user = get_user t ~username in 294 + Int64.of_int (Hashtbl.fold (fun _ mb acc -> 295 + acc + List.length mb.messages 296 + ) user.mailboxes 0) 297 + 298 + let calculate_mailbox_count t ~username = 299 + let user = get_user t ~username in 300 + Int64.of_int (Hashtbl.length user.mailboxes) 301 + ``` 302 + 303 + #### Task 2.4: Implement Maildir Storage Quota 304 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/storage.ml` 305 + 306 + Add to `Maildir_storage`: 307 + ```ocaml 308 + (* Quota can be stored in a .quota file or calculated from filesystem *) 309 + let quota_file_path path = Filename.concat path ".imapd-quota" 310 + 311 + (* Calculate actual storage usage by walking the maildir *) 312 + let calculate_storage_usage t ~username = 313 + let base = user_path t ~username in 314 + (* Walk all maildirs and sum file sizes *) 315 + ... 316 + 317 + (* For production, consider: 318 + - Caching quota calculations 319 + - Using filesystem quotas (statfs) 320 + - Storing limits in a database *) 321 + ``` 322 + 323 + ### Priority 3: Parser and Serializer (Effort: Medium) 324 + 325 + #### Task 3.1: Add Lexer Tokens 326 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/lexer.mll` 327 + 328 + Add keyword recognition: 329 + ```ocaml 330 + | "GETQUOTA" -> GETQUOTA 331 + | "GETQUOTAROOT" -> GETQUOTAROOT 332 + | "SETQUOTA" -> SETQUOTA 333 + | "STORAGE" -> STORAGE 334 + | "MESSAGE" -> MESSAGE_RESOURCE 335 + | "MAILBOX" -> MAILBOX_RESOURCE 336 + | "ANNOTATION-STORAGE" -> ANNOTATION_STORAGE 337 + ``` 338 + 339 + #### Task 3.2: Add Grammar Rules 340 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/grammar.mly` 341 + 342 + ``` 343 + quota_command: 344 + | GETQUOTA astring 345 + { Getquota $2 } 346 + | GETQUOTAROOT mailbox 347 + { Getquotaroot $2 } 348 + | SETQUOTA astring LPAREN setquota_list RPAREN 349 + { Setquota { root = $2; limits = $4 } } 350 + ; 351 + 352 + setquota_list: 353 + | /* empty */ { [] } 354 + | setquota_resource setquota_list { $1 :: $2 } 355 + ; 356 + 357 + setquota_resource: 358 + | resource_name NUMBER64 { ($1, $2) } 359 + ; 360 + 361 + resource_name: 362 + | STORAGE { Quota_storage } 363 + | MESSAGE_RESOURCE { Quota_message } 364 + | MAILBOX_RESOURCE { Quota_mailbox } 365 + | ANNOTATION_STORAGE { Quota_annotation_storage } 366 + ; 367 + ``` 368 + 369 + #### Task 3.3: Add Response Serialization 370 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/parser.ml` 371 + 372 + Add to `serialize_response`: 373 + ```ocaml 374 + | Quota_response { root; resources } -> 375 + write_string f "* QUOTA "; 376 + write_quoted_string f root; 377 + write_string f " ("; 378 + List.iteri (fun i { resource; usage; limit } -> 379 + if i > 0 then write_sp f; 380 + (match resource with 381 + | Quota_storage -> write_string f "STORAGE" 382 + | Quota_message -> write_string f "MESSAGE" 383 + | Quota_mailbox -> write_string f "MAILBOX" 384 + | Quota_annotation_storage -> write_string f "ANNOTATION-STORAGE"); 385 + write_sp f; 386 + write_string f (Int64.to_string usage); 387 + write_sp f; 388 + write_string f (Int64.to_string limit) 389 + ) resources; 390 + write_char f ')'; 391 + write_crlf f 392 + 393 + | Quotaroot_response { mailbox; roots } -> 394 + write_string f "* QUOTAROOT "; 395 + write_quoted_string f mailbox; 396 + List.iter (fun root -> 397 + write_sp f; 398 + write_quoted_string f root 399 + ) roots; 400 + write_crlf f 401 + ``` 402 + 403 + ### Priority 4: Server Command Handlers (Effort: Medium) 404 + 405 + #### Task 4.1: Add Capability Advertisement 406 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 407 + 408 + Update capabilities: 409 + ```ocaml 410 + let quota_capabilities = [ 411 + "QUOTA"; 412 + "QUOTA=RES-STORAGE"; 413 + "QUOTA=RES-MESSAGE"; 414 + "QUOTA=RES-MAILBOX"; 415 + (* "QUOTASET"; Add if SETQUOTA is supported *) 416 + ] 417 + 418 + let base_capabilities_pre_tls = [ 419 + (* existing capabilities *) 420 + ] @ quota_capabilities 421 + ``` 422 + 423 + #### Task 4.2: Implement GETQUOTA Handler 424 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 425 + 426 + ```ocaml 427 + (** Handle GETQUOTA command. 428 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.1}RFC 9208 Section 4.1.1}. *) 429 + let handle_getquota t flow tag root state = 430 + let username = match state with 431 + | Authenticated { username } -> Some username 432 + | Selected { username; _ } -> Some username 433 + | _ -> None 434 + in 435 + match username with 436 + | None -> 437 + send_response flow (Bad { 438 + tag = Some tag; code = None; 439 + text = "Command not valid in this state" 440 + }); 441 + state 442 + | Some username -> 443 + match Storage.get_quota t.storage ~username root with 444 + | Error Storage_types.Quota_root_not_found -> 445 + send_response flow (No { 446 + tag = Some tag; code = Some Code_nonexistent; 447 + text = "No such quota root" 448 + }); 449 + state 450 + | Error _ -> 451 + send_response flow (No { 452 + tag = Some tag; code = None; 453 + text = "GETQUOTA failed" 454 + }); 455 + state 456 + | Ok resources -> 457 + send_response flow (Quota_response { root; resources }); 458 + send_response flow (Ok { 459 + tag = Some tag; code = None; 460 + text = "GETQUOTA completed" 461 + }); 462 + state 463 + ``` 464 + 465 + #### Task 4.3: Implement GETQUOTAROOT Handler 466 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 467 + 468 + ```ocaml 469 + (** Handle GETQUOTAROOT command. 470 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.2}RFC 9208 Section 4.1.2}. *) 471 + let handle_getquotaroot t flow tag mailbox state = 472 + let username = match state with 473 + | Authenticated { username } -> Some username 474 + | Selected { username; _ } -> Some username 475 + | _ -> None 476 + in 477 + match username with 478 + | None -> 479 + send_response flow (Bad { 480 + tag = Some tag; code = None; 481 + text = "Command not valid in this state" 482 + }); 483 + state 484 + | Some username -> 485 + (* Security: Validate mailbox name *) 486 + if not (Protocol.is_safe_mailbox_name mailbox) then begin 487 + send_response flow (No { 488 + tag = Some tag; code = None; 489 + text = "Invalid mailbox name" 490 + }); 491 + state 492 + end else begin 493 + let roots = Storage.get_quota_roots t.storage ~username mailbox in 494 + (* Send QUOTAROOT response *) 495 + send_response flow (Quotaroot_response { mailbox; roots }); 496 + (* Send QUOTA response for each root *) 497 + List.iter (fun root -> 498 + match Storage.get_quota t.storage ~username root with 499 + | Ok resources -> 500 + send_response flow (Quota_response { root; resources }) 501 + | Error _ -> () 502 + ) roots; 503 + send_response flow (Ok { 504 + tag = Some tag; code = None; 505 + text = "GETQUOTAROOT completed" 506 + }); 507 + state 508 + end 509 + ``` 510 + 511 + #### Task 4.4: Implement SETQUOTA Handler 512 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 513 + 514 + ```ocaml 515 + (** Handle SETQUOTA command. 516 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.3}RFC 9208 Section 4.1.3}. 517 + Requires QUOTASET capability. *) 518 + let handle_setquota t flow tag ~root ~limits state = 519 + let username = match state with 520 + | Authenticated { username } -> Some username 521 + | Selected { username; _ } -> Some username 522 + | _ -> None 523 + in 524 + match username with 525 + | None -> 526 + send_response flow (Bad { 527 + tag = Some tag; code = None; 528 + text = "Command not valid in this state" 529 + }); 530 + state 531 + | Some username -> 532 + match Storage.set_quota t.storage ~username root limits with 533 + | Error Storage_types.Quota_root_not_found -> 534 + send_response flow (No { 535 + tag = Some tag; code = Some Code_nonexistent; 536 + text = "No such quota root" 537 + }); 538 + state 539 + | Error Storage_types.Quota_cannot_set -> 540 + send_response flow (No { 541 + tag = Some tag; code = Some Code_cannot; 542 + text = "Cannot change system limit" 543 + }); 544 + state 545 + | Error _ -> 546 + send_response flow (No { 547 + tag = Some tag; code = None; 548 + text = "SETQUOTA failed" 549 + }); 550 + state 551 + | Ok resources -> 552 + send_response flow (Quota_response { root; resources }); 553 + send_response flow (Ok { 554 + tag = Some tag; code = None; 555 + text = "SETQUOTA completed" 556 + }); 557 + state 558 + ``` 559 + 560 + #### Task 4.5: Add Quota Checks to APPEND/COPY/MOVE 561 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/lib/imapd/server.ml` 562 + 563 + Update `handle_append`: 564 + ```ocaml 565 + let handle_append t flow tag ~mailbox ~flags ~date ~message state = 566 + (* ... existing validation ... *) 567 + (* Check quota before appending *) 568 + let message_size = Int64.of_int (String.length message) in 569 + if not (Storage.check_quota t.storage ~username ~mailbox ~additional_size:message_size) then begin 570 + send_response flow (No { 571 + tag = Some tag; 572 + code = Some Code_overquota; 573 + text = "APPEND failed: quota exceeded" 574 + }); 575 + state 576 + end else 577 + (* ... existing append logic ... *) 578 + ``` 579 + 580 + Similar changes needed for `handle_copy` and `handle_move`. 581 + 582 + ### Priority 5: Testing (Effort: Medium) 583 + 584 + #### Task 5.1: Unit Tests for Quota Types 585 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/test/test_quota.ml` 586 + 587 + ```ocaml 588 + let test_quota_resource_string () = 589 + Alcotest.(check string) "STORAGE" "STORAGE" 590 + (quota_resource_to_string Quota_storage); 591 + Alcotest.(check string) "MESSAGE" "MESSAGE" 592 + (quota_resource_to_string Quota_message) 593 + 594 + let test_quota_response_format () = 595 + let resp = Quota_response { 596 + root = "#user/alice"; 597 + resources = [ 598 + { resource = Quota_storage; usage = 104L; limit = 10923847L }; 599 + { resource = Quota_message; usage = 42L; limit = 1000L }; 600 + ] 601 + } in 602 + let expected = "* QUOTA \"#user/alice\" (STORAGE 104 10923847 MESSAGE 42 1000)\r\n" in 603 + Alcotest.(check string) "quota response" expected (response_to_string resp) 604 + ``` 605 + 606 + #### Task 5.2: Integration Tests 607 + **File:** `/Users/avsm/src/git/tangled/anil/mono/ocaml-imap/test/test_server.ml` 608 + 609 + ```ocaml 610 + let test_getquotaroot () = 611 + (* Setup *) 612 + let storage = Memory_storage.create () in 613 + Memory_storage.add_test_user storage ~username:"alice"; 614 + (* Test GETQUOTAROOT command *) 615 + let cmd = { tag = "Q001"; command = Getquotaroot "INBOX" } in 616 + (* Verify QUOTAROOT and QUOTA responses *) 617 + ... 618 + 619 + let test_quota_exceeded () = 620 + (* Setup with low quota *) 621 + let storage = Memory_storage.create () in 622 + Memory_storage.add_test_user storage ~username:"alice"; 623 + Memory_storage.set_quota storage ~username:"alice" ~storage_limit:(Some 1L); 624 + (* Test APPEND when over quota *) 625 + let large_message = String.make 2048 'X' in 626 + let cmd = Append { mailbox = "INBOX"; flags = []; date = None; message = large_message } in 627 + (* Verify OVERQUOTA response *) 628 + ... 629 + ``` 630 + 631 + ## OCamldoc Citation Templates 632 + 633 + Use these templates when documenting quota-related code: 634 + 635 + ### Module-level documentation 636 + ```ocaml 637 + (** IMAP QUOTA Extension 638 + 639 + Implements {{:https://datatracker.ietf.org/doc/html/rfc9208}RFC 9208} for 640 + managing administrative limits on resource usage through the IMAP protocol. 641 + 642 + {2 References} 643 + {ul 644 + {- {{:https://datatracker.ietf.org/doc/html/rfc9208}RFC 9208} - IMAP QUOTA Extension} 645 + {- {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5}RFC 9208 Section 5} - Resource Type Definitions} 646 + {- {{:https://datatracker.ietf.org/doc/html/rfc9208#section-7}RFC 9208 Section 7} - Formal Syntax}} *) 647 + ``` 648 + 649 + ### Type documentation 650 + ```ocaml 651 + (** Quota resource type. 652 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5}RFC 9208 Section 5}. *) 653 + type quota_resource = ... 654 + 655 + (** Quota root name. 656 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-3.2}RFC 9208 Section 3.2}. *) 657 + type quota_root = string 658 + ``` 659 + 660 + ### Function documentation 661 + ```ocaml 662 + (** Get quota information for a quota root. 663 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1.1}RFC 9208 Section 4.1.1}. 664 + 665 + @param root The quota root name 666 + @return List of resource information or error *) 667 + val get_quota : ... 668 + ``` 669 + 670 + ## Implementation Priority Order 671 + 672 + | Priority | Task | Effort | Dependencies | 673 + |----------|------|--------|--------------| 674 + | P1 | 1.1-1.4 Protocol types | Low | None | 675 + | P2 | 3.1-3.3 Parser/Serializer | Medium | P1 | 676 + | P2 | 2.1-2.2 Storage interface | Low | P1 | 677 + | P3 | 2.3 Memory storage quota | Medium | P2 | 678 + | P3 | 4.1 Capability advertisement | Low | P1 | 679 + | P3 | 4.2-4.4 Command handlers | Medium | P2 | 680 + | P4 | 4.5 Quota enforcement | Medium | P3 | 681 + | P4 | 2.4 Maildir storage quota | High | P2 | 682 + | P5 | 5.1-5.2 Tests | Medium | P4 | 683 + 684 + ## File Modification Summary 685 + 686 + | File | Changes | 687 + |------|---------| 688 + | `lib/imapd/protocol.ml` | Add quota types, commands, responses | 689 + | `lib/imapd/protocol.mli` | Add quota type signatures | 690 + | `lib/imapd/storage.ml` | Add quota operations to backends | 691 + | `lib/imapd/storage.mli` | Add quota signatures to STORAGE | 692 + | `lib/imapd/lexer.mll` | Add quota-related tokens | 693 + | `lib/imapd/grammar.mly` | Add quota command grammar | 694 + | `lib/imapd/parser.ml` | Add quota response serialization | 695 + | `lib/imapd/server.ml` | Add command handlers, capabilities | 696 + | `test/test_quota.ml` | New file for quota tests | 697 + | `test/test_server.ml` | Add quota integration tests | 698 + 699 + ## Open Design Questions 700 + 701 + 1. **Quota Root Naming**: Should we use `#user/<username>` for per-user quotas or support hierarchical quota roots? 702 + 703 + 2. **Maildir Quota Storage**: Where should quota limits be stored? 704 + - Option A: `.imapd-quota` file in user's maildir 705 + - Option B: Separate database/file 706 + - Option C: Use filesystem quotas (via statfs) 707 + 708 + 3. **QUOTASET Permission**: Should all authenticated users be able to set quotas, or only administrators? 709 + 710 + 4. **Soft vs Hard Quotas**: Should we support both soft quotas (warning) and hard quotas (rejection)? 711 + 712 + 5. **ANNOTATION-STORAGE**: Do we plan to implement RFC 5257 (ANNOTATE)? If not, should we still advertise QUOTA=RES-ANNOTATION-STORAGE? 713 + 714 + ## Related Work 715 + 716 + - **RFC 9051** - IMAP4rev2 (core protocol, already implemented) 717 + - **RFC 4314** - IMAP ACL Extension (for quota permission checks) 718 + - **RFC 5257** - ANNOTATE Extension (for ANNOTATION-STORAGE resource)
+838
spec/PLAN-unified-mail-flag.md
··· 1 + # Unified Mail Flag Library Implementation Plan 2 + 3 + ## Overview 4 + 5 + This plan describes the creation of a shared `mail-flag` library that provides unified flag/keyword and mailbox attribute handling for both IMAP (`ocaml-imap`) and JMAP (`ocaml-jmap`) protocols. 6 + 7 + **Specification References:** 8 + - {{:https://datatracker.ietf.org/doc/html/rfc9051}RFC 9051} - IMAP4rev2 (system flags) 9 + - {{:https://datatracker.ietf.org/doc/html/rfc8621}RFC 8621} - JMAP Mail (keywords) 10 + - {{:https://datatracker.ietf.org/doc/html/rfc6154}RFC 6154} - Special-Use Mailboxes 11 + - {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute}draft-ietf-mailmaint-messageflag-mailboxattribute-13} - Extended keywords and attributes 12 + 13 + ## Current State Analysis 14 + 15 + ### ocaml-imap (`lib/imap/flag.ml`) 16 + ```ocaml 17 + type system = Seen | Answered | Flagged | Deleted | Draft 18 + 19 + type t = 20 + | System of system 21 + | Keyword of string (* stored without $ prefix *) 22 + ``` 23 + - System flags use `\` prefix on wire: `\Seen`, `\Flagged` 24 + - Keywords use `$` prefix on wire: `$Forwarded` 25 + - Keywords stored internally without prefix (normalization) 26 + - No typed support for standard keywords 27 + 28 + ### ocaml-imap (`lib/imap/list_attr.ml`) 29 + ```ocaml 30 + type t = 31 + | Noinferiors | Noselect | Marked | Unmarked | Subscribed 32 + | Haschildren | Hasnochildren 33 + | All | Archive | Drafts | Flagged | Junk | Sent | Trash 34 + | Extension of string 35 + ``` 36 + - Missing: `Important`, `Snoozed`, `Scheduled`, `Memos` 37 + - Uses `\` prefix on wire 38 + 39 + ### ocaml-jmap (`lib/core/jmap_types.ml`) 40 + ```ocaml 41 + type standard = [`Seen | `Flagged | `Answered | `Draft | `Forwarded | `Phishing | `Junk | `NotJunk] 42 + type extended = [`Notify | `Muted | `Followed | `Memo | ... ] 43 + type flag_bits = [`MailFlagBit0 | `MailFlagBit1 | `MailFlagBit2] 44 + type t = [standard | extended | flag_bits | `Custom of string] 45 + ``` 46 + - Fully typed keywords with polymorphic variants 47 + - Already has draft-ietf-mailmaint support 48 + - Flag color encoding implemented 49 + 50 + ### ocaml-jmap (`lib/mail/mail_mailbox.ml`) 51 + ```ocaml 52 + type role = [`All | `Archive | `Drafts | ... | `Snoozed | `Scheduled | `Memos | `Other of string] 53 + ``` 54 + - Has draft-ietf-mailmaint roles 55 + 56 + ## Design Goals 57 + 58 + 1. **Single Source of Truth**: One library defining all keywords and attributes 59 + 2. **Type Safety**: Typed variants for known keywords, extensible for custom 60 + 3. **Protocol Agnostic Core**: Types work for both IMAP and JMAP 61 + 4. **Wire Format Adapters**: Protocol-specific serialization modules 62 + 5. **Zero Breaking Changes**: Maintain backward compatibility with existing APIs 63 + 64 + ## Library Structure 65 + 66 + ``` 67 + mail-flag/ 68 + ├── dune 69 + ├── mail_flag.opam 70 + ├── keyword.ml # Message keywords 71 + ├── keyword.mli 72 + ├── system_flag.ml # IMAP system flags (non-keyword) 73 + ├── system_flag.mli 74 + ├── mailbox_attr.ml # Mailbox attributes/roles 75 + ├── mailbox_attr.mli 76 + ├── flag_color.ml # Apple Mail flag colors 77 + ├── flag_color.mli 78 + ├── imap_wire.ml # IMAP wire format conversion 79 + ├── imap_wire.mli 80 + ├── jmap_wire.ml # JMAP wire format conversion 81 + └── jmap_wire.mli 82 + ``` 83 + 84 + --- 85 + 86 + ## Task Breakdown 87 + 88 + ### Phase 1: Core Types (Priority: P0) 89 + 90 + #### Task 1.1: Create `mail-flag` opam package 91 + 92 + **File:** `../mail-flag/dune-project` 93 + ``` 94 + (lang dune 3.0) 95 + (name mail-flag) 96 + (generate_opam_files true) 97 + 98 + (package 99 + (name mail-flag) 100 + (synopsis "Unified message flags and mailbox attributes for IMAP/JMAP") 101 + (description "Type-safe message keywords, system flags, and mailbox attributes 102 + for email protocols. Supports RFC 9051 (IMAP4rev2), RFC 8621 (JMAP Mail), 103 + RFC 6154 (Special-Use), and draft-ietf-mailmaint extensions.") 104 + (depends 105 + (ocaml (>= 5.0)) 106 + (fmt (>= 0.9)))) 107 + ``` 108 + 109 + **File:** `../mail-flag/lib/dune` 110 + ``` 111 + (library 112 + (name mail_flag) 113 + (public_name mail-flag) 114 + (libraries fmt)) 115 + ``` 116 + 117 + #### Task 1.2: Implement `keyword.ml` - Message Keywords 118 + 119 + **File:** `../mail-flag/lib/keyword.mli` 120 + ```ocaml 121 + (** Message Keywords 122 + 123 + IMAP/JMAP message keywords as specified in: 124 + - {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2} 125 + - {{:https://datatracker.ietf.org/doc/html/rfc8621#section-4.1.1}RFC 8621 Section 4.1.1} 126 + - {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute}draft-ietf-mailmaint-messageflag-mailboxattribute-13} *) 127 + 128 + (** {1 Standard Keywords} 129 + 130 + RFC 8621 defines these keywords that have corresponding IMAP system flags. *) 131 + 132 + type standard = [ 133 + | `Seen (** Message has been read (IMAP: \Seen) *) 134 + | `Answered (** Message has been answered (IMAP: \Answered) *) 135 + | `Flagged (** Message is flagged (IMAP: \Flagged) *) 136 + | `Draft (** Message is a draft (IMAP: \Draft) *) 137 + | `Deleted (** Message is deleted (IMAP: \Deleted, JMAP: use destroy) *) 138 + | `Forwarded (** Message has been forwarded *) 139 + ] 140 + 141 + (** {1 Spam/Phishing Keywords} *) 142 + 143 + type spam = [ 144 + | `Phishing (** Message is a phishing attempt *) 145 + | `Junk (** Message is spam/junk *) 146 + | `NotJunk (** Message is explicitly not junk *) 147 + ] 148 + 149 + (** {1 Extended Keywords} 150 + 151 + {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute}draft-ietf-mailmaint} keywords. *) 152 + 153 + type extended = [ 154 + (* Attachment detection *) 155 + | `HasAttachment (** Message has attachments *) 156 + | `HasNoAttachment (** Message explicitly has no attachments *) 157 + (* Memos/annotations *) 158 + | `Memo (** Message is a note-to-self *) 159 + | `HasMemo (** Message has an associated memo *) 160 + (* Subscription management *) 161 + | `CanUnsubscribe (** Message has RFC 8058 List-Unsubscribe *) 162 + | `Unsubscribed (** User attempted to unsubscribe *) 163 + (* Thread behavior *) 164 + | `Muted (** User not interested in thread replies *) 165 + | `Followed (** User wants notifications for thread *) 166 + (* Message origin/status *) 167 + | `AutoSent (** Automatically sent (vacation reply, etc.) *) 168 + | `Imported (** Imported from another system *) 169 + | `IsTrusted (** Sender identity verified by server *) 170 + | `MaskedEmail (** Received via masked email alias *) 171 + | `New (** Should be emphasized (e.g., snoozed awakening) *) 172 + | `Notify (** Client should present notification *) 173 + ] 174 + 175 + (** {1 Apple Mail Flag Colors} 176 + 177 + {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute#section-3}Section 3} *) 178 + 179 + type flag_bit = [ 180 + | `MailFlagBit0 181 + | `MailFlagBit1 182 + | `MailFlagBit2 183 + ] 184 + 185 + (** {1 Unified Keyword Type} *) 186 + 187 + type t = [ 188 + | standard 189 + | spam 190 + | extended 191 + | flag_bit 192 + | `Custom of string (** Unknown/custom keyword *) 193 + ] 194 + 195 + (** {1 Constructors and Conversions} *) 196 + 197 + val of_string : string -> t 198 + (** Parse a keyword string. Handles both JMAP format ([$seen]) and 199 + plain format ([seen]). Case-insensitive for known keywords. *) 200 + 201 + val to_string : t -> string 202 + (** Convert to canonical JMAP format with [$] prefix. *) 203 + 204 + val pp : Format.formatter -> t -> unit 205 + 206 + (** {1 Predicates} *) 207 + 208 + val is_standard : t -> bool 209 + (** Returns [true] if keyword maps to an IMAP system flag. *) 210 + 211 + val is_advisory : t -> bool 212 + (** Returns [true] if keyword is advisory only (no automatic action). *) 213 + 214 + val is_mutually_exclusive : t -> t -> bool 215 + (** Returns [true] if two keywords cannot both be set. 216 + E.g., [$hasattachment] and [$hasnoattachment]. *) 217 + 218 + (** {1 Sets} *) 219 + 220 + module Set : Set.S with type elt = t 221 + 222 + val all_standard : Set.t 223 + val all_extended : Set.t 224 + ``` 225 + 226 + **File:** `../mail-flag/lib/keyword.ml` 227 + ```ocaml 228 + (* Implementation with case-insensitive parsing, normalization, 229 + and mutually exclusive keyword validation *) 230 + 231 + type standard = [`Seen | `Answered | `Flagged | `Draft | `Deleted | `Forwarded] 232 + type spam = [`Phishing | `Junk | `NotJunk] 233 + type extended = [ 234 + `HasAttachment | `HasNoAttachment | `Memo | `HasMemo | 235 + `CanUnsubscribe | `Unsubscribed | `Muted | `Followed | 236 + `AutoSent | `Imported | `IsTrusted | `MaskedEmail | `New | `Notify 237 + ] 238 + type flag_bit = [`MailFlagBit0 | `MailFlagBit1 | `MailFlagBit2] 239 + type t = [standard | spam | extended | flag_bit | `Custom of string] 240 + 241 + let normalize s = 242 + let s = String.lowercase_ascii s in 243 + if String.length s > 0 && s.[0] = '$' then String.sub s 1 (String.length s - 1) 244 + else s 245 + 246 + let of_string s = 247 + match normalize s with 248 + | "seen" -> `Seen 249 + | "answered" -> `Answered 250 + | "flagged" -> `Flagged 251 + | "draft" -> `Draft 252 + | "deleted" -> `Deleted 253 + | "forwarded" -> `Forwarded 254 + | "phishing" -> `Phishing 255 + | "junk" -> `Junk 256 + | "notjunk" -> `NotJunk 257 + | "hasattachment" -> `HasAttachment 258 + | "hasnoattachment" -> `HasNoAttachment 259 + | "memo" -> `Memo 260 + | "hasmemo" -> `HasMemo 261 + | "canunsubscribe" -> `CanUnsubscribe 262 + | "unsubscribed" -> `Unsubscribed 263 + | "muted" -> `Muted 264 + | "followed" -> `Followed 265 + | "autosent" -> `AutoSent 266 + | "imported" -> `Imported 267 + | "istrusted" -> `IsTrusted 268 + | "maskedemail" -> `MaskedEmail 269 + | "new" -> `New 270 + | "notify" -> `Notify 271 + | "mailflagbit0" -> `MailFlagBit0 272 + | "mailflagbit1" -> `MailFlagBit1 273 + | "mailflagbit2" -> `MailFlagBit2 274 + | s -> `Custom s 275 + 276 + let to_string = function 277 + | `Seen -> "$seen" 278 + | `Answered -> "$answered" 279 + | `Flagged -> "$flagged" 280 + | `Draft -> "$draft" 281 + | `Deleted -> "$deleted" 282 + | `Forwarded -> "$forwarded" 283 + | `Phishing -> "$phishing" 284 + | `Junk -> "$junk" 285 + | `NotJunk -> "$notjunk" 286 + | `HasAttachment -> "$hasattachment" 287 + | `HasNoAttachment -> "$hasnoattachment" 288 + | `Memo -> "$memo" 289 + | `HasMemo -> "$hasmemo" 290 + | `CanUnsubscribe -> "$canunsubscribe" 291 + | `Unsubscribed -> "$unsubscribed" 292 + | `Muted -> "$muted" 293 + | `Followed -> "$followed" 294 + | `AutoSent -> "$autosent" 295 + | `Imported -> "$imported" 296 + | `IsTrusted -> "$istrusted" 297 + | `MaskedEmail -> "$maskedemail" 298 + | `New -> "$new" 299 + | `Notify -> "$notify" 300 + | `MailFlagBit0 -> "$MailFlagBit0" 301 + | `MailFlagBit1 -> "$MailFlagBit1" 302 + | `MailFlagBit2 -> "$MailFlagBit2" 303 + | `Custom s -> if s.[0] = '$' then s else "$" ^ s 304 + 305 + let pp ppf k = Fmt.string ppf (to_string k) 306 + 307 + let is_standard = function 308 + | `Seen | `Answered | `Flagged | `Draft | `Deleted | `Forwarded -> true 309 + | _ -> false 310 + 311 + let is_advisory = function 312 + | `Muted | `Followed | `Notify -> false (* can cause automatic action *) 313 + | _ -> true 314 + 315 + let is_mutually_exclusive k1 k2 = 316 + match (k1, k2) with 317 + | (`HasAttachment, `HasNoAttachment) | (`HasNoAttachment, `HasAttachment) -> true 318 + | (`Memo, `HasMemo) | (`HasMemo, `Memo) -> true 319 + | (`Muted, `Followed) | (`Followed, `Muted) -> true 320 + | _ -> false 321 + 322 + module Set = Set.Make(struct 323 + type nonrec t = t 324 + let compare = compare 325 + end) 326 + 327 + let all_standard = Set.of_list [`Seen; `Answered; `Flagged; `Draft; `Deleted; `Forwarded] 328 + let all_extended = Set.of_list [ 329 + `HasAttachment; `HasNoAttachment; `Memo; `HasMemo; 330 + `CanUnsubscribe; `Unsubscribed; `Muted; `Followed; 331 + `AutoSent; `Imported; `IsTrusted; `MaskedEmail; `New; `Notify 332 + ] 333 + ``` 334 + 335 + #### Task 1.3: Implement `system_flag.ml` - IMAP System Flags 336 + 337 + **File:** `../mail-flag/lib/system_flag.mli` 338 + ```ocaml 339 + (** IMAP System Flags 340 + 341 + System flags as specified in {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2}. 342 + 343 + Note: System flags are IMAP-specific. In JMAP, these are represented as 344 + keywords (e.g., [\Seen] becomes [$seen]). Use {!Keyword} for protocol-agnostic code. *) 345 + 346 + type t = 347 + | Seen (** Message has been read *) 348 + | Answered (** Message has been answered *) 349 + | Flagged (** Message is flagged for urgent/special attention *) 350 + | Deleted (** Message is marked for deletion *) 351 + | Draft (** Message has not completed composition *) 352 + 353 + val pp : Format.formatter -> t -> unit 354 + val to_string : t -> string 355 + (** Returns IMAP wire format with backslash: [\Seen] *) 356 + 357 + val of_string : string -> t option 358 + (** Parse from IMAP wire format. Case-insensitive. *) 359 + 360 + val to_keyword : t -> Keyword.standard 361 + (** Convert to equivalent keyword. *) 362 + 363 + val of_keyword : Keyword.t -> t option 364 + (** Convert from keyword if it maps to a system flag. *) 365 + 366 + val all : t list 367 + ``` 368 + 369 + #### Task 1.4: Implement `mailbox_attr.ml` - Mailbox Attributes 370 + 371 + **File:** `../mail-flag/lib/mailbox_attr.mli` 372 + ```ocaml 373 + (** Mailbox Attributes and Roles 374 + 375 + Mailbox name attributes as specified in: 376 + - {{:https://datatracker.ietf.org/doc/html/rfc9051#section-7.2.2}RFC 9051 Section 7.2.2} 377 + - {{:https://datatracker.ietf.org/doc/html/rfc6154}RFC 6154} Special-Use 378 + - {{:https://datatracker.ietf.org/doc/html/rfc8457}RFC 8457} Important 379 + - {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute}draft-ietf-mailmaint} *) 380 + 381 + (** {1 List Attributes} 382 + 383 + Attributes returned by IMAP LIST command. *) 384 + 385 + type list_attr = [ 386 + (* RFC 9051 base attributes *) 387 + | `Noinferiors (** No child mailboxes possible *) 388 + | `Noselect (** Mailbox cannot be selected *) 389 + | `Marked (** Mailbox marked "interesting" by server *) 390 + | `Unmarked (** No new messages since last select *) 391 + | `Subscribed (** Mailbox is subscribed *) 392 + | `HasChildren (** Mailbox has child mailboxes *) 393 + | `HasNoChildren (** Mailbox has no child mailboxes *) 394 + | `NonExistent (** Mailbox does not exist *) 395 + | `Remote (** Mailbox is remote/on another server *) 396 + ] 397 + 398 + (** {1 Special-Use Roles} 399 + 400 + RFC 6154 special-use mailbox roles. *) 401 + 402 + type special_use = [ 403 + | `All (** Virtual: all messages *) 404 + | `Archive (** Archive folder *) 405 + | `Drafts (** Draft messages *) 406 + | `Flagged (** Flagged messages (virtual) *) 407 + | `Important (** Important messages (RFC 8457) *) 408 + | `Junk (** Spam/junk folder *) 409 + | `Sent (** Sent messages *) 410 + | `Trash (** Deleted messages *) 411 + (* draft-ietf-mailmaint extensions *) 412 + | `Snoozed (** Snoozed messages awaiting redelivery *) 413 + | `Scheduled (** Messages scheduled to be sent *) 414 + | `Memos (** User memo/annotation messages *) 415 + ] 416 + 417 + (** {1 Unified Attribute Type} *) 418 + 419 + type t = [ 420 + | list_attr 421 + | special_use 422 + | `Extension of string (** Unknown attribute *) 423 + ] 424 + 425 + (** {1 Conversions} *) 426 + 427 + val of_string : string -> t 428 + (** Parse from IMAP wire format (with or without backslash). Case-insensitive. *) 429 + 430 + val to_string : t -> string 431 + (** Convert to IMAP wire format with backslash prefix. *) 432 + 433 + val to_jmap_role : t -> string option 434 + (** Convert special-use attribute to JMAP role string. 435 + Returns [None] for list attributes. *) 436 + 437 + val of_jmap_role : string -> special_use option 438 + (** Parse from JMAP role string. *) 439 + 440 + val pp : Format.formatter -> t -> unit 441 + 442 + (** {1 Predicates} *) 443 + 444 + val is_special_use : t -> bool 445 + val is_selectable : t -> bool 446 + (** Returns [false] if attribute is [`Noselect] or [`NonExistent]. *) 447 + ``` 448 + 449 + #### Task 1.5: Implement `flag_color.ml` - Apple Mail Colors 450 + 451 + **File:** `../mail-flag/lib/flag_color.mli` 452 + ```ocaml 453 + (** Apple Mail Flag Colors 454 + 455 + Encoding of flag colors using [$MailFlagBit0/1/2] keywords as specified in 456 + {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute#section-3}draft-ietf-mailmaint Section 3}. *) 457 + 458 + type t = 459 + | Red (** Bit pattern: 000 *) 460 + | Orange (** Bit pattern: 100 *) 461 + | Yellow (** Bit pattern: 010 *) 462 + | Green (** Bit pattern: 110 *) 463 + | Blue (** Bit pattern: 001 *) 464 + | Purple (** Bit pattern: 101 *) 465 + | Gray (** Bit pattern: 011 *) 466 + 467 + val to_keywords : t -> Keyword.flag_bit list 468 + (** Convert color to keyword bits. [Red] returns empty list. *) 469 + 470 + val of_keywords : Keyword.t list -> t option 471 + (** Extract color from keyword list. Returns [None] if bit pattern 111 472 + or if no flag bits present. Only valid when [$flagged] is also set. *) 473 + 474 + val pp : Format.formatter -> t -> unit 475 + val to_string : t -> string 476 + val of_string : string -> t option 477 + ``` 478 + 479 + --- 480 + 481 + ### Phase 2: Wire Format Adapters (Priority: P0) 482 + 483 + #### Task 2.1: Implement `imap_wire.ml` - IMAP Serialization 484 + 485 + **File:** `../mail-flag/lib/imap_wire.mli` 486 + ```ocaml 487 + (** IMAP Wire Format 488 + 489 + Convert between internal types and IMAP protocol format. *) 490 + 491 + (** {1 Message Flags} *) 492 + 493 + type flag = 494 + | System of System_flag.t 495 + | Keyword of Keyword.t 496 + 497 + val flag_of_string : string -> flag option 498 + (** Parse IMAP flag: [\Seen] -> System, [$forwarded] -> Keyword *) 499 + 500 + val flag_to_string : flag -> string 501 + (** Serialize: System Seen -> [\Seen], Keyword `Forwarded -> [$forwarded] *) 502 + 503 + val flags_of_keywords : Keyword.t list -> flag list 504 + (** Convert keyword list to IMAP flags. Standard keywords become system flags. *) 505 + 506 + val keywords_of_flags : flag list -> Keyword.t list 507 + (** Convert IMAP flags to keywords. System flags become standard keywords. *) 508 + 509 + (** {1 Mailbox Attributes} *) 510 + 511 + val attr_of_string : string -> Mailbox_attr.t 512 + val attr_to_string : Mailbox_attr.t -> string 513 + 514 + (** {1 Parsing Helpers} *) 515 + 516 + val parse_flag_list : string -> flag list 517 + (** Parse IMAP flag list: [(\\Seen \\Flagged $forwarded)] *) 518 + 519 + val format_flag_list : flag list -> string 520 + (** Format as IMAP flag list. *) 521 + ``` 522 + 523 + #### Task 2.2: Implement `jmap_wire.ml` - JMAP Serialization 524 + 525 + **File:** `../mail-flag/lib/jmap_wire.mli` 526 + ```ocaml 527 + (** JMAP Wire Format 528 + 529 + Convert between internal types and JMAP JSON format. *) 530 + 531 + (** {1 Keywords as JSON} 532 + 533 + JMAP represents keywords as JSON object: [{"$seen": true, "$flagged": true}] *) 534 + 535 + val keywords_to_assoc : Keyword.t list -> (string * bool) list 536 + (** Convert to JMAP keywords object entries. *) 537 + 538 + val keywords_of_assoc : (string * bool) list -> Keyword.t list 539 + (** Parse from JMAP keywords object. Only includes entries with [true] value. *) 540 + 541 + (** {1 Mailbox Roles} *) 542 + 543 + val role_to_string : Mailbox_attr.special_use -> string 544 + val role_of_string : string -> Mailbox_attr.special_use option 545 + ``` 546 + 547 + --- 548 + 549 + ### Phase 3: Integration with ocaml-imap (Priority: P1) 550 + 551 + #### Task 3.1: Update ocaml-imap dependency 552 + 553 + **File:** `ocaml-imap/dune-project` 554 + ``` 555 + (package 556 + (name imap) 557 + (depends 558 + ... 559 + (mail-flag (>= 0.1)))) 560 + ``` 561 + 562 + #### Task 3.2: Refactor `lib/imap/flag.ml` 563 + 564 + Replace internal types with imports from `mail-flag`: 565 + 566 + ```ocaml 567 + (** Message Flags 568 + 569 + Re-exports from {!Mail_flag} for IMAP-specific use. 570 + See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2}. *) 571 + 572 + type system = Mail_flag.System_flag.t = 573 + | Seen | Answered | Flagged | Deleted | Draft 574 + 575 + type t = Mail_flag.Imap_wire.flag = 576 + | System of system 577 + | Keyword of Mail_flag.Keyword.t 578 + 579 + (* Re-export for backward compatibility *) 580 + let keyword name = Keyword (Mail_flag.Keyword.of_string name) 581 + let pp = Mail_flag.Imap_wire.pp_flag 582 + let to_string = Mail_flag.Imap_wire.flag_to_string 583 + let of_string = Mail_flag.Imap_wire.flag_of_string 584 + ``` 585 + 586 + #### Task 3.3: Update `lib/imap/list_attr.ml` 587 + 588 + ```ocaml 589 + (** LIST Command Attributes 590 + 591 + Re-exports from {!Mail_flag.Mailbox_attr}. *) 592 + 593 + type t = Mail_flag.Mailbox_attr.t 594 + 595 + (* Add new attributes *) 596 + let all_special_use = [ 597 + `All; `Archive; `Drafts; `Flagged; `Important; 598 + `Junk; `Sent; `Trash; `Snoozed; `Scheduled; `Memos 599 + ] 600 + 601 + (* Backward compatible exports *) 602 + let pp = Mail_flag.Mailbox_attr.pp 603 + let to_string = Mail_flag.Mailbox_attr.to_string 604 + ``` 605 + 606 + #### Task 3.4: Update server protocol types 607 + 608 + **File:** `lib/imapd/protocol.ml` 609 + 610 + Update to use shared types, ensuring Maildir storage correctly handles extended keywords. 611 + 612 + --- 613 + 614 + ### Phase 4: Integration with ocaml-jmap (Priority: P1) 615 + 616 + #### Task 4.1: Update ocaml-jmap dependency 617 + 618 + **File:** `ocaml-jmap/dune-project` 619 + ``` 620 + (package 621 + (name jmap) 622 + (depends 623 + ... 624 + (mail-flag (>= 0.1)))) 625 + ``` 626 + 627 + #### Task 4.2: Refactor `lib/core/jmap_types.ml` 628 + 629 + Replace Keyword module with re-export: 630 + 631 + ```ocaml 632 + module Keyword = struct 633 + include Mail_flag.Keyword 634 + 635 + (* JMAP-specific: flag colors *) 636 + type flag_color = Mail_flag.Flag_color.t 637 + let flag_color_of_keywords = Mail_flag.Flag_color.of_keywords 638 + let flag_color_to_keywords = Mail_flag.Flag_color.to_keywords 639 + end 640 + 641 + module Role = struct 642 + type t = [Mail_flag.Mailbox_attr.special_use | `Custom of string] 643 + (* ... re-export conversion functions *) 644 + end 645 + ``` 646 + 647 + #### Task 4.3: Update `lib/mail/mail_email.ml` 648 + 649 + Use `Mail_flag.Jmap_wire` for keyword JSON handling. 650 + 651 + --- 652 + 653 + ### Phase 5: Testing (Priority: P1) 654 + 655 + #### Task 5.1: Unit tests for keyword parsing 656 + 657 + ```ocaml 658 + (* test/test_keyword.ml *) 659 + let test_of_string () = 660 + assert (Keyword.of_string "$seen" = `Seen); 661 + assert (Keyword.of_string "SEEN" = `Seen); (* case insensitive *) 662 + assert (Keyword.of_string "$Seen" = `Seen); 663 + assert (Keyword.of_string "custom" = `Custom "custom") 664 + 665 + let test_mutual_exclusion () = 666 + assert (Keyword.is_mutually_exclusive `HasAttachment `HasNoAttachment); 667 + assert (Keyword.is_mutually_exclusive `Muted `Followed); 668 + assert (not (Keyword.is_mutually_exclusive `Seen `Flagged)) 669 + ``` 670 + 671 + #### Task 5.2: IMAP wire format tests 672 + 673 + ```ocaml 674 + let test_flag_roundtrip () = 675 + let flags = [System Seen; Keyword `Forwarded; Keyword (`Custom "label")] in 676 + let s = Imap_wire.format_flag_list flags in 677 + let parsed = Imap_wire.parse_flag_list s in 678 + assert (flags = parsed) 679 + ``` 680 + 681 + #### Task 5.3: JMAP wire format tests 682 + 683 + ```ocaml 684 + let test_keywords_json () = 685 + let kws = [`Seen; `Flagged; `Custom "label"] in 686 + let assoc = Jmap_wire.keywords_to_assoc kws in 687 + assert (List.assoc "$seen" assoc = true); 688 + assert (List.assoc "$flagged" assoc = true); 689 + assert (List.assoc "label" assoc = true) 690 + ``` 691 + 692 + #### Task 5.4: Integration tests 693 + 694 + Test IMAP↔JMAP keyword conversion to ensure: 695 + - `\Seen` (IMAP) ↔ `$seen` (JMAP) 696 + - `\Flagged` + `$MailFlagBit0` (IMAP) ↔ `$flagged` + `$MailFlagBit0` (JMAP) 697 + 698 + --- 699 + 700 + ## Migration Strategy 701 + 702 + 1. **Create mail-flag library** in `../mail-flag/` as new package 703 + 2. **Keep existing APIs** in ocaml-imap/ocaml-jmap initially 704 + 3. **Add dependency** and re-export types 705 + 4. **Deprecate old types** with `[@deprecated]` attribute 706 + 5. **Remove deprecated types** in next major version 707 + 708 + ## OCamldoc Templates 709 + 710 + ### Module-level for mail-flag 711 + 712 + ```ocaml 713 + (** RFC 9051/8621 Message Keywords and Mailbox Attributes. 714 + 715 + This library provides unified type-safe handling of message keywords 716 + and mailbox attributes for both IMAP and JMAP protocols. 717 + 718 + {2 Specifications} 719 + {ul 720 + {- {{:https://datatracker.ietf.org/doc/html/rfc9051}RFC 9051} - IMAP4rev2} 721 + {- {{:https://datatracker.ietf.org/doc/html/rfc8621}RFC 8621} - JMAP Mail} 722 + {- {{:https://datatracker.ietf.org/doc/html/rfc6154}RFC 6154} - Special-Use Mailboxes} 723 + {- {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute}draft-ietf-mailmaint} - Extended keywords}} *) 724 + ``` 725 + 726 + ### Section-specific 727 + 728 + ```ocaml 729 + (** Apple Mail flag color encoding. 730 + 731 + Implements {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute#section-3}draft-ietf-mailmaint Section 3}. 732 + 733 + The three flag bit keywords encode 7 colors: 734 + {ul 735 + {- [Red]: no bits set} 736 + {- [Orange]: bit 0} 737 + {- [Yellow]: bit 1} 738 + {- [Green]: bits 0, 1, 2} 739 + {- [Blue]: bit 2} 740 + {- [Purple]: bits 0, 2} 741 + {- [Gray]: bits 1, 2}} *) 742 + ``` 743 + 744 + --- 745 + 746 + ## Implementation Notes 747 + 748 + ### Keyword Normalization 749 + 750 + All keywords are stored internally without the `$` prefix and in lowercase for comparison: 751 + - IMAP `$Forwarded` → `forwarded` 752 + - JMAP `$forwarded` → `forwarded` 753 + 754 + The prefix is added back during serialization. 755 + 756 + ### System Flag Mapping 757 + 758 + | IMAP System Flag | JMAP Keyword | 759 + |------------------|--------------| 760 + | `\Seen` | `$seen` | 761 + | `\Answered` | `$answered` | 762 + | `\Flagged` | `$flagged` | 763 + | `\Deleted` | `$deleted` | 764 + | `\Draft` | `$draft` | 765 + 766 + Note: IMAP's `\Recent` flag has no JMAP equivalent (it's session-specific). 767 + 768 + ### Mutual Exclusion Rules 769 + 770 + From draft-ietf-mailmaint: 771 + - `$hasattachment` ⊕ `$hasnoattachment` 772 + - `$memo` ⊕ `$hasmemo` 773 + - `$muted` ⊕ `$followed` (if both present, treat as `$followed`) 774 + 775 + ### Flag Color Behavior 776 + 777 + - Flag color bits are only meaningful when `$flagged`/`\Flagged` is set 778 + - Clients MUST clear all color bits when clearing `$flagged` 779 + - Bit pattern `111` is undefined (no color assigned) 780 + 781 + --- 782 + 783 + ## Estimated Effort 784 + 785 + | Phase | Tasks | Complexity | 786 + |-------|-------|------------| 787 + | Phase 1: Core Types | 5 | Medium | 788 + | Phase 2: Wire Adapters | 2 | Low | 789 + | Phase 3: ocaml-imap | 4 | Medium | 790 + | Phase 4: ocaml-jmap | 3 | Medium | 791 + | Phase 5: Testing | 4 | Low | 792 + 793 + ## Dependencies 794 + 795 + - `fmt` - Pretty printing 796 + - No additional dependencies for core library 797 + 798 + ## Files to Create 799 + 800 + ``` 801 + ../mail-flag/ 802 + ├── dune-project 803 + ├── lib/ 804 + │ ├── dune 805 + │ ├── keyword.ml 806 + │ ├── keyword.mli 807 + │ ├── system_flag.ml 808 + │ ├── system_flag.mli 809 + │ ├── mailbox_attr.ml 810 + │ ├── mailbox_attr.mli 811 + │ ├── flag_color.ml 812 + │ ├── flag_color.mli 813 + │ ├── imap_wire.ml 814 + │ ├── imap_wire.mli 815 + │ ├── jmap_wire.ml 816 + │ └── jmap_wire.mli 817 + └── test/ 818 + ├── dune 819 + ├── test_keyword.ml 820 + ├── test_imap_wire.ml 821 + └── test_jmap_wire.ml 822 + ``` 823 + 824 + ## Files to Modify 825 + 826 + ``` 827 + ocaml-imap/ 828 + ├── dune-project # Add mail-flag dependency 829 + ├── lib/imap/flag.ml # Re-export from mail-flag 830 + ├── lib/imap/flag.mli # Re-export from mail-flag 831 + ├── lib/imap/list_attr.ml # Re-export from mail-flag 832 + └── lib/imapd/protocol.ml # Use shared types 833 + 834 + ocaml-jmap/ 835 + ├── dune-project # Add mail-flag dependency 836 + ├── lib/core/jmap_types.ml # Re-export from mail-flag 837 + └── lib/mail/mail_mailbox.ml # Use shared role types 838 + ```
+1288
spec/draft-messageflag-mailboxattribute-13.txt
··· 1 + 2 + 3 + 4 + 5 + MailMaint N.M. Jenkins 6 + Internet-Draft Fastmail 7 + Intended status: Informational D. Eggert 8 + Expires: 4 June 2026 Apple Inc 9 + 1 December 2025 10 + 11 + 12 + Registration of further IMAP/JMAP keywords and mailbox name attributes 13 + draft-ietf-mailmaint-messageflag-mailboxattribute-13 14 + 15 + Abstract 16 + 17 + This document defines a number of keywords and mailbox name 18 + attributes that have been in use across different server and client 19 + implementations. It defines the intended use of these keywords and 20 + mailbox name attributes. This document registers all of these with 21 + IANA to avoid name collisions. 22 + 23 + Status of This Memo 24 + 25 + This Internet-Draft is submitted in full conformance with the 26 + provisions of BCP 78 and BCP 79. 27 + 28 + Internet-Drafts are working documents of the Internet Engineering 29 + Task Force (IETF). Note that other groups may also distribute 30 + working documents as Internet-Drafts. The list of current Internet- 31 + Drafts is at https://datatracker.ietf.org/drafts/current/. 32 + 33 + Internet-Drafts are draft documents valid for a maximum of six months 34 + and may be updated, replaced, or obsoleted by other documents at any 35 + time. It is inappropriate to use Internet-Drafts as reference 36 + material or to cite them other than as "work in progress." 37 + 38 + This Internet-Draft will expire on 4 June 2026. 39 + 40 + Copyright Notice 41 + 42 + Copyright (c) 2025 IETF Trust and the persons identified as the 43 + document authors. All rights reserved. 44 + 45 + This document is subject to BCP 78 and the IETF Trust's Legal 46 + Provisions Relating to IETF Documents (https://trustee.ietf.org/ 47 + license-info) in effect on the date of publication of this document. 48 + Please review these documents carefully, as they describe your rights 49 + and restrictions with respect to this document. Code Components 50 + extracted from this document must include Revised BSD License text as 51 + described in Section 4.e of the Trust Legal Provisions and are 52 + provided without warranty as described in the Revised BSD License. 53 + 54 + 55 + 56 + Jenkins & Eggert Expires 4 June 2026 [Page 1] 57 + 58 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 59 + 60 + 61 + Table of Contents 62 + 63 + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 64 + 2. Requirements Language . . . . . . . . . . . . . . . . . . . . 4 65 + 3. Flag Color Keywords . . . . . . . . . . . . . . . . . . . . . 4 66 + 3.1. Definition of the $MailFlagBit_ Message Keywords . . . . 4 67 + 3.2. Implementation Notes . . . . . . . . . . . . . . . . . . 5 68 + 4. Attachment Detection Keywords . . . . . . . . . . . . . . . . 5 69 + 4.1. $hasattachment . . . . . . . . . . . . . . . . . . . . . 5 70 + 4.2. $hasnoattachment . . . . . . . . . . . . . . . . . . . . 6 71 + 5. Memos Keywords . . . . . . . . . . . . . . . . . . . . . . . 6 72 + 5.1. $hasmemo . . . . . . . . . . . . . . . . . . . . . . . . 6 73 + 5.2. $memo . . . . . . . . . . . . . . . . . . . . . . . . . . 7 74 + 6. Subscription Management Keywords . . . . . . . . . . . . . . 7 75 + 6.1. $canunsubscribe . . . . . . . . . . . . . . . . . . . . . 7 76 + 6.2. $unsubscribed . . . . . . . . . . . . . . . . . . . . . . 8 77 + 7. Other Message Keywords . . . . . . . . . . . . . . . . . . . 8 78 + 7.1. $autosent . . . . . . . . . . . . . . . . . . . . . . . . 8 79 + 7.2. $followed . . . . . . . . . . . . . . . . . . . . . . . . 9 80 + 7.3. $imported . . . . . . . . . . . . . . . . . . . . . . . . 9 81 + 7.4. $istrusted . . . . . . . . . . . . . . . . . . . . . . . 9 82 + 7.5. $maskedemail . . . . . . . . . . . . . . . . . . . . . . 10 83 + 7.6. $muted . . . . . . . . . . . . . . . . . . . . . . . . . 10 84 + 7.7. $new . . . . . . . . . . . . . . . . . . . . . . . . . . 11 85 + 7.8. $notify . . . . . . . . . . . . . . . . . . . . . . . . . 12 86 + 8. Mailbox Name Attributes . . . . . . . . . . . . . . . . . . . 12 87 + 8.1. Snoozed . . . . . . . . . . . . . . . . . . . . . . . . . 12 88 + 8.2. Scheduled . . . . . . . . . . . . . . . . . . . . . . . . 13 89 + 8.3. Memos . . . . . . . . . . . . . . . . . . . . . . . . . . 13 90 + 9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 14 91 + 9.1. IMAP/JMAP Keyword Registrations . . . . . . . . . . . . . 14 92 + 9.1.1. $autosent keyword registration . . . . . . . . . . . 14 93 + 9.1.2. $canunsubscribe keyword registration . . . . . . . . 14 94 + 9.1.3. $followed keyword registration . . . . . . . . . . . 14 95 + 9.1.4. $hasattachment keyword registration . . . . . . . . . 15 96 + 9.1.5. $hasmemo keyword registration . . . . . . . . . . . . 15 97 + 9.1.6. $hasnoattachment keyword registration . . . . . . . . 16 98 + 9.1.7. $imported keyword registration . . . . . . . . . . . 16 99 + 9.1.8. $istrusted keyword registration . . . . . . . . . . . 16 100 + 9.1.9. $MailFlagBit0 keyword registration . . . . . . . . . 17 101 + 9.1.10. $MailFlagBit1 keyword registration . . . . . . . . . 17 102 + 9.1.11. $MailFlagBit2 keyword registration . . . . . . . . . 18 103 + 9.1.12. $maskedemail keyword registration . . . . . . . . . . 18 104 + 9.1.13. $memo keyword registration . . . . . . . . . . . . . 18 105 + 9.1.14. $muted keyword registration . . . . . . . . . . . . . 19 106 + 9.1.15. $new keyword registration . . . . . . . . . . . . . . 19 107 + 9.1.16. $notify keyword registration . . . . . . . . . . . . 20 108 + 9.1.17. $unsubscribed keyword registration . . . . . . . . . 20 109 + 110 + 111 + 112 + Jenkins & Eggert Expires 4 June 2026 [Page 2] 113 + 114 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 115 + 116 + 117 + 9.2. IMAP Mailbox Name Attributes Registrations . . . . . . . 21 118 + 9.2.1. Snoozed mailbox name attribute registration . . . . . 21 119 + 9.2.2. Scheduled mailbox name attribute registration . . . . 21 120 + 9.2.3. Memos mailbox name attribute registration . . . . . . 21 121 + 10. Security Considerations . . . . . . . . . . . . . . . . . . . 21 122 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 21 123 + 11.1. Normative References . . . . . . . . . . . . . . . . . . 22 124 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 22 125 + 126 + 1. Introduction 127 + 128 + The Internet Message Access Protocol (IMAP) specification [RFC9051] 129 + defines the use of message keywords, and an "IMAP and JMAP Keywords" 130 + registry is created in [RFC5788]. Similarly [RFC8457] creates an 131 + "IMAP Mailbox Name Attributes Registry". JMAP Mail [RFC8621] updated 132 + these registries to apply to messages and mailboxes over the JMAP 133 + protocol as well. 134 + 135 + This document defines 17 message keywords: 136 + 137 + $autosent 138 + $canunsubscribe 139 + $followed 140 + $hasattachment 141 + $hasmemo 142 + $hasnoattachment 143 + $imported 144 + $istrusted 145 + $MailFlagBit0 146 + $MailFlagBit1 147 + $MailFlagBit2 148 + $maskedemail 149 + $memo 150 + $muted 151 + $new 152 + $notify 153 + $unsubscribed 154 + 155 + And defines 3 mailbox name attributes: 156 + 157 + Memos 158 + Scheduled 159 + Snoozed 160 + 161 + This document also registers these in the "IMAP and JMAP Keywords" 162 + registry and "IMAP Mailbox Name Attributes" registry. 163 + 164 + 165 + 166 + 167 + 168 + Jenkins & Eggert Expires 4 June 2026 [Page 3] 169 + 170 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 171 + 172 + 173 + 2. Requirements Language 174 + 175 + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 176 + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 177 + "OPTIONAL" in this document are to be interpreted as described in BCP 178 + 14 [RFC2119] [RFC8174] when, and only when, they appear in all 179 + capitals, as shown here. 180 + 181 + 3. Flag Color Keywords 182 + 183 + The Internet Message Access Protocol (IMAP) specification [RFC9051] 184 + defines a \Flagged system flag to mark a message for urgent/special 185 + attention. The new keywords defined in Section 3.1 allow such a 186 + flagged message to have that flag be of one of 7 colors. 187 + 188 + 3.1. Definition of the $MailFlagBit_ Message Keywords 189 + 190 + The 3 flag color keywords 191 + 192 + $MailFlagBit0 193 + $MailFlagBit1 194 + $MailFlagBit2 195 + 196 + make up a bit pattern that defines the color of the flag as such: 197 + 198 + +=======+=======+=======+========+ 199 + | Bit 0 | Bit 1 | Bit 2 | Color | 200 + +=======+=======+=======+========+ 201 + | 0 | 0 | 0 | red | 202 + +-------+-------+-------+--------+ 203 + | 1 | 0 | 0 | orange | 204 + +-------+-------+-------+--------+ 205 + | 0 | 1 | 0 | yellow | 206 + +-------+-------+-------+--------+ 207 + | 1 | 1 | 0 | green | 208 + +-------+-------+-------+--------+ 209 + | 0 | 0 | 1 | blue | 210 + +-------+-------+-------+--------+ 211 + | 1 | 0 | 1 | purple | 212 + +-------+-------+-------+--------+ 213 + | 0 | 1 | 1 | gray | 214 + +-------+-------+-------+--------+ 215 + 216 + Table 1: Flag Colors 217 + 218 + Note that the bit combination 111 (all three bits set) is not 219 + assigned a color, resulting in 7 distinct flag colors instead of 8 220 + possible combinations. 221 + 222 + 223 + 224 + Jenkins & Eggert Expires 4 June 2026 [Page 4] 225 + 226 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 227 + 228 + 229 + These flags MUST be ignored if the \Flagged system flag is not set. 230 + If the \Flagged system flag is set, the flagged status MAY be 231 + presented to the user in the color corresponding to the combination 232 + of the 3 flag color keywords. 233 + 234 + 3.2. Implementation Notes 235 + 236 + A mail client that is aware of these flag color keywords MUST clear 237 + all 3 flag color keywords when the user unflags the message, i.e. 238 + when clearing the \Flagged system flag, all 3 flag color keywords 239 + MUST also be cleared. 240 + 241 + A mail client MUST NOT set any of these flags unless the \Flagged 242 + system flag is already set or is being set. 243 + 244 + Servers MAY clear these flag color keywords when a client clears the 245 + \Flagged system flag. 246 + 247 + While these keywords are defined in terms of colors, clients SHOULD 248 + provide alternatives for users who cannot perceive colors. This 249 + could include using different shapes, patterns, text labels, audio 250 + cues, or other distinguishing characteristics that convey the same 251 + semantic meaning as the color variations. The specific bit patterns 252 + can serve as identifiers for such alternative representations. 253 + 254 + 4. Attachment Detection Keywords 255 + 256 + The following keywords help clients determine whether a message 257 + contains attachments without having to fetch and parse the entire 258 + message structure. This is particularly useful for displaying 259 + attachment indicators in message lists or implementing attachment- 260 + based filtering. 261 + 262 + The $hasattachment and $hasnoattachment keywords are mutually 263 + exclusive. A message MUST NOT have both keywords set simultaneously. 264 + 265 + 4.1. $hasattachment 266 + 267 + The $hasattachment keyword indicates that a message has one or more 268 + attachments. It is set by the server during message delivery, or by 269 + the client (if neither $hasattachment nor $hasnoattachment are 270 + currently set). 271 + 272 + This keyword enables clients to indicate attachments (e.g., paperclip 273 + icons) in message lists without having to fetch the full MIME 274 + structure for each message. It also facilitates attachment-based 275 + filtering and search operations. 276 + 277 + 278 + 279 + 280 + Jenkins & Eggert Expires 4 June 2026 [Page 5] 281 + 282 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 283 + 284 + 285 + When using JMAP, the "hasAttachment" Email property MUST reflect the 286 + same information as this keyword for consistency across protocols. 287 + 288 + 4.2. $hasnoattachment 289 + 290 + The $hasnoattachment keyword explicitly indicates that a message does 291 + not have any attachments. It is set by the server during message 292 + delivery, or by the client (if neither $hasattachment nor 293 + $hasnoattachment are currently set). 294 + 295 + This keyword complements $hasattachment by providing definitive 296 + information about messages that have been analyzed but found to 297 + contain no attachments. The absence of $hasattachment alone is 298 + inconclusive, as it might simply mean the message hasn't been 299 + processed for attachment detection. 300 + 301 + This explicit distinction is important for clients that need to know 302 + whether attachment detection has been performed on a message. When 303 + using JMAP, the "hasAttachment" Email property MUST reflect the same 304 + information as this keyword. 305 + 306 + 5. Memos Keywords 307 + 308 + The following keywords are used to support user-created annotations 309 + or memos attached to messages. They allow for contextual notes to be 310 + added to conversations while maintaining proper cross-referencing 311 + between messages and their annotations. 312 + 313 + The $memo keyword is applied to the memo message itself (the note-to- 314 + self), while the $hasmemo keyword is applied to the original message 315 + being annotated. This creates a bidirectional relationship that 316 + allows clients to efficiently locate memos and their associated 317 + messages. 318 + 319 + The $memo and $hasmemo keywords are mutually exclusive. A message 320 + MUST NOT have both keywords set simultaneously. 321 + 322 + 5.1. $hasmemo 323 + 324 + The $hasmemo keyword indicates that a message has an associated memo 325 + (identified by the $memo keyword) in the same thread. This allows 326 + clients to efficiently identify messages with annotations without 327 + having to examine all messages in a thread. 328 + 329 + When a client creates a memo for a message, it MUST add this keyword 330 + to the message being annotated while adding the $memo keyword to the 331 + memo message itself. Conversely, when a memo is deleted, the client 332 + MUST remove this keyword from the annotated message. 333 + 334 + 335 + 336 + Jenkins & Eggert Expires 4 June 2026 [Page 6] 337 + 338 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 339 + 340 + 341 + This keyword enables several optimizations for clients. It allows 342 + for efficient searching for messages with annotations, enables 343 + indicators in message lists to indicate which messages have memos, 344 + and helps clients decide whether to fetch entire conversation threads 345 + when loading a mailbox to ensure memos are properly presented. 346 + 347 + 5.2. $memo 348 + 349 + The $memo keyword identifies a message as a note-to-self created by 350 + the user regarding another message in the same thread. It allows for 351 + contextual annotations to be added to conversations. 352 + 353 + Messages with this keyword should be constructed similar to a reply 354 + to the message being annotated, with appropriate Subject and Reply-To 355 + headers set to maintain context and threading. Servers SHOULD store 356 + messages with this keyword in a mailbox with the "Memos" mailbox name 357 + attribute (see Section 9.2.3), if available. 358 + 359 + Supporting clients MUST present these messages differently from 360 + regular emails. Rather than presenting them as standalone messages, 361 + they MUST be presented as annotations attached to the message they're 362 + commenting on. Clients may provide special UI affordances for 363 + editing or deleting these memos, which typically requires replacing 364 + the message since email messages are immutable. 365 + 366 + When a client creates or removes a memo, it MUST also set or clear 367 + the related $hasmemo keyword on the message being annotated to 368 + maintain proper cross-referencing. 369 + 370 + 6. Subscription Management Keywords 371 + 372 + The following keywords help clients manage mailing list 373 + subscriptions. They provide mechanisms for tracking unsubscription 374 + attempts and identifying messages with valid unsubscribe options. 375 + 376 + 6.1. $canunsubscribe 377 + 378 + The $canunsubscribe keyword indicates that a message contains a 379 + valid, [RFC8058]-compliant List-Unsubscribe header that clients can 380 + use to provide one-click unsubscribe functionality. 381 + 382 + This keyword is set by servers during message delivery when they 383 + detect a valid List-Unsubscribe header and the message passes 384 + implementation-specific reputation checks. This pre-verification is 385 + important, as not all List-Unsubscribe headers are trustworthy, and 386 + some might lead to phishing sites or generate additional spam. 387 + 388 + 389 + 390 + 391 + 392 + Jenkins & Eggert Expires 4 June 2026 [Page 7] 393 + 394 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 395 + 396 + 397 + The primary benefit of this keyword is efficiency--clients can know 398 + whether to offer unsubscribe functionality in their user interface 399 + without having to fetch and validate the List-Unsubscribe header for 400 + every message. It also provides an extra layer of safety since the 401 + server has already performed reputation checks on the unsubscribe 402 + mechanism. 403 + 404 + 6.2. $unsubscribed 405 + 406 + The $unsubscribed keyword indicates that the user has attempted to 407 + unsubscribe from the mailing list associated with a message. It 408 + provides a persistent record of unsubscription attempts across 409 + multiple clients. 410 + 411 + This keyword is set by a client after a user attempts to unsubscribe 412 + from a mailing list, typically via a one-click List-Unsubscribe 413 + action as defined in [RFC8058]. It serves as a record that an 414 + unsubscription attempt has been made, even if confirmation of 415 + successful unsubscription hasn't been received. It MUST NOT be set 416 + if the unsubscription attempt definitely failed. 417 + 418 + Supporting clients can use this to provide an indicator on messages 419 + with this keyword to remind the user they have previously attempted 420 + to unsubscribe from this sender or mailing list. This can be helpful 421 + when users revisit old messages and might otherwise attempt to 422 + unsubscribe again, or when they receive additional messages despite 423 + unsubscribing and need to take further action. 424 + 425 + 7. Other Message Keywords 426 + 427 + 7.1. $autosent 428 + 429 + The $autosent keyword identifies messages that were automatically 430 + generated and sent by the system on behalf of the user, typically in 431 + response to user-defined filtering rules or settings. 432 + 433 + This keyword is set by the server on the user's copy of vacation 434 + auto-replies, automated responses, or other system-generated messages 435 + sent on behalf of the user. It allows clients to clearly distinguish 436 + these messages from those directly composed and sent by the user. 437 + 438 + Supporting clients can present these messages differently in the sent 439 + items folder, such as with a distinct indicator (e.g., icon or label) 440 + indicating their automated nature. This helps prevent user confusion 441 + when they encounter messages they don't remember writing, 442 + particularly in the case of vacation responses or other automated 443 + replies that may have been configured and then forgotten. 444 + 445 + 446 + 447 + 448 + Jenkins & Eggert Expires 4 June 2026 [Page 8] 449 + 450 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 451 + 452 + 453 + 7.2. $followed 454 + 455 + The $followed keyword indicates that a user is particularly 456 + interested in future messages in a specific thread. This enables 457 + special handling to ensure these messages receive appropriate 458 + attention. 459 + 460 + When a new message arrives in a thread where this keyword is present, 461 + supporting servers MAY take actions to prioritize the message. This 462 + could include ensuring it is available in the inbox regardless of 463 + filtering rules that might otherwise affect it, automatically adding 464 + the $notify keyword to ensure notifications, or applying other 465 + handling that increases its prominence. The specific actions taken 466 + and whether they can be configured by the user depends on the 467 + implementation. 468 + 469 + Thread identification for this keyword follows the same definition as 470 + described in $muted. 471 + 472 + This keyword is set or cleared by clients based on user actions to 473 + follow or unfollow a thread. When unfollowing a thread, clients MUST 474 + remove this keyword from all messages in the thread that have it. 475 + The $followed keyword is mutually exclusive with the $muted keyword. 476 + If both are present on messages in the same thread, servers MUST 477 + treat the thread as followed rather than muted. 478 + 479 + 7.3. $imported 480 + 481 + The $imported keyword identifies messages that were imported into the 482 + mailbox from another system rather than received through normal mail 483 + delivery channels. 484 + 485 + This keyword is set by servers during import operations from other 486 + mail systems, data migrations, or manual imports from local files. 487 + It helps distinguish messages that didn't arrive through normal mail 488 + delivery and may have different characteristics or behaviors. 489 + 490 + Supporting clients can provide an indicator for imported messages, 491 + especially if they have unusual properties such as unexpectedly old 492 + dates, unusual header structures, or other anomalies that might 493 + otherwise confuse users. Some clients might also offer filtering or 494 + search capabilities specifically for imported messages. 495 + 496 + 7.4. $istrusted 497 + 498 + The $istrusted keyword indicates that a message's sender identity has 499 + been verified by the server with a high degree of confidence. It 500 + provides an indication that the message is likely authentic. 501 + 502 + 503 + 504 + Jenkins & Eggert Expires 4 June 2026 [Page 9] 505 + 506 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 507 + 508 + 509 + This advisory keyword is set by the server during message delivery 510 + when the authenticity of both the sender's name and email address can 511 + be verified with a high degree of confidence. This level of 512 + verification typically applies to messages sent by the mailbox 513 + provider itself to its customers, where the provider has strong 514 + evidence of the message's origin. 515 + 516 + Supporting clients can provide a verification indicator (e.g., 517 + checkmark icon) for messages with this keyword, helping users 518 + identify legitimate communications from their service provider. This 519 + is particularly important for distinguishing authentic provider 520 + messages from phishing attempts that impersonate the provider. 521 + 522 + Servers MUST exercise caution when applying this keyword, as it 523 + conveys trust to the user. If misapplied, it could lead users to 524 + trust fraudulent messages. 525 + 526 + It MUST NOT be used for messages that have only passed standard 527 + authentication mechanisms like SPF, DKIM, or DMARC. 528 + 529 + 7.5. $maskedemail 530 + 531 + The $maskedemail keyword indicates that a message was received 532 + through a masked email address--an alias created specifically for 533 + communications with a particular sender to protect the user's primary 534 + email address. 535 + 536 + This advisory keyword is set by the server during message delivery on 537 + messages that arrive via such aliases. These might be automatically 538 + generated single-use addresses, service-specific addresses, or user- 539 + created aliases for specific correspondents. 540 + 541 + Supporting clients can provide an indicator (e.g., mask icon) for 542 + messages with this keyword. This helps users understand that the 543 + message was received through a privacy-enhancing alias rather than 544 + their primary address. Clients might also provide related 545 + functionality, such as the ability to disable the specific alias used 546 + if it starts receiving unwanted messages. 547 + 548 + 7.6. $muted 549 + 550 + The $muted keyword provides a way for users to indicate they are not 551 + interested in future messages in a particular conversation thread. 552 + This enables automated processing of subsequent messages in that 553 + thread to reduce their prominence. 554 + 555 + 556 + 557 + 558 + 559 + 560 + Jenkins & Eggert Expires 4 June 2026 [Page 10] 561 + 562 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 563 + 564 + 565 + When a new message arrives that belongs to the same thread as one 566 + marked with this keyword, supporting servers MAY automatically 567 + deprioritize the message. This could include moving it to an archive 568 + or trash folder, marking it as read, or applying other handling that 569 + reduces its prominence. The specific actions taken and whether they 570 + can be configured by the user depends on the implementation. 571 + 572 + For thread identification purposes, messages are considered part of 573 + the same thread when they share the same thread identifier as defined 574 + in [RFC8474] Section 5.2 for IMAP or [RFC8621], Section 3 for JMAP. 575 + This definition applies to all thread-related keywords in this 576 + document. 577 + 578 + This keyword is set or cleared by clients based on user actions to 579 + mute or unmute a thread. When unmuting a thread, clients MUST remove 580 + this keyword from all messages in the thread that have it. The 581 + $muted keyword is mutually exclusive with the $followed keyword. If 582 + both are present on messages in the same thread, both servers and 583 + clients MUST treat the thread as followed rather than muted. 584 + 585 + Implementers should note the security considerations in the IANA 586 + registration: if an attacker gains access to a user's account, they 587 + could mute threads to hide important communications. However, this 588 + represents only a small increase in risk since compromised accounts 589 + allow many other similar actions. 590 + 591 + 7.7. $new 592 + 593 + The $new keyword indicates that a message should be emphasized or 594 + made more prominent to the user due to a recent system action, even 595 + if the message itself is not new. 596 + 597 + This advisory keyword is typically set by servers when a previously 598 + snoozed message "awakens" and returns to the inbox after its snooze 599 + period has elapsed. It signals to clients that although this message 600 + might have an older date, it should be treated as effectively new in 601 + terms of user attention. 602 + 603 + Supporting clients can present these messages with special treatment 604 + to draw user attention, such as emphasizing, bolding, or placing them 605 + at the top of the message list, even if strict date sorting would 606 + place them elsewhere. 607 + 608 + Clients MUST clear this keyword when the user interacts with the 609 + message, such as by opening, replying to, or otherwise acknowledging 610 + it. This prevents the message from remaining emphasized indefinitely 611 + after the user has accessed it. 612 + 613 + 614 + 615 + 616 + Jenkins & Eggert Expires 4 June 2026 [Page 11] 617 + 618 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 619 + 620 + 621 + 7.8. $notify 622 + 623 + The $notify keyword indicates that a client should present a 624 + notification for a message. This provides a mechanism for more 625 + selective notifications than the common approach of notifying for 626 + every message arriving in the inbox. 627 + 628 + When a message with this keyword is delivered to a mailstore, 629 + supporting clients SHOULD present a notification to the user unless 630 + configured otherwise by the user. This notification may occur 631 + alongside other message notifications according to user preferences. 632 + 633 + This keyword enables both users (through filtering rules) and servers 634 + (through automated processing) to identify specific messages that 635 + warrant user attention, even if they might otherwise be filtered or 636 + sorted in a way that wouldn't normally trigger a notification. 637 + 638 + Servers typically set this keyword during message delivery when a 639 + message meets certain criteria indicating importance to the user. 640 + Clients may clear the keyword when the user interacts with the 641 + message by opening it, archiving it, or performing other actions. 642 + When one client clears this keyword, other clients connected to the 643 + same account may choose to automatically dismiss their corresponding 644 + notification. 645 + 646 + 8. Mailbox Name Attributes 647 + 648 + 8.1. Snoozed 649 + 650 + The Snoozed mailbox name attribute identifies a mailbox that is used 651 + to store messages that have been temporarily removed from the user's 652 + attention and scheduled to reappear at a later time. 653 + 654 + When a user chooses to "snooze" a message, the supporting server will 655 + move the message to a mailbox with this attribute. At the specified 656 + "awaken" time, the server will automatically move the message back to 657 + its original location (typically the inbox) and may mark it with the 658 + $new keyword to ensure it receives proper attention. 659 + 660 + This attribute standardizes the location of snoozed messages across 661 + clients, allowing them to identify and manage snoozed messages 662 + consistently. However, this attribute merely identifies the storage 663 + location for snoozed messages and does not itself define the snoozing 664 + mechanism or interface. 665 + 666 + 667 + 668 + 669 + 670 + 671 + 672 + Jenkins & Eggert Expires 4 June 2026 [Page 12] 673 + 674 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 675 + 676 + 677 + Supporting clients may present the contents of this mailbox 678 + differently from regular mailboxes, such as organizing messages by 679 + their scheduled "awaken" time rather than received date, or providing 680 + specialized interfaces for adjusting the snooze duration. 681 + 682 + 8.2. Scheduled 683 + 684 + The Scheduled mailbox name attribute identifies a mailbox that 685 + contains messages that have been composed but are scheduled to be 686 + sent at a future time rather than immediately. 687 + 688 + When a user composes a message and chooses to send it at a later date 689 + or time, the supporting server will store the message in a mailbox 690 + with this attribute until the scheduled sending time. Once that time 691 + is reached, the server will send the message and typically move it to 692 + the \Sent mailbox or delete it according to server policy. 693 + 694 + This attribute standardizes the location of scheduled messages across 695 + clients, enabling users to review, edit, or cancel scheduled messages 696 + before they are sent, regardless of which client was used to schedule 697 + them. 698 + 699 + Supporting clients may present the contents of this mailbox in a way 700 + that highlights the scheduled sending time and allow users to modify 701 + or cancel scheduled messages before they are sent. 702 + 703 + 8.3. Memos 704 + 705 + The Memos mailbox name attribute identifies a mailbox designated for 706 + storing messages that have the $memo keyword. These messages are 707 + user-created notes or annotations related to other messages. 708 + 709 + When a user creates a memo (a note-to-self regarding another 710 + message), clients SHOULD store these messages in a mailbox with this 711 + attribute. This separation allows clients to handle memos 712 + differently from regular messages, presenting them as annotations 713 + rather than standalone communications. 714 + 715 + Storing memos in a designated mailbox helps prevent them from 716 + cluttering the user's inbox or other message folders, while still 717 + maintaining them as proper email messages for compatibility and 718 + synchronization purposes. 719 + 720 + Supporting clients MUST NOT present the contents of this mailbox as 721 + regular messages in their interface, but instead MUST present them 722 + contextually alongside the messages they annotate when those messages 723 + are accessed. 724 + 725 + 726 + 727 + 728 + Jenkins & Eggert Expires 4 June 2026 [Page 13] 729 + 730 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 731 + 732 + 733 + 9. IANA Considerations 734 + 735 + The following 16 IMAP/JMAP keywords are registered in the _IMAP and 736 + JMAP Keywords_ registry, as established in [RFC5788]. 737 + 738 + 9.1. IMAP/JMAP Keyword Registrations 739 + 740 + 9.1.1. $autosent keyword registration 741 + 742 + IMAP/JMAP keyword name: $autosent 743 + Purpose: Indicate to the client that a message was sent 744 + automatically as a response due to a user rule or setting. 745 + Private or Shared on a server: SHARED 746 + Is it an advisory keyword or may it cause an automatic action: This 747 + keyword is advisory. 748 + When/by whom the keyword is set/cleared: This keyword is set by the 749 + server on delivery. 750 + Related keywords: None 751 + Related IMAP capabilities: None 752 + Security considerations: None 753 + Published specification: This document 754 + Intended usage: COMMON 755 + Scope: BOTH 756 + Owner/Change controller: IESG 757 + 758 + 9.1.2. $canunsubscribe keyword registration 759 + 760 + IMAP/JMAP keyword name: $canunsubscribe 761 + Purpose: Indicate to the client that this message has an [RFC8058]- 762 + compliant List-Unsubscribe header. 763 + Private or Shared on a server: SHARED 764 + Is it an advisory keyword or may it cause an automatic action: This 765 + keyword is advisory. 766 + When/by whom the keyword is set/cleared: This keyword is set by the 767 + server on delivery. 768 + Related keywords: None 769 + Related IMAP capabilities: None 770 + Security considerations: None 771 + Published specification: This document 772 + Intended usage: COMMON 773 + Scope: BOTH 774 + Owner/Change controller: IESG 775 + 776 + 9.1.3. $followed keyword registration 777 + 778 + IMAP/JMAP keyword name: $followed 779 + Purpose: Indicate to the server that the user is particularly 780 + interested in future replies to a particular thread. 781 + 782 + 783 + 784 + Jenkins & Eggert Expires 4 June 2026 [Page 14] 785 + 786 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 787 + 788 + 789 + Private or Shared on a server: SHARED 790 + Is it an advisory keyword or may it cause an automatic action: This 791 + keyword can cause automatic action. 792 + When/by whom the keyword is set/cleared: This keyword is set and 793 + cleared by the client. 794 + Related keywords: Mutually exclusive with $muted. If both are 795 + specified on a thread, servers MUST behave as though only 796 + $followed were set. 797 + Related IMAP capabilities: None 798 + Security considerations: None 799 + Published specification: This document 800 + Intended usage: COMMON 801 + Scope: BOTH 802 + Owner/Change controller: IESG 803 + 804 + 9.1.4. $hasattachment keyword registration 805 + 806 + IMAP/JMAP keyword name: $hasattachment 807 + Purpose: Indicate to the client that a message has an attachment. 808 + Private or Shared on a server: SHARED 809 + Is it an advisory keyword or may it cause an automatic action: This 810 + keyword is advisory. 811 + When/by whom the keyword is set/cleared: It is set by the server 812 + during message delivery, or by the client (if neither 813 + $hasattachment nor $hasnoattachment are currently set). 814 + Related keywords: $hasnoattachment 815 + Related IMAP capabilities: None 816 + Security considerations: None 817 + Published specification: This document 818 + Intended usage: COMMON 819 + Scope: BOTH 820 + Owner/Change controller: IESG 821 + 822 + 9.1.5. $hasmemo keyword registration 823 + 824 + IMAP/JMAP keyword name: $hasmemo 825 + Purpose: Indicate to the client that a message has an associated 826 + memo with the $memo keyword. 827 + Private or Shared on a server: SHARED 828 + Is it an advisory keyword or may it cause an automatic action: This 829 + keyword is advisory. 830 + When/by whom the keyword is set/cleared: This keyword is set and 831 + cleared by the client based on user interaction. 832 + Related keywords: The $memo and $hasmemo keywords are mutually 833 + exclusive. 834 + Related IMAP capabilities: None 835 + Security considerations: None 836 + Published specification: This document 837 + 838 + 839 + 840 + Jenkins & Eggert Expires 4 June 2026 [Page 15] 841 + 842 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 843 + 844 + 845 + Intended usage: COMMON 846 + Scope: BOTH 847 + Owner/Change controller: IESG 848 + 849 + 9.1.6. $hasnoattachment keyword registration 850 + 851 + IMAP/JMAP keyword name: $hasnoattachment 852 + Purpose: Indicate to the client that a message does not have an 853 + attachment. 854 + Private or Shared on a server: SHARED 855 + Is it an advisory keyword or may it cause an automatic action: This 856 + keyword is advisory. 857 + When/by whom the keyword is set/cleared: It is set by the server 858 + during message delivery, or by the client (if neither 859 + $hasattachment nor $hasnoattachment are currently set). 860 + Related keywords: None 861 + Related IMAP capabilities: None 862 + Security considerations: None 863 + Published specification: This document 864 + Intended usage: COMMON 865 + Scope: BOTH 866 + Owner/Change controller: IESG 867 + 868 + 9.1.7. $imported keyword registration 869 + 870 + IMAP/JMAP keyword name: $imported 871 + Purpose: Indicate to the client that this message was imported from 872 + another mailbox. 873 + Private or Shared on a server: SHARED 874 + Is it an advisory keyword or may it cause an automatic action: This 875 + keyword is advisory. 876 + When/by whom the keyword is set/cleared: This keyword is set by the 877 + server on delivery. 878 + Related keywords: None 879 + Related IMAP capabilities: None 880 + Security considerations: None 881 + Published specification: This document 882 + Intended usage: COMMON 883 + Scope: BOTH 884 + Owner/Change controller: IESG 885 + 886 + 9.1.8. $istrusted keyword registration 887 + 888 + IMAP/JMAP keyword name: $istrusted 889 + Purpose: Indicate to the client that the authenticity of the from 890 + name and email address have been verified by the server. 891 + Private or Shared on a server: SHARED 892 + Is it an advisory keyword or may it cause an automatic action: This 893 + 894 + 895 + 896 + Jenkins & Eggert Expires 4 June 2026 [Page 16] 897 + 898 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 899 + 900 + 901 + keyword is advisory. 902 + When/by whom the keyword is set/cleared: This keyword is set by the 903 + server on delivery. 904 + Related keywords: None 905 + Related IMAP capabilities: None 906 + Security considerations: Servers should make sure this keyword is 907 + only set for messages that really are trusted. 908 + Published specification: This document 909 + Intended usage: COMMON 910 + Scope: BOTH 911 + Owner/Change controller: IESG 912 + 913 + 9.1.9. $MailFlagBit0 keyword registration 914 + 915 + IMAP/JMAP keyword name: $MailFlagBit0 916 + Purpose: Bit 0 part of a 3-bit bitmask that defines the color of the 917 + flag when the message has the system flag \Flagged set. See 918 + Section 3 for details. 919 + Private or Shared on a server: SHARED 920 + Is it an advisory keyword or may it cause an automatic action: No 921 + When/by whom the keyword is set/cleared: This keyword is set by a 922 + client as the result of a user action to "flag" a message for 923 + urgent/special attention. 924 + Related keywords: $MailFlagBit1, $MailFlagBit2 925 + Related IMAP capabilities: None 926 + Security considerations: None 927 + Published specification: This document 928 + Intended usage: COMMON 929 + Scope: BOTH 930 + Owner/Change controller: IESG 931 + 932 + 9.1.10. $MailFlagBit1 keyword registration 933 + 934 + IMAP/JMAP keyword name: $MailFlagBit1 935 + Purpose: Bit 1 part of a 3-bit bitmask that defines the color of the 936 + flag when the message has the system flag \Flagged set. See 937 + Section 3 for details. 938 + Private or Shared on a server: SHARED 939 + Is it an advisory keyword or may it cause an automatic action: No 940 + When/by whom the keyword is set/cleared: This keyword is set by a 941 + client as the result of a user action to "flag" a message for 942 + urgent/special attention. 943 + Related keywords: $MailFlagBit0, $MailFlagBit2 944 + Related IMAP capabilities: None 945 + Security considerations: None 946 + Published specification: This document 947 + Intended usage: COMMON 948 + Scope: BOTH 949 + 950 + 951 + 952 + Jenkins & Eggert Expires 4 June 2026 [Page 17] 953 + 954 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 955 + 956 + 957 + Owner/Change controller: IESG 958 + 959 + 9.1.11. $MailFlagBit2 keyword registration 960 + 961 + IMAP/JMAP keyword name: $MailFlagBit2 962 + Purpose: Bit 2 part of a 3-bit bitmask that defines the color of the 963 + flag when the message has the system flag \Flagged set. See 964 + Section 3 for details. 965 + Private or Shared on a server: SHARED 966 + Is it an advisory keyword or may it cause an automatic action: No 967 + When/by whom the keyword is set/cleared: This keyword is set by a 968 + client as the result of a user action to "flag" a message for 969 + urgent/special attention. 970 + Related keywords: $MailFlagBit0, $MailFlagBit1 971 + Related IMAP capabilities: None 972 + Security considerations: None 973 + Published specification: This document 974 + Intended usage: COMMON 975 + Scope: BOTH 976 + Owner/Change controller: IESG 977 + 978 + 9.1.12. $maskedemail keyword registration 979 + 980 + IMAP/JMAP keyword name: $maskedemail 981 + Purpose: Indicate to the client that the message was received via an 982 + alias created for an individual sender. 983 + Private or Shared on a server: SHARED 984 + Is it an advisory keyword or may it cause an automatic action: This 985 + keyword is advisory. 986 + When/by whom the keyword is set/cleared: This keyword is set by the 987 + server on delivery. 988 + Related keywords: None 989 + Related IMAP capabilities: None 990 + Security considerations: None 991 + Published specification: This document 992 + Intended usage: LIMITED 993 + Scope: BOTH 994 + Owner/Change controller: IESG 995 + 996 + 9.1.13. $memo keyword registration 997 + 998 + IMAP/JMAP keyword name: $memo 999 + Purpose: Indicate to the client that a message is a note-to-self 1000 + from the user regarding another message in the same thread. 1001 + Private or Shared on a server: SHARED 1002 + Is it an advisory keyword or may it cause an automatic action: This 1003 + keyword is advisory. 1004 + When/by whom the keyword is set/cleared: This keyword is set and 1005 + 1006 + 1007 + 1008 + Jenkins & Eggert Expires 4 June 2026 [Page 18] 1009 + 1010 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 1011 + 1012 + 1013 + cleared by the client based on user interaction. 1014 + Related keywords: The $memo and $hasmemo keywords are mutually 1015 + exclusive. 1016 + Related IMAP capabilities: None 1017 + Security considerations: None 1018 + Published specification: This document 1019 + Intended usage: COMMON 1020 + Scope: BOTH 1021 + Owner/Change controller: IESG 1022 + 1023 + 9.1.14. $muted keyword registration 1024 + 1025 + IMAP/JMAP keyword name: $muted 1026 + Purpose: Indicate to the server that the user is not interested in 1027 + future replies to a particular thread. 1028 + Private or Shared on a server: SHARED 1029 + Is it an advisory keyword or may it cause an automatic action: This 1030 + keyword can cause an automatic action. 1031 + When/by whom the keyword is set/cleared: This keyword is set and 1032 + cleared by the client. 1033 + Related keywords: Mutually exclusive with $followed. If both are 1034 + specified on a thread, servers MUST behave as though only 1035 + $followed were set. 1036 + Related IMAP capabilities: None 1037 + Security considerations: Muting a thread can mean a user won't be 1038 + notified of a reply. If someone compromises a user's account, 1039 + they may mute threads where they don't want the user to be 1040 + notified of the reply, for example when sending phishing to the 1041 + user's contacts. There are many other ways an attacker with 1042 + access to the user's mailbox can also achieve this however, so 1043 + this is not greatly increasing the attack surface. When restoring 1044 + legitimate access to a stolen account, care must be taken to find 1045 + and confirm/revert mute actions that may have been taken by the 1046 + attacker. 1047 + Published specification: This document 1048 + Intended usage: COMMON 1049 + Scope: BOTH 1050 + Owner/Change controller: IESG 1051 + 1052 + 9.1.15. $new keyword registration 1053 + 1054 + IMAP/JMAP keyword name: $new 1055 + Purpose: Indicate to the client that a message should be made more 1056 + prominent to the user due to a recent action. 1057 + Private or Shared on a server: SHARED 1058 + Is it an advisory keyword or may it cause an automatic action: This 1059 + keyword is advisory. 1060 + When/by whom the keyword is set/cleared: This keyword is set by the 1061 + 1062 + 1063 + 1064 + Jenkins & Eggert Expires 4 June 2026 [Page 19] 1065 + 1066 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 1067 + 1068 + 1069 + server. Clients can clear the keyword based on user interaction. 1070 + Related keywords: None 1071 + Related IMAP capabilities: None 1072 + Security considerations: None 1073 + Published specification: This document 1074 + Intended usage: LIMITED 1075 + Scope: BOTH 1076 + Owner/Change controller: IESG 1077 + 1078 + 9.1.16. $notify keyword registration 1079 + 1080 + IMAP/JMAP keyword name: $notify 1081 + Purpose: Indicate to the client that a notification should be 1082 + presented for this message. 1083 + Private or Shared on a server: SHARED 1084 + Is it an advisory keyword or may it cause an automatic action: This 1085 + keyword can cause an automatic action. 1086 + When/by whom the keyword is set/cleared: This keyword is set by the 1087 + server on delivery when a message meets certain criteria. It may 1088 + be cleared by a client when the user interacts with the message. 1089 + Related keywords: None 1090 + Related IMAP capabilities: None 1091 + Security considerations: None 1092 + Published specification: This document 1093 + Intended usage: COMMON 1094 + Scope: BOTH 1095 + Owner/Change controller: IESG 1096 + 1097 + 9.1.17. $unsubscribed keyword registration 1098 + 1099 + IMAP/JMAP keyword name: $unsubscribed 1100 + Purpose: Indicate the client has attempted to unsubscribe from the 1101 + mailing list this message is from. 1102 + Private or Shared on a server: SHARED 1103 + Is it an advisory keyword or may it cause an automatic action: This 1104 + keyword is advisory. 1105 + When/by whom the keyword is set/cleared: This keyword is set by the 1106 + client based on user interaction. 1107 + Related keywords: None 1108 + Related IMAP capabilities: None 1109 + Security considerations: None 1110 + Published specification: This document 1111 + Intended usage: COMMON 1112 + Scope: BOTH 1113 + Owner/Change controller: IESG 1114 + 1115 + 1116 + 1117 + 1118 + 1119 + 1120 + Jenkins & Eggert Expires 4 June 2026 [Page 20] 1121 + 1122 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 1123 + 1124 + 1125 + 9.2. IMAP Mailbox Name Attributes Registrations 1126 + 1127 + The following 3 IMAP/JMAP mailbox name attributes are registered in 1128 + the IMAP Mailbox Name Attributes Registry, as established in 1129 + [RFC8457]. 1130 + 1131 + Note that none of the attributes in this section have an implied 1132 + backslash. This sets them apart from those specified in Section 2 of 1133 + [RFC6154]. 1134 + 1135 + 9.2.1. Snoozed mailbox name attribute registration 1136 + 1137 + Attribute Name: Snoozed 1138 + Description: Identifies the mailbox where temporarily snoozed 1139 + messages are stored. 1140 + Reference: This document. 1141 + 1142 + 9.2.2. Scheduled mailbox name attribute registration 1143 + 1144 + Attribute Name: Scheduled 1145 + Description: Identifies the mailbox where messages scheduled to be 1146 + sent at a later time are stored. 1147 + Reference: This document. 1148 + 1149 + 9.2.3. Memos mailbox name attribute registration 1150 + 1151 + Attribute Name: Memos 1152 + Description: Identifies the mailbox where user-created memo messages 1153 + are stored. 1154 + Reference: This document. 1155 + 1156 + 10. Security Considerations 1157 + 1158 + The security considerations for the $istrusted and $muted keywords 1159 + are described in Section 9.1.8, Section 7.4, and Section 9.1.14 1160 + respectively. 1161 + 1162 + The use and interpretation of the keywords and mailbox name 1163 + attributes defined in this document depend on the client's and user's 1164 + ability to trust the IMAP server. Clients should be aware that a 1165 + compromised or malicious server could set these keywords incorrectly 1166 + or manipulate them to mislead users. For additional security 1167 + considerations related to IMAP, refer to [RFC9051]. 1168 + 1169 + Besides that this document should not affect the security of the 1170 + Internet. 1171 + 1172 + 11. References 1173 + 1174 + 1175 + 1176 + Jenkins & Eggert Expires 4 June 2026 [Page 21] 1177 + 1178 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 1179 + 1180 + 1181 + 11.1. Normative References 1182 + 1183 + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1184 + Requirement Levels", BCP 14, RFC 2119, 1185 + DOI 10.17487/RFC2119, March 1997, 1186 + <https://www.rfc-editor.org/info/rfc2119>. 1187 + 1188 + [RFC5788] Melnikov, A. and D. Cridland, "IMAP4 Keyword Registry", 1189 + RFC 5788, DOI 10.17487/RFC5788, March 2010, 1190 + <https://www.rfc-editor.org/info/rfc5788>. 1191 + 1192 + [RFC6154] Leiba, B. and J. Nicolson, "IMAP LIST Extension for 1193 + Special-Use Mailboxes", RFC 6154, DOI 10.17487/RFC6154, 1194 + March 2011, <https://www.rfc-editor.org/info/rfc6154>. 1195 + 1196 + [RFC8058] Levine, J. and T. Herkula, "Signaling One-Click 1197 + Functionality for List Email Headers", RFC 8058, 1198 + DOI 10.17487/RFC8058, January 2017, 1199 + <https://www.rfc-editor.org/info/rfc8058>. 1200 + 1201 + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 1202 + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 1203 + May 2017, <https://www.rfc-editor.org/info/rfc8174>. 1204 + 1205 + [RFC8457] Leiba, B., Ed., "IMAP "$Important" Keyword and 1206 + "\Important" Special-Use Attribute", RFC 8457, 1207 + DOI 10.17487/RFC8457, September 2018, 1208 + <https://www.rfc-editor.org/info/rfc8457>. 1209 + 1210 + [RFC8474] Gondwana, B., Ed., "IMAP Extension for Object 1211 + Identifiers", RFC 8474, DOI 10.17487/RFC8474, September 1212 + 2018, <https://www.rfc-editor.org/info/rfc8474>. 1213 + 1214 + [RFC8621] Jenkins, N. and C. Newman, "The JSON Meta Application 1215 + Protocol (JMAP) for Mail", RFC 8621, DOI 10.17487/RFC8621, 1216 + August 2019, <https://www.rfc-editor.org/info/rfc8621>. 1217 + 1218 + [RFC9051] Melnikov, A., Ed. and B. Leiba, Ed., "Internet Message 1219 + Access Protocol (IMAP) - Version 4rev2", RFC 9051, 1220 + DOI 10.17487/RFC9051, August 2021, 1221 + <https://www.rfc-editor.org/info/rfc9051>. 1222 + 1223 + Authors' Addresses 1224 + 1225 + 1226 + 1227 + 1228 + 1229 + 1230 + 1231 + 1232 + Jenkins & Eggert Expires 4 June 2026 [Page 22] 1233 + 1234 + Internet-Draft Further IMAP/JMAP keywords & attributes December 2025 1235 + 1236 + 1237 + Neil Jenkins 1238 + Fastmail 1239 + PO Box 234, Collins St West 1240 + Melbourne VIC 8007 1241 + Australia 1242 + Email: neilj@fastmailteam.com 1243 + URI: https://www.fastmail.com 1244 + 1245 + 1246 + Daniel Eggert 1247 + Apple Inc 1248 + One Apple Park Way 1249 + Cupertino, CA 95014 1250 + United States of America 1251 + Email: deggert@apple.com 1252 + URI: https://www.apple.com 1253 + 1254 + 1255 + 1256 + 1257 + 1258 + 1259 + 1260 + 1261 + 1262 + 1263 + 1264 + 1265 + 1266 + 1267 + 1268 + 1269 + 1270 + 1271 + 1272 + 1273 + 1274 + 1275 + 1276 + 1277 + 1278 + 1279 + 1280 + 1281 + 1282 + 1283 + 1284 + 1285 + 1286 + 1287 + 1288 + Jenkins & Eggert Expires 4 June 2026 [Page 23]
+283
spec/rfc3691.txt
··· 1 + 2 + 3 + 4 + 5 + 6 + 7 + Network Working Group A. Melnikov 8 + Request for Comments: 3691 Isode Ltd. 9 + Category: Standards Track February 2004 10 + 11 + 12 + Internet Message Access Protocol (IMAP) UNSELECT command 13 + 14 + Status of this Memo 15 + 16 + This document specifies an Internet standards track protocol for the 17 + Internet community, and requests discussion and suggestions for 18 + improvements. Please refer to the current edition of the "Internet 19 + Official Protocol Standards" (STD 1) for the standardization state 20 + and status of this protocol. Distribution of this memo is unlimited. 21 + 22 + Copyright Notice 23 + 24 + Copyright (C) The Internet Society (2004). All Rights Reserved. 25 + 26 + Abstract 27 + 28 + This document defines an UNSELECT command that can be used to close 29 + the current mailbox in an Internet Message Access Protocol - version 30 + 4 (IMAP4) session without expunging it. Certain types of IMAP 31 + clients need to release resources associated with the selected 32 + mailbox without selecting a different mailbox. While IMAP4 provides 33 + this functionality (via a SELECT command with a nonexistent mailbox 34 + name or reselecting the same mailbox with EXAMINE command), a more 35 + clean solution is desirable. 36 + 37 + Table of Contents 38 + 39 + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 40 + 2. UNSELECT command . . . . . . . . . . . . . . . . . . . . . . . 2 41 + 3. Security Considerations. . . . . . . . . . . . . . . . . . . . 3 42 + 4. Formal Syntax. . . . . . . . . . . . . . . . . . . . . . . . . 3 43 + 5. IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 3 44 + 6. Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . . 3 45 + 7. Normative References . . . . . . . . . . . . . . . . . . . . . 4 46 + 8. Author's Address . . . . . . . . . . . . . . . . . . . . . . . 4 47 + 9. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 5 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + Melnikov Standards Track [Page 1] 59 + 60 + RFC 3691 IMAP UNSELECT command February 2004 61 + 62 + 63 + 1. Introduction 64 + 65 + Certain types of IMAP clients need to release resources associated 66 + with the selected mailbox without selecting a different mailbox. 67 + While [IMAP4] provides this functionality (via a SELECT command with 68 + a nonexistent mailbox name or reselecting the same mailbox with 69 + EXAMINE command), a more clean solution is desirable. 70 + 71 + [IMAP4] defines the CLOSE command that closes the selected mailbox as 72 + well as permanently removes all messages with the \Deleted flag set. 73 + 74 + However [IMAP4] lacks a command that simply closes the mailbox 75 + without expunging it. This document defines the UNSELECT command for 76 + this purpose. 77 + 78 + A server which supports this extension indicates this with a 79 + capability name of "UNSELECT". 80 + 81 + "C:" and "S:" in examples show lines sent by the client and server 82 + respectively. 83 + 84 + The keywords "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in 85 + this document when typed in uppercase are to be interpreted as 86 + defined in "Key words for use in RFCs to Indicate Requirement Levels" 87 + [KEYWORDS]. 88 + 89 + 2. UNSELECT Command 90 + 91 + Arguments: none 92 + 93 + Responses: no specific responses for this command 94 + 95 + Result: OK - unselect completed, now in authenticated state 96 + BAD - no mailbox selected, or argument supplied but 97 + none permitted 98 + 99 + The UNSELECT command frees server's resources associated with the 100 + selected mailbox and returns the server to the authenticated 101 + state. This command performs the same actions as CLOSE, except 102 + that no messages are permanently removed from the currently 103 + selected mailbox. 104 + 105 + Example: C: A341 UNSELECT 106 + S: A341 OK Unselect completed 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + Melnikov Standards Track [Page 2] 115 + 116 + RFC 3691 IMAP UNSELECT command February 2004 117 + 118 + 119 + 3. Security Considerations 120 + 121 + It is believed that this extension doesn't raise any additional 122 + security concerns not already discussed in [IMAP4]. 123 + 124 + 4. Formal Syntax 125 + 126 + The following syntax specification uses the Augmented Backus-Naur 127 + Form (ABNF) notation as specified in [ABNF]. Non-terminals 128 + referenced but not defined below are as defined by [IMAP4]. 129 + 130 + Except as noted otherwise, all alphabetic characters are case- 131 + insensitive. The use of upper or lower case characters to define 132 + token strings is for editorial clarity only. Implementations MUST 133 + accept these strings in a case-insensitive fashion. 134 + 135 + command-select /= "UNSELECT" 136 + 137 + 5. IANA Considerations 138 + 139 + IMAP4 capabilities are registered by publishing a standards track or 140 + IESG approved experimental RFC. The registry is currently located 141 + at: 142 + 143 + http://www.iana.org/assignments/imap4-capabilities 144 + 145 + This document defines the UNSELECT IMAP capabilities. IANA has added 146 + this capability to the registry. 147 + 148 + 6. Acknowledgments 149 + 150 + UNSELECT command was originally implemented by Tim Showalter in Cyrus 151 + IMAP server. 152 + 153 + Also, the author of the document would like to thank Vladimir Butenko 154 + and Mark Crispin for reminding that UNSELECT has to be documented. 155 + Also thanks to Simon Josefsson for pointing out that there are 156 + multiple ways to implement UNSELECT. 157 + 158 + 159 + 160 + 161 + 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + Melnikov Standards Track [Page 3] 171 + 172 + RFC 3691 IMAP UNSELECT command February 2004 173 + 174 + 175 + 7. Normative References 176 + 177 + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate 178 + Requirement Levels", BCP 14, RFC 2119, March 1997. 179 + 180 + [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 181 + 4rev1", RFC 3501, March 2003. 182 + 183 + [ABNF] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax 184 + Specifications: ABNF", RFC 2234, November 1997. 185 + 186 + 8. Author's Address 187 + 188 + Alexey Melnikov 189 + Isode Limited 190 + 5 Castle Business Village 191 + Hampton, Middlesex TW12 2BX 192 + 193 + EMail: Alexey.Melnikov@isode.com 194 + URI: http://www.melnikov.ca/ 195 + 196 + 197 + 198 + 199 + 200 + 201 + 202 + 203 + 204 + 205 + 206 + 207 + 208 + 209 + 210 + 211 + 212 + 213 + 214 + 215 + 216 + 217 + 218 + 219 + 220 + 221 + 222 + 223 + 224 + 225 + 226 + Melnikov Standards Track [Page 4] 227 + 228 + RFC 3691 IMAP UNSELECT command February 2004 229 + 230 + 231 + 9. Full Copyright Statement 232 + 233 + Copyright (C) The Internet Society (2004). This document is subject 234 + to the rights, licenses and restrictions contained in BCP 78 and 235 + except as set forth therein, the authors retain all their rights. 236 + 237 + This document and the information contained herein are provided on an 238 + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE 239 + REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE 240 + INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR 241 + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF 242 + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED 243 + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 244 + 245 + Intellectual Property 246 + 247 + The IETF takes no position regarding the validity or scope of any 248 + Intellectual Property Rights or other rights that might be claimed 249 + to pertain to the implementation or use of the technology 250 + described in this document or the extent to which any license 251 + under such rights might or might not be available; nor does it 252 + represent that it has made any independent effort to identify any 253 + such rights. Information on the procedures with respect to 254 + rights in RFC documents can be found in BCP 78 and BCP 79. 255 + 256 + Copies of IPR disclosures made to the IETF Secretariat and any 257 + assurances of licenses to be made available, or the result of an 258 + attempt made to obtain a general license or permission for the use 259 + of such proprietary rights by implementers or users of this 260 + specification can be obtained from the IETF on-line IPR repository 261 + at http://www.ietf.org/ipr. 262 + 263 + The IETF invites any interested party to bring to its attention 264 + any copyrights, patents or patent applications, or other 265 + proprietary rights that may cover technology that may be required 266 + to implement this standard. Please address the information to the 267 + IETF at ietf-ipr@ietf.org. 268 + 269 + Acknowledgement 270 + 271 + Funding for the RFC Editor function is currently provided by the 272 + Internet Society. 273 + 274 + 275 + 276 + 277 + 278 + 279 + 280 + 281 + 282 + Melnikov Standards Track [Page 5] 283 +
+451
spec/rfc4731.txt
··· 1 + 2 + 3 + 4 + 5 + 6 + 7 + Network Working Group A. Melnikov 8 + Request for Comments: 4731 Isode Ltd 9 + Category: Standards Track D. Cridland 10 + Inventure Systems Ltd 11 + November 2006 12 + 13 + 14 + IMAP4 Extension to SEARCH Command for Controlling 15 + What Kind of Information Is Returned 16 + 17 + Status of This Memo 18 + 19 + This document specifies an Internet standards track protocol for the 20 + Internet community, and requests discussion and suggestions for 21 + improvements. Please refer to the current edition of the "Internet 22 + Official Protocol Standards" (STD 1) for the standardization state 23 + and status of this protocol. Distribution of this memo is unlimited. 24 + 25 + Copyright Notice 26 + 27 + Copyright (C) The IETF Trust (2006). 28 + 29 + Abstract 30 + 31 + This document extends IMAP (RFC 3501) SEARCH and UID SEARCH commands 32 + with several result options, which can control what kind of 33 + information is returned. The following result options are defined: 34 + minimal value, maximal value, all found messages, and number of found 35 + messages. 36 + 37 + Table of Contents 38 + 39 + 1. Introduction ....................................................2 40 + 2. Conventions Used in This Document ...............................2 41 + 3. IMAP Protocol Changes ...........................................2 42 + 3.1. New SEARCH/UID SEARCH Result Options .......................2 43 + 3.2. Interaction with CONDSTORE extension .......................4 44 + 4. Formal Syntax ...................................................5 45 + 5. Security Considerations .........................................6 46 + 6. IANA Considerations .............................................6 47 + 7. Normative References ............................................6 48 + 8. Acknowledgments .................................................6 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + Melnikov & Cridland Standards Track [Page 1] 59 + 60 + RFC 4731 IMAP4 Extension to SEARCH November 2006 61 + 62 + 63 + 1. Introduction 64 + 65 + [IMAPABNF] extended SEARCH and UID SEARCH commands with result 66 + specifiers (also known as result options), which can control what 67 + kind of information is returned. 68 + 69 + A server advertising the ESEARCH capability supports the following 70 + result options: minimal value, maximal value, all found messages, 71 + and number of found messages. These result options allow clients to 72 + get SEARCH results in more convenient forms, while also saving 73 + bandwidth required to transport the results, for example, by finding 74 + the first unseen message or returning the number of unseen or deleted 75 + messages. Also, when a single MIN or a single MAX result option is 76 + specified, servers can optimize execution of SEARCHes. 77 + 78 + 2. Conventions Used in This Document 79 + 80 + In examples, "C:" and "S:" indicate lines sent by the client and 81 + server, respectively. 82 + 83 + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 84 + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 85 + document are to be interpreted as described in RFC 2119 [KEYWORDS]. 86 + 87 + 3. IMAP Protocol Changes 88 + 89 + 3.1. New SEARCH/UID SEARCH Result Options 90 + 91 + The SEARCH/UID SEARCH commands are extended to allow for the 92 + following result options: 93 + 94 + MIN 95 + Return the lowest message number/UID that satisfies the SEARCH 96 + criteria. 97 + 98 + If the SEARCH results in no matches, the server MUST NOT 99 + include the MIN result option in the ESEARCH response; however, 100 + it still MUST send the ESEARCH response. 101 + 102 + MAX 103 + Return the highest message number/UID that satisfies the SEARCH 104 + criteria. 105 + 106 + If the SEARCH results in no matches, the server MUST NOT 107 + include the MAX result option in the ESEARCH response; however, 108 + it still MUST send the ESEARCH response. 109 + 110 + 111 + 112 + 113 + 114 + Melnikov & Cridland Standards Track [Page 2] 115 + 116 + RFC 4731 IMAP4 Extension to SEARCH November 2006 117 + 118 + 119 + ALL 120 + Return all message numbers/UIDs that satisfy the SEARCH 121 + criteria. Unlike regular (unextended) SEARCH, the messages are 122 + always returned using the sequence-set syntax. A sequence-set 123 + representation may be more compact and can be used as is in a 124 + subsequent command that accepts sequence-set. Note, the client 125 + MUST NOT assume that messages/UIDs will be listed in any 126 + particular order. 127 + 128 + If the SEARCH results in no matches, the server MUST NOT 129 + include the ALL result option in the ESEARCH response; however, 130 + it still MUST send the ESEARCH response. 131 + 132 + COUNT 133 + Return number of the messages that satisfy the SEARCH criteria. 134 + This result option MUST always be included in the ESEARCH 135 + response. 136 + 137 + If one or more result options described above are specified, the 138 + extended SEARCH command MUST return a single ESEARCH response 139 + [IMAPABNF], instead of the SEARCH response. 140 + 141 + An extended UID SEARCH command MUST cause an ESEARCH response with 142 + the UID indicator present. 143 + 144 + Note that future extensions to this document can allow servers to 145 + return multiple ESEARCH responses for a single extended SEARCH 146 + command. These extensions will have to describe how results from 147 + multiple ESEARCH responses are to be amalgamated. 148 + 149 + If the list of result options is empty, that requests the server to 150 + return an ESEARCH response instead of the SEARCH response. This is 151 + equivalent to "(ALL)". 152 + 153 + Example: C: A282 SEARCH RETURN (MIN COUNT) FLAGGED 154 + SINCE 1-Feb-1994 NOT FROM "Smith" 155 + S: * ESEARCH (TAG "A282") MIN 2 COUNT 3 156 + S: A282 OK SEARCH completed 157 + 158 + Example: C: A283 SEARCH RETURN () FLAGGED 159 + SINCE 1-Feb-1994 NOT FROM "Smith" 160 + S: * ESEARCH (TAG "A283") ALL 2,10:11 161 + S: A283 OK SEARCH completed 162 + 163 + The following example demonstrates finding the first unseen message 164 + as returned in the UNSEEN response code on a successful SELECT 165 + command: 166 + 167 + 168 + 169 + 170 + Melnikov & Cridland Standards Track [Page 3] 171 + 172 + RFC 4731 IMAP4 Extension to SEARCH November 2006 173 + 174 + 175 + Example: C: A284 SEARCH RETURN (MIN) UNSEEN 176 + S: * ESEARCH (TAG "A284") MIN 4 177 + S: A284 OK SEARCH completed 178 + 179 + The following example demonstrates that if the ESEARCH UID indicator 180 + is present, all data in the ESEARCH response is referring to UIDs; 181 + for example, the MIN result specifier will be followed by a UID. 182 + 183 + Example: C: A285 UID SEARCH RETURN (MIN MAX) 1:5000 184 + S: * ESEARCH (TAG "A285") UID MIN 7 MAX 3800 185 + S: A285 OK SEARCH completed 186 + 187 + The following example demonstrates returning the number of deleted 188 + messages: 189 + 190 + Example: C: A286 SEARCH RETURN (COUNT) DELETED 191 + S: * ESEARCH (TAG "A286") COUNT 15 192 + S: A286 OK SEARCH completed 193 + 194 + 3.2. Interaction with CONDSTORE extension 195 + 196 + When the server supports both the ESEARCH and the CONDSTORE 197 + [CONDSTORE] extension, and the client requests one or more result 198 + option described in section 3.1 together with the MODSEQ search 199 + criterion in the same SEARCH/UID SEARCH command, then the server MUST 200 + return the ESEARCH response containing the MODSEQ result option 201 + (described in the following paragraph) instead of the extended SEARCH 202 + response described in section 3.5 of [CONDSTORE]. 203 + 204 + If the SEARCH/UID SEARCH command contained a single MIN or MAX result 205 + option, the MODSEQ result option contains the mod-sequence for the 206 + found message. If the SEARCH/UID SEARCH command contained both MIN 207 + and MAX result options and no ALL/COUNT option, the MODSEQ result 208 + option contains the highest mod-sequence for the two returned 209 + messages. Otherwise the MODSEQ result option contains the highest 210 + mod-sequence for all messages being returned. 211 + 212 + Example: The following example demonstrates how Example 15 from 213 + [CONDSTORE] would look in the presence of one or more result option: 214 + 215 + C: a1 SEARCH RETURN (MIN) MODSEQ "/flags/\\draft" 216 + all 620162338 217 + S: * ESEARCH (TAG "a1") MIN 2 MODSEQ 917162488 218 + S: a1 OK Search complete 219 + 220 + C: a2 SEARCH RETURN (MAX) MODSEQ "/flags/\\draft" 221 + all 620162338 222 + S: * ESEARCH (TAG "a2") MAX 23 MODSEQ 907162321 223 + 224 + 225 + 226 + Melnikov & Cridland Standards Track [Page 4] 227 + 228 + RFC 4731 IMAP4 Extension to SEARCH November 2006 229 + 230 + 231 + S: a2 OK Search complete 232 + 233 + C: a3 SEARCH RETURN (MIN MAX) MODSEQ "/flags/\\draft" 234 + all 620162338 235 + S: * ESEARCH (TAG "a3") MIN 2 MAX 23 MODSEQ 917162488 236 + S: a3 OK Search complete 237 + 238 + C: a4 SEARCH RETURN (MIN COUNT) MODSEQ "/flags/\\draft" 239 + all 620162338 240 + S: * ESEARCH (TAG "a4") MIN 2 COUNT 10 MODSEQ 917162500 241 + S: a4 OK Search complete 242 + 243 + 4. Formal Syntax 244 + 245 + The following syntax specification uses the Augmented Backus-Naur 246 + Form (ABNF) notation as specified in [ABNF]. 247 + 248 + Non-terminals referenced but not defined below are as defined by 249 + [IMAP4], [CONDSTORE], or [IMAPABNF]. 250 + 251 + Except as noted otherwise, all alphabetic characters are case- 252 + insensitive. The use of upper or lowercase characters to define 253 + token strings is for editorial clarity only. Implementations MUST 254 + accept these strings in a case-insensitive fashion. 255 + 256 + capability =/ "ESEARCH" 257 + 258 + search-return-data = "MIN" SP nz-number / 259 + "MAX" SP nz-number / 260 + "ALL" SP sequence-set / 261 + "COUNT" SP number 262 + ;; conforms to the generic 263 + ;; search-return-data syntax defined 264 + ;; in [IMAPABNF] 265 + 266 + search-return-opt = "MIN" / "MAX" / "ALL" / "COUNT" 267 + ;; conforms to generic search-return-opt 268 + ;; syntax defined in [IMAPABNF] 269 + 270 + When the CONDSTORE [CONDSTORE] IMAP extension is also supported, 271 + the ABNF is updated as follows: 272 + 273 + search-return-data =/ "MODSEQ" SP mod-sequence-value 274 + ;; mod-sequence-value is defined 275 + ;; in [CONDSTORE] 276 + 277 + 278 + 279 + 280 + 281 + 282 + Melnikov & Cridland Standards Track [Page 5] 283 + 284 + RFC 4731 IMAP4 Extension to SEARCH November 2006 285 + 286 + 287 + 5. Security Considerations 288 + 289 + In the general case, the IMAP SEARCH/UID SEARCH commands can be CPU 290 + and/or IO intensive, and are seen by some as a potential attack point 291 + for denial of service attacks, so some sites/implementations even 292 + disable them entirely. This is quite unfortunate, as SEARCH command 293 + is one of the best examples demonstrating IMAP advantage over POP3. 294 + 295 + The ALL and COUNT return options don't change how SEARCH is working 296 + internally; they only change how information about found messages is 297 + returned. MIN and MAX SEARCH result options described in this 298 + document can lighten the load on IMAP servers that choose to optimize 299 + SEARCHes containing only one or both of them. 300 + 301 + It is believed that this extension doesn't raise any additional 302 + security concerns not already discussed in [IMAP4]. 303 + 304 + 6. IANA Considerations 305 + 306 + IMAP4 capabilities are registered by publishing a standards track RFC 307 + or an IESG-approved experimental RFC. The registry is currently 308 + located at <http://www.iana.org/assignments/imap4-capabilities>. 309 + 310 + This document defines the ESEARCH IMAP capability, which IANA added 311 + to the registry. 312 + 313 + 7. Normative References 314 + 315 + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate 316 + Requirement Levels", BCP 14, RFC 2119, March 1997. 317 + 318 + [IMAP4] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 319 + 4rev1", RFC 3501, March 2003. 320 + 321 + [ABNF] Crocker, D. (Ed.) and P. Overell , "Augmented BNF for 322 + Syntax Specifications: ABNF", RFC 4234, October 2005. 323 + 324 + [IMAPABNF] Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4 325 + ABNF", RFC 4466, April 2006.. 326 + 327 + [CONDSTORE] Melnikov, A. and S. Hole, "IMAP Extension for Conditional 328 + STORE", RFC 4551, June 2006. 329 + 330 + 8. Acknowledgments 331 + 332 + Thanks to Michael Wener, Arnt Gulbrandsen, Cyrus Daboo, Mark Crispin, 333 + and Pete Maclean for comments and corrections. 334 + 335 + 336 + 337 + 338 + Melnikov & Cridland Standards Track [Page 6] 339 + 340 + RFC 4731 IMAP4 Extension to SEARCH November 2006 341 + 342 + 343 + Authors' Addresses 344 + 345 + Alexey Melnikov 346 + Isode Limited 347 + 5 Castle Business Village 348 + 36 Station Road 349 + Hampton, Middlesex, TW12 2BX 350 + UK 351 + 352 + EMail: Alexey.Melnikov@isode.com 353 + 354 + 355 + Dave A. Cridland 356 + Inventure Systems Limited 357 + 358 + EMail: dave.cridland@inventuresystems.co.uk 359 + URL: http://invsys.co.uk/dave/ 360 + 361 + 362 + 363 + 364 + 365 + 366 + 367 + 368 + 369 + 370 + 371 + 372 + 373 + 374 + 375 + 376 + 377 + 378 + 379 + 380 + 381 + 382 + 383 + 384 + 385 + 386 + 387 + 388 + 389 + 390 + 391 + 392 + 393 + 394 + Melnikov & Cridland Standards Track [Page 7] 395 + 396 + RFC 4731 IMAP4 Extension to SEARCH November 2006 397 + 398 + 399 + Full Copyright Statement 400 + 401 + Copyright (C) The IETF Trust (2006). 402 + 403 + This document is subject to the rights, licenses and restrictions 404 + contained in BCP 78, and except as set forth therein, the authors 405 + retain all their rights. 406 + 407 + This document and the information contained herein are provided on an 408 + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS 409 + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST, 410 + AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, 411 + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT 412 + THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY 413 + IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR 414 + PURPOSE. 415 + 416 + Intellectual Property 417 + 418 + The IETF takes no position regarding the validity or scope of any 419 + Intellectual Property Rights or other rights that might be claimed to 420 + pertain to the implementation or use of the technology described in 421 + this document or the extent to which any license under such rights 422 + might or might not be available; nor does it represent that it has 423 + made any independent effort to identify any such rights. Information 424 + on the procedures with respect to rights in RFC documents can be 425 + found in BCP 78 and BCP 79. 426 + 427 + Copies of IPR disclosures made to the IETF Secretariat and any 428 + assurances of licenses to be made available, or the result of an 429 + attempt made to obtain a general license or permission for the use of 430 + such proprietary rights by implementers or users of this 431 + specification can be obtained from the IETF on-line IPR repository at 432 + http://www.ietf.org/ipr. 433 + 434 + The IETF invites any interested party to bring to its attention any 435 + copyrights, patents or patent applications, or other proprietary 436 + rights that may cover technology that may be required to implement 437 + this standard. Please address the information to the IETF at 438 + ietf-ipr@ietf.org. 439 + 440 + Acknowledgement 441 + 442 + Funding for the RFC Editor function is currently provided by the 443 + Internet Society. 444 + 445 + 446 + 447 + 448 + 449 + 450 + Melnikov & Cridland Standards Track [Page 8] 451 +
+1067
spec/rfc5256.txt
··· 1 + 2 + 3 + 4 + 5 + 6 + 7 + Network Working Group M. Crispin 8 + Request for Comments: 5256 Panda Programming 9 + Category: Standards Track K. Murchison 10 + Carnegie Mellon University 11 + June 2008 12 + 13 + 14 + Internet Message Access Protocol - SORT and THREAD Extensions 15 + 16 + Status of This Memo 17 + 18 + This document specifies an Internet standards track protocol for the 19 + Internet community, and requests discussion and suggestions for 20 + improvements. Please refer to the current edition of the "Internet 21 + Official Protocol Standards" (STD 1) for the standardization state 22 + and status of this protocol. Distribution of this memo is unlimited. 23 + 24 + Abstract 25 + 26 + This document describes the base-level server-based sorting and 27 + threading extensions to the IMAP protocol. These extensions provide 28 + substantial performance improvements for IMAP clients that offer 29 + sorted and threaded views. 30 + 31 + 1. Introduction 32 + 33 + The SORT and THREAD extensions to the [IMAP] protocol provide a means 34 + of server-based sorting and threading of messages, without requiring 35 + that the client download the necessary data to do so itself. This is 36 + particularly useful for online clients as described in [IMAP-MODELS]. 37 + 38 + A server that supports the base-level SORT extension indicates this 39 + with a capability name which starts with "SORT". Future, upwards- 40 + compatible extensions to the SORT extension will all start with 41 + "SORT", indicating support for this base level. 42 + 43 + A server that supports the THREAD extension indicates this with one 44 + or more capability names consisting of "THREAD=" followed by a 45 + supported threading algorithm name as described in this document. 46 + This provides for future upwards-compatible extensions. 47 + 48 + A server that implements the SORT and/or THREAD extensions MUST 49 + collate strings in accordance with the requirements of I18NLEVEL=1, 50 + as described in [IMAP-I18N], and SHOULD implement and advertise the 51 + I18NLEVEL=1 extension. Alternatively, a server MAY implement 52 + I18NLEVEL=2 (or higher) and comply with the rules of that level. 53 + 54 + 55 + 56 + 57 + 58 + Crispin & Murchison Standards Track [Page 1] 59 + 60 + RFC 5256 IMAP Sort June 2008 61 + 62 + 63 + Discussion: The SORT and THREAD extensions predate [IMAP-I18N] by 64 + several years. At the time of this writing, all known server 65 + implementations of SORT and THREAD comply with the rules of 66 + I18NLEVEL=1, but do not necessarily advertise it. As discussed in 67 + [IMAP-I18N] section 4.5, all server implementations should 68 + eventually be updated to comply with the I18NLEVEL=2 extension. 69 + 70 + Historical note: The REFERENCES threading algorithm is based on the 71 + [THREADING] algorithm written and used in "Netscape Mail and News" 72 + versions 2.0 through 3.0. 73 + 74 + 2. Terminology 75 + 76 + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 77 + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 78 + document are to be interpreted as described in [KEYWORDS]. 79 + 80 + The word "can" (not "may") is used to refer to a possible 81 + circumstance or situation, as opposed to an optional facility of the 82 + protocol. 83 + 84 + "User" is used to refer to a human user, whereas "client" refers to 85 + the software being run by the user. 86 + 87 + In examples, "C:" and "S:" indicate lines sent by the client and 88 + server, respectively. 89 + 90 + 2.1. Base Subject 91 + 92 + Subject sorting and threading use the "base subject", which has 93 + specific subject artifacts removed. Due to the complexity of these 94 + artifacts, the formal syntax for the subject extraction rules is 95 + ambiguous. The following procedure is followed to determine the 96 + "base subject", using the [ABNF] formal syntax rules described in 97 + section 5: 98 + 99 + (1) Convert any RFC 2047 encoded-words in the subject to [UTF-8] 100 + as described in "Internationalization Considerations". 101 + Convert all tabs and continuations to space. Convert all 102 + multiple spaces to a single space. 103 + 104 + (2) Remove all trailing text of the subject that matches the 105 + subj-trailer ABNF; repeat until no more matches are possible. 106 + 107 + (3) Remove all prefix text of the subject that matches the subj- 108 + leader ABNF. 109 + 110 + 111 + 112 + 113 + 114 + Crispin & Murchison Standards Track [Page 2] 115 + 116 + RFC 5256 IMAP Sort June 2008 117 + 118 + 119 + (4) If there is prefix text of the subject that matches the subj- 120 + blob ABNF, and removing that prefix leaves a non-empty subj- 121 + base, then remove the prefix text. 122 + 123 + (5) Repeat (3) and (4) until no matches remain. 124 + 125 + Note: It is possible to defer step (2) until step (6), but this 126 + requires checking for subj-trailer in step (4). 127 + 128 + (6) If the resulting text begins with the subj-fwd-hdr ABNF and 129 + ends with the subj-fwd-trl ABNF, remove the subj-fwd-hdr and 130 + subj-fwd-trl and repeat from step (2). 131 + 132 + (7) The resulting text is the "base subject" used in the SORT. 133 + 134 + All servers and disconnected (as described in [IMAP-MODELS]) clients 135 + MUST use exactly this algorithm to determine the "base subject". 136 + Otherwise, there is potential for a user to get inconsistent results 137 + based on whether they are running in connected or disconnected mode. 138 + 139 + 2.2. Sent Date 140 + 141 + As used in this document, the term "sent date" refers to the date and 142 + time from the Date: header, adjusted by time zone to normalize to 143 + UTC. For example, "31 Dec 2000 16:01:33 -0800" is equivalent to the 144 + UTC date and time of "1 Jan 2001 00:01:33 +0000". 145 + 146 + If the time zone is invalid, the date and time SHOULD be treated as 147 + UTC. If the time is also invalid, the time SHOULD be treated as 148 + 00:00:00. If there is no valid date or time, the date and time 149 + SHOULD be treated as 00:00:00 on the earliest possible date. 150 + 151 + This differs from the date-related criteria in the SEARCH command 152 + (described in [IMAP] section 6.4.4), which use just the date and not 153 + the time, and are not adjusted by time zone. 154 + 155 + If the sent date cannot be determined (a Date: header is missing or 156 + cannot be parsed), the INTERNALDATE for that message is used as the 157 + sent date. 158 + 159 + When comparing two sent dates that match exactly, the order in which 160 + the two messages appear in the mailbox (that is, by sequence number) 161 + is used as a tie-breaker to determine the order. 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + Crispin & Murchison Standards Track [Page 3] 171 + 172 + RFC 5256 IMAP Sort June 2008 173 + 174 + 175 + 3. Additional Commands 176 + 177 + These commands are extensions to the [IMAP] base protocol. 178 + 179 + The section headings are intended to correspond with where they would 180 + be located in the main document if they were part of the base 181 + specification. 182 + 183 + BASE.6.4.SORT. SORT Command 184 + 185 + Arguments: sort program 186 + charset specification 187 + searching criteria (one or more) 188 + 189 + Data: untagged responses: SORT 190 + 191 + Result: OK - sort completed 192 + NO - sort error: can't sort that charset or 193 + criteria 194 + BAD - command unknown or arguments invalid 195 + 196 + The SORT command is a variant of SEARCH with sorting semantics for 197 + the results. There are two arguments before the searching 198 + criteria argument: a parenthesized list of sort criteria, and the 199 + searching charset. 200 + 201 + The charset argument is mandatory (unlike SEARCH) and indicates 202 + the [CHARSET] of the strings that appear in the searching 203 + criteria. The US-ASCII and [UTF-8] charsets MUST be implemented. 204 + All other charsets are optional. 205 + 206 + There is also a UID SORT command that returns unique identifiers 207 + instead of message sequence numbers. Note that there are separate 208 + searching criteria for message sequence numbers and UIDs; thus, 209 + the arguments to UID SORT are interpreted the same as in SORT. 210 + This is analogous to the behavior of UID SEARCH, as opposed to UID 211 + COPY, UID FETCH, or UID STORE. 212 + 213 + The SORT command first searches the mailbox for messages that 214 + match the given searching criteria using the charset argument for 215 + the interpretation of strings in the searching criteria. It then 216 + returns the matching messages in an untagged SORT response, sorted 217 + according to one or more sort criteria. 218 + 219 + Sorting is in ascending order. Earlier dates sort before later 220 + dates; smaller sizes sort before larger sizes; and strings are 221 + sorted according to ascending values established by their 222 + collation algorithm (see "Internationalization Considerations"). 223 + 224 + 225 + 226 + Crispin & Murchison Standards Track [Page 4] 227 + 228 + RFC 5256 IMAP Sort June 2008 229 + 230 + 231 + If two or more messages exactly match according to the sorting 232 + criteria, these messages are sorted according to the order in 233 + which they appear in the mailbox. In other words, there is an 234 + implicit sort criterion of "sequence number". 235 + 236 + When multiple sort criteria are specified, the result is sorted in 237 + the priority order that the criteria appear. For example, 238 + (SUBJECT DATE) will sort messages in order by their base subject 239 + text; and for messages with the same base subject text, it will 240 + sort by their sent date. 241 + 242 + Untagged EXPUNGE responses are not permitted while the server is 243 + responding to a SORT command, but are permitted during a UID SORT 244 + command. 245 + 246 + The defined sort criteria are as follows. Refer to the Formal 247 + Syntax section for the precise syntactic definitions of the 248 + arguments. If the associated RFC-822 header for a particular 249 + criterion is absent, it is treated as the empty string. The empty 250 + string always collates before non-empty strings. 251 + 252 + ARRIVAL 253 + Internal date and time of the message. This differs from the 254 + ON criteria in SEARCH, which uses just the internal date. 255 + 256 + CC 257 + [IMAP] addr-mailbox of the first "cc" address. 258 + 259 + DATE 260 + Sent date and time, as described in section 2.2. 261 + 262 + FROM 263 + [IMAP] addr-mailbox of the first "From" address. 264 + 265 + REVERSE 266 + Followed by another sort criterion, has the effect of that 267 + criterion but in reverse (descending) order. 268 + Note: REVERSE only reverses a single criterion, and does not 269 + affect the implicit "sequence number" sort criterion if all 270 + other criteria are identical. Consequently, a sort of 271 + REVERSE SUBJECT is not the same as a reverse ordering of a 272 + SUBJECT sort. This can be avoided by use of additional 273 + criteria, e.g., SUBJECT DATE vs. REVERSE SUBJECT REVERSE 274 + DATE. In general, however, it's better (and faster, if the 275 + client has a "reverse current ordering" command) to reverse 276 + the results in the client instead of issuing a new SORT. 277 + 278 + 279 + 280 + 281 + 282 + Crispin & Murchison Standards Track [Page 5] 283 + 284 + RFC 5256 IMAP Sort June 2008 285 + 286 + 287 + SIZE 288 + Size of the message in octets. 289 + 290 + SUBJECT 291 + Base subject text. 292 + 293 + TO 294 + [IMAP] addr-mailbox of the first "To" address. 295 + 296 + Example: C: A282 SORT (SUBJECT) UTF-8 SINCE 1-Feb-1994 297 + S: * SORT 2 84 882 298 + S: A282 OK SORT completed 299 + C: A283 SORT (SUBJECT REVERSE DATE) UTF-8 ALL 300 + S: * SORT 5 3 4 1 2 301 + S: A283 OK SORT completed 302 + C: A284 SORT (SUBJECT) US-ASCII TEXT "not in mailbox" 303 + S: * SORT 304 + S: A284 OK SORT completed 305 + 306 + BASE.6.4.THREAD. THREAD Command 307 + 308 + Arguments: threading algorithm 309 + charset specification 310 + searching criteria (one or more) 311 + 312 + Data: untagged responses: THREAD 313 + 314 + Result: OK - thread completed 315 + NO - thread error: can't thread that charset or 316 + criteria 317 + BAD - command unknown or arguments invalid 318 + 319 + The THREAD command is a variant of SEARCH with threading semantics 320 + for the results. Thread has two arguments before the searching 321 + criteria argument: a threading algorithm and the searching 322 + charset. 323 + 324 + The charset argument is mandatory (unlike SEARCH) and indicates 325 + the [CHARSET] of the strings that appear in the searching 326 + criteria. The US-ASCII and [UTF-8] charsets MUST be implemented. 327 + All other charsets are optional. 328 + 329 + There is also a UID THREAD command that returns unique identifiers 330 + instead of message sequence numbers. Note that there are separate 331 + searching criteria for message sequence numbers and UIDs; thus the 332 + arguments to UID THREAD are interpreted the same as in THREAD. 333 + This is analogous to the behavior of UID SEARCH, as opposed to UID 334 + COPY, UID FETCH, or UID STORE. 335 + 336 + 337 + 338 + Crispin & Murchison Standards Track [Page 6] 339 + 340 + RFC 5256 IMAP Sort June 2008 341 + 342 + 343 + The THREAD command first searches the mailbox for messages that 344 + match the given searching criteria using the charset argument for 345 + the interpretation of strings in the searching criteria. It then 346 + returns the matching messages in an untagged THREAD response, 347 + threaded according to the specified threading algorithm. 348 + 349 + All collation is in ascending order. Earlier dates collate before 350 + later dates and strings are collated according to ascending values 351 + established by their collation algorithm (see 352 + "Internationalization Considerations"). 353 + 354 + Untagged EXPUNGE responses are not permitted while the server is 355 + responding to a THREAD command, but are permitted during a UID 356 + THREAD command. 357 + 358 + The defined threading algorithms are as follows: 359 + 360 + ORDEREDSUBJECT 361 + 362 + The ORDEREDSUBJECT threading algorithm is also referred to as 363 + "poor man's threading". The searched messages are sorted by 364 + base subject and then by the sent date. The messages are then 365 + split into separate threads, with each thread containing 366 + messages with the same base subject text. Finally, the threads 367 + are sorted by the sent date of the first message in the thread. 368 + 369 + The top level or "root" in ORDEREDSUBJECT threading contains 370 + the first message of every thread. All messages in the root 371 + are siblings of each other. The second message of a thread is 372 + the child of the first message, and subsequent messages of the 373 + thread are siblings of the second message and hence children of 374 + the message at the root. Hence, there are no grandchildren in 375 + ORDEREDSUBJECT threading. 376 + 377 + Children in ORDEREDSUBJECT threading do not have descendents. 378 + Client implementations SHOULD treat descendents of a child in a 379 + server response as being siblings of that child. 380 + 381 + REFERENCES 382 + 383 + The REFERENCES threading algorithm threads the searched 384 + messages by grouping them together in parent/child 385 + relationships based on which messages are replies to others. 386 + The parent/child relationships are built using two methods: 387 + reconstructing a message's ancestry using the references 388 + contained within it; and checking the original (not base) 389 + subject of a message to see if it is a reply to (or forward of) 390 + another message. 391 + 392 + 393 + 394 + Crispin & Murchison Standards Track [Page 7] 395 + 396 + RFC 5256 IMAP Sort June 2008 397 + 398 + 399 + Note: "Message ID" in the following description refers to a 400 + normalized form of the msg-id in [RFC2822]. The actual text 401 + in RFC 2822 may use quoting, resulting in multiple ways of 402 + expressing the same Message ID. Implementations of the 403 + REFERENCES threading algorithm MUST normalize any msg-id in 404 + order to avoid false non-matches due to differences in 405 + quoting. 406 + 407 + For example, the msg-id 408 + <"01KF8JCEOCBS0045PS"@xxx.yyy.com> 409 + and the msg-id 410 + <01KF8JCEOCBS0045PS@xxx.yyy.com> 411 + MUST be interpreted as being the same Message ID. 412 + 413 + The references used for reconstructing a message's ancestry are 414 + found using the following rules: 415 + 416 + If a message contains a References header line, then use the 417 + Message IDs in the References header line as the references. 418 + 419 + If a message does not contain a References header line, or 420 + the References header line does not contain any valid 421 + Message IDs, then use the first (if any) valid Message ID 422 + found in the In-Reply-To header line as the only reference 423 + (parent) for this message. 424 + 425 + Note: Although [RFC2822] permits multiple Message IDs in 426 + the In-Reply-To header, in actual practice this 427 + discipline has not been followed. For example, 428 + In-Reply-To headers have been observed with message 429 + addresses after the Message ID, and there are no good 430 + heuristics for software to determine the difference. 431 + This is not a problem with the References header, 432 + however. 433 + 434 + If a message does not contain an In-Reply-To header line, or 435 + the In-Reply-To header line does not contain a valid Message 436 + ID, then the message does not have any references (NIL). 437 + 438 + A message is considered to be a reply or forward if the base 439 + subject extraction rules, applied to the original subject, 440 + remove any of the following: a subj-refwd, a "(fwd)" subj- 441 + trailer, or a subj-fwd-hdr and subj-fwd-trl. 442 + 443 + The REFERENCES algorithm is significantly more complex than 444 + ORDEREDSUBJECT and consists of six main steps. These steps are 445 + outlined in detail below. 446 + 447 + 448 + 449 + 450 + Crispin & Murchison Standards Track [Page 8] 451 + 452 + RFC 5256 IMAP Sort June 2008 453 + 454 + 455 + (1) For each searched message: 456 + 457 + (A) Using the Message IDs in the message's references, link 458 + the corresponding messages (those whose Message-ID 459 + header line contains the given reference Message ID) 460 + together as parent/child. Make the first reference the 461 + parent of the second (and the second a child of the 462 + first), the second the parent of the third (and the 463 + third a child of the second), etc. The following rules 464 + govern the creation of these links: 465 + 466 + If a message does not contain a Message-ID header 467 + line, or the Message-ID header line does not 468 + contain a valid Message ID, then assign a unique 469 + Message ID to this message. 470 + 471 + If two or more messages have the same Message ID, 472 + then only use that Message ID in the first (lowest 473 + sequence number) message, and assign a unique 474 + Message ID to each of the subsequent messages with 475 + a duplicate of that Message ID. 476 + 477 + If no message can be found with a given Message ID, 478 + create a dummy message with this ID. Use this 479 + dummy message for all subsequent references to this 480 + ID. 481 + 482 + If a message already has a parent, don't change the 483 + existing link. This is done because the References 484 + header line may have been truncated by a Mail User 485 + Agent (MUA). As a result, there is no guarantee 486 + that the messages corresponding to adjacent Message 487 + IDs in the References header line are parent and 488 + child. 489 + 490 + Do not create a parent/child link if creating that 491 + link would introduce a loop. For example, before 492 + making message A the parent of B, make sure that A 493 + is not a descendent of B. 494 + 495 + Note: Message ID comparisons are case-sensitive. 496 + 497 + (B) Create a parent/child link between the last reference 498 + (or NIL if there are no references) and the current 499 + message. If the current message already has a parent, 500 + it is probably the result of a truncated References 501 + header line, so break the current parent/child link 502 + before creating the new correct one. As in step 1.A, 503 + 504 + 505 + 506 + Crispin & Murchison Standards Track [Page 9] 507 + 508 + RFC 5256 IMAP Sort June 2008 509 + 510 + 511 + do not create the parent/child link if creating that 512 + link would introduce a loop. Note that if this message 513 + has no references, it will now have no parent. 514 + 515 + Note: The parent/child links created in steps 1.A 516 + and 1.B MUST be kept consistent with one another at 517 + ALL times. 518 + 519 + (2) Gather together all of the messages that have no parents 520 + and make them all children (siblings of one another) of a 521 + dummy parent (the "root"). These messages constitute the 522 + first (head) message of the threads created thus far. 523 + 524 + (3) Prune dummy messages from the thread tree. Traverse each 525 + thread under the root, and for each message: 526 + 527 + If it is a dummy message with NO children, delete it. 528 + 529 + If it is a dummy message with children, delete it, but 530 + promote its children to the current level. In other 531 + words, splice them in with the dummy's siblings. 532 + 533 + Do not promote the children if doing so would make them 534 + children of the root, unless there is only one child. 535 + 536 + (4) Sort the messages under the root (top-level siblings only) 537 + by sent date as described in section 2.2. In the case of a 538 + dummy message, sort its children by sent date and then use 539 + the first child for the top-level sort. 540 + 541 + (5) Gather together messages under the root that have the same 542 + base subject text. 543 + 544 + (A) Create a table for associating base subjects with 545 + messages, called the subject table. 546 + 547 + (B) Populate the subject table with one message per each 548 + base subject. For each child of the root: 549 + 550 + (i) Find the subject of this thread, by using the 551 + base subject from either the current message or 552 + its first child if the current message is a 553 + dummy. This is the thread subject. 554 + 555 + (ii) If the thread subject is empty, skip this 556 + message. 557 + 558 + 559 + 560 + 561 + 562 + Crispin & Murchison Standards Track [Page 10] 563 + 564 + RFC 5256 IMAP Sort June 2008 565 + 566 + 567 + (iii) Look up the message associated with the thread 568 + subject in the subject table. 569 + 570 + (iv) If there is no message in the subject table with 571 + the thread subject, add the current message and 572 + the thread subject to the subject table. 573 + 574 + Otherwise, if the message in the subject table is 575 + not a dummy, AND either of the following criteria 576 + are true: 577 + 578 + The current message is a dummy, OR 579 + 580 + The message in the subject table is a reply 581 + or forward and the current message is not. 582 + 583 + then replace the message in the subject table 584 + with the current message. 585 + 586 + (C) Merge threads with the same thread subject. For each 587 + child of the root: 588 + 589 + (i) Find the message's thread subject as in step 590 + 5.B.i above. 591 + 592 + (ii) If the thread subject is empty, skip this 593 + message. 594 + 595 + (iii) Lookup the message associated with this thread 596 + subject in the subject table. 597 + 598 + (iv) If the message in the subject table is the 599 + current message, skip this message. 600 + 601 + Otherwise, merge the current message with the one in 602 + the subject table using the following rules: 603 + 604 + If both messages are dummies, append the current 605 + message's children to the children of the message 606 + in the subject table (the children of both messages 607 + become siblings), and then delete the current 608 + message. 609 + 610 + If the message in the subject table is a dummy and 611 + the current message is not, make the current 612 + message a child of the message in the subject table 613 + (a sibling of its children). 614 + 615 + 616 + 617 + 618 + Crispin & Murchison Standards Track [Page 11] 619 + 620 + RFC 5256 IMAP Sort June 2008 621 + 622 + 623 + If the current message is a reply or forward and 624 + the message in the subject table is not, make the 625 + current message a child of the message in the 626 + subject table (a sibling of its children). 627 + 628 + Otherwise, create a new dummy message and make both 629 + the current message and the message in the subject 630 + table children of the dummy. Then replace the 631 + message in the subject table with the dummy 632 + message. 633 + 634 + Note: Subject comparisons are case-insensitive, 635 + as described under "Internationalization 636 + Considerations". 637 + 638 + (6) Traverse the messages under the root and sort each set of 639 + siblings by sent date as described in section 2.2. 640 + Traverse the messages in such a way that the "youngest" set 641 + of siblings are sorted first, and the "oldest" set of 642 + siblings are sorted last (grandchildren are sorted before 643 + children, etc). In the case of a dummy message (which can 644 + only occur with top-level siblings), use its first child 645 + for sorting. 646 + 647 + Example: C: A283 THREAD ORDEREDSUBJECT UTF-8 SINCE 5-MAR-2000 648 + S: * THREAD (166)(167)(168)(169)(172)(170)(171) 649 + (173)(174 (175)(176)(178)(181)(180))(179)(177 650 + (183)(182)(188)(184)(185)(186)(187)(189))(190) 651 + (191)(192)(193)(194 195)(196 (197)(198))(199) 652 + (200 202)(201)(203)(204)(205)(206 207)(208) 653 + S: A283 OK THREAD completed 654 + C: A284 THREAD ORDEREDSUBJECT US-ASCII TEXT "gewp" 655 + S: * THREAD 656 + S: A284 OK THREAD completed 657 + C: A285 THREAD REFERENCES UTF-8 SINCE 5-MAR-2000 658 + S: * THREAD (166)(167)(168)(169)(172)((170)(179)) 659 + (171)(173)((174)(175)(176)(178)(181)(180)) 660 + ((177)(183)(182)(188 (184)(189))(185 186)(187)) 661 + (190)(191)(192)(193)((194)(195 196))(197 198) 662 + (199)(200 202)(201)(203)(204)(205 206 207)(208) 663 + S: A285 OK THREAD completed 664 + 665 + Note: The line breaks in the first and third server 666 + responses are for editorial clarity and do not appear in 667 + real THREAD responses. 668 + 669 + 670 + 671 + 672 + 673 + 674 + Crispin & Murchison Standards Track [Page 12] 675 + 676 + RFC 5256 IMAP Sort June 2008 677 + 678 + 679 + 4. Additional Responses 680 + 681 + These responses are extensions to the [IMAP] base protocol. 682 + 683 + The section headings of these responses are intended to correspond 684 + with where they would be located in the main document. 685 + 686 + BASE.7.2.SORT. SORT Response 687 + 688 + Data: zero or more numbers 689 + 690 + The SORT response occurs as a result of a SORT or UID SORT 691 + command. The number(s) refer to those messages that match the 692 + search criteria. For SORT, these are message sequence numbers; 693 + for UID SORT, these are unique identifiers. Each number is 694 + delimited by a space. 695 + 696 + Example: S: * SORT 2 3 6 697 + 698 + BASE.7.2.THREAD. THREAD Response 699 + 700 + Data: zero or more threads 701 + 702 + The THREAD response occurs as a result of a THREAD or UID THREAD 703 + command. It contains zero or more threads. A thread consists of 704 + a parenthesized list of thread members. 705 + 706 + Thread members consist of zero or more message numbers, delimited 707 + by spaces, indicating successive parent and child. This continues 708 + until the thread splits into multiple sub-threads, at which point, 709 + the thread nests into multiple sub-threads with the first member 710 + of each sub-thread being siblings at this level. There is no 711 + limit to the nesting of threads. 712 + 713 + The messages numbers refer to those messages that match the search 714 + criteria. For THREAD, these are message sequence numbers; for UID 715 + THREAD, these are unique identifiers. 716 + 717 + Example: S: * THREAD (2)(3 6 (4 23)(44 7 96)) 718 + 719 + The first thread consists only of message 2. The second thread 720 + consists of the messages 3 (parent) and 6 (child), after which it 721 + splits into two sub-threads; the first of which contains messages 722 + 4 (child of 6, sibling of 44) and 23 (child of 4), and the second 723 + of which contains messages 44 (child of 6, sibling of 4), 7 (child 724 + of 44), and 96 (child of 7). Since some later messages are 725 + parents of earlier messages, the messages were probably moved from 726 + some other mailbox at different times. 727 + 728 + 729 + 730 + Crispin & Murchison Standards Track [Page 13] 731 + 732 + RFC 5256 IMAP Sort June 2008 733 + 734 + 735 + -- 2 736 + 737 + -- 3 738 + \-- 6 739 + |-- 4 740 + | \-- 23 741 + | 742 + \-- 44 743 + \-- 7 744 + \-- 96 745 + 746 + Example: S: * THREAD ((3)(5)) 747 + 748 + In this example, 3 and 5 are siblings of a parent that does not 749 + match the search criteria (and/or does not exist in the mailbox); 750 + however they are members of the same thread. 751 + 752 + 5. Formal Syntax of SORT and THREAD Commands and Responses 753 + 754 + The following syntax specification uses the Augmented Backus-Naur 755 + Form (ABNF) notation as specified in [ABNF]. It also uses [ABNF] 756 + rules defined in [IMAP]. 757 + 758 + sort = ["UID" SP] "SORT" SP sort-criteria SP search-criteria 759 + 760 + sort-criteria = "(" sort-criterion *(SP sort-criterion) ")" 761 + 762 + sort-criterion = ["REVERSE" SP] sort-key 763 + 764 + sort-key = "ARRIVAL" / "CC" / "DATE" / "FROM" / "SIZE" / 765 + "SUBJECT" / "TO" 766 + 767 + thread = ["UID" SP] "THREAD" SP thread-alg SP search-criteria 768 + 769 + thread-alg = "ORDEREDSUBJECT" / "REFERENCES" / thread-alg-ext 770 + 771 + thread-alg-ext = atom 772 + ; New algorithms MUST be registered with IANA 773 + 774 + search-criteria = charset 1*(SP search-key) 775 + 776 + charset = atom / quoted 777 + ; CHARSET values MUST be registered with IANA 778 + 779 + sort-data = "SORT" *(SP nz-number) 780 + 781 + thread-data = "THREAD" [SP 1*thread-list] 782 + 783 + 784 + 785 + 786 + Crispin & Murchison Standards Track [Page 14] 787 + 788 + RFC 5256 IMAP Sort June 2008 789 + 790 + 791 + thread-list = "(" (thread-members / thread-nested) ")" 792 + 793 + thread-members = nz-number *(SP nz-number) [SP thread-nested] 794 + 795 + thread-nested = 2*thread-list 796 + 797 + The following syntax describes base subject extraction rules (2)-(6): 798 + 799 + subject = *subj-leader [subj-middle] *subj-trailer 800 + 801 + subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" 802 + 803 + subj-blob = "[" *BLOBCHAR "]" *WSP 804 + 805 + subj-fwd = subj-fwd-hdr subject subj-fwd-trl 806 + 807 + subj-fwd-hdr = "[fwd:" 808 + 809 + subj-fwd-trl = "]" 810 + 811 + subj-leader = (*subj-blob subj-refwd) / WSP 812 + 813 + subj-middle = *subj-blob (subj-base / subj-fwd) 814 + ; last subj-blob is subj-base if subj-base would 815 + ; otherwise be empty 816 + 817 + subj-trailer = "(fwd)" / WSP 818 + 819 + subj-base = NONWSP *(*WSP NONWSP) 820 + ; can be a subj-blob 821 + 822 + BLOBCHAR = %x01-5a / %x5c / %x5e-ff 823 + ; any CHAR8 except '[' and ']'. 824 + ; SHOULD comply with [UTF-8] 825 + 826 + NONWSP = %x01-08 / %x0a-1f / %x21-ff 827 + ; any CHAR8 other than WSP. 828 + ; SHOULD comply with [UTF-8] 829 + 830 + 6. Security Considerations 831 + 832 + The SORT and THREAD extensions do not raise any security 833 + considerations that are not present in the base [IMAP] protocol, and 834 + these issues are discussed in [IMAP]. Nevertheless, it is important 835 + to remember that [IMAP] protocol transactions, including message 836 + data, are sent in the clear over the network unless protection from 837 + snooping is negotiated, either by the use of STARTTLS, privacy 838 + protection in AUTHENTICATE, or some other protection mechanism. 839 + 840 + 841 + 842 + Crispin & Murchison Standards Track [Page 15] 843 + 844 + RFC 5256 IMAP Sort June 2008 845 + 846 + 847 + Although not a security consideration, it is important to recognize 848 + that sorting by REFERENCES can lead to misleading threading trees. 849 + For example, a message with false References: header data will cause 850 + a thread to be incorporated into another thread. 851 + 852 + The process of extracting the base subject may lead to incorrect 853 + collation if the extracted data was significant text as opposed to a 854 + subject artifact. 855 + 856 + 7. Internationalization Considerations 857 + 858 + As stated in the introduction, the rules of I18NLEVEL=1 as described 859 + in [IMAP-I18N] MUST be followed; that is, the SORT and THREAD 860 + extensions MUST collate strings according to the i;unicode-casemap 861 + collation described in [UNICASEMAP]. Servers SHOULD also advertise 862 + the I18NLEVEL=1 extension. Alternatively, a server MAY implement 863 + I18NLEVEL=2 (or higher) and comply with the rules of that level. 864 + 865 + As discussed in [IMAP-I18N] section 4.5, all server implementations 866 + should eventually be updated to support the [IMAP-I18N] I18NLEVEL=2 867 + extension. 868 + 869 + Translations of the "re" or "fw"/"fwd" tokens are not specified for 870 + removal in the base subject extraction process. An attempt to add 871 + such translated tokens would result in a geometrically complex, and 872 + ultimately unimplementable, task. 873 + 874 + Instead, note that [RFC2822] section 3.6.5 recommends that "re:" 875 + (from the Latin "res", meaning "in the matter of") be used to 876 + identify a reply. Although it is evident that, from the multiple 877 + forms of token to identify a forwarded message, there is considerable 878 + variation found in the wild, the variations are (still) manageable. 879 + Consequently, it is suggested that "re:" and one of the variations of 880 + the tokens for a forward supported by the base subject extraction 881 + rules be adopted for Internet mail messages, since doing so makes it 882 + a simple display-time task to localize the token language for the 883 + user. 884 + 885 + 8. IANA Considerations 886 + 887 + [IMAP] capabilities are registered by publishing a standards track or 888 + IESG-approved experimental RFC. This document constitutes 889 + registration of the SORT and THREAD capabilities in the [IMAP] 890 + capabilities registry. 891 + 892 + 893 + 894 + 895 + 896 + 897 + 898 + Crispin & Murchison Standards Track [Page 16] 899 + 900 + RFC 5256 IMAP Sort June 2008 901 + 902 + 903 + This document creates a new [IMAP] threading algorithms registry, 904 + which registers threading algorithms by publishing a standards track 905 + or IESG-approved experimental RFC. This document constitutes 906 + registration of the ORDEREDSUBJECT and REFERENCES algorithms in that 907 + registry. 908 + 909 + 9. Normative References 910 + 911 + [ABNF] Crocker, D., Ed., and P. Overell, "Augmented BNF for 912 + Syntax Specifications: ABNF", STD 68, RFC 5234, January 913 + 2008. 914 + 915 + [CHARSET] Freed, N. and J. Postel, "IANA Charset Registration 916 + Procedures", BCP 19, RFC 2978, October 2000. 917 + 918 + [IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - 919 + VERSION 4rev1", RFC 3501, March 2003. 920 + 921 + [IMAP-I18N] Newman, C., Gulbrandsen, A., and A. Melnikov, "Internet 922 + Message Access Protocol Internationalization", RFC 923 + 5255, June 2008. 924 + 925 + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate 926 + Requirement Levels", BCP 14, RFC 2119, March 1997. 927 + 928 + [RFC2822] Resnick, P., Ed., "Internet Message Format", RFC 2822, 929 + April 2001. 930 + 931 + [UNICASEMAP] Crispin, M., "i;unicode-casemap - Simple Unicode 932 + Collation Algorithm", RFC 5051, October 2007. 933 + 934 + [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 935 + 10646", STD 63, RFC 3629, November 2003. 936 + 937 + 10. Informative References 938 + 939 + [IMAP-MODELS] Crispin, M., "Distributed Electronic Mail Models in 940 + IMAP4", RFC 1733, December 1994. 941 + 942 + [THREADING] Zawinski, J. "Message Threading", 943 + http://www.jwz.org/doc/threading.html, 1997-2002. 944 + 945 + 946 + 947 + 948 + 949 + 950 + 951 + 952 + 953 + 954 + Crispin & Murchison Standards Track [Page 17] 955 + 956 + RFC 5256 IMAP Sort June 2008 957 + 958 + 959 + Authors' Addresses 960 + 961 + Mark R. Crispin 962 + Panda Programming 963 + 6158 NE Lariat Loop 964 + Bainbridge Island, WA 98110-2098 965 + 966 + Phone: +1 (206) 842-2385 967 + EMail: IMAP+SORT+THREAD@Lingling.Panda.COM 968 + 969 + 970 + Kenneth Murchison 971 + Carnegie Mellon University 972 + 5000 Forbes Avenue 973 + Cyert Hall 285 974 + Pittsburgh, PA 15213 975 + 976 + Phone: +1 (412) 268-2638 977 + EMail: murch@andrew.cmu.edu 978 + 979 + 980 + 981 + 982 + 983 + 984 + 985 + 986 + 987 + 988 + 989 + 990 + 991 + 992 + 993 + 994 + 995 + 996 + 997 + 998 + 999 + 1000 + 1001 + 1002 + 1003 + 1004 + 1005 + 1006 + 1007 + 1008 + 1009 + 1010 + Crispin & Murchison Standards Track [Page 18] 1011 + 1012 + RFC 5256 IMAP Sort June 2008 1013 + 1014 + 1015 + Full Copyright Statement 1016 + 1017 + Copyright (C) The IETF Trust (2008). 1018 + 1019 + This document is subject to the rights, licenses and restrictions 1020 + contained in BCP 78, and except as set forth therein, the authors 1021 + retain all their rights. 1022 + 1023 + This document and the information contained herein are provided on an 1024 + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS 1025 + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND 1026 + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS 1027 + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF 1028 + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED 1029 + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 1030 + 1031 + Intellectual Property 1032 + 1033 + The IETF takes no position regarding the validity or scope of any 1034 + Intellectual Property Rights or other rights that might be claimed to 1035 + pertain to the implementation or use of the technology described in 1036 + this document or the extent to which any license under such rights 1037 + might or might not be available; nor does it represent that it has 1038 + made any independent effort to identify any such rights. Information 1039 + on the procedures with respect to rights in RFC documents can be 1040 + found in BCP 78 and BCP 79. 1041 + 1042 + Copies of IPR disclosures made to the IETF Secretariat and any 1043 + assurances of licenses to be made available, or the result of an 1044 + attempt made to obtain a general license or permission for the use of 1045 + such proprietary rights by implementers or users of this 1046 + specification can be obtained from the IETF on-line IPR repository at 1047 + http://www.ietf.org/ipr. 1048 + 1049 + The IETF invites any interested party to bring to its attention any 1050 + copyrights, patents or patent applications, or other proprietary 1051 + rights that may cover technology that may be required to implement 1052 + this standard. Please address the information to the IETF at 1053 + ietf-ipr@ietf.org. 1054 + 1055 + 1056 + 1057 + 1058 + 1059 + 1060 + 1061 + 1062 + 1063 + 1064 + 1065 + 1066 + Crispin & Murchison Standards Track [Page 19] 1067 +
+1739
spec/rfc5258.txt
··· 1 + 2 + 3 + 4 + 5 + 6 + 7 + Network Working Group B. Leiba 8 + Request for Comments: 5258 IBM T.J. Watson Research Center 9 + Obsoletes: 3348 A. Melnikov 10 + Updates: 2193 Isode Limited 11 + Category: Standards Track June 2008 12 + 13 + 14 + Internet Message Access Protocol version 4 - LIST Command Extensions 15 + 16 + Status of This Memo 17 + 18 + This document specifies an Internet standards track protocol for the 19 + Internet community, and requests discussion and suggestions for 20 + improvements. Please refer to the current edition of the "Internet 21 + Official Protocol Standards" (STD 1) for the standardization state 22 + and status of this protocol. Distribution of this memo is unlimited. 23 + 24 + Abstract 25 + 26 + IMAP4 has two commands for listing mailboxes: LIST and LSUB. As we 27 + have added extensions, such as Mailbox Referrals, that have required 28 + specialized lists we have had to expand the number of list commands, 29 + since each extension must add its function to both LIST and LSUB, and 30 + these commands are not, as they are defined, extensible. If we've 31 + needed the extensions to work together, we've had to add a set of 32 + commands to mix the different options, the set increasing in size 33 + with each new extension. This document describes an extension to the 34 + base LIST command that will allow these additions to be done with 35 + mutually compatible options to the LIST command, avoiding the 36 + exponential increase in specialized list commands. 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + Leiba & Melnikov Standards Track [Page 1] 59 + 60 + RFC 5258 IMAP4 LIST Command Extensions June 2008 61 + 62 + 63 + Table of Contents 64 + 65 + 1. Introduction and Overview . . . . . . . . . . . . . . . . . . 3 66 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 4 67 + 3. Extended LIST Command . . . . . . . . . . . . . . . . . . . . 4 68 + 3.1. Initial List of Selection Options . . . . . . . . . . . . 7 69 + 3.2. Initial List of Return Options . . . . . . . . . . . . . . 8 70 + 3.3. General Principles for Returning LIST Responses . . . . . 9 71 + 3.4. Additional Requirements on LIST-EXTENDED Clients . . . . . 9 72 + 3.5. CHILDINFO Extended Data Item . . . . . . . . . . . . . . . 10 73 + 4. The CHILDREN Return Option . . . . . . . . . . . . . . . . . . 11 74 + 5. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 75 + 6. Formal Syntax . . . . . . . . . . . . . . . . . . . . . . . . 19 76 + 7. Internationalization Considerations . . . . . . . . . . . . . 22 77 + 8. Security Considerations . . . . . . . . . . . . . . . . . . . 23 78 + 9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 23 79 + 9.1. Guidelines for IANA . . . . . . . . . . . . . . . . . . . 23 80 + 9.2. Registration Procedure and Change Control . . . . . . . . 23 81 + 9.3. Registration Template for LIST-EXTENDED Options . . . . . 25 82 + 9.4. Initial LIST-EXTENDED Option Registrations . . . . . . . . 25 83 + 9.5. Registration Template for LIST-EXTENDED Extended Data 84 + Item . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 85 + 9.6. Initial LIST-EXTENDED Extended Data Item Registrations . . 28 86 + 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 29 87 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 29 88 + 11.1. Normative References . . . . . . . . . . . . . . . . . . . 29 89 + 11.2. Informative References . . . . . . . . . . . . . . . . . . 30 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + Leiba & Melnikov Standards Track [Page 2] 115 + 116 + RFC 5258 IMAP4 LIST Command Extensions June 2008 117 + 118 + 119 + 1. Introduction and Overview 120 + 121 + The LIST command is extended by amending the syntax to allow options 122 + and multiple patterns to be specified. The list of options replaces 123 + the several commands that are currently used to mix and match the 124 + information requested. The new syntax is backward compatible, with 125 + no ambiguity: the new syntax is being used if one of the following 126 + conditions is true: 127 + 128 + 1. if the first word after the command name begins with a 129 + parenthesis ("LIST selection options") 130 + 131 + 2. if the second word after the command name begins with a 132 + parenthesis ("multiple mailbox patterns") 133 + 134 + 3. if the LIST command has more than 2 parameters ("LIST return 135 + options") 136 + 137 + Otherwise the original syntax is used. 138 + 139 + By adding options to the LIST command, we are announcing the intent 140 + to phase out and eventually to deprecate the RLIST and RLSUB commands 141 + described in [MBRef]. We are also defining the mechanism to request 142 + extended mailbox information, such as is described in the Child 143 + Mailbox Extension [CMbox]. The base LSUB command is not deprecated 144 + by this extension; rather, this extension adds a way to obtain 145 + subscription information with more options, with those server 146 + implementations that support it. Clients that simply need a list of 147 + subscribed mailboxes, as provided by the LSUB command, SHOULD 148 + continue to use that command. 149 + 150 + This document defines an IMAP4 extension that is identified by the 151 + capability string "LIST-EXTENDED". The LIST-EXTENDED extension makes 152 + the following changes to the IMAP4 protocol, which are described in 153 + more detail in Section 3 and Section 4: 154 + 155 + a. defines new syntax for LIST command options. 156 + 157 + b. extends LIST to allow for multiple mailbox patterns. 158 + 159 + c. adds LIST command selection options: SUBSCRIBED, REMOTE, and 160 + RECURSIVEMATCH. 161 + 162 + d. adds LIST command return options: SUBSCRIBED and CHILDREN. 163 + 164 + e. adds new mailbox attributes: "\NonExistent", "\Subscribed", 165 + "\Remote", "\HasChildren", and "\HasNoChildren". 166 + 167 + 168 + 169 + 170 + Leiba & Melnikov Standards Track [Page 3] 171 + 172 + RFC 5258 IMAP4 LIST Command Extensions June 2008 173 + 174 + 175 + f. adds CHILDINFO extended data item. 176 + 177 + 2. Conventions Used in This Document 178 + 179 + In examples, "C:" indicates lines sent by a client that is connected 180 + to a server. "S:" indicates lines sent by the server to the client. 181 + 182 + The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" 183 + are used in this document as specified in RFC 2119 [Kwds]. 184 + 185 + The term "canonical LIST pattern" refers to the canonical pattern 186 + constructed internally by the server from the reference and mailbox 187 + name arguments (Section 6.3.8 of [IMAP4]). The [IMAP4] LIST command 188 + returns only mailboxes that match the canonical LIST pattern. 189 + 190 + Other terms are introduced where they are referenced for the first 191 + time. 192 + 193 + 3. Extended LIST Command 194 + 195 + This extension updates the syntax of the LIST command to allow for 196 + multiple mailbox patterns to be specified, if they are enclosed in 197 + parentheses. A mailbox name matches a list of mailbox patterns if it 198 + matches at least one mailbox pattern. If a mailbox name matches 199 + multiple mailbox patterns from the list, the server SHOULD return 200 + only a single LIST response. 201 + 202 + Note that the non-extended LIST command is required to treat an empty 203 + ("" string) mailbox name argument as a special request to return the 204 + hierarchy delimiter and the root name of the name given in the 205 + reference parameter (as per [IMAP4]). However, ANY extended LIST 206 + command (extended in any of 3 ways specified in Section 1, or any 207 + combination thereof) MUST NOT treat the empty mailbox name as such a 208 + special request, and any regular processing described in this 209 + document applies. In particular, if an extended LIST command has 210 + multiple mailbox names and one (or more) of them is the empty string, 211 + the empty string MUST be ignored for the purpose of matching. 212 + 213 + Some servers might restrict which patterns are allowed in a LIST 214 + command. If a server doesn't accept a particular pattern, it MUST 215 + silently ignore it. 216 + 217 + The LIST command syntax is also extended in two additional ways: by 218 + adding a parenthesized list of command options between the command 219 + name and the reference name (LIST selection options) and an optional 220 + 221 + 222 + 223 + 224 + 225 + 226 + Leiba & Melnikov Standards Track [Page 4] 227 + 228 + RFC 5258 IMAP4 LIST Command Extensions June 2008 229 + 230 + 231 + list of options at the end that control what kind of information 232 + should be returned (LIST return options). See the formal syntax in 233 + Section 6 for specific details. 234 + 235 + A LIST selection option tells the server which mailbox names should 236 + be selected by the LIST operation. The server should return 237 + information about all mailbox names that match any of the "canonical 238 + LIST pattern" (as described above) and satisfy additional selection 239 + criteria (if any) specified by the LIST selection options. Let's 240 + call any such mailbox name a "matched mailbox name". When multiple 241 + selection options are specified, the server MUST return information 242 + about mailbox names that satisfy every selection option, unless a 243 + description of a particular specified option prescribes special 244 + rules. An example of an option prescribing special rules is the 245 + RECURSIVEMATCH selection option described later in this section. We 246 + will use the term "selection criteria" when referring collectively to 247 + all selection options specified in a LIST command. 248 + 249 + A LIST return option controls which information is returned for each 250 + matched mailbox name. Note that return options MUST NOT cause the 251 + server to report information about additional mailbox names. If the 252 + client has not specified any return option, only information about 253 + attributes should be returned by the server. (Of course, the server 254 + is allowed to include any other information at will.) 255 + 256 + Both selection and return command options will be defined in this 257 + document and in approved extension documents; each option will be 258 + enabled by a capability string (one capability may enable multiple 259 + options), and a client MUST NOT send an option for which the server 260 + has not advertised support. A server MUST respond to options it does 261 + not recognize with a BAD response. The client SHOULD NOT specify any 262 + option more than once; however, if the client does this, the server 263 + MUST act as if it received the option only once. The order in which 264 + options are specified by the client is not significant. 265 + 266 + In general, each selection option except RECURSIVEMATCH will have a 267 + corresponding return option. The REMOTE selection option is an 268 + anomaly in this regard, and does not have a corresponding return 269 + option. That is because it expands, rather than restricts, the set 270 + of mailboxes that are returned. Future extensions to this 271 + specification should keep parallelism in mind and define a pair of 272 + corresponding options. 273 + 274 + This extension is identified by the capability string 275 + "LIST-EXTENDED", and support for it is a prerequisite for any future 276 + extensions that require specialized forms of the LIST command. Such 277 + extensions MUST refer to this document and MUST add their function 278 + through command options as described herein. Note that extensions 279 + 280 + 281 + 282 + Leiba & Melnikov Standards Track [Page 5] 283 + 284 + RFC 5258 IMAP4 LIST Command Extensions June 2008 285 + 286 + 287 + that don't require support for an extended LIST command, but use 288 + extended LIST responses (see below), don't need to advertise the 289 + "LIST-EXTENDED" capability string. 290 + 291 + This extension also defines extensions to the LIST response, allowing 292 + a series of extended fields at the end, a parenthesized list of 293 + tagged data (also referred to as "extended data item"). The first 294 + element of an extended field is a tag, which identifies the type of 295 + data. Tags MUST be registered with IANA, as described in Section 9.5 296 + of this document. An example of such an extended set might be 297 + 298 + tablecloth (("edge" "lacy") ("color" "red"))) (X-Sample "text")) 299 + 300 + or 301 + 302 + tablecloth ("edge" "lacy")) (X-Sample "text" "more text")) 303 + 304 + See the formal syntax, in Section 6, for the full syntactic details. 305 + The server MUST NOT return any extended data item unless the client 306 + has expressed its ability to support extended LIST responses, for 307 + example, by using an extended LIST command. The server MAY return 308 + data in the extended fields that was not directly solicited by the 309 + client in the corresponding LIST command. For example, the client 310 + can enable extra extended fields by using another IMAP extension that 311 + make use of the extended LIST responses. The client MUST ignore all 312 + extended fields it doesn't recognize. 313 + 314 + The LIST-EXTENDED capability also defines several new mailbox 315 + attributes. 316 + 317 + The "\NonExistent" attribute indicates that a mailbox name does not 318 + refer to an existing mailbox. Note that this attribute is not 319 + meaningful by itself, as mailbox names that match the canonical LIST 320 + pattern but don't exist must not be returned unless one of the two 321 + conditions listed below is also satisfied: 322 + 323 + a. The mailbox name also satisfies the selection criteria (for 324 + example, it is subscribed and the "SUBSCRIBED" selection option 325 + has been specified). 326 + 327 + b. "RECURSIVEMATCH" has been specified, and the mailbox name has at 328 + least one descendant mailbox name that does not match the LIST 329 + pattern and does match the selection criteria. 330 + 331 + In practice, this means that the "\NonExistent" attribute is usually 332 + returned with one or more of "\Subscribed", "\Remote", 333 + "\HasChildren", or the CHILDINFO extended data item (see their 334 + description below). 335 + 336 + 337 + 338 + Leiba & Melnikov Standards Track [Page 6] 339 + 340 + RFC 5258 IMAP4 LIST Command Extensions June 2008 341 + 342 + 343 + The "\NonExistent" attribute implies "\NoSelect". The "\NonExistent" 344 + attribute MUST be supported and MUST be accurately computed. 345 + 346 + 3.1. Initial List of Selection Options 347 + 348 + The selection options defined in this specification are as follows: 349 + 350 + SUBSCRIBED - causes the LIST command to list subscribed names, 351 + rather than the existing mailboxes. This will often be a subset 352 + of the actual mailboxes. It's also possible for this list to 353 + contain the names of mailboxes that don't exist. In any case, the 354 + list MUST include exactly those mailbox names that match the 355 + canonical list pattern and are subscribed to. This option is 356 + intended to supplement the LSUB command. Of particular note are 357 + the mailbox attributes as returned by this option, compared with 358 + what is returned by LSUB. With the latter, the attributes 359 + returned may not reflect the actual attribute status on the 360 + mailbox name, and the \NoSelect attribute has a second special 361 + meaning (it indicates that this mailbox is not, itself, 362 + subscribed, but that it has descendant mailboxes that are). With 363 + the SUBSCRIBED selection option described here, the attributes are 364 + accurate and complete, and have no special meanings. "LSUB" and 365 + "LIST (SUBSCRIBED)" are, thus, not the same thing, and some 366 + servers must do significant extra work to respond to "LIST 367 + (SUBSCRIBED)". Because of this, clients SHOULD continue to use 368 + "LSUB" unless they specifically want the additional information 369 + offered by "LIST (SUBSCRIBED)". 370 + 371 + This option defines a new mailbox attribute, "\Subscribed", that 372 + indicates that a mailbox name is subscribed to. The "\Subscribed" 373 + attribute MUST be supported and MUST be accurately computed when 374 + the SUBSCRIBED selection option is specified. 375 + 376 + Note that the SUBSCRIBED selection option implies the SUBSCRIBED 377 + return option (see below). 378 + 379 + REMOTE - causes the LIST command to show remote mailboxes as well as 380 + local ones, as described in [MBRef]. This option is intended to 381 + replace the RLIST command and, in conjunction with the SUBSCRIBED 382 + selection option, the RLSUB command. 383 + 384 + This option defines a new mailbox attribute, "\Remote", that 385 + indicates that a mailbox is a remote mailbox. The "\Remote" 386 + attribute MUST be accurately computed when the REMOTE option is 387 + specified. 388 + 389 + The REMOTE selection option has no interaction with other options. 390 + Its effect is to tell the server to apply the other options, if 391 + 392 + 393 + 394 + Leiba & Melnikov Standards Track [Page 7] 395 + 396 + RFC 5258 IMAP4 LIST Command Extensions June 2008 397 + 398 + 399 + any, to remote mailboxes, in addition to local ones. In 400 + particular, it has no interaction with RECURSIVEMATCH (see below). 401 + A request for (REMOTE RECURSIVEMATCH) is invalid, because a 402 + request for (RECURSIVEMATCH) is. A request for (REMOTE 403 + RECURSIVEMATCH SUBSCRIBED) is asking for all subscribed mailboxes, 404 + both local and remote. 405 + 406 + RECURSIVEMATCH - this option forces the server to return information 407 + about parent mailboxes that don't match other selection options, 408 + but have some submailboxes that do. Information about children is 409 + returned in the CHILDINFO extended data item, as described in 410 + Section 3.5. 411 + 412 + Note 1: In order for a parent mailbox to be returned, it still has 413 + to match the canonical LIST pattern. 414 + 415 + Note 2: When returning the CHILDINFO extended data item, it 416 + doesn't matter whether or not the submailbox matches the canonical 417 + LIST pattern. See also example 9 in Section 5. 418 + 419 + The RECURSIVEMATCH option MUST NOT occur as the only selection 420 + option (or only with REMOTE), as it only makes sense when other 421 + selection options are also used. The server MUST return BAD 422 + tagged response in such case. 423 + 424 + Note that even if the RECURSIVEMATCH option is specified, the 425 + client MUST still be able to handle a case when a CHILDINFO 426 + extended data item is returned and there are no submailboxes that 427 + meet the selection criteria of the subsequent LIST command, as 428 + they can be deleted/renamed after the LIST response was sent, but 429 + before the client had a chance to access them. 430 + 431 + 3.2. Initial List of Return Options 432 + 433 + The return options defined in this specification are as follows: 434 + 435 + SUBSCRIBED - causes the LIST command to return subscription state 436 + for all matching mailbox names. The "\Subscribed" attribute MUST 437 + be supported and MUST be accurately computed when the SUBSCRIBED 438 + return option is specified. Further, all mailbox flags MUST be 439 + accurately computed (this differs from the behavior of the LSUB 440 + command). 441 + 442 + CHILDREN - requests mailbox child information as originally proposed 443 + in [CMbox]. See Section 4, below, for details. This option MUST 444 + be supported by all servers. 445 + 446 + 447 + 448 + 449 + 450 + Leiba & Melnikov Standards Track [Page 8] 451 + 452 + RFC 5258 IMAP4 LIST Command Extensions June 2008 453 + 454 + 455 + 3.3. General Principles for Returning LIST Responses 456 + 457 + This section outlines several principles that can be used by server 458 + implementations of this document to decide whether a LIST response 459 + should be returned, as well as how many responses and what kind of 460 + information they may contain. 461 + 462 + 1. At most one LIST response should be returned for each mailbox 463 + name that matches the canonical LIST pattern. Server 464 + implementors must not assume that clients will be able to 465 + assemble mailbox attributes and other information returned in 466 + multiple LIST responses. 467 + 468 + 2. There are only two reasons for including a matching mailbox name 469 + in the responses to the LIST command (note that the server is 470 + allowed to return unsolicited responses at any time, and such 471 + responses are not governed by this rule): 472 + 473 + A. The mailbox name also satisfies the selection criteria. 474 + 475 + B. The mailbox name doesn't satisfy the selection criteria, but 476 + it has at least one descendant mailbox name that satisfies 477 + the selection criteria and that doesn't match the canonical 478 + LIST pattern. 479 + 480 + For more information on this case, see the CHILDINFO extended 481 + data item described in Section 3.5. Note that the CHILDINFO 482 + extended data item can only be returned when the 483 + RECURSIVEMATCH selection option is specified. 484 + 485 + 3. Attributes returned in the same LIST response must be treated 486 + additively. For example, the following response 487 + 488 + S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach" 489 + 490 + means that the "Fruit/Peach" mailbox doesn't exist, but it is 491 + subscribed. 492 + 493 + 3.4. Additional Requirements on LIST-EXTENDED Clients 494 + 495 + All clients that support this extension MUST treat an attribute with 496 + a stronger meaning as implying any attribute that can be inferred 497 + from it. For example, the client must treat the presence of the 498 + \NoInferiors attribute as if the \HasNoChildren attribute was also 499 + sent by the server. 500 + 501 + 502 + 503 + 504 + 505 + 506 + Leiba & Melnikov Standards Track [Page 9] 507 + 508 + RFC 5258 IMAP4 LIST Command Extensions June 2008 509 + 510 + 511 + The following table summarizes inference rules described in 512 + Section 3. 513 + 514 + +--------------------+-------------------+ 515 + | returned attribute | implied attribute | 516 + +--------------------+-------------------+ 517 + | \NoInferiors | \HasNoChildren | 518 + | \NonExistent | \NoSelect | 519 + +--------------------+-------------------+ 520 + 521 + 3.5. CHILDINFO Extended Data Item 522 + 523 + The CHILDINFO extended data item MUST NOT be returned unless the 524 + client has specified the RECURSIVEMATCH selection option. 525 + 526 + The CHILDINFO extended data item in a LIST response describes the 527 + selection criteria that has caused it to be returned and indicates 528 + that the mailbox has at least one descendant mailbox that matches the 529 + selection criteria. 530 + 531 + The LSUB command indicates this condition by using the "\NoSelect" 532 + attribute, but the LIST (SUBSCRIBED) command MUST NOT do that, since 533 + "\NoSelect" retains its original meaning here. Further, the 534 + CHILDINFO extended data item is more general, in that it can be used 535 + with any extended set of selection criteria. 536 + 537 + Note: Some servers allow for mailboxes to exist without requiring 538 + their parent to exist. For example, a mailbox "Customers/ABC" can 539 + exist while the mailbox "Customers" does not. As CHILDINFO extended 540 + data item is not allowed if the RECURSIVEMATCH selection option is 541 + not specified, such servers SHOULD use the "\NonExistent 542 + \HasChildren" attribute pair to signal to the client that there is a 543 + descendant mailbox that matches the selection criteria. See example 544 + 11 in Section 5. 545 + 546 + The returned selection criteria allow the client to distinguish a 547 + solicited response from an unsolicited one, as well as to distinguish 548 + among solicited responses caused by multiple pipelined LIST commands 549 + that specify different criteria. 550 + 551 + Servers SHOULD ONLY return a non-matching mailbox name along with 552 + CHILDINFO if at least one matching child is not also being returned. 553 + That is, servers SHOULD suppress redundant CHILDINFO responses. 554 + 555 + Examples 8 and 10 in Section 5 demonstrate the difference between 556 + present CHILDINFO extended data item and the "\HasChildren" 557 + attribute. 558 + 559 + 560 + 561 + 562 + Leiba & Melnikov Standards Track [Page 10] 563 + 564 + RFC 5258 IMAP4 LIST Command Extensions June 2008 565 + 566 + 567 + The following table summarizes interaction between the "\NonExistent" 568 + attribute and CHILDINFO (the first column indicates whether the 569 + parent mailbox exists): 570 + 571 + +--------+--------------+--------------------+----------------------+ 572 + | exists | meets the | has a child that | returned | 573 + | | selection | meets the | LIST-EXTENDED | 574 + | | criteria | selection criteria | attributes and | 575 + | | | | CHILDINFO | 576 + +--------+--------------+--------------------+----------------------+ 577 + | no | no | no | no LIST response | 578 + | | | | returned | 579 + | yes | no | no | no LIST response | 580 + | | | | returned | 581 + | no | yes | no | (\NonExistent | 582 + | | | | <attr>) | 583 + | yes | yes | no | (<attr>) | 584 + | no | no | yes | (\NonExistent) + | 585 + | | | | CHILDINFO | 586 + | yes | no | yes | () + CHILDINFO | 587 + | no | yes | yes | (\NonExistent | 588 + | | | | <attr>) + CHILDINFO | 589 + | yes | yes | yes | (<attr>) + CHILDINFO | 590 + +--------+--------------+--------------------+----------------------+ 591 + 592 + where <attr> is one or more attributes that correspond to the 593 + selection criteria; for example, for the SUBSCRIBED option the <attr> 594 + is \Subscribed. 595 + 596 + 4. The CHILDREN Return Option 597 + 598 + The CHILDREN return option implements the Child Mailbox Extension, 599 + originally proposed by Mike Gahrns and Raymond Cheng, of Microsoft 600 + Corporation. Most of the information in this section is taken 601 + directly from their original specification [CMbox]. The CHILDREN 602 + return option is simply an indication that the client wants this 603 + information; a server MAY provide it even if the option is not 604 + specified. 605 + 606 + Many IMAP4 [IMAP4] clients present to the user a hierarchical view of 607 + the mailboxes that a user has access to. Rather than initially 608 + presenting to the user the entire mailbox hierarchy, it is often 609 + preferable to show to the user a collapsed outline list of the 610 + mailbox hierarchy (particularly if there is a large number of 611 + mailboxes). The user can then expand the collapsed outline hierarchy 612 + as needed. It is common to include within the collapsed hierarchy a 613 + visual clue (such as a ''+'') to indicate that there are child 614 + mailboxes under a particular mailbox. When the visual clue is 615 + 616 + 617 + 618 + Leiba & Melnikov Standards Track [Page 11] 619 + 620 + RFC 5258 IMAP4 LIST Command Extensions June 2008 621 + 622 + 623 + clicked, the hierarchy list is expanded to show the child mailboxes. 624 + The CHILDREN return option provides a mechanism for a client to 625 + efficiently determine whether a particular mailbox has children, 626 + without issuing a LIST "" * or a LIST "" % for each mailbox name. 627 + The CHILDREN return option defines two new attributes that MUST be 628 + returned within a LIST response: \HasChildren and \HasNoChildren. 629 + Although these attributes MAY be returned in response to any LIST 630 + command, the CHILDREN return option is provided to indicate that the 631 + client particularly wants this information. If the CHILDREN return 632 + option is present, the server MUST return these attributes even if 633 + their computation is expensive. 634 + 635 + \HasChildren 636 + 637 + The presence of this attribute indicates that the mailbox has child 638 + mailboxes. A server SHOULD NOT set this attribute if there are 639 + child mailboxes and the user does not have permission to access 640 + any of them. In this case, \HasNoChildren SHOULD be used. In 641 + many cases, however, a server may not be able to efficiently 642 + compute whether a user has access to any child mailbox. Note 643 + that even though the \HasChildren attribute for a mailbox must 644 + be correct at the time of processing of the mailbox, a client 645 + must be prepared to deal with a situation when a mailbox is 646 + marked with the \HasChildren attribute, but no child mailbox 647 + appears in the response to the LIST command. This might happen, 648 + for example, due to children mailboxes being deleted or made 649 + inaccessible to the user (using access control) by another 650 + client before the server is able to list them. 651 + 652 + \HasNoChildren 653 + 654 + The presence of this attribute indicates that the mailbox has NO 655 + child mailboxes that are accessible to the currently 656 + authenticated user. 657 + 658 + It is an error for the server to return both a \HasChildren and a 659 + \HasNoChildren attribute in the same LIST response. 660 + 661 + Note: the \HasNoChildren attribute should not be confused with the 662 + IMAP4 [IMAP4] defined attribute \NoInferiors, which indicates that no 663 + child mailboxes exist now and none can be created in the future. 664 + 665 + 666 + 667 + 668 + 669 + 670 + 671 + 672 + 673 + 674 + Leiba & Melnikov Standards Track [Page 12] 675 + 676 + RFC 5258 IMAP4 LIST Command Extensions June 2008 677 + 678 + 679 + 5. Examples 680 + 681 + 1: The first example shows the complete local hierarchy that will 682 + be used for the other examples. 683 + 684 + C: A01 LIST "" "*" 685 + S: * LIST (\Marked \NoInferiors) "/" "inbox" 686 + S: * LIST () "/" "Fruit" 687 + S: * LIST () "/" "Fruit/Apple" 688 + S: * LIST () "/" "Fruit/Banana" 689 + S: * LIST () "/" "Tofu" 690 + S: * LIST () "/" "Vegetable" 691 + S: * LIST () "/" "Vegetable/Broccoli" 692 + S: * LIST () "/" "Vegetable/Corn" 693 + S: A01 OK done 694 + 695 + 2: In the next example, we will see the subscribed mailboxes. This 696 + is similar to, but not equivalent with, <LSUB "" "*">. Note 697 + that the mailbox called "Fruit/Peach" is subscribed to, but does 698 + not actually exist (perhaps it was deleted while still 699 + subscribed). The "Fruit" mailbox is not subscribed to, but it 700 + has two subscribed children. The "Vegetable" mailbox is 701 + subscribed and has two children; one of them is subscribed as 702 + well. 703 + 704 + C: A02 LIST (SUBSCRIBED) "" "*" 705 + S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox" 706 + S: * LIST (\Subscribed) "/" "Fruit/Banana" 707 + S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach" 708 + S: * LIST (\Subscribed) "/" "Vegetable" 709 + S: * LIST (\Subscribed) "/" "Vegetable/Broccoli" 710 + S: A02 OK done 711 + 712 + 3: The next example shows the use of the CHILDREN option. The 713 + client, without having to list the second level of hierarchy, 714 + now knows which of the top-level mailboxes have submailboxes 715 + (children) and which do not. Note that it's not necessary for 716 + the server to return the \HasNoChildren attribute for the inbox, 717 + because the \NoInferiors attribute already implies that, and has 718 + a stronger meaning. 719 + 720 + C: A03 LIST () "" "%" RETURN (CHILDREN) 721 + S: * LIST (\Marked \NoInferiors) "/" "inbox" 722 + S: * LIST (\HasChildren) "/" "Fruit" 723 + S: * LIST (\HasNoChildren) "/" "Tofu" 724 + S: * LIST (\HasChildren) "/" "Vegetable" 725 + S: A03 OK done 726 + 727 + 728 + 729 + 730 + Leiba & Melnikov Standards Track [Page 13] 731 + 732 + RFC 5258 IMAP4 LIST Command Extensions June 2008 733 + 734 + 735 + 4: In this example, we see more mailboxes that reside on another 736 + server. This is similar to the command <RLIST "" "%">. 737 + 738 + C: A04 LIST (REMOTE) "" "%" RETURN (CHILDREN) 739 + S: * LIST (\Marked \NoInferiors) "/" "inbox" 740 + S: * LIST (\HasChildren) "/" "Fruit" 741 + S: * LIST (\HasNoChildren) "/" "Tofu" 742 + S: * LIST (\HasChildren) "/" "Vegetable" 743 + S: * LIST (\Remote) "/" "Bread" 744 + S: * LIST (\HasChildren \Remote) "/" "Meat" 745 + S: A04 OK done 746 + 747 + 5: The following example also requests the server to include 748 + mailboxes that reside on another server. The server returns 749 + information about all mailboxes that are subscribed. This is 750 + similar to the command <RLSUB "" "*">. We also see the use of 751 + two selection options. 752 + 753 + C: A05 LIST (REMOTE SUBSCRIBED) "" "*" 754 + S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox" 755 + S: * LIST (\Subscribed) "/" "Fruit/Banana" 756 + S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach" 757 + S: * LIST (\Subscribed) "/" "Vegetable" 758 + S: * LIST (\Subscribed) "/" "Vegetable/Broccoli" 759 + S: * LIST (\Remote \Subscribed) "/" "Bread" 760 + S: A05 OK done 761 + 762 + 6: The following example requests the server to include mailboxes 763 + that reside on another server. The server is asked to return 764 + subscription information for all returned mailboxes. This is 765 + different from the example above. 766 + 767 + Note that the output of this command is not a superset of the 768 + output in the previous example, as it doesn't include LIST 769 + response for the non-existent "Fruit/Peach". 770 + 771 + C: A06 LIST (REMOTE) "" "*" RETURN (SUBSCRIBED) 772 + S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox" 773 + S: * LIST () "/" "Fruit" 774 + S: * LIST () "/" "Fruit/Apple" 775 + S: * LIST (\Subscribed) "/" "Fruit/Banana" 776 + S: * LIST () "/" "Tofu" 777 + S: * LIST (\Subscribed) "/" "Vegetable" 778 + S: * LIST (\Subscribed) "/" "Vegetable/Broccoli" 779 + S: * LIST () "/" "Vegetable/Corn" 780 + S: * LIST (\Remote \Subscribed) "/" "Bread" 781 + S: * LIST (\Remote) "/" "Meat" 782 + S: A06 OK done 783 + 784 + 785 + 786 + Leiba & Melnikov Standards Track [Page 14] 787 + 788 + RFC 5258 IMAP4 LIST Command Extensions June 2008 789 + 790 + 791 + 7: In the following example, the client has specified multiple 792 + mailbox patterns. Note that this example does not use the 793 + mailbox hierarchy used in the previous examples. 794 + 795 + C: BBB LIST "" ("INBOX" "Drafts" "Sent/%") 796 + S: * LIST () "/" "INBOX" 797 + S: * LIST (\NoInferiors) "/" "Drafts" 798 + S: * LIST () "/" "Sent/March2004" 799 + S: * LIST (\Marked) "/" "Sent/December2003" 800 + S: * LIST () "/" "Sent/August2004" 801 + S: BBB OK done 802 + 803 + 8: The following example demonstrates the difference between the 804 + \HasChildren attribute and the CHILDINFO extended data item. 805 + 806 + Let's assume there is the following hierarchy: 807 + 808 + C: C01 LIST "" "*" 809 + S: * LIST (\Marked \NoInferiors) "/" "inbox" 810 + S: * LIST () "/" "Foo" 811 + S: * LIST () "/" "Foo/Bar" 812 + S: * LIST () "/" "Foo/Baz" 813 + S: * LIST () "/" "Moo" 814 + S: C01 OK done 815 + 816 + If the client asks RETURN (CHILDREN), it will get this: 817 + 818 + C: CA3 LIST "" "%" RETURN (CHILDREN) 819 + S: * LIST (\Marked \NoInferiors) "/" "inbox" 820 + S: * LIST (\HasChildren) "/" "Foo" 821 + S: * LIST (\HasNoChildren) "/" "Moo" 822 + S: CA3 OK done 823 + 824 + A) Let's also assume that the mailbox "Foo/Baz" is the only 825 + subscribed mailbox. Then we get this result: 826 + 827 + C: C02 LIST (SUBSCRIBED) "" "*" 828 + S: * LIST (\Subscribed) "/" "Foo/Baz" 829 + S: C02 OK done 830 + 831 + Now, if the client issues <LIST (SUBSCRIBED) "" "%">, the server will 832 + return no mailboxes (as the mailboxes "Moo", "Foo", and "Inbox" are 833 + NOT subscribed). However, if the client issues this: 834 + 835 + C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" 836 + S: * LIST () "/" "Foo" ("CHILDINFO" ("SUBSCRIBED")) 837 + S: C04 OK done 838 + 839 + 840 + 841 + 842 + Leiba & Melnikov Standards Track [Page 15] 843 + 844 + RFC 5258 IMAP4 LIST Command Extensions June 2008 845 + 846 + 847 + (i.e., the mailbox "Foo" is not subscribed, but it has a child that 848 + is.) 849 + 850 + A1) If the mailbox "Foo" had also been subscribed, the last command 851 + would return this: 852 + 853 + C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" 854 + S: * LIST (\Subscribed) "/" "Foo" ("CHILDINFO" ("SUBSCRIBED")) 855 + S: C04 OK done 856 + 857 + or even this: 858 + 859 + C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" 860 + S: * LIST (\Subscribed \HasChildren) "/" "Foo" ("CHILDINFO" 861 + ("SUBSCRIBED")) 862 + S: C04 OK done 863 + 864 + A2) If we assume instead that the mailbox "Foo" is not part of the 865 + original hierarchy and is not subscribed, the last command will give 866 + this result: 867 + 868 + C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" 869 + S: * LIST (\NonExistent) "/" "Foo" ("CHILDINFO" ("SUBSCRIBED")) 870 + S: C04 OK done 871 + 872 + B) Now, let's assume that no mailbox is subscribed. In this case, 873 + the command <LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"> will return no 874 + responses, as there are no subscribed children (even though "Foo" has 875 + children). 876 + 877 + C) And finally, suppose that only the mailboxes "Foo" and "Moo" are 878 + subscribed. In that case, we see this result: 879 + 880 + C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" RETURN (CHILDREN) 881 + S: * LIST (\HasChildren \Subscribed) "/" "Foo" 882 + S: * LIST (\HasNoChildren \Subscribed) "/" "Moo" 883 + S: C04 OK done 884 + 885 + (which means that the mailbox "Foo" has children, but none of them is 886 + subscribed). 887 + 888 + 9: The following example demonstrates that the CHILDINFO extended 889 + data item is returned whether or not children mailboxes match 890 + the canonical LIST pattern. 891 + 892 + 893 + 894 + 895 + 896 + 897 + 898 + Leiba & Melnikov Standards Track [Page 16] 899 + 900 + RFC 5258 IMAP4 LIST Command Extensions June 2008 901 + 902 + 903 + Let's assume there is the following hierarchy: 904 + 905 + C: D01 LIST "" "*" 906 + S: * LIST (\Marked \NoInferiors) "/" "inbox" 907 + S: * LIST () "/" "foo2" 908 + S: * LIST () "/" "foo2/bar1" 909 + S: * LIST () "/" "foo2/bar2" 910 + S: * LIST () "/" "baz2" 911 + S: * LIST () "/" "baz2/bar2" 912 + S: * LIST () "/" "baz2/bar22" 913 + S: * LIST () "/" "baz2/bar222" 914 + S: * LIST () "/" "eps2" 915 + S: * LIST () "/" "eps2/mamba" 916 + S: * LIST () "/" "qux2/bar2" 917 + S: D01 OK done 918 + 919 + And that the following mailboxes are subscribed: 920 + 921 + C: D02 LIST (SUBSCRIBED) "" "*" 922 + S: * LIST (\Subscribed) "/" "foo2/bar1" 923 + S: * LIST (\Subscribed) "/" "foo2/bar2" 924 + S: * LIST (\Subscribed) "/" "baz2/bar2" 925 + S: * LIST (\Subscribed) "/" "baz2/bar22" 926 + S: * LIST (\Subscribed) "/" "baz2/bar222" 927 + S: * LIST (\Subscribed) "/" "eps2" 928 + S: * LIST (\Subscribed) "/" "eps2/mamba" 929 + S: * LIST (\Subscribed) "/" "qux2/bar2" 930 + S: D02 OK done 931 + 932 + The client issues the following command first: 933 + 934 + C: D03 LIST (RECURSIVEMATCH SUBSCRIBED) "" "*2" 935 + S: * LIST () "/" "foo2" ("CHILDINFO" ("SUBSCRIBED")) 936 + S: * LIST (\Subscribed) "/" "foo2/bar2" 937 + S: * LIST (\Subscribed) "/" "baz2/bar2" 938 + S: * LIST (\Subscribed) "/" "baz2/bar22" 939 + S: * LIST (\Subscribed) "/" "baz2/bar222" 940 + S: * LIST (\Subscribed) "/" "eps2" ("CHILDINFO" ("SUBSCRIBED")) 941 + S: * LIST (\Subscribed) "/" "qux2/bar2" 942 + S: D03 OK done 943 + 944 + and the server may also include (but this would violate a SHOULD NOT 945 + in Section 3.5, because CHILDINFO is redundant) 946 + 947 + S: * LIST () "/" "baz2" ("CHILDINFO" ("SUBSCRIBED")) 948 + S: * LIST (\NonExistent) "/" "qux2" ("CHILDINFO" ("SUBSCRIBED")) 949 + 950 + 951 + 952 + 953 + 954 + Leiba & Melnikov Standards Track [Page 17] 955 + 956 + RFC 5258 IMAP4 LIST Command Extensions June 2008 957 + 958 + 959 + The CHILDINFO extended data item is returned for mailboxes "foo2", 960 + "baz2", and "eps2", because all of them have subscribed children, 961 + even though for the mailbox "foo2" only one of the two subscribed 962 + children matches the pattern, for the mailbox "baz2" all the 963 + subscribed children match the pattern, and for the mailbox "eps2" 964 + none of the subscribed children matches the pattern. 965 + 966 + Note that if the client issues 967 + 968 + C: D03 LIST (RECURSIVEMATCH SUBSCRIBED) "" "*" 969 + S: * LIST () "/" "foo2" ("CHILDINFO" ("SUBSCRIBED")) 970 + S: * LIST (\Subscribed) "/" "foo2/bar1" 971 + S: * LIST (\Subscribed) "/" "foo2/bar2" 972 + S: * LIST () "/" "baz2" ("CHILDINFO" ("SUBSCRIBED")) 973 + S: * LIST (\Subscribed) "/" "baz2/bar2" 974 + S: * LIST (\Subscribed) "/" "baz2/bar22" 975 + S: * LIST (\Subscribed) "/" "baz2/bar222" 976 + S: * LIST (\Subscribed) "/" "eps2" ("CHILDINFO" ("SUBSCRIBED")) 977 + S: * LIST (\Subscribed) "/" "eps2/mamba" 978 + S: * LIST (\Subscribed) "/" "qux2/bar2" 979 + S: D03 OK done 980 + 981 + The LIST responses for mailboxes "foo2", "baz2", and "eps2" still 982 + have the CHILDINFO extended data item, even though this information 983 + is redundant and the client can determine it by itself. 984 + 985 + 10: The following example shows usage of multiple mailbox patterns. 986 + It also demonstrates that the presence of the CHILDINFO extended 987 + data item doesn't necessarily imply \HasChildren. 988 + 989 + C: a1 LIST "" ("foo" "foo/*") 990 + S: * LIST () "/" foo 991 + S: a1 OK done 992 + 993 + C: a2 LIST (SUBSCRIBED) "" "foo/*" 994 + S: * LIST (\Subscribed \NonExistent) "/" foo/bar 995 + S: a2 OK done 996 + 997 + C: a3 LIST (SUBSCRIBED RECURSIVEMATCH) "" foo RETURN (CHILDREN) 998 + S: * LIST (\HasNoChildren) "/" foo ("CHILDINFO" ("SUBSCRIBED")) 999 + S: a3 OK done 1000 + 1001 + 11: The following example shows how a server that supports missing 1002 + mailbox hierarchy elements can signal to a client that didn't 1003 + specify the RECURSIVEMATCH selection option that there is a 1004 + child mailbox that matches the selection criteria. 1005 + 1006 + 1007 + 1008 + 1009 + 1010 + Leiba & Melnikov Standards Track [Page 18] 1011 + 1012 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1013 + 1014 + 1015 + C: a1 LIST (REMOTE) "" * 1016 + S: * LIST () "/" music/rock 1017 + S: * LIST (\Remote) "/" also/jazz 1018 + S: a1 OK done 1019 + 1020 + C: a2 LIST () "" % 1021 + S: * LIST (\NonExistent \HasChildren) "/" music 1022 + S: a2 OK done 1023 + 1024 + C: a3 LIST (REMOTE) "" % 1025 + S: * LIST (\NonExistent \HasChildren) "/" music 1026 + S: * LIST (\NonExistent \HasChildren) "/" also 1027 + S: a3 OK done 1028 + 1029 + C: a3.1 LIST "" (% music/rock) 1030 + S: * LIST () "/" music/rock 1031 + S: a3.1 OK done 1032 + 1033 + Because "music/rock" is the only mailbox under "music", there's no 1034 + need for the server to also return "music". However clients must 1035 + handle both cases. 1036 + 1037 + 6. Formal Syntax 1038 + 1039 + The following syntax specification uses the Augmented Backus-Naur 1040 + Form (ABNF) as described in [ABNF]. Terms not defined here are taken 1041 + from [IMAP4]. In particular, note that the version of "mailbox-list" 1042 + below, which defines the payload of the LIST response, updates the 1043 + version defined in the IMAP specification. It is pointed to by 1044 + "mailbox-data", which is defined in [IMAP4]. 1045 + 1046 + "vendor-token" is defined in [ACAP]. Note that this normative 1047 + reference to ACAP will be an issue in moving this spec forward, since 1048 + it introduces a dependency on ACAP. The definitions of 1049 + "vendor-token" and of the IANA registry must eventually go somewhere 1050 + else, in a document that can be moved forward on the standards track 1051 + independently of ACAP. 1052 + 1053 + 1054 + 1055 + 1056 + 1057 + 1058 + 1059 + 1060 + 1061 + 1062 + 1063 + 1064 + 1065 + 1066 + Leiba & Melnikov Standards Track [Page 19] 1067 + 1068 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1069 + 1070 + 1071 + childinfo-extended-item = "CHILDINFO" SP "(" 1072 + list-select-base-opt-quoted 1073 + *(SP list-select-base-opt-quoted) ")" 1074 + ; Extended data item (mbox-list-extended-item) 1075 + ; returned when the RECURSIVEMATCH 1076 + ; selection option is specified. 1077 + ; Note 1: the CHILDINFO tag can be returned 1078 + ; with and without surrounding quotes, as per 1079 + ; mbox-list-extended-item-tag production. 1080 + ; Note 2: The selection options are always returned 1081 + ; quoted, unlike their specification in 1082 + ; the extended LIST command. 1083 + 1084 + child-mbox-flag = "\HasChildren" / "\HasNoChildren" 1085 + ; attributes for CHILDREN return option, at most one 1086 + ; possible per LIST response 1087 + 1088 + eitem-standard-tag = atom 1089 + ; a tag for extended list data defined in a Standard 1090 + ; Track or Experimental RFC. 1091 + 1092 + eitem-vendor-tag = vendor-token "-" atom 1093 + ; a vendor-specific tag for extended list data 1094 + 1095 + list = "LIST" [SP list-select-opts] SP mailbox SP mbox-or-pat 1096 + [SP list-return-opts] 1097 + 1098 + list-return-opts = "RETURN" SP 1099 + "(" [return-option *(SP return-option)] ")" 1100 + ; list return options, e.g., CHILDREN 1101 + 1102 + list-select-base-opt = "SUBSCRIBED" / option-extension 1103 + ; options that can be used by themselves 1104 + 1105 + list-select-base-opt-quoted = DQUOTE list-select-base-opt DQUOTE 1106 + 1107 + list-select-independent-opt = "REMOTE" / option-extension 1108 + ; options that do not syntactically interact with 1109 + ; other options 1110 + 1111 + list-select-mod-opt = "RECURSIVEMATCH" / option-extension 1112 + ; options that require a list-select-base-opt 1113 + ; to also be present 1114 + 1115 + list-select-opt = list-select-base-opt / list-select-independent-opt 1116 + / list-select-mod-opt 1117 + ; An option registration template is described in 1118 + ; Section 9.3 of this document. 1119 + 1120 + 1121 + 1122 + Leiba & Melnikov Standards Track [Page 20] 1123 + 1124 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1125 + 1126 + 1127 + list-select-opts = "(" [ 1128 + (*(list-select-opt SP) list-select-base-opt 1129 + *(SP list-select-opt)) 1130 + / (list-select-independent-opt 1131 + *(SP list-select-independent-opt)) 1132 + ] ")" 1133 + ; Any number of options may be in any order. 1134 + ; If a list-select-mod-opt appears, then a 1135 + ; list-select-base-opt must also appear. 1136 + ; This allows these: 1137 + ; () 1138 + ; (REMOTE) 1139 + ; (SUBSCRIBED) 1140 + ; (SUBSCRIBED REMOTE) 1141 + ; (SUBSCRIBED RECURSIVEMATCH) 1142 + ; (SUBSCRIBED REMOTE RECURSIVEMATCH) 1143 + ; But does NOT allow these: 1144 + ; (RECURSIVEMATCH) 1145 + ; (REMOTE RECURSIVEMATCH) 1146 + 1147 + mailbox-list = "(" [mbx-list-flags] ")" SP 1148 + (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox 1149 + [SP mbox-list-extended] 1150 + ; This is the list information pointed to by the ABNF 1151 + ; item "mailbox-data", which is defined in [IMAP4] 1152 + 1153 + mbox-list-extended = "(" [mbox-list-extended-item 1154 + *(SP mbox-list-extended-item)] ")" 1155 + 1156 + mbox-list-extended-item = mbox-list-extended-item-tag SP 1157 + tagged-ext-val 1158 + 1159 + mbox-list-extended-item-tag = astring 1160 + ; The content MUST conform to either "eitem-vendor-tag" 1161 + ; or "eitem-standard-tag" ABNF productions. 1162 + ; A tag registration template is described in this 1163 + ; document in Section 9.5. 1164 + 1165 + mbx-list-oflag =/ child-mbox-flag / "\Subscribed" / "\Remote" 1166 + 1167 + mbx-list-sflag =/ "\NonExistent" 1168 + 1169 + mbox-or-pat = list-mailbox / patterns 1170 + 1171 + option-extension = (option-standard-tag / option-vendor-tag) 1172 + [SP option-value] 1173 + 1174 + 1175 + 1176 + 1177 + 1178 + Leiba & Melnikov Standards Track [Page 21] 1179 + 1180 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1181 + 1182 + 1183 + option-standard-tag = atom 1184 + ; an option defined in a Standards Track or 1185 + ; Experimental RFC 1186 + 1187 + option-val-comp = astring / 1188 + option-val-comp *(SP option-val-comp) / 1189 + "(" option-val-comp ")" 1190 + 1191 + option-value = "(" option-val-comp ")" 1192 + 1193 + option-vendor-tag = vendor-token "-" atom 1194 + ; a vendor-specific option, non-standard 1195 + 1196 + patterns = "(" list-mailbox *(SP list-mailbox) ")" 1197 + 1198 + return-option = "SUBSCRIBED" / "CHILDREN" / option-extension 1199 + 1200 + tagged-ext-comp = astring / 1201 + tagged-ext-comp *(SP tagged-ext-comp) / 1202 + "(" tagged-ext-comp ")" 1203 + ; Extensions that follow this general 1204 + ; syntax should use nstring instead of 1205 + ; astring when appropriate in the context 1206 + ; of the extension. 1207 + ; Note that a message set or a "number" 1208 + ; can always be represented as an "atom". 1209 + ; A URL should be represented as 1210 + ; a "quoted" string. 1211 + 1212 + tagged-ext-simple = sequence-set / number 1213 + 1214 + tagged-ext-val = tagged-ext-simple / 1215 + "(" [tagged-ext-comp] ")" 1216 + 1217 + 7. Internationalization Considerations 1218 + 1219 + The LIST command selection option types defined in this specification 1220 + involve simple tests of mailbox properties. However, future 1221 + extensions to LIST-EXTENDED may define selection options that do more 1222 + sophisticated tests. In the case of a test that requires matching 1223 + text, in the presence of the COMPARATOR [I18N] extension, the active 1224 + comparator must be used to do comparisons. Such LIST-EXTENDED 1225 + extensions MUST indicate in their specification the interaction with 1226 + the COMPARATOR [I18N] extension. 1227 + 1228 + 1229 + 1230 + 1231 + 1232 + 1233 + 1234 + Leiba & Melnikov Standards Track [Page 22] 1235 + 1236 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1237 + 1238 + 1239 + 8. Security Considerations 1240 + 1241 + This document describes syntactic changes to the specification of the 1242 + IMAP4 commands LIST, LSUB, RLIST, and RLSUB, and the modified LIST 1243 + command has the same security considerations as those commands. They 1244 + are described in [IMAP4] and [MBRef]. 1245 + 1246 + The Child Mailbox Extension provides a client a more efficient means 1247 + of determining whether a particular mailbox has children. If a 1248 + mailbox has children, but the currently authenticated user does not 1249 + have access to any of them, the server SHOULD respond with a 1250 + \HasNoChildren attribute. In many cases, however, a server may not 1251 + be able to efficiently compute whether a user has access to any child 1252 + mailbox. If such a server responds with a \HasChildren attribute, 1253 + when in fact the currently authenticated user does not have access to 1254 + any child mailboxes, potentially more information is conveyed about 1255 + the mailbox than intended. In most situations, this will not be a 1256 + security concern, because if information regarding whether a mailbox 1257 + has children is considered sensitive, a user would not be granted 1258 + access to that mailbox in the first place. 1259 + 1260 + The CHILDINFO extended data item has the same security considerations 1261 + as the \HasChildren attribute described above. 1262 + 1263 + 9. IANA Considerations 1264 + 1265 + 9.1. Guidelines for IANA 1266 + 1267 + IANA has created two new registries for LIST-EXTENDED options and 1268 + LIST-EXTENDED response data. The templates and the initial 1269 + registrations are detailed below. 1270 + 1271 + 9.2. Registration Procedure and Change Control 1272 + 1273 + Registration of a LIST-EXTENDED option is done by filling in the 1274 + template in Section 9.3 and sending it via electronic mail to 1275 + iana@iana.org. Registration of a LIST-EXTENDED extended data item is 1276 + done by filling in the template in Section 9.5 and sending it via 1277 + electronic mail to iana@iana.org. IANA has the right to reject 1278 + obviously bogus registrations, but will perform no review of claims 1279 + made in the registration form. 1280 + 1281 + A LIST-EXTENDED option/extended data item name that starts with "V-" 1282 + is reserved for vendor-specific options/extended data items. All 1283 + options, whether they are vendor specific or global, should be 1284 + registered with IANA. If a LIST-EXTENDED extended data item is 1285 + returned as a result of requesting a particular LIST-EXTENDED option, 1286 + 1287 + 1288 + 1289 + 1290 + Leiba & Melnikov Standards Track [Page 23] 1291 + 1292 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1293 + 1294 + 1295 + the name of the option SHOULD be used as the name of the 1296 + LIST-EXTENDED extended data item. 1297 + 1298 + Each vendor-specific option/extended data item MUST start with its 1299 + vendor-token ("vendor prefix"). The vendor-token MUST be registered 1300 + with IANA, using the [ACAP] vendor subtree registry. 1301 + 1302 + Standard LIST-EXTENDED option/extended data item names are case 1303 + insensitive. If the vendor prefix is omitted from a vendor-specific 1304 + LIST-EXTENDED option/extended data item name, the rest is case 1305 + insensitive. The vendor prefix itself is not case sensitive, as it 1306 + might contain non-ASCII characters. While the registration 1307 + procedures do not require it, authors of 1308 + LIST-EXTENDED options/extended data items are encouraged to seek 1309 + community review and comment whenever that is feasible. Authors may 1310 + seek community review by posting a specification of their proposed 1311 + mechanism as an 1312 + Internet-Draft. LIST-EXTENDED option/extended data items intended 1313 + for widespread use should be standardized through the normal IETF 1314 + process, when appropriate. 1315 + 1316 + Comments on registered LIST-EXTENDED options/extended response data 1317 + should first be sent to the "owner" of the mechanism and/or to the 1318 + IMAPEXT WG mailing list. Submitters of comments may, after a 1319 + reasonable attempt to contact the owner, request IANA to attach their 1320 + comment to the registration itself. If IANA approves of this, the 1321 + comment will be made accessible in conjunction with the registration 1322 + LIST-EXTENDED options/extended response data itself. 1323 + 1324 + Once a LIST-EXTENDED registration has been published by IANA, the 1325 + author may request a change to its definition. The change request 1326 + follows the same procedure as the registration request. 1327 + 1328 + The owner of a LIST-EXTENDED registration may pass responsibility for 1329 + the registered option/extended data item to another person or agency 1330 + by informing IANA; this can be done without discussion or review. 1331 + 1332 + The IESG may reassign responsibility for a LIST-EXTENDED 1333 + option/extended data item. The most common case of this will be to 1334 + enable changes to be made to mechanisms where the author of the 1335 + registration has died, has moved out of contact, or is otherwise 1336 + unable to make changes that are important to the community. 1337 + 1338 + LIST-EXTENDED registrations may not be deleted; mechanisms that are 1339 + no longer believed appropriate for use can be declared OBSOLETE by a 1340 + change to their "intended use" field. Such LIST-EXTENDED 1341 + options/extended data items will be clearly marked in the lists 1342 + published by IANA. 1343 + 1344 + 1345 + 1346 + Leiba & Melnikov Standards Track [Page 24] 1347 + 1348 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1349 + 1350 + 1351 + The IESG is considered to be the owner of all LIST-EXTENDED 1352 + options/extended data items that are on the IETF standards track. 1353 + 1354 + 9.3. Registration Template for LIST-EXTENDED Options 1355 + 1356 + To: iana@iana.org 1357 + Subject: Registration of LIST-EXTENDED option X 1358 + 1359 + LIST-EXTENDED option name: 1360 + 1361 + LIST-EXTENDED option type: (One of SELECTION or RETURN) 1362 + 1363 + Implied return options(s), if the option type is SELECTION: (zero or 1364 + more) 1365 + 1366 + LIST-EXTENDED option description: 1367 + 1368 + Published specification (optional, recommended): 1369 + 1370 + Security considerations: 1371 + 1372 + Intended usage: 1373 + (One of COMMON, LIMITED USE, or OBSOLETE) 1374 + 1375 + Person and email address to contact for further information: 1376 + 1377 + Owner/Change controller: 1378 + 1379 + (Any other information that the author deems interesting may be added 1380 + below this line.) 1381 + 1382 + 9.4. Initial LIST-EXTENDED Option Registrations 1383 + 1384 + The LIST-EXTENDED option registry has been populated with the 1385 + following entries: 1386 + 1387 + 1. To: iana@iana.org 1388 + Subject: Registration of LIST-EXTENDED option SUBSCRIBED 1389 + 1390 + LIST-EXTENDED option name: SUBSCRIBED 1391 + 1392 + LIST-EXTENDED option type: SELECTION 1393 + 1394 + Implied return options(s): SUBSCRIBED 1395 + 1396 + LIST-EXTENDED option description: Causes the LIST command to list 1397 + subscribed mailboxes, rather than the actual mailboxes. 1398 + 1399 + 1400 + 1401 + 1402 + Leiba & Melnikov Standards Track [Page 25] 1403 + 1404 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1405 + 1406 + 1407 + Published specification: RFC 5258, Section 3. 1408 + 1409 + Security considerations: RFC 5258, Section 8. 1410 + 1411 + Intended usage: COMMON 1412 + 1413 + Person and email address to contact for further information: 1414 + Alexey Melnikov <Alexey.Melnikov@isode.com> 1415 + 1416 + Owner/Change controller: iesg@ietf.org 1417 + 1418 + 2. To: iana@iana.org 1419 + Subject: Registration of LIST-EXTENDED option REMOTE 1420 + 1421 + LIST-EXTENDED option name: REMOTE 1422 + 1423 + LIST-EXTENDED option type: SELECTION 1424 + 1425 + Implied return options(s): (none) 1426 + 1427 + LIST-EXTENDED option description: Causes the LIST command to 1428 + return remote mailboxes as well as local ones, as described in 1429 + RFC 2193. 1430 + 1431 + Published specification: RFC 5258, Section 3. 1432 + 1433 + Security considerations: RFC 5258, Section 8. 1434 + 1435 + Intended usage: COMMON 1436 + 1437 + Person and email address to contact for further information: 1438 + Alexey Melnikov <Alexey.Melnikov@isode.com> 1439 + 1440 + Owner/Change controller: iesg@ietf.org 1441 + 1442 + 3. To: iana@iana.org 1443 + Subject: Registration of LIST-EXTENDED option SUBSCRIBED 1444 + 1445 + LIST-EXTENDED option name: SUBSCRIBED 1446 + 1447 + LIST-EXTENDED option type: RETURN 1448 + 1449 + LIST-EXTENDED option description: Causes the LIST command to 1450 + return subscription state. 1451 + 1452 + Published specification: RFC 5258, Section 3. 1453 + 1454 + Security considerations: RFC 5258, Section 8. 1455 + 1456 + 1457 + 1458 + Leiba & Melnikov Standards Track [Page 26] 1459 + 1460 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1461 + 1462 + 1463 + Intended usage: COMMON 1464 + 1465 + Person and email address to contact for further information: 1466 + Alexey Melnikov <Alexey.Melnikov@isode.com> 1467 + 1468 + Owner/Change controller: iesg@ietf.org 1469 + 1470 + 4. To: iana@iana.org 1471 + Subject: Registration of LIST-EXTENDED option RECURSIVEMATCH 1472 + 1473 + LIST-EXTENDED option name: RECURSIVEMATCH 1474 + 1475 + LIST-EXTENDED option type: SELECTION 1476 + 1477 + Implied return options(s): (none) 1478 + 1479 + LIST-EXTENDED option description: Requests that CHILDINFO 1480 + extended data item (childinfo-extended-item) is to be returned. 1481 + 1482 + Published specification: RFC 5258, Section 3. 1483 + 1484 + Security considerations: RFC 5258, Section 8. 1485 + 1486 + Intended usage: COMMON 1487 + 1488 + Person and email address to contact for further information: 1489 + Alexey Melnikov <Alexey.Melnikov@isode.com> 1490 + 1491 + Owner/Change controller: iesg@ietf.org 1492 + 1493 + 5. To: iana@iana.org 1494 + Subject: Registration of LIST-EXTENDED option CHILDREN 1495 + 1496 + LIST-EXTENDED option name: CHILDREN 1497 + 1498 + LIST-EXTENDED option type: RETURN 1499 + 1500 + LIST-EXTENDED option description: Requests mailbox child 1501 + information. 1502 + 1503 + Published specification: RFC 5258, Section 3 and Section 4. 1504 + 1505 + Security considerations: RFC 5258, Section 8. 1506 + 1507 + Intended usage: COMMON 1508 + 1509 + Person and email address to contact for further information: 1510 + Alexey Melnikov <Alexey.Melnikov@isode.com> 1511 + 1512 + 1513 + 1514 + Leiba & Melnikov Standards Track [Page 27] 1515 + 1516 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1517 + 1518 + 1519 + Owner/Change controller: iesg@ietf.org 1520 + 1521 + 9.5. Registration Template for LIST-EXTENDED Extended Data Item 1522 + 1523 + To: iana@iana.org 1524 + Subject: Registration of X LIST-EXTENDED extended data item 1525 + 1526 + LIST-EXTENDED extended data item tag: 1527 + 1528 + LIST-EXTENDED extended data item description: 1529 + 1530 + Which LIST-EXTENDED option(s) (and their types) causes this extended 1531 + data item to be returned (if any): 1532 + 1533 + Published specification (optional, recommended): 1534 + 1535 + Security considerations: 1536 + 1537 + Intended usage: 1538 + (One of COMMON, LIMITED USE, or OBSOLETE) 1539 + 1540 + Person and email address to contact for further information: 1541 + 1542 + Owner/Change controller: 1543 + 1544 + (Any other information that the author deems interesting may be added 1545 + below this line.) 1546 + 1547 + 9.6. Initial LIST-EXTENDED Extended Data Item Registrations 1548 + 1549 + The LIST-EXTENDED extended data item registry has been populated with 1550 + the following entries: 1551 + 1552 + 1. To: iana@iana.org 1553 + Subject: Registration of CHILDINFO LIST-EXTENDED extended data 1554 + item 1555 + 1556 + LIST-EXTENDED extended data item tag: CHILDINFO 1557 + 1558 + LIST-EXTENDED extended data item description: The CHILDINFO 1559 + extended data item describes the selection criteria that has 1560 + caused it to be returned and indicates that the mailbox has one 1561 + or more child mailboxes that match the selection criteria. 1562 + 1563 + Which LIST-EXTENDED option(s) (and their types) causes this 1564 + extended data item to be returned (if any): RECURSIVEMATCH 1565 + selection option 1566 + 1567 + 1568 + 1569 + 1570 + Leiba & Melnikov Standards Track [Page 28] 1571 + 1572 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1573 + 1574 + 1575 + Published specification: RFC 5258, Section 3.5. 1576 + 1577 + Security considerations: RFC 5258, Section 8. 1578 + 1579 + Intended usage: COMMON 1580 + 1581 + Person and email address to contact for further information: 1582 + Alexey Melnikov <Alexey.Melnikov@isode.com> 1583 + 1584 + Owner/Change controller: iesg@ietf.org 1585 + 1586 + 10. Acknowledgements 1587 + 1588 + Mike Gahrns and Raymond Cheng of Microsoft Corporation originally 1589 + devised the Child Mailbox Extension and proposed it in 1997; the 1590 + idea, as well as most of the text in Section 4, is theirs. 1591 + 1592 + This document is the result of discussions on the IMAP4 and IMAPEXT 1593 + mailing lists and is meant to reflect consensus of those groups. In 1594 + particular, Mark Crispin, Philip Guenther, Cyrus Daboo, Timo 1595 + Sirainen, Ken Murchison, Rob Siemborski, Steve Hole, Arnt 1596 + Gulbrandsen, Larry Greenfield, Dave Cridland, and Pete Maclean were 1597 + active participants in those discussions or made suggestions to this 1598 + document. 1599 + 1600 + 11. References 1601 + 1602 + 11.1. Normative References 1603 + 1604 + [ABNF] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax 1605 + Specifications: ABNF", STD 68, RFC 5234, January 2008. 1606 + 1607 + [ACAP] Newman, C. and J. Myers, "ACAP -- Application Configuration 1608 + Access Protocol", RFC 2244, November 1997. 1609 + 1610 + [I18N] Newman, C., Gulbrandsen, A., and A. Melnikov, "Internet 1611 + Message Access Protocol Internationalization", RFC 5255, 1612 + June 2008. 1613 + 1614 + [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 1615 + 4rev1", RFC 3501, March 2003. 1616 + 1617 + [Kwds] Bradner, S., "Key words for use in RFCs to Indicate 1618 + Requirement Levels", RFC 2119, March 1997. 1619 + 1620 + [MBRef] Gahrns, M., "IMAP4 Mailbox Referrals", RFC 2193, 1621 + September 1997. 1622 + 1623 + 1624 + 1625 + 1626 + Leiba & Melnikov Standards Track [Page 29] 1627 + 1628 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1629 + 1630 + 1631 + 11.2. Informative References 1632 + 1633 + [CMbox] Gahrns, M. and R. Cheng, "The Internet Message Action 1634 + Protocol (IMAP4) Child Mailbox Extension", RFC 3348, 1635 + July 2002. 1636 + 1637 + Authors' Addresses 1638 + 1639 + Barry Leiba 1640 + IBM T.J. Watson Research Center 1641 + 19 Skyline Drive 1642 + Hawthorne, NY 10532 1643 + US 1644 + 1645 + Phone: +1 914 784 7941 1646 + EMail: leiba@watson.ibm.com 1647 + 1648 + 1649 + Alexey Melnikov 1650 + Isode Limited 1651 + 5 Castle Business Village 1652 + 36 Station Road 1653 + Hampton, Middlesex TW12 2BX 1654 + UK 1655 + 1656 + EMail: Alexey.Melnikov@isode.com 1657 + URI: http://www.melnikov.ca/ 1658 + 1659 + 1660 + 1661 + 1662 + 1663 + 1664 + 1665 + 1666 + 1667 + 1668 + 1669 + 1670 + 1671 + 1672 + 1673 + 1674 + 1675 + 1676 + 1677 + 1678 + 1679 + 1680 + 1681 + 1682 + Leiba & Melnikov Standards Track [Page 30] 1683 + 1684 + RFC 5258 IMAP4 LIST Command Extensions June 2008 1685 + 1686 + 1687 + Full Copyright Statement 1688 + 1689 + Copyright (C) The IETF Trust (2008). 1690 + 1691 + This document is subject to the rights, licenses and restrictions 1692 + contained in BCP 78, and except as set forth therein, the authors 1693 + retain all their rights. 1694 + 1695 + This document and the information contained herein are provided on an 1696 + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS 1697 + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND 1698 + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS 1699 + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF 1700 + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED 1701 + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 1702 + 1703 + Intellectual Property 1704 + 1705 + The IETF takes no position regarding the validity or scope of any 1706 + Intellectual Property Rights or other rights that might be claimed to 1707 + pertain to the implementation or use of the technology described in 1708 + this document or the extent to which any license under such rights 1709 + might or might not be available; nor does it represent that it has 1710 + made any independent effort to identify any such rights. Information 1711 + on the procedures with respect to rights in RFC documents can be 1712 + found in BCP 78 and BCP 79. 1713 + 1714 + Copies of IPR disclosures made to the IETF Secretariat and any 1715 + assurances of licenses to be made available, or the result of an 1716 + attempt made to obtain a general license or permission for the use of 1717 + such proprietary rights by implementers or users of this 1718 + specification can be obtained from the IETF on-line IPR repository at 1719 + http://www.ietf.org/ipr. 1720 + 1721 + The IETF invites any interested party to bring to its attention any 1722 + copyrights, patents or patent applications, or other proprietary 1723 + rights that may cover technology that may be required to implement 1724 + this standard. Please address the information to the IETF at 1725 + ietf-ipr@ietf.org. 1726 + 1727 + 1728 + 1729 + 1730 + 1731 + 1732 + 1733 + 1734 + 1735 + 1736 + 1737 + 1738 + Leiba & Melnikov Standards Track [Page 31] 1739 +
+507
spec/rfc5530.txt
··· 1 + 2 + 3 + 4 + 5 + 6 + 7 + Network Working Group A. Gulbrandsen 8 + Request for Comments: 5530 Oryx Mail Systems GmbH 9 + Category: Standards Track May 2009 10 + 11 + 12 + IMAP Response Codes 13 + 14 + Status of This Memo 15 + 16 + This document specifies an Internet standards track protocol for the 17 + Internet community, and requests discussion and suggestions for 18 + improvements. Please refer to the current edition of the "Internet 19 + Official Protocol Standards" (STD 1) for the standardization state 20 + and status of this protocol. Distribution of this memo is unlimited. 21 + 22 + Copyright Notice 23 + 24 + Copyright (c) 2009 IETF Trust and the persons identified as the 25 + document authors. All rights reserved. 26 + 27 + This document is subject to BCP 78 and the IETF Trust's Legal 28 + Provisions Relating to IETF Documents in effect on the date of 29 + publication of this document (http://trustee.ietf.org/license-info). 30 + Please review these documents carefully, as they describe your rights 31 + and restrictions with respect to this document. 32 + 33 + Abstract 34 + 35 + IMAP responses consist of a response type (OK, NO, BAD), an optional 36 + machine-readable response code, and a human-readable text. 37 + 38 + This document collects and documents a variety of machine-readable 39 + response codes, for better interoperation and error reporting. 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + Gulbrandsen Standards Track [Page 1] 59 + 60 + RFC 5530 IMAP Response Codes May 2009 61 + 62 + 63 + 1. Introduction 64 + 65 + Section 7.1 of [RFC3501] defines a number of response codes that can 66 + help tell an IMAP client why a command failed. However, experience 67 + has shown that more codes are useful. For example, it is useful for 68 + a client to know that an authentication attempt failed because of a 69 + server problem as opposed to a password problem. 70 + 71 + Currently, many IMAP servers use English-language, human-readable 72 + text to describe these errors, and a few IMAP clients attempt to 73 + translate this text into the user's language. 74 + 75 + This document names a variety of errors as response codes. It is 76 + based on errors that have been checked and reported on in some IMAP 77 + server implementations, and on the needs of some IMAP clients. 78 + 79 + This document doesn't require any servers to test for these errors or 80 + any clients to test for these names. It only names errors for better 81 + reporting and handling. 82 + 83 + 2. Conventions Used in This Document 84 + 85 + Formal syntax is defined by [RFC5234] as modified by [RFC3501]. 86 + 87 + Example lines prefaced by "C:" are sent by the client and ones 88 + prefaced by "S:" by the server. "[...]" means elision. 89 + 90 + 3. Response Codes 91 + 92 + This section defines all the new response codes. Each definition is 93 + followed by one or more examples. 94 + 95 + UNAVAILABLE 96 + Temporary failure because a subsystem is down. For example, an 97 + IMAP server that uses a Lightweight Directory Access Protocol 98 + (LDAP) or Radius server for authentication might use this 99 + response code when the LDAP/Radius server is down. 100 + 101 + C: a LOGIN "fred" "foo" 102 + S: a NO [UNAVAILABLE] User's backend down for maintenance 103 + 104 + AUTHENTICATIONFAILED 105 + Authentication failed for some reason on which the server is 106 + unwilling to elaborate. Typically, this includes "unknown 107 + user" and "bad password". 108 + 109 + 110 + 111 + 112 + 113 + 114 + Gulbrandsen Standards Track [Page 2] 115 + 116 + RFC 5530 IMAP Response Codes May 2009 117 + 118 + 119 + This is the same as not sending any response code, except that 120 + when a client sees AUTHENTICATIONFAILED, it knows that the 121 + problem wasn't, e.g., UNAVAILABLE, so there's no point in 122 + trying the same login/password again later. 123 + 124 + C: b LOGIN "fred" "foo" 125 + S: b NO [AUTHENTICATIONFAILED] Authentication failed 126 + 127 + AUTHORIZATIONFAILED 128 + Authentication succeeded in using the authentication identity, 129 + but the server cannot or will not allow the authentication 130 + identity to act as the requested authorization identity. This 131 + is only applicable when the authentication and authorization 132 + identities are different. 133 + 134 + C: c1 AUTHENTICATE PLAIN 135 + [...] 136 + S: c1 NO [AUTHORIZATIONFAILED] No such authorization-ID 137 + 138 + C: c2 AUTHENTICATE PLAIN 139 + [...] 140 + S: c2 NO [AUTHORIZATIONFAILED] Authenticator is not an admin 141 + 142 + 143 + EXPIRED 144 + Either authentication succeeded or the server no longer had the 145 + necessary data; either way, access is no longer permitted using 146 + that passphrase. The client or user should get a new 147 + passphrase. 148 + 149 + C: d login "fred" "foo" 150 + S: d NO [EXPIRED] That password isn't valid any more 151 + 152 + PRIVACYREQUIRED 153 + The operation is not permitted due to a lack of privacy. If 154 + Transport Layer Security (TLS) is not in use, the client could 155 + try STARTTLS (see Section 6.2.1 of [RFC3501]) and then repeat 156 + the operation. 157 + 158 + C: d login "fred" "foo" 159 + S: d NO [PRIVACYREQUIRED] Connection offers no privacy 160 + 161 + C: d select inbox 162 + S: d NO [PRIVACYREQUIRED] Connection offers no privacy 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + Gulbrandsen Standards Track [Page 3] 171 + 172 + RFC 5530 IMAP Response Codes May 2009 173 + 174 + 175 + CONTACTADMIN 176 + The user should contact the system administrator or support 177 + desk. 178 + 179 + C: e login "fred" "foo" 180 + S: e OK [CONTACTADMIN] 181 + 182 + NOPERM 183 + The access control system (e.g., Access Control List (ACL), see 184 + [RFC4314]) does not permit this user to carry out an operation, 185 + such as selecting or creating a mailbox. 186 + 187 + C: f select "/archive/projects/experiment-iv" 188 + S: f NO [NOPERM] Access denied 189 + 190 + INUSE 191 + An operation has not been carried out because it involves 192 + sawing off a branch someone else is sitting on. Someone else 193 + may be holding an exclusive lock needed for this operation, or 194 + the operation may involve deleting a resource someone else is 195 + using, typically a mailbox. 196 + 197 + The operation may succeed if the client tries again later. 198 + 199 + C: g delete "/archive/projects/experiment-iv" 200 + S: g NO [INUSE] Mailbox in use 201 + 202 + EXPUNGEISSUED 203 + Someone else has issued an EXPUNGE for the same mailbox. The 204 + client may want to issue NOOP soon. [RFC2180] discusses this 205 + subject in depth. 206 + 207 + C: h search from fred@example.com 208 + S: * SEARCH 1 2 3 5 8 13 21 42 209 + S: h OK [EXPUNGEISSUED] Search completed 210 + 211 + CORRUPTION 212 + The server discovered that some relevant data (e.g., the 213 + mailbox) are corrupt. This response code does not include any 214 + information about what's corrupt, but the server can write that 215 + to its logfiles. 216 + 217 + C: i select "/archive/projects/experiment-iv" 218 + S: i NO [CORRUPTION] Cannot open mailbox 219 + 220 + 221 + 222 + 223 + 224 + 225 + 226 + Gulbrandsen Standards Track [Page 4] 227 + 228 + RFC 5530 IMAP Response Codes May 2009 229 + 230 + 231 + SERVERBUG 232 + The server encountered a bug in itself or violated one of its 233 + own invariants. 234 + 235 + C: j select "/archive/projects/experiment-iv" 236 + S: j NO [SERVERBUG] This should not happen 237 + 238 + CLIENTBUG 239 + The server has detected a client bug. This can accompany all 240 + of OK, NO, and BAD, depending on what the client bug is. 241 + 242 + C: k1 select "/archive/projects/experiment-iv" 243 + [...] 244 + S: k1 OK [READ-ONLY] Done 245 + C: k2 status "/archive/projects/experiment-iv" (messages) 246 + [...] 247 + S: k2 OK [CLIENTBUG] Done 248 + 249 + CANNOT 250 + The operation violates some invariant of the server and can 251 + never succeed. 252 + 253 + C: l create "///////" 254 + S: l NO [CANNOT] Adjacent slashes are not supported 255 + 256 + LIMIT 257 + The operation ran up against an implementation limit of some 258 + kind, such as the number of flags on a single message or the 259 + number of flags used in a mailbox. 260 + 261 + C: m STORE 42 FLAGS f1 f2 f3 f4 f5 ... f250 262 + S: m NO [LIMIT] At most 32 flags in one mailbox supported 263 + 264 + OVERQUOTA 265 + The user would be over quota after the operation. (The user 266 + may or may not be over quota already.) 267 + 268 + Note that if the server sends OVERQUOTA but doesn't support the 269 + IMAP QUOTA extension defined by [RFC2087], then there is a 270 + quota, but the client cannot find out what the quota is. 271 + 272 + C: n1 uid copy 1:* oldmail 273 + S: n1 NO [OVERQUOTA] Sorry 274 + 275 + C: n2 uid copy 1:* oldmail 276 + S: n2 OK [OVERQUOTA] You are now over your soft quota 277 + 278 + 279 + 280 + 281 + 282 + Gulbrandsen Standards Track [Page 5] 283 + 284 + RFC 5530 IMAP Response Codes May 2009 285 + 286 + 287 + ALREADYEXISTS 288 + The operation attempts to create something that already exists, 289 + such as when the CREATE or RENAME directories attempt to create 290 + a mailbox and there is already one of that name. 291 + 292 + C: o RENAME this that 293 + S: o NO [ALREADYEXISTS] Mailbox "that" already exists 294 + 295 + NONEXISTENT 296 + The operation attempts to delete something that does not exist. 297 + Similar to ALREADYEXISTS. 298 + 299 + C: p RENAME this that 300 + S: p NO [NONEXISTENT] No such mailbox 301 + 302 + 4. Formal Syntax 303 + 304 + The following syntax specification uses the Augmented Backus-Naur 305 + Form (ABNF) notation as specified in [RFC5234]. [RFC3501] defines 306 + the non-terminal "resp-text-code". 307 + 308 + Except as noted otherwise, all alphabetic characters are case- 309 + insensitive. The use of upper or lowercase characters to define 310 + token strings is for editorial clarity only. 311 + 312 + resp-text-code =/ "UNAVAILABLE" / "AUTHENTICATIONFAILED" / 313 + "AUTHORIZATIONFAILED" / "EXPIRED" / 314 + "PRIVACYREQUIRED" / "CONTACTADMIN" / "NOPERM" / 315 + "INUSE" / "EXPUNGEISSUED" / "CORRUPTION" / 316 + "SERVERBUG" / "CLIENTBUG" / "CANNOT" / 317 + "LIMIT" / "OVERQUOTA" / "ALREADYEXISTS" / 318 + "NONEXISTENT" 319 + 320 + 5. Security Considerations 321 + 322 + Revealing information about a passphrase to unauthenticated IMAP 323 + clients causes bad karma. 324 + 325 + Response codes are easier to parse than human-readable text. This 326 + can amplify the consequences of an information leak. For example, 327 + selecting a mailbox can fail because the mailbox doesn't exist, 328 + because the user doesn't have the "l" right (right to know the 329 + mailbox exists) or "r" right (right to read the mailbox). If the 330 + server sent different responses in the first two cases in the past, 331 + only malevolent clients would discover it. With response codes it's 332 + possible, perhaps probable, that benevolent clients will forward the 333 + 334 + 335 + 336 + 337 + 338 + Gulbrandsen Standards Track [Page 6] 339 + 340 + RFC 5530 IMAP Response Codes May 2009 341 + 342 + 343 + leaked information to the user. Server authors are encouraged to be 344 + particularly careful with the NOPERM and authentication-related 345 + responses. 346 + 347 + 6. IANA Considerations 348 + 349 + The IANA has created the IMAP Response Codes registry. The registry 350 + has been populated with the following codes: 351 + 352 + NEWNAME RFC 2060 (obsolete) 353 + REFERRAL RFC 2221 354 + ALERT RFC 3501 355 + BADCHARSET RFC 3501 356 + PARSE RFC 3501 357 + PERMANENTFLAGS RFC 3501 358 + READ-ONLY RFC 3501 359 + READ-WRITE RFC 3501 360 + TRYCREATE RFC 3501 361 + UIDNEXT RFC 3501 362 + UIDVALIDITY RFC 3501 363 + UNSEEN RFC 3501 364 + UNKNOWN-CTE RFC 3516 365 + UIDNOTSTICKY RFC 4315 366 + APPENDUID RFC 4315 367 + COPYUID RFC 4315 368 + URLMECH RFC 4467 369 + TOOBIG RFC 4469 370 + BADURL RFC 4469 371 + HIGHESTMODSEQ RFC 4551 372 + NOMODSEQ RFC 4551 373 + MODIFIED RFC 4551 374 + COMPRESSIONACTIVE RFC 4978 375 + CLOSED RFC 5162 376 + NOTSAVED RFC 5182 377 + BADCOMPARATOR RFC 5255 378 + ANNOTATE RFC 5257 379 + ANNOTATIONS RFC 5257 380 + TEMPFAIL RFC 5259 381 + MAXCONVERTMESSAGES RFC 5259 382 + MAXCONVERTPARTS RFC 5259 383 + NOUPDATE RFC 5267 384 + METADATA RFC 5464 385 + NOTIFICATIONOVERFLOW RFC 5465 386 + BADEVENT RFC 5465 387 + UNDEFINED-FILTER RFC 5466 388 + UNAVAILABLE RFC 5530 389 + AUTHENTICATIONFAILED RFC 5530 390 + AUTHORIZATIONFAILED RFC 5530 391 + 392 + 393 + 394 + Gulbrandsen Standards Track [Page 7] 395 + 396 + RFC 5530 IMAP Response Codes May 2009 397 + 398 + 399 + EXPIRED RFC 5530 400 + PRIVACYREQUIRED RFC 5530 401 + CONTACTADMIN RFC 5530 402 + NOPERM RFC 5530 403 + INUSE RFC 5530 404 + EXPUNGEISSUED RFC 5530 405 + CORRUPTION RFC 5530 406 + SERVERBUG RFC 5530 407 + CLIENTBUG RFC 5530 408 + CANNOT RFC 5530 409 + LIMIT RFC 5530 410 + OVERQUOTA RFC 5530 411 + ALREADYEXISTS RFC 5530 412 + NONEXISTENT RFC 5530 413 + 414 + The new registry can be extended by sending a registration request to 415 + IANA. IANA will forward this request to a Designated Expert, 416 + appointed by the responsible IESG Area Director, CCing it to the IMAP 417 + Extensions mailing list at <ietf-imapext@imc.org> (or a successor 418 + designated by the Area Director). After either allowing 30 days for 419 + community input on the IMAP Extensions mailing list or a successful 420 + IETF Last Call, the expert will determine the appropriateness of the 421 + registration request and either approve or disapprove the request by 422 + sending a notice of the decision to the requestor, CCing the IMAP 423 + Extensions mailing list and IANA. A denial notice must be justified 424 + by an explanation, and, in cases where it is possible, concrete 425 + suggestions on how the request can be modified so as to become 426 + acceptable should be provided. 427 + 428 + For each response code, the registry contains a list of relevant RFCs 429 + that describe (or extend) the response code and an optional response 430 + code status description, such as "obsolete" or "reserved to prevent 431 + collision with deployed software". (Note that in the latter case, 432 + the RFC number can be missing.) Presence of the response code status 433 + description means that the corresponding response code is NOT 434 + RECOMMENDED for widespread use. 435 + 436 + The intention is that any future allocation will be accompanied by a 437 + published RFC (including direct submissions to the RFC Editor). But 438 + in order to allow for the allocation of values prior to the RFC being 439 + approved for publication, the Designated Expert can approve 440 + allocations once it seems clear that an RFC will be published, for 441 + example, before requesting IETF LC for the document. 442 + 443 + The Designated Expert can also approve registrations for response 444 + codes used in deployed software when no RFC exists. Such 445 + registrations must be marked as "reserved to prevent collision with 446 + deployed software". 447 + 448 + 449 + 450 + Gulbrandsen Standards Track [Page 8] 451 + 452 + RFC 5530 IMAP Response Codes May 2009 453 + 454 + 455 + Response code registrations may not be deleted; response codes that 456 + are no longer believed appropriate for use (for example, if there is 457 + a problem with the syntax of said response code or if the 458 + specification describing it was moved to Historic) should be marked 459 + "obsolete" in the registry, clearly marking the lists published by 460 + IANA. 461 + 462 + 7. Acknowledgements 463 + 464 + Peter Coates, Mark Crispin, Philip Guenther, Alexey Melnikov, Ken 465 + Murchison, Chris Newman, Timo Sirainen, Philip Van Hoof, Dale 466 + Wiggins, and Sarah Wilkin helped with this document. 467 + 468 + 8. References 469 + 470 + 8.1. Normative References 471 + 472 + [RFC3501] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 473 + 4rev1", RFC 3501, March 2003. 474 + 475 + [RFC5234] Crocker, D., Ed., and P. Overell, "Augmented BNF for 476 + Syntax Specifications: ABNF", STD 68, RFC 5234, January 477 + 2008. 478 + 479 + 9. Informative References 480 + 481 + [RFC2087] Myers, J., "IMAP4 QUOTA extension", RFC 2087, January 482 + 1997. 483 + 484 + [RFC2180] Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC 485 + 2180, July 1997. 486 + 487 + [RFC4314] Melnikov, A., "IMAP4 Access Control List (ACL) Extension", 488 + RFC 4314, December 2005. 489 + 490 + Author's Address 491 + 492 + Arnt Gulbrandsen 493 + Oryx Mail Systems GmbH 494 + Schweppermannstr. 8 495 + D-81671 Muenchen 496 + Germany 497 + 498 + Fax: +49 89 4502 9758 499 + EMail: arnt@oryx.com 500 + 501 + 502 + 503 + 504 + 505 + 506 + Gulbrandsen Standards Track [Page 9] 507 +
+675
spec/rfc6154.txt
··· 1 + 2 + 3 + 4 + 5 + 6 + 7 + Internet Engineering Task Force (IETF) B. Leiba 8 + Request for Comments: 6154 Huawei Technologies 9 + Category: Standards Track J. Nicolson 10 + ISSN: 2070-1721 Google 11 + March 2011 12 + 13 + 14 + IMAP LIST Extension for Special-Use Mailboxes 15 + 16 + Abstract 17 + 18 + Some IMAP message stores include special-use mailboxes, such as those 19 + used to hold draft messages or sent messages. Many mail clients 20 + allow users to specify where draft or sent messages should be put, 21 + but configuring them requires that the user know which mailboxes the 22 + server has set aside for these purposes. This extension adds new 23 + optional mailbox attributes that a server may include in IMAP LIST 24 + command responses to identify special-use mailboxes to the client, 25 + easing configuration. 26 + 27 + Status of This Memo 28 + 29 + This is an Internet Standards Track document. 30 + 31 + This document is a product of the Internet Engineering Task Force 32 + (IETF). It represents the consensus of the IETF community. It has 33 + received public review and has been approved for publication by the 34 + Internet Engineering Steering Group (IESG). Further information on 35 + Internet Standards is available in Section 2 of RFC 5741. 36 + 37 + Information about the current status of this document, any errata, 38 + and how to provide feedback on it may be obtained at 39 + http://www.rfc-editor.org/info/rfc6154. 40 + 41 + Copyright Notice 42 + 43 + Copyright (c) 2011 IETF Trust and the persons identified as the 44 + document authors. All rights reserved. 45 + 46 + This document is subject to BCP 78 and the IETF Trust's Legal 47 + Provisions Relating to IETF Documents 48 + (http://trustee.ietf.org/license-info) in effect on the date of 49 + publication of this document. Please review these documents 50 + carefully, as they describe your rights and restrictions with respect 51 + to this document. Code Components extracted from this document must 52 + include Simplified BSD License text as described in Section 4.e of 53 + the Trust Legal Provisions and are provided without warranty as 54 + described in the Simplified BSD License. 55 + 56 + 57 + 58 + Leiba & Nicolson Standards Track [Page 1] 59 + 60 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 61 + 62 + 63 + Table of Contents 64 + 65 + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 66 + 1.1. Conventions Used in This Document . . . . . . . . . . . . 3 67 + 2. New Mailbox Attributes Identifying Special-Use Mailboxes . . . 3 68 + 3. Extension to IMAP CREATE Command to Set Special-Use 69 + Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . 5 70 + 4. IMAP METADATA Entry for Special-Use Attributes . . . . . . . . 6 71 + 5. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 72 + 5.1. Example of an IMAP LIST Command . . . . . . . . . . . . . 7 73 + 5.2. Example of an Extended IMAP LIST Command . . . . . . . . . 7 74 + 5.3. Example of an IMAP CREATE Command . . . . . . . . . . . . 8 75 + 5.4. Example of Using IMAP METADATA to Manipulate 76 + Special-Use Attributes . . . . . . . . . . . . . . . . . . 8 77 + 6. Formal Syntax . . . . . . . . . . . . . . . . . . . . . . . . 9 78 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 9 79 + 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 10 80 + 8.1. Registration of USEATTR IMAP Response Code . . . . . . . . 10 81 + 8.2. Registration of CREATE-SPECIAL-USE IMAP Capability . . . . 10 82 + 8.3. Registration of SPECIAL-USE IMAP Capability . . . . . . . 10 83 + 8.4. Registration of SPECIAL-USE Selection Option . . . . . . . 10 84 + 8.5. Registration of SPECIAL-USE Return Option . . . . . . . . 11 85 + 8.6. Registration of SPECIAL-USE Metadata . . . . . . . . . . . 11 86 + 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 12 87 + 9.1. Normative References . . . . . . . . . . . . . . . . . . . 12 88 + 9.2. Informative References . . . . . . . . . . . . . . . . . . 12 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + Leiba & Nicolson Standards Track [Page 2] 115 + 116 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 117 + 118 + 119 + 1. Introduction 120 + 121 + Some IMAP message stores include special-use mailboxes, such as those 122 + used to hold draft messages or sent messages. Many mail clients 123 + allow users to specify where draft or sent messages should be put, 124 + but configuring them requires that the user know which mailboxes the 125 + server has set aside for these purposes. This extension adds new 126 + optional mailbox attributes that a server may include in IMAP LIST 127 + command responses to identify special-use mailboxes to the client, 128 + easing configuration. 129 + 130 + In addition, this extension adds an optional parameter on the IMAP 131 + CREATE command, allowing a client to assign a special use to a 132 + mailbox when it is created. Servers may choose to support this part 133 + of the extension, but are not required to. 134 + 135 + 1.1. Conventions Used in This Document 136 + 137 + In examples, "C:" indicates lines sent by a client that is connected 138 + to a server. "S:" indicates lines sent by the server to the client. 139 + 140 + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 141 + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 142 + document are to be interpreted as described in RFC 2119 [RFC2119]. 143 + 144 + 2. New Mailbox Attributes Identifying Special-Use Mailboxes 145 + 146 + An IMAP server that supports this extension MAY include any or all of 147 + the following attributes in responses to the non-extended IMAP LIST 148 + command. The new attributes are included along with existing 149 + attributes, such as "\Marked" and "\Noselect". A given mailbox may 150 + have none, one, or more than one of these attributes. In some cases, 151 + a special use is advice to a client about what to put in that 152 + mailbox. In other cases, it's advice to a client about what to 153 + expect to find there. There is no capability string related to the 154 + support of special-use attributes on the non-extended LIST command. 155 + 156 + For the extended list command [RFC5258], this extension adds a new 157 + capability string, a new selection option, and a new return option, 158 + all called "SPECIAL-USE". Supporting implementations MUST include 159 + the "SPECIAL-USE" capability string in response to an IMAP CAPABILITY 160 + command. If the client specifies the "SPECIAL-USE" selection option, 161 + the LIST command MUST return only those mailboxes that have a 162 + special-use attribute set. If the client specifies the "SPECIAL-USE" 163 + return option, the LIST command MUST return the new special-use 164 + attributes on those mailboxes that have them set. The "SPECIAL-USE" 165 + 166 + 167 + 168 + 169 + 170 + Leiba & Nicolson Standards Track [Page 3] 171 + 172 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 173 + 174 + 175 + return option is implied by the "SPECIAL-USE" selection option. The 176 + extended LIST command MAY return SPECIAL-USE attributes even if the 177 + client does not specify the return option. 178 + 179 + The new attributes defined here are as follows: 180 + 181 + \All 182 + This mailbox presents all messages in the user's message store. 183 + Implementations MAY omit some messages, such as, perhaps, those 184 + in \Trash and \Junk. When this special use is supported, it is 185 + almost certain to represent a virtual mailbox. 186 + 187 + \Archive 188 + This mailbox is used to archive messages. The meaning of an 189 + "archival" mailbox is server-dependent; typically, it will be 190 + used to get messages out of the inbox, or otherwise keep them 191 + out of the user's way, while still making them accessible. 192 + 193 + \Drafts 194 + This mailbox is used to hold draft messages -- typically, 195 + messages that are being composed but have not yet been sent. In 196 + some server implementations, this might be a virtual mailbox, 197 + containing messages from other mailboxes that are marked with 198 + the "\Draft" message flag. Alternatively, this might just be 199 + advice that a client put drafts here. 200 + 201 + \Flagged 202 + This mailbox presents all messages marked in some way as 203 + "important". When this special use is supported, it is likely 204 + to represent a virtual mailbox collecting messages (from other 205 + mailboxes) that are marked with the "\Flagged" message flag. 206 + 207 + \Junk 208 + This mailbox is where messages deemed to be junk mail are held. 209 + Some server implementations might put messages here 210 + automatically. Alternatively, this might just be advice to a 211 + client-side spam filter. 212 + 213 + \Sent 214 + This mailbox is used to hold copies of messages that have been 215 + sent. Some server implementations might put messages here 216 + automatically. Alternatively, this might just be advice that a 217 + client save sent messages here. 218 + 219 + \Trash 220 + This mailbox is used to hold messages that have been deleted or 221 + marked for deletion. In some server implementations, this might 222 + be a virtual mailbox, containing messages from other mailboxes 223 + 224 + 225 + 226 + Leiba & Nicolson Standards Track [Page 4] 227 + 228 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 229 + 230 + 231 + that are marked with the "\Deleted" message flag. 232 + Alternatively, this might just be advice that a client that 233 + chooses not to use the IMAP "\Deleted" model should use this as 234 + its trash location. In server implementations that strictly 235 + expect the IMAP "\Deleted" model, this special use is likely not 236 + to be supported. 237 + 238 + All of the above attributes are OPTIONAL, and any given server or 239 + message store may support any combination of the attributes, or none 240 + at all. In most cases, there will likely be at most one mailbox with 241 + a given attribute for a given user, but in some server or message 242 + store implementations it might be possible for multiple mailboxes to 243 + have the same special-use attribute. 244 + 245 + Special-use attributes are likely to be user-specific. User Adam 246 + might share his \Sent mailbox with user Barb, but that mailbox is 247 + unlikely to also serve as Barb's \Sent mailbox. It's certainly 248 + possible for Adam and Barb to each set the \Sent use on the same 249 + mailbox, but that would be done by specific action (see the sections 250 + below). 251 + 252 + 3. Extension to IMAP CREATE Command to Set Special-Use Attributes 253 + 254 + As an OPTIONAL feature, a server MAY allow clients to designate a 255 + mailbox, at creation, as having one or more special uses. This 256 + extension defines the "USE" parameter to the IMAP CREATE command for 257 + that purpose (using the syntax defined in RFC 4466 section 2.2 258 + [RFC4466]). The new OPTIONAL "USE" parameter is followed by a 259 + parenthesized list of zero or more special-use attributes, as defined 260 + above. 261 + 262 + In some server implementations, some special uses may imply automatic 263 + action by the server. For example, creation of a "\Junk" mailbox 264 + might cause the server to start placing messages that have been 265 + evaluated as spam into the mailbox. 266 + 267 + In some server implementations, some special uses may result in a 268 + mailbox with unusual characteristics or side effects. For example, 269 + creation of an "\All" mailbox might cause the server to create a 270 + virtual mailbox, rather than a standard one, and that mailbox might 271 + behave in unexpected ways (COPY into it might fail, for example). 272 + 273 + Servers MAY allow the creation of a special-use mailbox even if one 274 + so designated already exists. This might have the effect of moving 275 + the special use from the old mailbox to the new one, or might create 276 + multiple mailboxes with the same special use. Alternatively, servers 277 + MAY refuse the creation, considering the designation to be a 278 + conflict. 279 + 280 + 281 + 282 + Leiba & Nicolson Standards Track [Page 5] 283 + 284 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 285 + 286 + 287 + If the server cannot create a mailbox with the designated special use 288 + defined, for whatever reason, it MUST NOT create the mailbox, and 289 + MUST respond to the CREATE command with a tagged NO response. If the 290 + reason for the failure is related to the special-use attribute (the 291 + specified special use is not supported or cannot be assigned to the 292 + specified mailbox), the server SHOULD include the new "USEATTR" 293 + response code in the tagged response (see Section 5.3 for an 294 + example). 295 + 296 + An IMAP server that supports this OPTIONAL feature will advertise the 297 + "CREATE-SPECIAL-USE" capability string. Clients MUST NOT use the 298 + "USE" parameter unless the server advertises the capability. Note 299 + that this capability string is different from the "SPECIAL-USE" 300 + string defined above, and a server that supports both functions MUST 301 + advertise both capability strings. 302 + 303 + 4. IMAP METADATA Entry for Special-Use Attributes 304 + 305 + If a server supports this extension and the METADATA extension 306 + [RFC5464], it SHOULD tie the special-use attributes for a mailbox to 307 + its metadata entry "/private/specialuse". The value of /private/ 308 + specialuse is either NIL (if there are no special-use attributes for 309 + that mailbox) or a space-separated list of special-use attributes, 310 + presented the same way they would be presented in the LIST command 311 + response. 312 + 313 + Such a server MAY allow the setting of special-use attributes through 314 + the METADATA mechanisms, thereby allowing clients to change the 315 + special uses of existing mailboxes. These changes might have side 316 + effects, as the server automatically adjusts the special uses 317 + accordingly, just as it might do with CREATE USE, above. See 318 + Section 5.4 for an example. 319 + 320 + A server that supports this MUST check the validity of changes to the 321 + special-use attributes that are done through the metadata in the same 322 + way that it checks validity for the CREATE command and for any 323 + internal mechanisms for setting special uses on mailboxes. It MUST 324 + NOT just blindly accept setting of these metadata by clients, which 325 + might result in the setting of special uses that the implementation 326 + does not support, multiple mailboxes with the same special use, or 327 + other situations that the implementation considers invalid. 328 + 329 + 330 + 331 + 332 + 333 + 334 + 335 + 336 + 337 + 338 + Leiba & Nicolson Standards Track [Page 6] 339 + 340 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 341 + 342 + 343 + 5. Examples 344 + 345 + 5.1. Example of an IMAP LIST Command 346 + 347 + This example shows an IMAP LIST response from a server that supports 348 + this extension. Note that not all of the attributes are used. This 349 + server also supports the Child Mailbox extension [RFC3348]. 350 + 351 + C: t1 LIST "" "%" 352 + S: * LIST (\Marked \HasNoChildren) "/" Inbox 353 + S: * LIST (\HasNoChildren) "/" ToDo 354 + S: * LIST (\HasChildren) "/" Projects 355 + S: * LIST (\Sent \HasNoChildren) "/" SentMail 356 + S: * LIST (\Marked \Drafts \HasNoChildren) "/" MyDrafts 357 + S: * LIST (\Trash \HasNoChildren) "/" Trash 358 + S: t1 OK done 359 + 360 + 5.2. Example of an Extended IMAP LIST Command 361 + 362 + This example shows an IMAP LIST response from a server that supports 363 + this extension. The client uses the extended IMAP LIST command. 364 + 365 + C: t1 CAPABILITY 366 + S: * CAPABILITY IMAP4rev1 SPECIAL-USE 367 + S: t1 OK done 368 + 369 + C: t2 LIST "" "%" RETURN (SPECIAL-USE) 370 + S: * LIST (\Marked) "/" Inbox 371 + S: * LIST () "/" ToDo 372 + S: * LIST () "/" Projects 373 + S: * LIST (\Sent) "/" SentMail 374 + S: * LIST (\Marked \Drafts) "/" MyDrafts 375 + S: * LIST (\Trash) "/" Trash 376 + S: t2 OK done 377 + 378 + Here, the client also includes the "SPECIAL-USE" selection option for 379 + the same list. The "SPECIAL-USE" return option could also have been 380 + specified, but it is unnecessary, as it is implied by the selection 381 + option. Note that in this case, mailboxes that do not have a 382 + special-use attribute are not listed. Also note that we've used the 383 + wildcard "*", rather than "%", to make sure we see all special-use 384 + mailboxes, even ones that might not be at the namespace's root. 385 + 386 + C: t3 LIST (SPECIAL-USE) "" "*" 387 + S: * LIST (\Sent) "/" SentMail 388 + S: * LIST (\Marked \Drafts) "/" MyDrafts 389 + S: * LIST (\Trash) "/" Trash 390 + S: t3 OK done 391 + 392 + 393 + 394 + Leiba & Nicolson Standards Track [Page 7] 395 + 396 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 397 + 398 + 399 + 5.3. Example of an IMAP CREATE Command 400 + 401 + This example shows an IMAP CREATE command that might be used to 402 + create a mailbox designated to hold draft and sent messages. It also 403 + attempts to create a mailbox that will contain all the user's 404 + messages, but the server does not support that special use for this 405 + user's message store. 406 + 407 + C: t1 CAPABILITY 408 + S: * CAPABILITY IMAP4rev1 CREATE-SPECIAL-USE 409 + S: t1 OK done 410 + 411 + C: t2 CREATE MySpecial (USE (\Drafts \Sent)) 412 + S: t2 OK MySpecial created 413 + 414 + C: t3 CREATE Everything (USE (\All)) 415 + S: t3 NO [USEATTR] \All not supported 416 + 417 + 5.4. Example of Using IMAP METADATA to Manipulate Special-Use 418 + Attributes 419 + 420 + This example shows how IMAP METADATA can be used to manipulate 421 + special-use attributes, if the operation is supported on the server. 422 + 423 + ==> Starting point: 424 + C: t1 LIST "" "%" RETURN (SPECIAL-USE) 425 + S: * LIST (\Sent) "/" SentMail 426 + S: * LIST (\Drafts) "/" MyDrafts 427 + S: * LIST () "/" SavedDrafts 428 + S: * LIST (\Trash) "/" Trash 429 + S: t1 OK done 430 + 431 + ==> Demonstrate the connection: 432 + C: t2 GETMETADATA "MyDrafts" /private/specialuse 433 + S: * METADATA "MyDrafts" (/private/specialuse "\\Drafts") 434 + S: t2 OK done 435 + 436 + ==> Set new use for SavedDrafts; MyDrafts changes automatically: 437 + C: t3 SETMETADATA "SavedDrafts" (/private/specialuse "\\Drafts") 438 + S: * METADATA "MyDrafts" (/private/specialuse NIL) 439 + S: t3 OK SETMETADATA complete 440 + 441 + ==> Remove special use for SentMail: 442 + C: t4 SETMETADATA "SentMail" (/private/specialuse NIL) 443 + S: t4 OK SETMETADATA complete 444 + 445 + 446 + 447 + 448 + 449 + 450 + Leiba & Nicolson Standards Track [Page 8] 451 + 452 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 453 + 454 + 455 + ==> Check the results: 456 + C: t5 LIST "" "%" RETURN (SPECIAL-USE) 457 + S: * LIST () "/" SentMail 458 + S: * LIST () "/" MyDrafts 459 + S: * LIST (\Drafts) "/" SavedDrafts 460 + S: * LIST (\Trash) "/" Trash 461 + S: t5 OK done 462 + 463 + 6. Formal Syntax 464 + 465 + The following syntax specification uses the augmented Backus-Naur 466 + Form (BNF) as described in [RFC5234]. 467 + 468 + create-param =/ "USE" SP "(" [use-attr *(SP use-attr)] ")" 469 + ; Extends "create-param" from RFC 4466 [RFC4466] 470 + 471 + mbx-list-oflag =/ use-attr 472 + ; Extends "mbx-list-oflag" from IMAP base [RFC3501] 473 + 474 + list-select-independent-opt =/ "SPECIAL-USE" 475 + ; Extends "list-select-independent-opt" from 476 + ; LIST-extended [RFC5258] 477 + 478 + return-option =/ "SPECIAL-USE" 479 + ; Extends "return-option" from 480 + ; LIST-extended [RFC5258] 481 + 482 + resp-text-code =/ "USEATTR" 483 + ; Extends "resp-text-code" from 484 + ; IMAP [RFC3501] 485 + 486 + use-attr = "\All" / "\Archive" / "\Drafts" / "\Flagged" / 487 + "\Junk" / "\Sent" / "\Trash" / use-attr-ext 488 + 489 + use-attr-ext = "\" atom 490 + ; Reserved for future extensions. Clients 491 + ; MUST ignore list attributes they do not understand 492 + ; Server implementations MUST NOT generate 493 + ; extension attributes except as defined by 494 + ; future Standards-Track revisions of or 495 + ; extensions to this specification. 496 + 497 + 7. Security Considerations 498 + 499 + LIST response: 500 + Conveying special-use information to a client exposes a small bit of 501 + extra information that could be of value to an attacker. Knowing, 502 + for example, that a particular mailbox (\All) contains pointers to 503 + 504 + 505 + 506 + Leiba & Nicolson Standards Track [Page 9] 507 + 508 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 509 + 510 + 511 + every message the user has might be of particular value. If the IMAP 512 + channel is not protected from passive eavesdropping, this could be an 513 + issue. 514 + 515 + CREATE command "USE" parameter and metadata extension: In some server 516 + implementations, some special uses may imply automatic action by the 517 + server. For example, creation of a "\Junk" mailbox might cause the 518 + server to start placing messages that have been evaluated as spam 519 + into the mailbox. Implementors SHOULD consider the consequences of 520 + allowing a user (or client program) to designate the target of such 521 + automatic action. 522 + 523 + Example: If a user is allowed to give the "\Junk" attribute to a 524 + shared mailbox, legitimate mail that's misclassified as junk (false 525 + positives) will be put into that shared mailbox, exposing the user's 526 + private mail to others. The server might warn a user of that 527 + possibility, or might refuse to allow the specification to be made on 528 + a shared mailbox. (Note that this problem exists independent of this 529 + specification, if the server allows a user to share a mailbox that's 530 + already in use for such a function.) 531 + 532 + 8. IANA Considerations 533 + 534 + 8.1. Registration of USEATTR IMAP Response Code 535 + 536 + This document defines a new IMAP response code, "USEATTR", which IANA 537 + added to the IMAP Response Codes registry. 538 + 539 + 8.2. Registration of CREATE-SPECIAL-USE IMAP Capability 540 + 541 + This document defines a new IMAP capability, "CREATE-SPECIAL-USE", 542 + which IANA added to the IMAP 4 Capabilities registry. 543 + 544 + 8.3. Registration of SPECIAL-USE IMAP Capability 545 + 546 + This document defines a new IMAP capability, "SPECIAL-USE", which 547 + IANA added to the IMAP 4 Capabilities registry. 548 + 549 + 8.4. Registration of SPECIAL-USE Selection Option 550 + 551 + This document defines a new IMAP4 List Extended selection option, 552 + "SPECIAL-USE", which IANA added to the IMAP4 List Extended registry, 553 + as follows: 554 + 555 + To: iana@iana.org 556 + Subject: Registration of LIST-EXTENDED selection option SPECIAL-USE 557 + LIST-EXTENDED option name: SPECIAL-USE 558 + LIST-EXTENDED option type: SELECTION 559 + 560 + 561 + 562 + Leiba & Nicolson Standards Track [Page 10] 563 + 564 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 565 + 566 + 567 + Implied return option(s): SPECIAL-USE 568 + LIST-EXTENDED option description: Limit the list to special-use 569 + mailboxes only 570 + Published specification: RFC 6154 571 + Security considerations: none 572 + Intended usage: COMMON 573 + Person and email address to contact for further information: Authors' 574 + Addresses at the end of RFC 6154 575 + Owner/Change controller: iesg@ietf.org 576 + 577 + 8.5. Registration of SPECIAL-USE Return Option 578 + 579 + This document defines a new IMAP4 List Extended return option, 580 + "SPECIAL-USE", which IANA added to the IMAP4 List Extended registry, 581 + as follows: 582 + 583 + To: iana@iana.org 584 + Subject: Registration of LIST-EXTENDED return option SPECIAL-USE 585 + LIST-EXTENDED option name: SPECIAL-USE 586 + LIST-EXTENDED option type: RETURN 587 + LIST-EXTENDED option description: Request special-use mailbox 588 + information 589 + Published specification: RFC 6154 590 + Security considerations: none 591 + Intended usage: COMMON 592 + Person and email address to contact for further information: Authors' 593 + Addresses at the end of RFC 6154 594 + Owner/Change controller: iesg@ietf.org 595 + 596 + 8.6. Registration of SPECIAL-USE Metadata 597 + 598 + This document defines a new IMAP METADATA entry. IANA added the 599 + following to the IMAP METADATA Mailbox Entry registry: 600 + 601 + To: iana@iana.org 602 + Subject: IMAP METADATA Entry Registration 603 + Type: Mailbox 604 + Name: /private/specialuse 605 + Description: Defines any special-use features of a mailbox. See the 606 + reference specification for details of its use. 607 + Content-type: text/plain; charset=us-ascii 608 + RFC Number: RFC 6154 609 + Contact: MORG mailing list mailto:morg@ietf.org 610 + 611 + 612 + 613 + 614 + 615 + 616 + 617 + 618 + Leiba & Nicolson Standards Track [Page 11] 619 + 620 + RFC 6154 IMAP LIST: Special-Use Mailboxes March 2011 621 + 622 + 623 + 9. References 624 + 625 + 9.1. Normative References 626 + 627 + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 628 + Requirement Levels", BCP 14, RFC 2119, March 1997. 629 + 630 + [RFC3501] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 631 + 4rev1", RFC 3501, March 2003. 632 + 633 + [RFC4466] Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4 634 + ABNF", RFC 4466, April 2006. 635 + 636 + [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax 637 + Specifications: ABNF", STD 68, RFC 5234, January 2008. 638 + 639 + [RFC5258] Leiba, B. and A. Melnikov, "Internet Message Access 640 + Protocol version 4 - LIST Command Extensions", RFC 5258, 641 + June 2008. 642 + 643 + [RFC5464] Daboo, C., "The IMAP METADATA Extension", RFC 5464, 644 + February 2009. 645 + 646 + 9.2. Informative References 647 + 648 + [RFC3348] Gahrns, M. and R. Cheng, "The Internet Message Action 649 + Protocol (IMAP4) Child Mailbox Extension", RFC 3348, 650 + July 2002. 651 + 652 + Authors' Addresses 653 + 654 + Barry Leiba 655 + Huawei Technologies 656 + 657 + Phone: +1 646 827 0648 658 + EMail: barryleiba@computer.org 659 + URI: http://internetmessagingtechnology.org/ 660 + 661 + 662 + Jamie Nicolson 663 + Google 664 + 665 + EMail: nicolson@google.com 666 + 667 + 668 + 669 + 670 + 671 + 672 + 673 + 674 + Leiba & Nicolson Standards Track [Page 12] 675 +
+675
spec/rfc6855.txt
··· 1 + 2 + 3 + 4 + 5 + 6 + 7 + Internet Engineering Task Force (IETF) P. Resnick, Ed. 8 + Request for Comments: 6855 Qualcomm Incorporated 9 + Obsoletes: 5738 C. Newman, Ed. 10 + Category: Standards Track Oracle 11 + ISSN: 2070-1721 S. Shen, Ed. 12 + CNNIC 13 + March 2013 14 + 15 + 16 + IMAP Support for UTF-8 17 + 18 + Abstract 19 + 20 + This specification extends the Internet Message Access Protocol 21 + (IMAP) to support UTF-8 encoded international characters in user 22 + names, mail addresses, and message headers. This specification 23 + replaces RFC 5738. 24 + 25 + Status of This Memo 26 + 27 + This is an Internet Standards Track document. 28 + 29 + This document is a product of the Internet Engineering Task Force 30 + (IETF). It represents the consensus of the IETF community. It has 31 + received public review and has been approved for publication by the 32 + Internet Engineering Steering Group (IESG). Further information on 33 + Internet Standards is available in Section 2 of RFC 5741. 34 + 35 + Information about the current status of this document, any errata, 36 + and how to provide feedback on it may be obtained at 37 + http://www.rfc-editor.org/info/rfc6855. 38 + 39 + Copyright Notice 40 + 41 + Copyright (c) 2013 IETF Trust and the persons identified as the 42 + document authors. All rights reserved. 43 + 44 + This document is subject to BCP 78 and the IETF Trust's Legal 45 + Provisions Relating to IETF Documents 46 + (http://trustee.ietf.org/license-info) in effect on the date of 47 + publication of this document. Please review these documents 48 + carefully, as they describe your rights and restrictions with respect 49 + to this document. Code Components extracted from this document must 50 + include Simplified BSD License text as described in Section 4.e of 51 + the Trust Legal Provisions and are provided without warranty as 52 + described in the Simplified BSD License. 53 + 54 + 55 + 56 + 57 + 58 + Resnick, et al. Standards Track [Page 1] 59 + 60 + RFC 6855 IMAP Support for UTF-8 March 2013 61 + 62 + 63 + Table of Contents 64 + 65 + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 66 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 2 67 + 3. "UTF8=ACCEPT" IMAP Capability and UTF-8 in IMAP 68 + Quoted-Strings . . . . . . . . . . . . . . . . . . . . . . . . 3 69 + 4. IMAP UTF8 "APPEND" Data Extension . . . . . . . . . . . . . . 4 70 + 5. "LOGIN" Command and UTF-8 . . . . . . . . . . . . . . . . . . 5 71 + 6. "UTF8=ONLY" Capability . . . . . . . . . . . . . . . . . . . . 5 72 + 7. Dealing with Legacy Clients . . . . . . . . . . . . . . . . . 6 73 + 8. Issues with UTF-8 Header Mailstore . . . . . . . . . . . . . . 7 74 + 9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8 75 + 10. Security Considerations . . . . . . . . . . . . . . . . . . . 8 76 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 9 77 + 11.1. Normative References . . . . . . . . . . . . . . . . . . 9 78 + 11.2. Informative References . . . . . . . . . . . . . . . . . 10 79 + Appendix A. Design Rationale . . . . . . . . . . . . . . . . . . 11 80 + Appendix B. Acknowledgments . . . . . . . . . . . . . . . . . . . 11 81 + 82 + 1. Introduction 83 + 84 + This specification forms part of the Email Address 85 + Internationalization protocols described in the Email Address 86 + Internationalization Framework document [RFC6530]. It extends IMAP 87 + [RFC3501] to permit UTF-8 [RFC3629] in headers, as described in 88 + "Internationalized Email Headers" [RFC6532]. It also adds a 89 + mechanism to support mailbox names using the UTF-8 charset. This 90 + specification creates two new IMAP capabilities to allow servers to 91 + advertise these new extensions. 92 + 93 + This specification assumes that the IMAP server will be operating in 94 + a fully internationalized environment, i.e., one in which all clients 95 + accessing the server will be able to accept non-ASCII message header 96 + fields and other information, as specified in Section 3. At least 97 + during a transition period, that assumption will not be realistic for 98 + many environments; the issues involved are discussed in Section 7 99 + below. 100 + 101 + This specification replaces an earlier, experimental approach to the 102 + same problem [RFC5738]. 103 + 104 + 2. Conventions Used in This Document 105 + 106 + The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" 107 + in this document are to be interpreted as defined in "Key words for 108 + use in RFCs to Indicate Requirement Levels" [RFC2119]. 109 + 110 + 111 + 112 + 113 + 114 + Resnick, et al. Standards Track [Page 2] 115 + 116 + RFC 6855 IMAP Support for UTF-8 March 2013 117 + 118 + 119 + The formal syntax uses the Augmented Backus-Naur Form (ABNF) 120 + [RFC5234] notation. In addition, rules from IMAP [RFC3501], UTF-8 121 + [RFC3629], Extensions to IMAP ABNF [RFC4466], and IMAP "LIST" command 122 + extensions [RFC5258] are also referenced. This document assumes that 123 + the reader will have a reasonably good understanding of these RFCs. 124 + 125 + 3. "UTF8=ACCEPT" IMAP Capability and UTF-8 in IMAP Quoted-Strings 126 + 127 + The "UTF8=ACCEPT" capability indicates that the server supports the 128 + ability to open mailboxes containing internationalized messages with 129 + the "SELECT" and "EXAMINE" commands, and the server can provide UTF-8 130 + responses to the "LIST" and "LSUB" commands. This capability also 131 + affects other IMAP extensions that can return mailbox names or their 132 + prefixes, such as NAMESPACE [RFC2342] and ACL [RFC4314]. 133 + 134 + The "UTF8=ONLY" capability, described in Section 6, implies the 135 + "UTF8=ACCEPT" capability. A server is said to support "UTF8=ACCEPT" 136 + if it advertises either "UTF8=ACCEPT" or "UTF8=ONLY". 137 + 138 + A client MUST use the "ENABLE" command [RFC5161] with the 139 + "UTF8=ACCEPT" option (defined in Section 4 below) to indicate to the 140 + server that the client accepts UTF-8 in quoted-strings and supports 141 + the "UTF8=ACCEPT" extension. The "ENABLE UTF8=ACCEPT" command is 142 + only valid in the authenticated state. 143 + 144 + The IMAP base specification [RFC3501] forbids the use of 8-bit 145 + characters in atoms or quoted-strings. Thus, a UTF-8 string can only 146 + be sent as a literal. This can be inconvenient from a coding 147 + standpoint, and unless the server offers IMAP non-synchronizing 148 + literals [RFC2088], this requires an extra round trip for each UTF-8 149 + string sent by the client. When the IMAP server supports 150 + "UTF8=ACCEPT", it supports UTF-8 in quoted-strings with the following 151 + syntax: 152 + 153 + quoted =/ DQUOTE *uQUOTED-CHAR DQUOTE 154 + ; QUOTED-CHAR is not modified, as it will affect 155 + ; other RFC 3501 ABNF non-terminals. 156 + 157 + uQUOTED-CHAR = QUOTED-CHAR / UTF8-2 / UTF8-3 / UTF8-4 158 + 159 + UTF8-2 = <Defined in Section 4 of RFC 3629> 160 + 161 + UTF8-3 = <Defined in Section 4 of RFC 3629> 162 + 163 + UTF8-4 = <Defined in Section 4 of RFC 3629> 164 + 165 + When this extended quoting mechanism is used by the client, the 166 + server MUST reject, with a "BAD" response, any octet sequences with 167 + 168 + 169 + 170 + Resnick, et al. Standards Track [Page 3] 171 + 172 + RFC 6855 IMAP Support for UTF-8 March 2013 173 + 174 + 175 + the high bit set that fail to comply with the formal syntax 176 + requirements of UTF-8 [RFC3629]. The IMAP server MUST NOT send UTF-8 177 + in quoted-strings to the client unless the client has indicated 178 + support for that syntax by using the "ENABLE UTF8=ACCEPT" command. 179 + 180 + If the server supports "UTF8=ACCEPT", the client MAY use extended 181 + quoted syntax with any IMAP argument that permits a string (including 182 + astring and nstring). However, if characters outside the US-ASCII 183 + repertoire are used in an inappropriate place, the results would be 184 + the same as if other syntactically valid but semantically invalid 185 + characters were used. Specific cases where UTF-8 characters are 186 + permitted or not permitted are described in the following paragraphs. 187 + 188 + All IMAP servers that support "UTF8=ACCEPT" SHOULD accept UTF-8 in 189 + mailbox names, and those that also support the Mailbox International 190 + Naming Convention described in RFC 3501, Section 5.1.3, MUST accept 191 + UTF8-quoted mailbox names and convert them to the appropriate 192 + internal format. Mailbox names MUST comply with the Net-Unicode 193 + Definition ([RFC5198], Section 2) with the specific exception that 194 + they MUST NOT contain control characters (U+0000-U+001F and U+0080-U+ 195 + 009F), a delete character (U+007F), a line separator (U+2028), or a 196 + paragraph separator (U+2029). 197 + 198 + Once an IMAP client has enabled UTF-8 support with the "ENABLE 199 + UTF8=ACCEPT" command, it MUST NOT issue a "SEARCH" command that 200 + contains a charset specification. If an IMAP server receives such a 201 + "SEARCH" command in that situation, it SHOULD reject the command with 202 + a "BAD" response (due to the conflicting charset labels). 203 + 204 + 4. IMAP UTF8 "APPEND" Data Extension 205 + 206 + If the server supports "UTF8=ACCEPT", then the server accepts UTF-8 207 + headers in the "APPEND" command message argument. A client that 208 + sends a message with UTF-8 headers to the server MUST send them using 209 + the "UTF8" data extension to the "APPEND" command. If the server 210 + also advertises the "CATENATE" capability [RFC4469], the client can 211 + use the same data extension to include such a message in a catenated 212 + message part. The ABNF for the "APPEND" data extension and 213 + "CATENATE" extension follows: 214 + 215 + utf8-literal = "UTF8" SP "(" literal8 ")" 216 + 217 + literal8 = <Defined in RFC 4466> 218 + 219 + append-data =/ utf8-literal 220 + 221 + cat-part =/ utf8-literal 222 + 223 + 224 + 225 + 226 + Resnick, et al. Standards Track [Page 4] 227 + 228 + RFC 6855 IMAP Support for UTF-8 March 2013 229 + 230 + 231 + If an IMAP server supports "UTF8=ACCEPT" and the IMAP client has not 232 + issued the "ENABLE UTF8=ACCEPT" command, the server MUST reject, with 233 + a "NO" response, an "APPEND" command that includes any 8-bit 234 + character in message header fields. 235 + 236 + 5. "LOGIN" Command and UTF-8 237 + 238 + This specification does not extend the IMAP "LOGIN" command [RFC3501] 239 + to support UTF-8 usernames and passwords. Whenever a client needs to 240 + use UTF-8 usernames or passwords, it MUST use the IMAP "AUTHENTICATE" 241 + command, which is already capable of passing UTF-8 usernames and 242 + credentials. 243 + 244 + Although using the IMAP "AUTHENTICATE" command in this way makes it 245 + syntactically legal to have a UTF-8 username or password, there is no 246 + guarantee that the user provisioning system utilized by the IMAP 247 + server will allow such identities. This is an implementation 248 + decision and may depend on what identity system the IMAP server is 249 + configured to use. 250 + 251 + 6. "UTF8=ONLY" Capability 252 + 253 + The "UTF8=ONLY" capability indicates that the server supports 254 + "UTF8=ACCEPT" (see Section 4) and that it requires support for UTF-8 255 + from clients. In particular, this means that the server will send 256 + UTF-8 in quoted-strings, and it will not accept the older 257 + international mailbox name convention (modified UTF-7 [RFC3501]). 258 + Because these are incompatible changes to IMAP, explicit server 259 + announcement and client confirmation is necessary: clients MUST use 260 + the "ENABLE UTF8=ACCEPT" command before using this server. A server 261 + that advertises "UTF8=ONLY" will reject, with a "NO [CANNOT]" 262 + response [RFC5530], any command that might require UTF-8 support and 263 + is not preceded by an "ENABLE UTF8=ACCEPT" command. 264 + 265 + IMAP clients that find support for a server that announces 266 + "UTF8=ONLY" problematic are encouraged to at least detect the 267 + announcement and provide an informative error message to the 268 + end-user. 269 + 270 + Because the "UTF8=ONLY" server capability includes support for 271 + "UTF8=ACCEPT", the capability string will include, at most, one of 272 + those and never both. For the client, "ENABLE UTF8=ACCEPT" is always 273 + used -- never "ENABLE UTF8=ONLY". 274 + 275 + 276 + 277 + 278 + 279 + 280 + 281 + 282 + Resnick, et al. Standards Track [Page 5] 283 + 284 + RFC 6855 IMAP Support for UTF-8 March 2013 285 + 286 + 287 + 7. Dealing with Legacy Clients 288 + 289 + In most situations, it will be difficult or impossible for the 290 + implementer or operator of an IMAP (or POP) server to know whether 291 + all of the clients that might access it, or the associated mail store 292 + more generally, will be able to support the facilities defined in 293 + this document. In almost all cases, servers that conform to this 294 + specification will have to be prepared to deal with clients that do 295 + not enable the relevant capabilities. Unfortunately, there is no 296 + completely satisfactory way to do so other than for systems that wish 297 + to receive email that requires SMTPUTF8 capabilities to be sure that 298 + all components of those systems -- including IMAP and other clients 299 + selected by users -- are upgraded appropriately. 300 + 301 + When a message that requires SMTPUTF8 is encountered and the client 302 + does not enable UTF-8 capability, choices available to the server 303 + include hiding the problematic message(s), creating in-band or 304 + out-of-band notifications or error messages, or somehow trying to 305 + create a surrogate of the message with the intention of providing 306 + useful information to that client about what has occurred. Such 307 + surrogate messages cannot be actual substitutes for the original 308 + message: they will almost always be impossible to reply to (either at 309 + all or without loss of information) and the new header fields or 310 + specialized constructs for server-client communications may go beyond 311 + the requirements of current email specifications (e.g., [RFC5322]). 312 + Consequently, such messages may confuse some legacy mail user agents 313 + (including IMAP clients) or not provide expected information to 314 + users. There are also trade-offs in constructing surrogates of the 315 + original message between accepting complexity and additional 316 + computation costs in order to try to preserve as much information as 317 + possible (for example, in "Post-Delivery Message Downgrading for 318 + Internationalized Email Messages" [RFC6857]) and trying to minimize 319 + those costs while still providing useful information (for example, in 320 + "Simplified POP and IMAP Downgrading for Internationalized Email" 321 + [RFC6858]). 322 + 323 + Implementations that choose to perform downgrading SHOULD use one of 324 + the standardized algorithms provided in RFC 6857 or RFC 6858. 325 + Getting downgrade algorithms right, and minimizing the risk of 326 + operational problems and harm to the email system, is tricky and 327 + requires careful engineering. These two algorithms are well 328 + understood and carefully designed. 329 + 330 + Because such messages are really surrogates of the original ones, not 331 + really "downgraded" ones (although that terminology is often used for 332 + convenience), they inevitably have relationships to the originals 333 + that the IMAP specification [RFC3501] did not anticipate. This 334 + brings up two concerns in particular: First, digital signatures 335 + 336 + 337 + 338 + Resnick, et al. Standards Track [Page 6] 339 + 340 + RFC 6855 IMAP Support for UTF-8 March 2013 341 + 342 + 343 + computed over and intended for the original message will often not be 344 + applicable to the surrogate message, and will often fail signature 345 + verification. (It will be possible for some digital signatures to be 346 + verified, if they cover only parts of the original message that are 347 + not affected in the creation of the surrogate.) Second, servers that 348 + may be accessed by the same user with different clients or methods 349 + (e.g., POP or webmail systems in addition to IMAP or IMAP clients 350 + with different capabilities) will need to exert extreme care to be 351 + sure that UIDVALIDITY [RFC3501] behaves as the user would expect. 352 + Those issues may be especially sensitive if the server caches the 353 + surrogate message or computes and stores it when the message arrives 354 + with the intent of making either form available depending on client 355 + capabilities. Additionally, in order to cope with the case when a 356 + server compliant with this extension returns the same UIDVALIDITY to 357 + both legacy and "UTF8=ACCEPT"-aware clients, a client upgraded from 358 + being non-"UTF8=ACCEPT"-aware MUST discard its cache of messages 359 + downloaded from the server. 360 + 361 + The best (or "least bad") approach for any given environment will 362 + depend on local conditions, local assumptions about user behavior, 363 + the degree of control the server operator has over client usage and 364 + upgrading, the options that are actually available, and so on. It is 365 + impossible, at least at the time of publication of this 366 + specification, to give good advice that will apply to all situations, 367 + or even particular profiles of situations, other than "upgrade legacy 368 + clients as soon as possible". 369 + 370 + 8. Issues with UTF-8 Header Mailstore 371 + 372 + When an IMAP server uses a mailbox format that supports UTF-8 headers 373 + and it permits selection or examination of that mailbox without 374 + issuing "ENABLE UTF8=ACCEPT" first, it is the responsibility of the 375 + server to comply with the IMAP base specification [RFC3501] and the 376 + Internet Message Format [RFC5322] with respect to all header 377 + information transmitted over the wire. The issue of handling 378 + messages containing non-ASCII characters in legacy environments is 379 + discussed in Section 7. 380 + 381 + 382 + 383 + 384 + 385 + 386 + 387 + 388 + 389 + 390 + 391 + 392 + 393 + 394 + Resnick, et al. Standards Track [Page 7] 395 + 396 + RFC 6855 IMAP Support for UTF-8 March 2013 397 + 398 + 399 + 9. IANA Considerations 400 + 401 + This document redefines two capabilities ("UTF8=ACCEPT" and 402 + "UTF8=ONLY") in the "IMAP 4 Capabilities" registry [RFC3501]. Three 403 + other capabilities that were described in the experimental 404 + predecessor to this document ("UTF8=ALL", "UTF8=APPEND", "UTF8=USER") 405 + are now OBSOLETE. IANA has updated the registry as follows: 406 + 407 + OLD: 408 + +--------------+-----------------+ 409 + | UTF8=ACCEPT | [RFC5738] | 410 + | UTF8=ALL | [RFC5738] | 411 + | UTF8=APPEND | [RFC5738] | 412 + | UTF8=ONLY | [RFC5738] | 413 + | UTF8=USER | [RFC5738] | 414 + +--------------+-----------------+ 415 + 416 + 417 + NEW: 418 + +------------------------+---------------------+ 419 + | UTF8=ACCEPT | [RFC6855] | 420 + | UTF8=ALL (OBSOLETE) | [RFC5738] [RFC6855]| 421 + | UTF8=APPEND (OBSOLETE) | [RFC5738] [RFC6855]| 422 + | UTF8=ONLY | [RFC6855] | 423 + | UTF8=USER (OBSOLETE) | [RFC5738] [RFC6855]| 424 + +------------------------+---------------------+ 425 + 426 + 10. Security Considerations 427 + 428 + The security considerations of UTF-8 [RFC3629] and SASLprep [RFC4013] 429 + apply to this specification, particularly with respect to use of 430 + UTF-8 in usernames and passwords. Otherwise, this is not believed to 431 + alter the security considerations of IMAP. 432 + 433 + Special considerations, some of them with security implications, 434 + occur if a server that conforms to this specification is accessed by 435 + a client that does not, as well as in some more complex situations in 436 + which a given message is accessed by multiple clients that might use 437 + different protocols and/or support different capabilities. Those 438 + issues are discussed in Section 7. 439 + 440 + 441 + 442 + 443 + 444 + 445 + 446 + 447 + 448 + 449 + 450 + Resnick, et al. Standards Track [Page 8] 451 + 452 + RFC 6855 IMAP Support for UTF-8 March 2013 453 + 454 + 455 + 11. References 456 + 457 + 11.1. Normative References 458 + 459 + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 460 + Requirement Levels", BCP 14, RFC 2119, March 1997. 461 + 462 + [RFC3501] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 463 + 4rev1", RFC 3501, March 2003. 464 + 465 + [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 466 + 10646", STD 63, RFC 3629, November 2003. 467 + 468 + [RFC4013] Zeilenga, K., "SASLprep: Stringprep Profile for User Names 469 + and Passwords", RFC 4013, February 2005. 470 + 471 + [RFC4466] Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4 472 + ABNF", RFC 4466, April 2006. 473 + 474 + [RFC4469] Resnick, P., "Internet Message Access Protocol (IMAP) 475 + CATENATE Extension", RFC 4469, April 2006. 476 + 477 + [RFC5161] Gulbrandsen, A. and A. Melnikov, "The IMAP ENABLE 478 + Extension", RFC 5161, March 2008. 479 + 480 + [RFC5198] Klensin, J. and M. Padlipsky, "Unicode Format for Network 481 + Interchange", RFC 5198, March 2008. 482 + 483 + [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax 484 + Specifications: ABNF", STD 68, RFC 5234, January 2008. 485 + 486 + [RFC5258] Leiba, B. and A. Melnikov, "Internet Message Access 487 + Protocol version 4 - LIST Command Extensions", RFC 5258, 488 + June 2008. 489 + 490 + [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, 491 + October 2008. 492 + 493 + [RFC6530] Klensin, J. and Y. Ko, "Overview and Framework for 494 + Internationalized Email", RFC 6530, February 2012. 495 + 496 + [RFC6532] Yang, A., Steele, S., and N. Freed, "Internationalized 497 + Email Headers", RFC 6532, February 2012. 498 + 499 + [RFC6857] Fujiwara, K., "Post-Delivery Message Downgrading for 500 + Internationalized Email Messages", RFC 6857, March 2013. 501 + 502 + 503 + 504 + 505 + 506 + Resnick, et al. Standards Track [Page 9] 507 + 508 + RFC 6855 IMAP Support for UTF-8 March 2013 509 + 510 + 511 + [RFC6858] Gulbrandsen, A., "Simplified POP and IMAP Downgrading for 512 + Internationalized Email", RFC 6858, March 2013. 513 + 514 + 11.2. Informative References 515 + 516 + [RFC2088] Myers, J., "IMAP4 non-synchronizing literals", RFC 2088, 517 + January 1997. 518 + 519 + [RFC2342] Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342, 520 + May 1998. 521 + 522 + [RFC4314] Melnikov, A., "IMAP4 Access Control List (ACL) Extension", 523 + RFC 4314, December 2005. 524 + 525 + [RFC5530] Gulbrandsen, A., "IMAP Response Codes", RFC 5530, 526 + May 2009. 527 + 528 + [RFC5738] Resnick, P. and C. Newman, "IMAP Support for UTF-8", 529 + RFC 5738, March 2010. 530 + 531 + 532 + 533 + 534 + 535 + 536 + 537 + 538 + 539 + 540 + 541 + 542 + 543 + 544 + 545 + 546 + 547 + 548 + 549 + 550 + 551 + 552 + 553 + 554 + 555 + 556 + 557 + 558 + 559 + 560 + 561 + 562 + Resnick, et al. Standards Track [Page 10] 563 + 564 + RFC 6855 IMAP Support for UTF-8 March 2013 565 + 566 + 567 + Appendix A. Design Rationale 568 + 569 + This non-normative section discusses the reasons behind some of the 570 + design choices in this specification. 571 + 572 + The "UTF8=ONLY" mechanism simplifies diagnosis of interoperability 573 + problems when legacy support goes away. In the situation where 574 + backwards compatibility is not working anyway, the non-conforming 575 + "just-send-UTF-8 IMAP" has the advantage that it might work with some 576 + legacy clients. However, the difficulty of diagnosing 577 + interoperability problems caused by a "just-send-UTF-8 IMAP" 578 + mechanism is the reason the "UTF8=ONLY" capability mechanism was 579 + chosen. 580 + 581 + Appendix B. Acknowledgments 582 + 583 + The authors wish to thank the participants of the EAI working group 584 + for their contributions to this document, with particular thanks to 585 + Harald Alvestrand, David Black, Randall Gellens, Arnt Gulbrandsen, 586 + Kari Hurtta, John Klensin, Xiaodong Lee, Charles Lindsey, Alexey 587 + Melnikov, Subramanian Moonesamy, Shawn Steele, Daniel Taharlev, and 588 + Joseph Yee for their specific contributions to the discussion. 589 + 590 + 591 + 592 + 593 + 594 + 595 + 596 + 597 + 598 + 599 + 600 + 601 + 602 + 603 + 604 + 605 + 606 + 607 + 608 + 609 + 610 + 611 + 612 + 613 + 614 + 615 + 616 + 617 + 618 + Resnick, et al. Standards Track [Page 11] 619 + 620 + RFC 6855 IMAP Support for UTF-8 March 2013 621 + 622 + 623 + Authors' Addresses 624 + 625 + Pete Resnick (editor) 626 + Qualcomm Incorporated 627 + 5775 Morehouse Drive 628 + San Diego, CA 92121-1714 629 + USA 630 + 631 + Phone: +1 858 651 4478 632 + EMail: presnick@qti.qualcomm.com 633 + 634 + 635 + Chris Newman (editor) 636 + Oracle 637 + 800 Royal Oaks 638 + Monrovia, CA 91016 639 + USA 640 + 641 + Phone: 642 + EMail: chris.newman@oracle.com 643 + 644 + 645 + Sean Shen (editor) 646 + CNNIC 647 + No.4 South 4th Zhongguancun Street 648 + Beijing, 100190 649 + China 650 + 651 + Phone: +86 10-58813038 652 + EMail: shenshuo@cnnic.cn 653 + 654 + 655 + 656 + 657 + 658 + 659 + 660 + 661 + 662 + 663 + 664 + 665 + 666 + 667 + 668 + 669 + 670 + 671 + 672 + 673 + 674 + Resnick, et al. Standards Track [Page 12] 675 +
+1001
spec/rfc9208.txt
··· 1 +  2 + 3 + 4 + 5 + Internet Engineering Task Force (IETF) A. Melnikov 6 + Request for Comments: 9208 Isode 7 + Obsoletes: 2087 March 2022 8 + Category: Standards Track 9 + ISSN: 2070-1721 10 + 11 + 12 + IMAP QUOTA Extension 13 + 14 + Abstract 15 + 16 + This document defines a QUOTA extension of the Internet Message 17 + Access Protocol (IMAP) (see RFCs 3501 and 9051) that permits 18 + administrative limits on resource usage (quotas) to be manipulated 19 + through the IMAP protocol. 20 + 21 + This document obsoletes RFC 2087 but attempts to remain backwards 22 + compatible whenever possible. 23 + 24 + Status of This Memo 25 + 26 + This is an Internet Standards Track document. 27 + 28 + This document is a product of the Internet Engineering Task Force 29 + (IETF). It represents the consensus of the IETF community. It has 30 + received public review and has been approved for publication by the 31 + Internet Engineering Steering Group (IESG). Further information on 32 + Internet Standards is available in Section 2 of RFC 7841. 33 + 34 + Information about the current status of this document, any errata, 35 + and how to provide feedback on it may be obtained at 36 + https://www.rfc-editor.org/info/rfc9208. 37 + 38 + Copyright Notice 39 + 40 + Copyright (c) 2022 IETF Trust and the persons identified as the 41 + document authors. All rights reserved. 42 + 43 + This document is subject to BCP 78 and the IETF Trust's Legal 44 + Provisions Relating to IETF Documents 45 + (https://trustee.ietf.org/license-info) in effect on the date of 46 + publication of this document. Please review these documents 47 + carefully, as they describe your rights and restrictions with respect 48 + to this document. Code Components extracted from this document must 49 + include Revised BSD License text as described in Section 4.e of the 50 + Trust Legal Provisions and are provided without warranty as described 51 + in the Revised BSD License. 52 + 53 + This document may contain material from IETF Documents or IETF 54 + Contributions published or made publicly available before November 55 + 10, 2008. The person(s) controlling the copyright in some of this 56 + material may not have granted the IETF Trust the right to allow 57 + modifications of such material outside the IETF Standards Process. 58 + Without obtaining an adequate license from the person(s) controlling 59 + the copyright in such materials, this document may not be modified 60 + outside the IETF Standards Process, and derivative works of it may 61 + not be created outside the IETF Standards Process, except to format 62 + it for publication as an RFC or to translate it into languages other 63 + than English. 64 + 65 + Table of Contents 66 + 67 + 1. Introduction and Overview 68 + 2. Document Conventions 69 + 3. Terms 70 + 3.1. Resource 71 + 3.1.1. Name 72 + 3.1.2. Definition 73 + 3.2. Quota Root 74 + 4. Definitions 75 + 4.1. Commands 76 + 4.1.1. GETQUOTA 77 + 4.1.2. GETQUOTAROOT 78 + 4.1.3. SETQUOTA 79 + 4.1.4. New STATUS attributes 80 + 4.2. Responses 81 + 4.2.1. QUOTA 82 + 4.2.2. QUOTAROOT 83 + 4.3. Response Codes 84 + 4.3.1. OVERQUOTA 85 + 5. Resource Type Definitions 86 + 5.1. STORAGE 87 + 5.2. MESSAGE 88 + 5.3. MAILBOX 89 + 5.4. ANNOTATION-STORAGE 90 + 6. Interaction with IMAP ACL Extension (RFC 4314) 91 + 7. Formal Syntax 92 + 8. Security Considerations 93 + 9. IANA Considerations 94 + 9.1. Changes/Additions to the IMAP Capabilities Registry 95 + 9.2. IMAP Quota Resource Type Registry 96 + 10. Changes Since RFC 2087 97 + 11. References 98 + 11.1. Normative References 99 + 11.2. Informative References 100 + Acknowledgments 101 + Contributors 102 + Author's Address 103 + 104 + 1. Introduction and Overview 105 + 106 + This document defines a couple of extensions to the Internet Message 107 + Access Protocol [RFC3501] [RFC9051] for querying and manipulating 108 + administrative limits on resource usage (quotas). This extension is 109 + compatible with both IMAP4rev1 [RFC3501] and IMAP4rev2 [RFC9051]. 110 + 111 + The "QUOTA" capability denotes a server compliant with [RFC2087]. 112 + Some responses and response codes defined in this document are not 113 + present in such servers (see Section 10 for more details), and 114 + clients MUST NOT rely on their presence in the absence of any 115 + capability beginning with "QUOTA=". 116 + 117 + Any server compliant with this document MUST also return at least one 118 + capability starting with the "QUOTA=RES-" prefix, as described in 119 + Section 3.1. 120 + 121 + Any server compliant with this document that implements the SETQUOTA 122 + command (see Section 4.1.3) MUST also return the "QUOTASET" 123 + capability. 124 + 125 + This document also reserves all other capabilities starting with the 126 + "QUOTA=" prefix for future IETF Stream Standard Track, Informational, 127 + or Experimental extensions to this document. 128 + 129 + Quotas can be used to restrict clients for administrative reasons, 130 + but the QUOTA extension can also be used to indicate system limits 131 + and current usage levels to clients. 132 + 133 + Although the IMAP4 QUOTA extension specified in [RFC2087] has seen 134 + deployment in servers, it has seen little deployment in clients. 135 + Since the meaning of the resources was implementation dependent, it 136 + was impossible for a client implementation to determine which 137 + resources were supported, and it was impossible to determine which 138 + mailboxes were in a given quota root (see Section 3.2) without a 139 + priori knowledge of the implementation. 140 + 141 + 2. Document Conventions 142 + 143 + In protocol examples, this document uses a prefix of "C: " to denote 144 + lines sent by the client to the server and "S: " for lines sent by 145 + the server to the client. Lines prefixed with "//" are comments 146 + explaining the previous protocol line. These prefixes and comments 147 + are not part of the protocol. Lines without any of these prefixes 148 + are continuations of the previous line, and no line break is present 149 + in the protocol before such lines unless specifically mentioned. 150 + 151 + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 152 + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 153 + "OPTIONAL" in this document are to be interpreted as described in 154 + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all 155 + capitals, as shown here. 156 + 157 + Other capitalized words are IMAP keywords [RFC3501] [RFC9051] or 158 + keywords from this document. 159 + 160 + 3. Terms 161 + 162 + 3.1. Resource 163 + 164 + A resource has a name, a formal definition. 165 + 166 + 3.1.1. Name 167 + 168 + The resource name is an atom, as defined in IMAP4rev1 [RFC3501]. 169 + These MUST be registered with IANA. 170 + 171 + Supported resource names MUST be advertised as a capability by 172 + prepending the resource name with "QUOTA=RES-". A server compliant 173 + with this specification is not required to support all reported 174 + resource types on all quota roots. 175 + 176 + 3.1.2. Definition 177 + 178 + The resource definition or document containing it, while not visible 179 + through the protocol, SHOULD be registered with IANA. 180 + 181 + The usage of a resource MUST be represented as a 63-bit unsigned 182 + integer. 0 indicates that the resource is exhausted. Usage integers 183 + don't necessarily represent proportional use, so clients MUST NOT 184 + compare an available resource between two separate quota roots on the 185 + same or different servers. 186 + 187 + Limits will be specified as, and MUST be represented as, an integer. 188 + 0 indicates that any usage is prohibited. 189 + 190 + Limits may be hard or soft; that is, an implementation MAY choose, or 191 + be configured, to disallow any command if the limit on a resource is 192 + or would be exceeded. 193 + 194 + All resources that the server handles MUST be advertised in a 195 + CAPABILITY response/response code consisting of the resource name 196 + prefixed by "QUOTA=RES-". 197 + 198 + The resources STORAGE (Section 5.1), MESSAGE (Section 5.2), MAILBOX 199 + (Section 5.3), and ANNOTATION-STORAGE (Section 5.4) are defined in 200 + this document. 201 + 202 + 3.2. Quota Root 203 + 204 + This document introduces the concept of a "quota root", as resource 205 + limits can apply across multiple IMAP mailboxes. 206 + 207 + Each mailbox has zero or more implementation-defined named "quota 208 + roots". Each quota root has zero or more resource limits (quotas). 209 + All mailboxes that share the same named quota root share the resource 210 + limits of the quota root. 211 + 212 + Quota root names need not be mailbox names, nor is there any 213 + relationship defined by this document between a quota root name and a 214 + mailbox name. A quota root name is an astring, as defined in IMAP4 215 + [RFC3501] [RFC9051]. It SHOULD be treated as an opaque string by any 216 + clients. 217 + 218 + Quota roots are used since not all implementations may be able to 219 + calculate usage, or apply quotas, on arbitrary mailboxes or mailbox 220 + hierarchies. 221 + 222 + Not all resources may be limitable or calculable for all quota roots. 223 + Furthermore, not all resources may support all limits; some limits 224 + may be present in the underlying system. A server implementation of 225 + this memo SHOULD advise the client of such inherent limits, by 226 + generating QUOTA (Section 4.2.1) responses, and SHOULD advise the 227 + client of which resources are limitable for a particular quota root. 228 + A SETQUOTA (Section 4.1.3) command MAY also round a quota limit in an 229 + implementation-dependent way, if the granularity of the underlying 230 + system demands it. A client MUST be prepared for a SETQUOTA 231 + (Section 4.1.3) command to fail if a limit cannot be set. 232 + 233 + Implementation Notes: This means that, for example, under UNIX, a 234 + quota root may have a MESSAGE (Section 5.2) quota always set due to 235 + the number of inodes available on the filesystem; similarly, STORAGE 236 + (Section 5.1) may be rounded to the nearest block and limited by free 237 + filesystem space. 238 + 239 + 4. Definitions 240 + 241 + 4.1. Commands 242 + 243 + The following commands exist for manipulation and querying quotas. 244 + 245 + 4.1.1. GETQUOTA 246 + 247 + Arguments: quota root 248 + 249 + Responses: REQUIRED untagged responses: QUOTA 250 + 251 + Result: OK - getquota completed 252 + 253 + NO - getquota error: no such quota root, permission 254 + denied 255 + 256 + BAD - command unknown or arguments invalid 257 + 258 + The GETQUOTA command takes the name of a quota root and returns the 259 + quota root's resource usage and limits in an untagged QUOTA response. 260 + (Names of quota roots applicable to a particular mailbox can be 261 + discovered by issuing the GETQUOTAROOT command; see Section 4.1.2.) 262 + Note that the server is not required to support any specific resource 263 + type (as advertised in the CAPABILITY response, i.e., all capability 264 + items with the "QUOTA=RES-" prefix) for any particular quota root. 265 + 266 + Example: 267 + 268 + S: * CAPABILITY [...] QUOTA QUOTA=RES-STORAGE [...] 269 + 270 + [...] 271 + 272 + C: G0001 GETQUOTA "!partition/sda4" 273 + 274 + S: * QUOTA "!partition/sda4" (STORAGE 104 10923847) 275 + 276 + S: G0001 OK Getquota complete 277 + 278 + 4.1.2. GETQUOTAROOT 279 + 280 + Arguments: mailbox name 281 + 282 + Responses: REQUIRED untagged responses: QUOTAROOT, QUOTA 283 + 284 + Result: OK - getquotaroot completed 285 + 286 + NO - getquotaroot error: permission denied 287 + 288 + BAD - command unknown or arguments invalid 289 + 290 + The GETQUOTAROOT command takes a mailbox name and returns the list of 291 + quota roots for the mailbox in an untagged QUOTAROOT response. For 292 + each listed quota root, it also returns the quota root's resource 293 + usage and limits in an untagged QUOTA response. 294 + 295 + Note that the mailbox name parameter doesn't have to reference an 296 + existing mailbox. This can be handy in order to determine which 297 + quota root would apply to a mailbox when it gets created. 298 + 299 + Example: 300 + 301 + S: * CAPABILITY [...] QUOTA QUOTA=RES-STORAGE QUOTA=RES-MESSAGE 302 + [...] 303 + 304 + [...] 305 + 306 + C: G0002 GETQUOTAROOT INBOX 307 + 308 + S: * QUOTAROOT INBOX "#user/alice" "!partition/sda4" 309 + 310 + S: * QUOTA "#user/alice" (MESSAGE 42 1000) 311 + 312 + S: * QUOTA "!partition/sda4" (STORAGE 104 10923847) 313 + 314 + S: G0002 OK Getquotaroot complete 315 + 316 + 4.1.3. SETQUOTA 317 + 318 + Arguments: quota root list of resource limits 319 + 320 + Responses: untagged responses: QUOTA 321 + 322 + Result: OK - setquota completed 323 + 324 + NO - setquota error: can't set that data 325 + 326 + BAD - command unknown or arguments invalid 327 + 328 + Note that unlike other command/responses/response codes defined in 329 + this document, support for the SETQUOTA command requires the server 330 + to advertise the "QUOTASET" capability. 331 + 332 + The SETQUOTA command takes the name of a mailbox quota root and a 333 + list of resource limits. The resource limits for the named quota 334 + root are changed to the specified limits. Any previous resource 335 + limits for the named quota root are discarded, even resource limits 336 + not explicitly listed in the SETQUOTA command. (For example, if the 337 + quota root had both STORAGE and MESSAGE limits assigned to the quota 338 + root before the SETQUOTA is called and the SETQUOTA only includes the 339 + STORAGE limit, then the MESSAGE limit is removed from the quota 340 + root.) 341 + 342 + If the named quota root did not previously exist, an implementation 343 + may optionally create it and change the quota roots for any number of 344 + existing mailboxes in an implementation-defined manner. 345 + 346 + If the implementation chooses to change the quota roots for some 347 + existing mailboxes, such changes SHOULD be announced with untagged 348 + QUOTA responses. 349 + 350 + Example: 351 + 352 + S: * CAPABILITY [...] QUOTA QUOTASET QUOTA=RES-STORAGE QUOTA=RES- 353 + MESSAGE [...] 354 + 355 + [...] 356 + 357 + C: S0000 GETQUOTA "#user/alice" 358 + 359 + S: * QUOTA "#user/alice" (STORAGE 54 111 MESSAGE 42 1000) 360 + 361 + S: S0000 OK Getquota completed 362 + 363 + C: S0001 SETQUOTA "#user/alice" (STORAGE 510) 364 + 365 + S: * QUOTA "#user/alice" (STORAGE 58 512) 366 + 367 + // The server has rounded the STORAGE quota limit requested to 368 + the nearest 512 blocks of 1024 octets; otherwise, another client 369 + has performed a near-simultaneous SETQUOTA using a limit of 512. 370 + 371 + S: S0001 OK Rounded quota 372 + 373 + C: S0002 SETQUOTA "!partition/sda4" (STORAGE 99999999) 374 + 375 + S: * QUOTA "!partition/sda4" (STORAGE 104 10923847) 376 + 377 + // The server has not changed the quota, since this is a 378 + filesystem limit, and it cannot be changed. The QUOTA 379 + response here is entirely optional. 380 + 381 + S: S0002 NO Cannot change system limit 382 + 383 + 4.1.4. New STATUS attributes 384 + 385 + The DELETED and DELETED-STORAGE status data items allow for 386 + estimation of the amount of resources that could be freed by an 387 + EXPUNGE on a mailbox. 388 + 389 + The DELETED status data item requests the server to return the number 390 + of messages with the \Deleted flag set. The DELETED status data item 391 + is only required to be implemented when the server advertises the 392 + "QUOTA=RES-MESSAGE" capability. 393 + 394 + The DELETED-STORAGE status data item requests the server to return 395 + the amount of storage space that can be reclaimed by performing 396 + EXPUNGE on the mailbox. The server SHOULD return the exact value; 397 + however, it is recognized that the server may have to do a non- 398 + trivial amount of work to calculate it. If the calculation of the 399 + exact value would take a long time, the server MAY instead return the 400 + sum of the RFC822.SIZE of the messages with the \Deleted flag set. 401 + The DELETED-STORAGE status data item is only required to be 402 + implemented when the server advertises the "QUOTA=RES-STORAGE" 403 + capability. 404 + 405 + Example: 406 + 407 + S: * CAPABILITY [...] QUOTA QUOTA=RES-STORAGE QUOTA=RES- 408 + MESSAGE [...] 409 + 410 + [...] 411 + 412 + C: S0003 STATUS INBOX (MESSAGES DELETED DELETED-STORAGE) 413 + 414 + S: * STATUS INBOX (MESSAGES 12 DELETED 4 DELETED-STORAGE 8) 415 + 416 + // 12 messages, 4 of which would be deleted when an EXPUNGE 417 + happens. 418 + 419 + S: S0003 OK Status complete. 420 + 421 + 4.2. Responses 422 + 423 + The following responses may be sent by the server. 424 + 425 + 4.2.1. QUOTA 426 + 427 + Data: quota root name 428 + 429 + list of resource names, usages, and limits 430 + 431 + This response occurs as a result of a GETQUOTA, GETQUOTAROOT, or 432 + SETQUOTA command. The first string is the name of the quota root for 433 + which this quota applies. 434 + 435 + The name is followed by an S-expression format list of the resource 436 + usage and limits of the quota root. The list contains zero or more 437 + triplets. Each triplet contains a resource name, the current usage 438 + of the resource, and the resource limit. 439 + 440 + Resources not named in the list are not limited in the quota root. 441 + Thus, an empty list means there are no administrative resource limits 442 + in the quota root. 443 + 444 + Example: 445 + 446 + S: * QUOTA "" (STORAGE 10 512) 447 + 448 + 4.2.2. QUOTAROOT 449 + 450 + Data: mailbox name 451 + 452 + zero or more quota root names 453 + 454 + This response occurs as a result of a GETQUOTAROOT command. The 455 + first string is the mailbox and the remaining strings are the names 456 + of the quota roots for the mailbox. 457 + 458 + Examples: 459 + 460 + S: * QUOTAROOT INBOX "" 461 + 462 + // The INBOX mailbox is covered by a single quota root with 463 + name "". 464 + 465 + S: * QUOTAROOT comp.mail.mime 466 + 467 + // The comp.mail.mime mailbox has no quota root associated 468 + with it, but one can be created. 469 + 470 + 4.3. Response Codes 471 + 472 + 4.3.1. OVERQUOTA 473 + 474 + The OVERQUOTA response code SHOULD be returned in the tagged NO 475 + response to an APPEND/COPY/MOVE when the addition of the message(s) 476 + puts the target mailbox over any one of its quota limits. 477 + 478 + Example 1: 479 + 480 + C: A003 APPEND saved-messages (\Seen) {326} 481 + S: + Ready for literal data 482 + C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) 483 + C: From: Fred Foobar <foobar@Blurdybloop.example> 484 + C: Subject: afternoon meeting 485 + C: To: mooch@owatagu.siam.edu.example 486 + C: Message-Id: <B27397-0100000@Blurdybloop.example> 487 + C: MIME-Version: 1.0 488 + C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII 489 + C: 490 + C: Hello Joe, do you think we can meet at 3:30 tomorrow? 491 + C: 492 + S: A003 NO [OVERQUOTA] APPEND Failed 493 + 494 + The OVERQUOTA response code MAY also be returned in an untagged NO 495 + response in the authenticated or the selected state when a mailbox 496 + exceeds soft quota. For example, such OVERQUOTA response codes might 497 + be sent as a result of an external event (e.g., Local Mail Transfer 498 + Protocol (LMTP) [RFC2033] delivery or COPY/MOVE/APPEND in another 499 + IMAP connection) that causes the currently selected mailbox to exceed 500 + soft quota. Note that such an OVERQUOTA response code might be 501 + ambiguous because it might relate to the target mailbox (as specified 502 + in COPY/MOVE/APPEND) or to the currently selected mailbox. (The 503 + EXTRA WG chose not to address this deficiency due to syntactic 504 + limitations of IMAP response codes and because such events are likely 505 + to be rare.) This form of the OVERQUOTA response codes MUST NOT be 506 + returned if there is no mailbox selected and no command in progress 507 + that adds a message to a mailbox (e.g., APPEND). 508 + 509 + Example 2: 510 + 511 + C: A003 APPEND saved-messages (\Seen) {326} 512 + S: + Ready for literal data 513 + C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) 514 + C: From: Fred Foobar <foobar@Blurdybloop.example> 515 + C: Subject: afternoon meeting 516 + C: To: mooch@owatagu.siam.edu.example 517 + C: Message-Id: <B27397-0100000@Blurdybloop.example> 518 + C: MIME-Version: 1.0 519 + C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII 520 + C: 521 + C: Hello Joe, do you think we can meet at 3:30 tomorrow? 522 + C: 523 + S: * NO [OVERQUOTA] Soft quota has been exceeded 524 + S: A003 OK [APPENDUID 38505 3955] APPEND completed 525 + 526 + Example 3: 527 + 528 + C: A004 COPY 2:4 MEETING 529 + S: * NO [OVERQUOTA] Soft quota has been exceeded 530 + S: A004 OK [COPYUID 38505 304,319:320 3956:3958] COPY 531 + command completed 532 + 533 + 5. Resource Type Definitions 534 + 535 + The following resource types are defined in this memo. A server 536 + supporting a resource type MUST advertise this as a CAPABILITY with a 537 + name consisting of the resource name prefixed by "QUOTA=RES-". A 538 + server MAY support multiple resource types and MUST advertise all 539 + resource types it supports. 540 + 541 + 5.1. STORAGE 542 + 543 + "STORAGE" is the physical space estimate, in units of 1024 octets, of 544 + the mailboxes governed by the quota root. This MAY not be the same 545 + as the sum of the RFC822.SIZE of the messages. Some implementations 546 + MAY include metadata sizes for the messages and mailboxes, and other 547 + implementations MAY store messages in such a way that the physical 548 + space used is smaller, for example, due to use of compression. 549 + Additional messages might not increase the usage. Clients MUST NOT 550 + use the usage figure for anything other than informational purposes; 551 + for example, they MUST NOT refuse to APPEND a message if the limit 552 + less the usage is smaller than the RFC822.SIZE divided by 1024 octets 553 + of the message, but it MAY warn about such condition. 554 + 555 + The usage figure may change as a result of performing actions not 556 + associated with adding new messages to the mailbox, such as SEARCH, 557 + since this may increase the amount of metadata included in the 558 + calculations. 559 + 560 + When the server supports this resource type, it MUST also support the 561 + DELETED-STORAGE status data item. 562 + 563 + Support for this resource MUST be indicated by the server by 564 + advertising the "QUOTA=RES-STORAGE" capability. 565 + 566 + A resource named the same was also given as an example in [RFC2087]. 567 + This document provides a more precise definition. 568 + 569 + 5.2. MESSAGE 570 + 571 + "MESSAGE" is the number of messages stored within the mailboxes 572 + governed by the quota root. This MUST be an exact number; however, 573 + clients MUST NOT assume that a change in the usage indicates a change 574 + in the number of messages available, since the quota root may include 575 + mailboxes the client has no access to. 576 + 577 + When the server supports this resource type, it MUST also support the 578 + DELETED status data item. 579 + 580 + Support for this resource MUST be indicated by the server by 581 + advertising the "QUOTA=RES-MESSAGE" capability. 582 + 583 + A resource named the same was also given as an example in [RFC2087]. 584 + This document provides a more precise definition. 585 + 586 + 5.3. MAILBOX 587 + 588 + "MAILBOX" is the number of mailboxes governed by the quota root. 589 + This MUST be an exact number; however, clients MUST NOT assume that a 590 + change in the usage indicates a change in the number of mailboxes, 591 + since the quota root may include mailboxes the client has no access 592 + to. 593 + 594 + Support for this resource MUST be indicated by the server by 595 + advertising the "QUOTA=RES-MAILBOX" capability. 596 + 597 + 5.4. ANNOTATION-STORAGE 598 + 599 + "ANNOTATION-STORAGE" is the maximum size of all annotations 600 + [RFC5257], in units of 1024 octets, associated with all messages in 601 + the mailboxes governed by the quota root. 602 + 603 + Support for this resource MUST be indicated by the server by 604 + advertising the "QUOTA=RES-ANNOTATION-STORAGE" capability. 605 + 606 + 6. Interaction with IMAP ACL Extension (RFC 4314) 607 + 608 + This section lists [RFC4314] rights required to execute quota-related 609 + commands when both RFC 4314 and this document are implemented. 610 + 611 + +===================+=+=+===+===+===+===+===+===+===+===+=====+=====+ 612 + | Operations\Rights |l|r| s | w | i | c | x | t | e | a | Any | Non | 613 + +===================+=+=+===+===+===+===+===+===+===+===+=====+=====+ 614 + | GETQUOTA | | | | | | | | | | | | + | 615 + +-------------------+-+-+---+---+---+---+---+---+---+---+-----+-----+ 616 + | GETQUOTAROOT | |*| | | | | | | | | | * | 617 + +-------------------+-+-+---+---+---+---+---+---+---+---+-----+-----+ 618 + | SETQUOTA | | | | | | | | | | + | | | 619 + +-------------------+-+-+---+---+---+---+---+---+---+---+-----+-----+ 620 + 621 + Table 1 622 + 623 + See Section 4 of [RFC4314] for conventions used in this table. 624 + 625 + Legend: 626 + 627 + "+": The right is required 628 + 629 + "*": Only one of the rights marked with * is required 630 + 631 + "Any": At least one of the "l", "r", "i", "k", "x", or "a" rights is 632 + required 633 + 634 + "Non": No rights required to perform the command 635 + 636 + Note that which permissions are needed in order to perform a 637 + GETQUOTAROOT command depends on the quota resource type being 638 + requested. For example, a quota on the number of messages (MESSAGE 639 + resource type) or total size of messages (STORAGE resource type) 640 + requires "r" right on the mailbox in question, since the quota 641 + involved would reveal information about the number (or total size) of 642 + messages in the mailbox. By comparison, the MAILBOX resource type 643 + doesn't require any right. 644 + 645 + 7. Formal Syntax 646 + 647 + The following syntax specification uses the Augmented Backus-Naur 648 + Form (ABNF) notation as specified in [ABNF]. 649 + 650 + Non-terminals referenced but not defined below are as defined by 651 + IMAP4 [RFC3501] [RFC9051]. 652 + 653 + Except as noted otherwise, all alphabetic characters are case 654 + insensitive. The use of uppercase or lowercase characters to define 655 + token strings is for editorial clarity only. Implementations MUST 656 + accept these strings in a case-insensitive fashion. 657 + 658 + getquota = "GETQUOTA" SP quota-root-name 659 + 660 + getquotaroot = "GETQUOTAROOT" SP mailbox 661 + 662 + quota-list = "(" quota-resource *(SP quota-resource) ")" 663 + 664 + quota-resource = resource-name SP resource-usage SP resource-limit 665 + 666 + quota-response = "QUOTA" SP quota-root-name SP quota-list 667 + 668 + quotaroot-response = "QUOTAROOT" SP mailbox *(SP quota-root-name) 669 + 670 + setquota = "SETQUOTA" SP quota-root-name SP setquota-list 671 + 672 + setquota-list = "(" [setquota-resource *(SP setquota-resource)] 673 + ")" 674 + 675 + setquota-resource = resource-name SP resource-limit 676 + 677 + quota-root-name = astring 678 + 679 + resource-limit = number64 680 + 681 + resource-name = "STORAGE" / "MESSAGE" / "MAILBOX" / 682 + "ANNOTATION-STORAGE" / resource-name-ext 683 + 684 + resource-name-ext = atom 685 + ;; Future resource registrations 686 + 687 + resource-usage = number64 688 + ;; must be less than corresponding resource-limit 689 + 690 + capability-quota = capa-quota-res / "QUOTASET" 691 + ;; One or more capa-quota-res must be returned. 692 + ;; Also "QUOTASET" can optionally be returned. 693 + 694 + capa-quota-res = "QUOTA=RES-" resource-name 695 + 696 + status-att =/ "DELETED" / "DELETED-STORAGE" 697 + ;; DELETED status data item MUST be supported 698 + ;; when the "QUOTA=RES-MESSAGE" capability is 699 + ;; advertised. 700 + ;; DELETED-STORAGE status data item MUST be 701 + ;; supported when the "QUOTA=RES-STORAGE" 702 + ;; capability is advertised. 703 + 704 + status-att-val =/ status-att-deleted / 705 + status-att-deleted-storage 706 + 707 + status-att-deleted = "DELETED" SP number 708 + ;; DELETED status data item MUST be supported 709 + ;; when the "QUOTA=RES-MESSAGE" capability is 710 + ;; advertised. 711 + 712 + status-att-deleted-storage = "DELETED-STORAGE" SP number64 713 + ;; DELETED-STORAGE status data item MUST be 714 + ;; supported when the "QUOTA=RES-STORAGE" 715 + ;; capability is advertised. 716 + 717 + resp-text-code =/ "OVERQUOTA" 718 + 719 + number64 = <Defined in RFC 9051> 720 + 721 + 8. Security Considerations 722 + 723 + Implementors should be careful to make sure the implementation of 724 + these commands does not violate the site's security policy. The 725 + resource usage of other users is likely to be considered confidential 726 + information and should not be divulged to unauthorized persons. In 727 + particular, no quota information should be disclosed to anonymous 728 + users. 729 + 730 + As for any resource shared across users (for example, a quota root 731 + attached to a set of shared mailboxes), a user that can consume or 732 + render unusable the resource can affect the resources available to 733 + the other users; this might occur, for example, by a user with 734 + permission to execute the SETQUOTA setting, which sets an 735 + artificially small value. 736 + 737 + Note that computing resource usage might incur a heavy load on the 738 + server. Server implementers should consider implementation 739 + techniques that lower the load on servers such as caching of resource 740 + usage information or usage of less precise computations when under 741 + heavy load. 742 + 743 + 9. IANA Considerations 744 + 745 + 9.1. Changes/Additions to the IMAP Capabilities Registry 746 + 747 + IMAP4 capabilities are registered by publishing a Standards Track or 748 + an IESG-approved Informational or Experimental RFC. The "IMAP 749 + Capabilities" registry is currently located at 750 + <https://www.iana.org/assignments/imap4-capabilities>. 751 + 752 + IANA has updated the reference for the QUOTA extension to point to 753 + this document. IANA has also added the "QUOTA=" prefix and the 754 + "QUOTASET" capability to the "IMAP Capabilities" registry with this 755 + document as the reference. 756 + 757 + IANA has added the following notes to the "IMAP Capabilities" 758 + registry: 759 + 760 + The prefix "QUOTA=RES-" is reserved per RFC 9208, Section 9.1. See 761 + Section 9.2 of that document for values that follow this prefix. 762 + 763 + All other capabilities starting with the "QUOTA=" prefix are reserved 764 + for future IETF Stream extensions to RFC 9208. 765 + 766 + 9.2. IMAP Quota Resource Type Registry 767 + 768 + IANA has created a new registry for IMAP quota resource types. The 769 + registration policy for the "IMAP Quota Resource Types" registry is 770 + "Specification Required" [RFC8126]. 771 + 772 + When registering a new quota resource type, the registrant needs to 773 + provide the following: 774 + 775 + * the name of the quota resource type 776 + 777 + * a short description 778 + 779 + * extra required IMAP commands/responses (if any) 780 + 781 + * extra optional IMAP commands/responses (if any) 782 + 783 + * name and email address of author 784 + 785 + * name and email address of change controller 786 + 787 + * a reference to a specification that describes the quota resource 788 + type in more detail 789 + 790 + Designated experts should check that the provided references are 791 + correct, the references describe the quota resource type being 792 + registered in sufficient detail to be implementable, the syntax of 793 + any optional commands/responses is correct (e.g., ABNF validates), 794 + and the syntax/description complies with rules and limitations 795 + imposed by IMAP [RFC3501] [RFC9051]. Designated experts should avoid 796 + registering multiple identical quota resource types under different 797 + names and should provide advice to requestors about other possible 798 + quota resource types to use. 799 + 800 + The initial contents of the "IMAP Quota Resource Types" registry are 801 + as follows: 802 + 803 + +===================+=======================================+ 804 + | field name | field value | 805 + +===================+=======================================+ 806 + | Name of the quota | STORAGE | 807 + | resource type: | | 808 + +-------------------+---------------------------------------+ 809 + | Description: | The physical space estimate, in units | 810 + | | of 1024 octets, of the mailboxes | 811 + | | governed by the quota root. | 812 + +-------------------+---------------------------------------+ 813 + | Extra required | DELETED-STORAGE STATUS request data | 814 + | IMAP commands/ | item and response data item | 815 + | responses: | | 816 + +-------------------+---------------------------------------+ 817 + | Extra optional | N/A | 818 + | IMAP commands/ | | 819 + | responses: | | 820 + +-------------------+---------------------------------------+ 821 + | Author: | Alexey Melnikov | 822 + | | <alexey.melnikov@isode.com> | 823 + +-------------------+---------------------------------------+ 824 + | Change | IESG <iesg@ietf.org> | 825 + | Controller: | | 826 + +-------------------+---------------------------------------+ 827 + | Reference: | Section 5.1 of RFC 9208 | 828 + +-------------------+---------------------------------------+ 829 + 830 + Table 2: STORAGE 831 + 832 + +=====================+==========================================+ 833 + | field name | field value | 834 + +=====================+==========================================+ 835 + | Name of the quota | MESSAGE | 836 + | resource type: | | 837 + +---------------------+------------------------------------------+ 838 + | Description: | The number of messages stored within the | 839 + | | mailboxes governed by the quota root. | 840 + +---------------------+------------------------------------------+ 841 + | Extra required IMAP | DELETED STATUS request data item and | 842 + | commands/responses: | response data item | 843 + +---------------------+------------------------------------------+ 844 + | Extra optional IMAP | N/A | 845 + | commands/responses: | | 846 + +---------------------+------------------------------------------+ 847 + | Author: | Alexey Melnikov | 848 + | | <alexey.melnikov@isode.com> | 849 + +---------------------+------------------------------------------+ 850 + | Change Controller: | IESG <iesg@ietf.org> | 851 + +---------------------+------------------------------------------+ 852 + | Reference: | Section 5.2 of RFC 9208 | 853 + +---------------------+------------------------------------------+ 854 + 855 + Table 3: MESSAGE 856 + 857 + +==================================+=============================+ 858 + | field name | field value | 859 + +==================================+=============================+ 860 + | Name of the quota resource type: | MAILBOX | 861 + +----------------------------------+-----------------------------+ 862 + | Description: | The number of mailboxes | 863 + | | governed by the quota root. | 864 + +----------------------------------+-----------------------------+ 865 + | Extra required IMAP commands/ | N/A | 866 + | responses: | | 867 + +----------------------------------+-----------------------------+ 868 + | Extra optional IMAP commands/ | N/A | 869 + | responses: | | 870 + +----------------------------------+-----------------------------+ 871 + | Author: | Alexey Melnikov | 872 + | | <alexey.melnikov@isode.com> | 873 + +----------------------------------+-----------------------------+ 874 + | Change Controller: | IESG <iesg@ietf.org> | 875 + +----------------------------------+-----------------------------+ 876 + | Reference: | Section 5.3 of RFC 9208 | 877 + +----------------------------------+-----------------------------+ 878 + 879 + Table 4: MAILBOX 880 + 881 + +================+=======================================+ 882 + | field name | field value | 883 + +================+=======================================+ 884 + | Name of the | ANNOTATION-STORAGE | 885 + | quota resource | | 886 + | type: | | 887 + +----------------+---------------------------------------+ 888 + | Description: | The maximum size of all annotations | 889 + | | [RFC5257], in units of 1024 octets, | 890 + | | associated with all messages in the | 891 + | | mailboxes governed by the quota root. | 892 + +----------------+---------------------------------------+ 893 + | Extra required | N/A | 894 + | IMAP commands/ | | 895 + | responses: | | 896 + +----------------+---------------------------------------+ 897 + | Extra optional | N/A | 898 + | IMAP commands/ | | 899 + | responses: | | 900 + +----------------+---------------------------------------+ 901 + | Author: | Alexey Melnikov | 902 + | | <alexey.melnikov@isode.com> | 903 + +----------------+---------------------------------------+ 904 + | Change | IESG <iesg@ietf.org> | 905 + | Controller: | | 906 + +----------------+---------------------------------------+ 907 + | Reference: | Section 5.4 of RFC 9208 | 908 + +----------------+---------------------------------------+ 909 + 910 + Table 5: ANNOTATION-STORAGE 911 + 912 + 10. Changes Since RFC 2087 913 + 914 + This document is a revision of [RFC2087], and it aims to clarify the 915 + meaning of different terms that were used in that RFC. It also 916 + provides more examples, gives guidance on allowed server behavior, 917 + defines an IANA registry for quota resource types, and provides 918 + initial registrations for 4 of them. 919 + 920 + When compared with [RFC2087], this document defines two more commonly 921 + used resource types, adds an optional OVERQUOTA response code, and 922 + defines two extra STATUS data items ("DELETED" and "DELETED- 923 + STORAGE"). The DELETED STATUS data item must be implemented if the 924 + "QUOTA=RES-MESSAGE" capability is advertised. The DELETED-STORAGE 925 + STATUS data item must be implemented if the "QUOTA=RES-STORAGE" 926 + capability is advertised. For extensibility, quota usage and quota 927 + limits are now 63-bit unsigned integers. 928 + 929 + 11. References 930 + 931 + 11.1. Normative References 932 + 933 + [ABNF] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax 934 + Specifications: ABNF", STD 68, RFC 5234, 935 + DOI 10.17487/RFC5234, January 2008, 936 + <https://www.rfc-editor.org/info/rfc5234>. 937 + 938 + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 939 + Requirement Levels", BCP 14, RFC 2119, 940 + DOI 10.17487/RFC2119, March 1997, 941 + <https://www.rfc-editor.org/info/rfc2119>. 942 + 943 + [RFC3501] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 944 + 4rev1", RFC 3501, DOI 10.17487/RFC3501, March 2003, 945 + <https://www.rfc-editor.org/info/rfc3501>. 946 + 947 + [RFC4314] Melnikov, A., "IMAP4 Access Control List (ACL) Extension", 948 + RFC 4314, DOI 10.17487/RFC4314, December 2005, 949 + <https://www.rfc-editor.org/info/rfc4314>. 950 + 951 + [RFC5257] Daboo, C. and R. Gellens, "Internet Message Access 952 + Protocol - ANNOTATE Extension", RFC 5257, 953 + DOI 10.17487/RFC5257, June 2008, 954 + <https://www.rfc-editor.org/info/rfc5257>. 955 + 956 + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 957 + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 958 + May 2017, <https://www.rfc-editor.org/info/rfc8174>. 959 + 960 + [RFC9051] Melnikov, A., Ed. and B. Leiba, Ed., "Internet Message 961 + Access Protocol (IMAP) - Version 4rev2", RFC 9051, 962 + DOI 10.17487/RFC9051, August 2021, 963 + <https://www.rfc-editor.org/info/rfc9051>. 964 + 965 + 11.2. Informative References 966 + 967 + [RFC2033] Myers, J., "Local Mail Transfer Protocol", RFC 2033, 968 + DOI 10.17487/RFC2033, October 1996, 969 + <https://www.rfc-editor.org/info/rfc2033>. 970 + 971 + [RFC2087] Myers, J., "IMAP4 QUOTA extension", RFC 2087, 972 + DOI 10.17487/RFC2087, January 1997, 973 + <https://www.rfc-editor.org/info/rfc2087>. 974 + 975 + [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for 976 + Writing an IANA Considerations Section in RFCs", BCP 26, 977 + RFC 8126, DOI 10.17487/RFC8126, June 2017, 978 + <https://www.rfc-editor.org/info/rfc8126>. 979 + 980 + Acknowledgments 981 + 982 + The editor of this document would like to thank the following people 983 + who provided useful comments or participated in discussions that lead 984 + to this update of [RFC2087]: John Myers, Cyrus Daboo, Lyndon 985 + Nerenberg, Benjamin Kaduk, Roman Danyliw, and Éric Vyncke. 986 + 987 + This document is a revision of [RFC2087], and it borrows a lot of 988 + text from that RFC. Thus, the work of John Myers, the author of 989 + [RFC2087], is appreciated. 990 + 991 + Contributors 992 + 993 + Dave Cridland wrote a lot of text in an earlier draft version that 994 + became the basis for this document. 995 + 996 + Author's Address 997 + 998 + Alexey Melnikov 999 + Isode Limited 1000 + Email: alexey.melnikov@isode.com 1001 + URI: https://www.isode.com