diff --git a/docs/dnd-protocol.rst b/docs/dnd-protocol.rst index 7e39af25d..accdc952d 100644 --- a/docs/dnd-protocol.rst +++ b/docs/dnd-protocol.rst @@ -104,23 +104,22 @@ it is interested in. Requesting data is done by sending an escape code of the form:: - OSC _dnd_code ; t=r:r=request_id ; MIME type ST + OSC _dnd_code ; t=r:x=idx ST +Here ``idx`` is a 1-based index into the list of MIME types sent previously. This will request data for the specified MIME type. The terminal must respond with a series of escape codes of the form:: - OSC _dnd_code ; t=r:r=request_id ; base64 encoded data ST + OSC _dnd_code ; t=r:x=idx; base64 encoded data possibly chunked ST -End of data is indicated by an empty payload. If some error occurs while +End of data is indicated by an empty payload and ``m=0``. If some error occurs while getting the data, the terminal must send an escape code of the form:: - OSC _dnd_code ; t=R:r=request_id ; POSIX error name ST + OSC _dnd_code ; t=R:x=idx ; POSIX error name ST -Here POSIX error name is a POSIX symbolic error name such as ``ENOENT`` or -``EIO`` or the value ``EUNKNOWN`` for an unknown error. Note that if a client -sends a request for another MIME type before the data for the previous MIME type -is completed, the terminal *must* switch over to sending data for the new MIME -type. +Here ``POSIX error name`` is a POSIX symbolic error name such as ``ENOENT`` or +``EIO`` or the value ``EUNKNOWN`` for an unknown error. Unless otherwise noted, +any error response means the drop is terminated. Once the client program finishes reading all the dropped data it needs, it must send an escape code of the form:: @@ -138,51 +137,78 @@ clients can first request the :rfc:`text/uri-list <2483>` MIME type to get a list of dropped URIs. For every URI in the list, they can send the terminal emulator a data request of the form:: - OSC _dnd_code ; t=s:r=request_id ; text/uri-list:idx ST + OSC _dnd_code ; t=r:x=idx:y=subidx ST -Here ``idx`` is the zero based index into the array of MIME types in +Here ``idx`` is the one based index of the ``text/uri-list`` MIME type. And +``subidx`` is the one based index into the array of MIME types in the ``text/uri-list`` entry. The terminal will then read the file and -transmit the data as for a normal MIME data request. +transmit the data as for a normal MIME data request, except it will have +``y=subidx`` as well in its response, for example:: -Terminals must reply with ``t=R:r=request_id ; ENOENT`` if the index is out of bounds. + OSC _dnd_code ; t=r:x=idx:y=subidx ; base64 encoded data possibly chunked ST + +Similarly, error responses are as above, except for the addition of +``y=subidx``, for example:: + + OSC _dnd_code ; t=R:x=idx:y=subidx ; POSIX error name ST + +Terminals must reply with ``ENOENT`` if the index is out of bounds. If the client does not first request the ``text/uri-list`` MIME type or that MIME type is not present in the drop, the terminal must reply with -``t=R:r=request_id ; EINVAL``. Terminals must support at least ``file://`` URIs. +``EINVAL``. Terminals must support at least ``file://`` URIs. If the client requests an entry that is not a supported URI type the -terminal must reply with ``t=R:r=request_id ; EUNKNOWN``. +terminal must reply with ``EUNKNOWN``. Terminals must ONLY send data for regular files or directories. Symbolic links must be resolved and the corresponding file or directory read. If the terminal does not have -permission to read the file it must reply with ``t=R:r=request_id ; EPERM``. Terminals -must respond with ``t=R:r=request_id ; EINVAL`` if the file is not a regular file after -resolving symlinks and ``t=R:r=request_id ; ENOENT`` if the file does not exist. If an -I/O error occurs the terminal must send ``t=R:r=request_id ; EIO``. +permission to read the file it must reply with ``EPERM``. Terminals +must respond with ``EINVAL`` if the file is not a regular file after +resolving symlinks and ``ENOENT`` if the file does not exist. If an +I/O error occurs the terminal must send ``EIO``. -For security reasons, terminals must reply with ``t=R:r=request_id ; EPERM`` if the drag +For security reasons, terminals must reply with ``EPERM`` if the drag originated in the same window as the drop, this prevents malicious programs from reading files on the computer by starting their own drag. This is a defense in depth feature since drags can only be started by the terminal, but it helps in case of accidental drag starts and drops into the same window. -Terminals may queue requests with different ids and respond in order, or they -may respond in any order. If too many requests are received, they must deny -the request with ``t:R:r=request_id ; EMFILE`` and end the drop. +Clients may send multiple requests without waiting for any request to complete. +Terminals may queue requests and respond in any order they choose, including +interleaving responses to different requests. However, for simplicity, this +specification recommends terminals queue requests and respond in first-in, +first-out order. Every response can be matched to a corresponding request +using the ``x``, ``y`` and ``Y`` keys. To prevent Denial of service attacks, +if too many requests are received, terminals must deny the request +with ``EMFILE`` and end the drop. Reading remote directories +++++++++++++++++++++++++++ -If the file is actually a directory the terminal must respond with ``t=d:x=idx:r=request_id ; payload``. -Here payload is a null byte separated list of entries in the directory that are +If the file is actually a directory the terminal must instead respond with:: + + OSC _dnd_code ; t=r:x=idx:y=subidx:Y=handle:X=2 ; base64 encoded list of dir entries ST + +The presence of ``X=2`` indicates this is a directory response not a regular +file. Here, the payload is a null byte separated list of entries in the directory that are either regular files, directories or symlinks. The payload must be base64 encoded and might be chunked if the directory has a lot of entries. -``idx`` is an arbitrary 32 bit integer that acts as a handle to this -directory. The client can now read the files in this directory using requests of the form -``t=d:x=idx:y=num:r=request_id``, here ``num`` is the 1-based index into the list of -directory entries previously transmitted to the client, where, ``1`` will -correspond to the first entry in the directory. Once the client is done -reading a directory it should transmit ``t=d:x=idx:r=request_id`` to the terminal. The +``handle`` is an arbitrary non-zero integer that acts as a handle to this +directory. The client can now read the files in this directory using requests of the form:: + + OSC _dnd_code ; t=r:Y=handle:x=num ST + +Here ``num`` is the 1-based index into the list of directory entries previously transmitted +to the client. The terminal will respond with an escape code of the form:: + + OSC _dnd_code ; t=r:Y=handle:x=num ; base64 encoded data of entry ST + +In case of any errors, the terminal will respond with:: + + OSC _dnd_code ; t=R:Y=handle:x=num ; POSIX error name ST + +Once the client is done reading a directory it should transmit ``t=r:Y=handle`` to the terminal. The terminal can then free any resources associated with that directory. The directory handle is now invalid and terminals must return ``EINVAL`` if the client sends a request using an invalid directory handle. It is recommended @@ -192,12 +218,13 @@ resources are used, in order to prevent denial or service attacks. In such cases the terminal must respond with ``ENOMEM``. When transmitting a symlink that is inside a directory, -the terminal responds with escape code of the form:: +the terminal responds with an escape code of the form:: - OSC _dnd_code ; t=r:r=request_id:X=1 ; base64 encoded symlink target ST + OSC _dnd_code ; t=r:Y=handle:x=num:X=1 ; base64 encoded symlink target ST -Here, the presence of ``X=1`` indicates that the file is a symlink, not a -regular file. +The presence of ``X=1`` indicates that the file is a symlink, not a +regular file. Similarly for sub-directories it would be ``X=2`` and the payload +would be the null separated list of directory entries, as above. Starting drags @@ -351,9 +378,7 @@ Key Value Default Description ``m`` - a drop move event ``M`` - a drop dropped event ``r`` - request dropped data - ``R`` - report an error to the terminal program - ``s`` - request data from the URI list entry - ``d`` - send directory contents + ``R`` - report an error ``o`` - start offering drags ``O`` - stop offering drags ``p`` - present data for drag offers @@ -372,8 +397,6 @@ Key Value Default Description means rejected, ``1`` means copy and ``2`` means move. -``r`` Positive integer ``0`` The request id - **Keys for location** ----------------------------------------------------------- ``x`` Integer ``0`` Cell x-coordinate origin is 0, 0 at top left of screen diff --git a/gen/apc_parsers.py b/gen/apc_parsers.py index 786a6ed71..547de834d 100755 --- a/gen/apc_parsers.py +++ b/gen/apc_parsers.py @@ -333,11 +333,10 @@ def parsers() -> None: write_header(text, 'kitty/parse-multicell-command.h') keymap = { - 't': ('type', flag('aAmMrRsdoOpPeE')), + 't': ('type', flag('aAmMrRoOpPeE')), 'm': ('more', 'uint'), 'i': ('client_id', 'uint'), 'o': ('operation', 'uint'), - 'r': ('request_id', 'uint'), 'x': ('cell_x', 'int'), 'y': ('cell_y', 'int'), 'X': ('pixel_x', 'int'), diff --git a/kitty/parse-dnd-command.h b/kitty/parse-dnd-command.h index 124bd2987..5e9b03cc9 100644 --- a/kitty/parse-dnd-command.h +++ b/kitty/parse-dnd-command.h @@ -23,7 +23,6 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf, more = 'm', client_id = 'i', operation = 'o', - request_id = 'r', cell_x = 'x', cell_y = 'y', pixel_x = 'X', @@ -52,9 +51,6 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf, case operation: value_state = UINT; break; - case request_id: - value_state = UINT; - break; case cell_x: value_state = INT; break; @@ -91,9 +87,8 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf, case type: { g.type = parser_buf[pos++]; if (g.type != 'A' && g.type != 'E' && g.type != 'M' && g.type != 'O' && - g.type != 'P' && g.type != 'R' && g.type != 'a' && g.type != 'd' && - g.type != 'e' && g.type != 'm' && g.type != 'o' && g.type != 'p' && - g.type != 'r' && g.type != 's') { + g.type != 'P' && g.type != 'R' && g.type != 'a' && g.type != 'e' && + g.type != 'm' && g.type != 'o' && g.type != 'p' && g.type != 'r') { REPORT_ERROR("Malformed DnDCommand control block, unknown flag value " "for type: 0x%x", g.type); @@ -160,7 +155,6 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf, U(more); U(client_id); U(operation); - U(request_id); default: break; } @@ -212,13 +206,12 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf, } REPORT_VA_COMMAND( - "K s {sc sI sI sI sI si si si si ss#}", self->window_id, "dnd_command", + "K s {sc sI sI sI si si si si ss#}", self->window_id, "dnd_command", "type", g.type, "more", (unsigned int)g.more, "client_id", (unsigned int)g.client_id, - "operation", (unsigned int)g.operation, "request_id", - (unsigned int)g.request_id, + "operation", (unsigned int)g.operation, "cell_x", (int)g.cell_x, "cell_y", (int)g.cell_y, "pixel_x", (int)g.pixel_x, "pixel_y", (int)g.pixel_y, diff --git a/kitty/screen.h b/kitty/screen.h index a01636cde..d2554b5a7 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -17,7 +17,7 @@ typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } Scr typedef struct DnDCommand { char type; unsigned more; - uint32_t client_id, request_id; + uint32_t client_id; size_t payload_sz; int32_t cell_x, cell_y, pixel_x, pixel_y; uint32_t operation;