-
Notifications
You must be signed in to change notification settings - Fork 85
[multiline] Multiline message batches #398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
294dcf0
d09657d
65b2f96
a4c6f7e
858e5fa
5947faa
281f386
0b4ec81
ff7f73b
bacbc49
051b87a
e8efcae
63d5c9e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
| --- | ||
| title: Multiline messages | ||
| layout: spec | ||
| work-in-progress: true | ||
| copyrights: | ||
| - | ||
| name: "James Wheare" | ||
| period: "2019" | ||
| email: "james@irccloud.com" | ||
| contributors: | ||
| - | ||
| name: "jesopo" | ||
| email: "jess@jesopo.uk" | ||
| --- | ||
|
|
||
| ## Notes for implementing work-in-progress version | ||
|
|
||
| This is a work-in-progress specification. | ||
|
|
||
| Software implementing this work-in-progress specification MUST NOT use the unprefixed `multiline-concat` tag or `multiline` CAP/batch names. Instead, implementations SHOULD use the `draft/multiline-concat` tag, `draft/multiline` CAP and `draft/multiline` batch names to be interoperable with other software implementing a compatible work-in-progress version. | ||
|
|
||
| The final version of the specification will use an unprefixed tag name. | ||
|
|
||
| ## Introduction | ||
|
|
||
| This specification adds a new batch type and tag sent by clients and servers to send messages that can exceed the usual byte length limit and that can contain line breaks. | ||
|
|
||
| ## Motivation | ||
|
|
||
| IRC messages have been traditionally limited by the line-based nature of the protocol and the line length limit of 512. To work around these limitations, client implementations split longer messages into multiple lines, and users need to rely on snippet hosting services to send multiple lines without flooding the chat or having their messages interrupted by other users. | ||
|
|
||
| Mulitline messages allow for a more coherent experience that avoids the disconnected messages that result from these workarounds. | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Dependencies | ||
|
|
||
| This specification uses the [batch][] capability which MUST be negotiated at the same time. It also uses the [message tags][] and [standard replies][] frameworks. | ||
|
|
||
| ### Capabilities | ||
|
|
||
| This specification adds the `draft/multiline` capability. | ||
|
|
||
| Implementations requesting this capability indicate that they are capable of handling the batch type and message tag described below. | ||
|
|
||
| The capability has a REQUIRED value: a comma (`,`) (0x2C) separated list of tokens. Each token consists of a key which might have a value attached. If there is a value attached, the value is separated from the key by an equals sign (`=`) (0x3D). That is, `<key>[=<value>][,<key2>[=<value2>][,<keyN>[=<valueN>]]]`. Keys specified in this document MUST only occur at most once. | ||
jwheare marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Clients MUST ignore every token with a key that they don't understand. | ||
|
|
||
| The only defined capability key so far is: | ||
|
|
||
| * `max-bytes` - This defines the maximum allowed total byte length of multiline batched content *REQUIRED* | ||
| * `max-lines` - This defines the maximum allowed number of lines in a multiline batch content *OPTIONAL* | ||
|
|
||
| ### Tags | ||
|
|
||
| This specification adds the `draft/multiline-concat` message tag, which has no value and is used to send message lines that extend beyond the usual byte length limit. Its usage is described below. | ||
|
|
||
| ### Batch types | ||
|
|
||
| This specification adds the `draft/multiline` batch type, and introduces client initiated batches. These use the same syntax as server initiated batches. | ||
|
|
||
| In addition to the base batch parameters (reference-tag and type) a multiline batch has one additional parameter, the target recipient. | ||
|
|
||
| Multiline batches MUST contain one or more PRIVMSG lines whose target MUST match the batch target. | ||
jwheare marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| When receiving a well-formed mulitiline message batch, implementations MUST collect each PRIVMSG message content and wait until the full batch has been received before processing the message. Processing in this context refers to: | ||
|
|
||
| * Servers: delivering the batch to the intended recipients | ||
| * Clients: displaying the batched message to the user | ||
|
|
||
| Messages in a multiline batch MUST be concatenated with a line break unless the `draft/multiline-concat` message tag is sent, in which case the message is directly concatenated with the previous message without any separation. | ||
|
|
||
| Clients MUST NOT send messages other than PRIVMSG while a multiline batch is open. | ||
|
|
||
| ### Fallback | ||
|
|
||
| When delivering multiline batches to clients that have not negotiated the multiline capability, servers MUST deliver the component messages without using a multiline BATCH. | ||
|
|
||
| Any tags that would have been added to the batch, e.g. message IDs, account tags etc MUST be included on the first message line. Tags MAY also be included on subsequent lines where it makes sense to do so. | ||
|
|
||
| ### Errors | ||
|
|
||
| Servers MUST use `FAIL` messages from the [standard replies][] framework to notify clients of errors with multiline batches. The command is `BATCH` and the following codes are defined: | ||
|
|
||
| * `MULTILINE_MAX_BYTES <limit>`: `max-bytes` limit exceeded | ||
| * `MULTILINE_MAX_LINES <limit>`: `max-lines` limit exceeded | ||
| * `MULTILINE_INVALID_TARGET <batch-target> <provided-target>`: mismatched PRIVMSG target within a batch | ||
| * `MULTILINE_INVALID`: any other error | ||
|
|
||
| ## Interaction with other specifications | ||
|
|
||
| ### Message tags ([spec][message tags]) | ||
|
|
||
| Clients MUST only send non-`batch` tags on the opening BATCH command when sending multiline batches. | ||
jwheare marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Message ids ([spec][message ids]) | ||
|
|
||
| Servers MUST only include a message ID on the first message of a batch when sending a fallback to non-supporting clients. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the first one? If the message ID is used eg for a reply or a reaction emoji, it visually makes more sense to have it attached to the last message.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand correctly, this is saying that (some of) the fallback
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For comparison, oragono.io/maxline-2 generates n+1 distinct message IDs for the original message and all n lines of the split message. This isn't perfect, but it maintains the expectation that The msgid spec says: "If this tag is being used, it SHOULD be attached to all PRIVMSG and NOTICE events."
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. msgids can't appear more than once. Generating unique n+1 msgids and only sending them on the fallback creates undesirable situations where people might reply to a fallback message and the context would then be missing for people who fully support maxline (i.e. discard fallback message tags) If you're concerned about missing msgids, the solution would be to properly support the maxline batch spec.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that's true. It'd be easy to generate unique fallback msgids that the server can recognise as such and translate back or refuse replies for or something.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jwheare, just to be clear, when you say "maxline" you're referring to the present multiline spec, not to oragono.io/maxline-2? Some degradation of experience is inevitable under any proposal to support PRIVMSG over 512 bytes. I'm much less concerned about the case you're describing than I am about sending PRIVMSG without IDs, which seems to complicate the handling of chat history at a more fundamental level. I'm not 100% sold on @edk0's suggestion because it violates an expectation I have that servers shouldn't need to care about client-only tags, but I could be convinced. Hypothetically, we could define a new tag like
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm going to care about client-only tags anyway, so it's not a bother for me. You don't have to implement my suggestion; I'm just saying a solution is possible. |
||
|
|
||
| ### Labeled response ([draft][labeled response]) with echo-message ([spec][echo message]) | ||
|
|
||
| Servers MUST only include the label tag on the opening BATCH command when replying to a client using `echo-message`. | ||
|
|
||
| ## Client implementation considerations | ||
|
|
||
| This section is non-normative. | ||
|
|
||
| ### Splitting long lines | ||
|
|
||
| When splitting long lines, care is required to ensure messages are displayed appropriately when combined or in the fallback case. | ||
|
|
||
| The recommended splitting method is to split long lines between words where possible and leave the space character at the end of the line. This ensures that concatenated lines don't lose the space, while fallback lines don't start with a space. | ||
|
|
||
| In order to calculate the maximum allowed space before splitting a line, consider the following line: | ||
|
|
||
| ``` | ||
| :nick!~user@host PRIVMSG #channel :hello \n\r | ||
| ``` | ||
|
|
||
| The parts of a message that must fit within the 512 byte limit are as follows | ||
|
|
||
| | part | syntax | length | | ||
| |-|-|-| | ||
| | leading | `:` | 1 | | ||
| | nick | `nick` | variable | | ||
| | nick/mask separator | `!` | 1 | | ||
| | user | `~user` | variable | | ||
| | user/host separator | `@` | 1 | | ||
| | host | `host` | variable | | ||
| | command | `PRIVMSG` | 7 | | ||
| | channel | `#channel` | variable | | ||
| | message separator | ` :` | 2 | | ||
| | crlf | `\n\r` | 2 | | ||
|
||
| | message | `hello ` | variable | | ||
|
|
||
| Not all parts may appear in a message, but a safe limit should take them into account and include an extra safety buffer in case of any unexpected syntax added by a server, e.g. a statusmsg prefix. | ||
|
|
||
| With a safety buffer of 10, the total message size available before a split is needed can be calculated as follows | ||
|
|
||
| ``` | ||
| 512 - 14 - 10 - <nick> - <user> - <host> - <channel> | ||
| ``` | ||
|
|
||
| Clients might wish to perform a `WHO` query on themselves when connecting to a server, and keep track of numeric `396 RPL_VISIBLEHOST` to keep their `user@host` mask in sync. | ||
|
|
||
| Clients might alternatively prefer to use a hard coded limit. A possible worst case scenario for the variable parts might be: | ||
|
|
||
| * nick: 20 | ||
| * user: 20 | ||
| * host: 63 | ||
| * channel: 32 | ||
|
|
||
| Which would leave 353 bytes for each message. | ||
|
|
||
| ## Server implementation considerations | ||
jwheare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| This section is non-normative. | ||
|
|
||
| In the context of flood protection, keep in mind that clients might send an entire batched multiline message all at once. | ||
|
||
|
|
||
| ## Examples | ||
|
|
||
| This section is non-normative. | ||
|
|
||
| NOTE: In these examples, `<SPACE>` indicates a space character which would otherwise not be clearly visible. | ||
|
|
||
| Client sending a mutliline batch | ||
|
|
||
| Client: BATCH +123 draft/multiline #channel | ||
| Client: @batch=123 PRIVMSG #channel hello | ||
| Client: @batch=123 privmsg #channel :how is<SPACE> | ||
| Client: @batch=123;draft/multiline-concat PRIVMSG #channel :everyone? | ||
| Client: BATCH -123 | ||
|
|
||
| Server sending the same batch | ||
|
|
||
| Server: @msgid=xxx;account=account :n!u@h BATCH +123 draft/multiline #channel | ||
| Server: @batch=123 :n!u@h PRIVMSG #channel hello | ||
| Server: @batch=123 :n!u@h PRIVMSG #channel :how is<SPACE> | ||
| Server: @batch=123;draft/multiline-concat :n!u@h PRIVMSG #channel :everyone? | ||
| Server: BATCH -123 | ||
|
|
||
| Server sending messages to clients without multiline support | ||
|
|
||
| Server: @msgid=xxx;account=account :n!u@h PRIVMSG #channel hello | ||
| Server: @account=account :n!u@h PRIVMSG #channel :how is<SPACE> | ||
| Server: @account=account :n!u@h PRIVMSG #channel :everyone? | ||
|
|
||
| Final concatenated message | ||
|
|
||
| hello | ||
| how is everyone? | ||
|
|
||
| --- | ||
|
|
||
| Invalid multiline batch target | ||
|
|
||
| Client: BATCH +456 draft/multiline #foo | ||
| Client: @batch=456 PRIVMSG #bar hello | ||
| Client: BATCH -456 | ||
|
|
||
| Server: :irc.example.com FAIl BATCH MULTILINE_INVALID_TARGET #foo #bar :Invalid multiline target | ||
|
|
||
| --- | ||
|
|
||
| `max-bytes` exceeded multiline batch | ||
|
|
||
| Server: CAP * LS :draft/multiline=max-bytes=40000 | ||
|
|
||
| Client: BATCH +abc draft/multiline #channel | ||
| Client: @batch=abc PRIVMSG #channel hello | ||
| ... lines that exceeed the max-bytes=40000 limit ... | ||
|
|
||
| Server: :irc.example.com FAIl BATCH MULTILINE_MAX_BYTES 40000 :Multiline batch max-bytes exceeded | ||
|
|
||
| `max-bytes` exceeded multiline batch | ||
|
|
||
| Server: CAP * LS :draft/multiline=max-lines=10 | ||
jwheare marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Client: BATCH +abc draft/multiline #channel | ||
| Client: @batch=abc PRIVMSG #channel hello | ||
| ... 10 more lines ... | ||
|
|
||
| Server: :irc.example.com FAIl BATCH MULTILINE_MAX_LINES 10 :Multiline batch max-lines exceeded | ||
|
|
||
| --- | ||
|
|
||
| Invalid multiline batch | ||
|
|
||
| Client: BATCH +999 draft/multiline #channel | ||
| ... invalid batch contents ... | ||
|
|
||
| Server: :irc.example.com FAIl BATCH MULTILINE_INVALID :Invalid multiline batch | ||
|
|
||
| [message tags]: ../extensions/message-tags.html | ||
| [batch]: ../extensions/batch-3.2.html | ||
| [standard replies]: ../extensions/standard-replies.html | ||
| [message ids]: ../extensions/message-ids.html | ||
| [labeled response]: ../extensions/labeled-response.html | ||
| [echo message]: ../extensions/echo-message-3.2.html | ||
Uh oh!
There was an error while loading. Please reload this page.