diff --git a/docs/dnd-protocol.rst b/docs/dnd-protocol.rst index 60bdcfc5f..d26d8afd5 100644 --- a/docs/dnd-protocol.rst +++ b/docs/dnd-protocol.rst @@ -104,17 +104,17 @@ it is interested in. Requesting data is done by sending an escape code of the form:: - OSC _dnd_code ; t=r ; MIME type ST + OSC _dnd_code ; t=r:r=request_id ; MIME type ST 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 ; base64 encoded data ST + OSC _dnd_code ; t=r:r=request_id ; base64 encoded data ST End of data is indicated by an empty payload. If some error occurs while getting the data, the terminal must send an escape code of the form:: - OSC _dnd_code ; t=R ; POSIX error name ST + OSC _dnd_code ; t=R:r=request_id ; 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 @@ -138,37 +138,41 @@ 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 ; text/uri-list:idx ST + OSC _dnd_code ; t=s:r=request_id ; text/uri-list:idx ST Here ``idx`` is the zero 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. -Terminals must reply with ``t=R ; ENOENT`` if the index is out of bounds. +Terminals must reply with ``t=R:r=request_id ; 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 ; EINVAL``. Terminals must support at least ``file://`` URIs. +``t=R:r=request_id ; 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 ; EUNKNOWN``. +terminal must reply with ``t=R:r=request_id ; EUNKNOWN``. Terminals must ONLY send data for regular files. Symbolic links must be resolved and the corresponding file read. If the terminal does not have -permission to read the file it must reply with ``t=R ; EPERM``. Terminals -must respond with ``t=R ; EINVAL`` if the file is not a regular file after -resolving symlinks and ``t=R ; ENOENT`` if the file does not exist. If an -I/O error occurs the terminal must send ``t=R ; EIO``. +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``. -For security reasons, terminals must reply with ``t=R ; EPERM`` if the drag +For security reasons, terminals must reply with ``t=R:r=request_id ; 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. + Reading remote directories +++++++++++++++++++++++++++ -If the file is actually a directory the terminal must respond with ``t=d:x=idx ; payload``. +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 either regular files, directories or symlinks. The payload must be base64 encoded and might be chunked if the directory has a lot of entries. The first @@ -180,10 +184,10 @@ number. ``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``, here ``num`` is the index into the list of +``t=d:x=idx:y=num:r=request_id``, here ``num`` is the index into the list of directory entries previously transmitted to the client. Here, ``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`` to the terminal. The +reading a directory it should transmit ``t=d:x=idx:r=request_id`` 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 and invalid directory handle. It is recommended @@ -352,7 +356,7 @@ Key Value Default Description ``P`` - Change drag image or start drag ``e`` - a drag offer event occurred -``m`` Chunking indicator ``0`` ``0`` or ``i`` +``m`` Chunking indicator ``0`` ``0`` or ``1`` ``i`` Postive integer ``0`` This id is for use by multiplexers. When it is set, all responses from @@ -363,6 +367,8 @@ 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 4214397fc..d9559c105 100755 --- a/gen/apc_parsers.py +++ b/gen/apc_parsers.py @@ -335,6 +335,7 @@ def parsers() -> None: '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/dnd.c b/kitty/dnd.c index 1ab902125..ff4896773 100644 --- a/kitty/dnd.c +++ b/kitty/dnd.c @@ -392,6 +392,7 @@ get_errno_name(int err) { case ENOENT: return "ENOENT"; case EIO: return "EIO"; case EINVAL: return "EINVAL"; + case EMFILE: return "EMFILE"; case ENOMEM: return "ENOMEM"; case 0: return "OK"; default: return "EUNKNOWN"; @@ -1195,6 +1196,7 @@ parse_errno_name(const uint8_t *data, size_t sz) { if (sz >= 6 && memcmp(data, "ENOMEM", 6) == 0) return ENOMEM; if (sz >= 5 && memcmp(data, "EFBIG", 5) == 0) return EFBIG; if (sz >= 3 && memcmp(data, "EIO", 3) == 0) return EIO; + if (sz >= 6 && memcmp(data, "EMFILE", 6) == 0) return EMFILE; return EIO; } diff --git a/kitty/parse-dnd-command.h b/kitty/parse-dnd-command.h index a79dbfa52..124bd2987 100644 --- a/kitty/parse-dnd-command.h +++ b/kitty/parse-dnd-command.h @@ -23,6 +23,7 @@ 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', @@ -51,6 +52,9 @@ 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; @@ -156,6 +160,7 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf, U(more); U(client_id); U(operation); + U(request_id); default: break; } @@ -207,12 +212,13 @@ 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 ss#}", self->window_id, "dnd_command", + "K s {sc sI 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, + "operation", (unsigned int)g.operation, "request_id", + (unsigned int)g.request_id, "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 d2554b5a7..a01636cde 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; + uint32_t client_id, request_id; size_t payload_sz; int32_t cell_x, cell_y, pixel_x, pixel_y; uint32_t operation;