unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: sbaugh@catern.com
To: Eli Zaretskii <eliz@gnu.org>
Cc: jporterbugs@gmail.com, 65902@debbugs.gnu.org, sbaugh@janestreet.com
Subject: bug#65902: 29.0.92; emacsclient-mail.desktop fails due to complicated escaping
Date: Sat, 23 Sep 2023 20:24:07 +0000 (UTC)	[thread overview]
Message-ID: <87zg1cprix.fsf@catern.com> (raw)
In-Reply-To: <835y4290kf.fsf@gnu.org> (Eli Zaretskii's message of "Fri, 22 Sep 2023 09:36:16 +0300")

[-- Attachment #1: Type: text/plain, Size: 1769 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> From: sbaugh@catern.com
>> Date: Fri, 22 Sep 2023 01:36:47 +0000 (UTC)
>> Cc: Spencer Baugh <sbaugh@janestreet.com>, jporterbugs@gmail.com,
>> 	65902@debbugs.gnu.org
>> 
>> > Currently, when emacsclient is invoked like this:
>> >
>> >   $ emacsclient --eval '(func args)' foo bar
>> >
>> > we send to the server the following commands:
>> >
>> >   -eval (func args)
>> >   -eval foo
>> >   -eval bar
>> >
>> > IOW, every command-line argument after --eval is treated as being
>> > implicitly preceded with --eval.
>> >
>> > With your proposal, how will the server know that some of "-eval foo"
>> > commands should cause foo to be added to server-eval-args-left instead
>> > of being evaluated as it does now?
>> 
>> As in the attached patch.
>
> I wish you'd accompanied the patch with some plain-text description of
> the idea, to make it easier to understand and to avoid unnecessary
> misunderstandings.

Ah, well, the basic idea is that for each -eval request we receive in
the protocol, we accumulate the argument as a string into a single list
(instead of immediately turning it into a closure which calls
server-eval-and-print).  Then we let-bind server-eval-args-left to that
list around the calls to to server-eval-and-print, and consume each
argument from the list one by one.

> IIUC, this kind of solution is fine by me, but the protocol of
> accessing and using server-eval-args-left in the Lisp expressions
> specified on the emacsclient command line should be well-documented to
> avoid any confusion and UB.

Added a docstring and included it in NEWS.  I would have put it in the
manual, but it seems rather niche to put in the Emacs manual and I
didn't see a natural place to put it in the Emacs Lisp manual.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-server-eval-args-left-to-server.el.patch --]
[-- Type: text/x-patch, Size: 7851 bytes --]

From cf7fcda1374491cc73a751d5636f36a95b2e8669 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <sbaugh@catern.com>
Date: Thu, 21 Sep 2023 21:35:50 -0400
Subject: [PATCH] Add server-eval-args-left to server.el

Passing arbitrary arguments to functions through emacsclient --eval
requires complicated escaping to avoid them being parsed as Lisp (as
seen in emacsclient-mail.desktop before this change).

This new variable server-eval-args-left allows access to the arguments
before they are parsed as Lisp.  By removing arguments from the
variable before they're parsed, a snippet of Lisp can consume
arguments, as in emacsclient-mail.desktop.

org-protocol might be able to use this as well, which might allow it
to drop its current advice on server-visit-files.

* etc/emacsclient-mail.desktop: Use server-eval-args-left. (bug#65902)
* lisp/server.el (server-eval-args-left): Add.
(server-process-filter, server-execute): Make -eval arguments
available through server-eval-args-left.
* lisp/startup.el (argv): Mention server-eval-args-left in docstring.
* etc/NEWS: Announce server-eval-args-left.
---
 etc/NEWS                     | 10 ++++++++++
 etc/emacsclient-mail.desktop |  7 ++-----
 lisp/server.el               | 35 ++++++++++++++++++++++++++++-------
 lisp/startup.el              |  5 ++++-
 4 files changed, 44 insertions(+), 13 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index cd4c414a64c..de1d79fcb98 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -121,6 +121,16 @@ Anything following the symbol 'mode-line-format-right-align' in
 right-aligned to is controlled by the new user option
 'mode-line-right-align-edge'.
 
+** Emacs Server and Client
+
+---
+*** 'server-eval-args-left' can be used to pop subsequent eval args
+When '--eval' is passed to emacsclient and Emacs is evaluating each
+argument, this variable is set to those which have not yet been
+evaluated.  It can be used to 'pop' arguments to prevent them from
+being evaluated, which is useful when those arguments contain
+arbitrary data.
+
 \f
 * Editing Changes in Emacs 30.1
 
diff --git a/etc/emacsclient-mail.desktop b/etc/emacsclient-mail.desktop
index 0a2420ddead..5962fa1764c 100644
--- a/etc/emacsclient-mail.desktop
+++ b/etc/emacsclient-mail.desktop
@@ -1,10 +1,7 @@
 [Desktop Entry]
 Categories=Network;Email;
 Comment=GNU Emacs is an extensible, customizable text editor - and more
-# We want to pass the following commands to the shell wrapper:
-# u=$(echo "$1" | sed 's/[\"]/\\&/g'); exec emacsclient --alternate-editor= --display="$DISPLAY" --eval "(message-mailto \"$u\")"
-# Special chars '"', '$', and '\' must be escaped as '\\"', '\\$', and '\\\\'.
-Exec=sh -c "u=\\$(echo \\"\\$1\\" | sed 's/[\\\\\\"]/\\\\\\\\&/g'); exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\"(message-mailto \\\\\\"\\$u\\\\\\")\\"" sh %u
+Exec=emacsclient --alternate-editor= --eval '(message-mailto (pop server-eval-args-left))' %u
 Icon=emacs
 Name=Emacs (Mail, Client)
 MimeType=x-scheme-handler/mailto;
@@ -16,7 +13,7 @@ Actions=new-window;new-instance;
 
 [Desktop Action new-window]
 Name=New Window
-Exec=sh -c "u=\\$(echo \\"\\$1\\" | sed 's/[\\\\\\"]/\\\\\\\\&/g'); exec emacsclient --alternate-editor= --create-frame --eval \\"(message-mailto \\\\\\"\\$u\\\\\\")\\"" sh %u
+Exec=emacsclient --alternate-editor= --create-frame --eval '(message-mailto (pop server-eval-args-left))' %u
 
 [Desktop Action new-instance]
 Name=New Instance
diff --git a/lisp/server.el b/lisp/server.el
index c3325e5a24c..65f28cdea23 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -1189,6 +1189,7 @@ server-process-filter
 		parent-id  ; Window ID for XEmbed
 		dontkill   ; t if client should not be killed.
 		commands
+		evalexprs
 		dir
 		use-current-frame
 		frame-parameters  ;parameters for newly created frame
@@ -1319,8 +1320,7 @@ server-process-filter
                  (let ((expr (pop args-left)))
                    (if coding-system
                        (setq expr (decode-coding-string expr coding-system)))
-                   (push (lambda () (server-eval-and-print expr proc))
-                         commands)
+                   (push expr evalexprs)
                    (setq filepos nil)))
 
                 ;; -env NAME=VALUE:  An environment variable.
@@ -1345,7 +1345,7 @@ server-process-filter
 	    ;; arguments, use an existing frame.
 	    (and nowait
 		 (not (eq tty-name 'window-system))
-		 (or files commands)
+		 (or files commands evalexprs)
 		 (setq use-current-frame t))
 
 	    (setq frame
@@ -1394,7 +1394,7 @@ server-process-filter
                  (let ((default-directory
                          (if (and dir (file-directory-p dir))
                              dir default-directory)))
-                   (server-execute proc files nowait commands
+                   (server-execute proc files nowait commands evalexprs
                                    dontkill frame tty-name)))))
 
             (when (or frame files)
@@ -1404,22 +1404,43 @@ server-process-filter
     ;; condition-case
     (t (server-return-error proc err))))
 
-(defun server-execute (proc files nowait commands dontkill frame tty-name)
+(defvar server-eval-args-left nil
+  "List of eval args not yet processed.
+
+When the server receives a request to eval one or more strings,
+it stores them in this variable.  Then, until this variable is
+nil, it `pop's a string from this variable and evaluates it with
+`server-eval-and-print'.  Adding or removing strings from this
+variable during this process will affect what is evaluated.
+
+This allows an expression passed to \"emacsclient --eval\" to
+consume one or more subsequent arguments before they're parsed or
+evaluated, with (pop server-eval-args-left).  This is useful if
+those arguments are arbitrary strings which should not be
+evaluated.
+
+See also `command-line-args-left' for a similar variable which
+works for command line invocations of \"emacs\".")
+
+(defun server-execute (proc files nowait commands evalexprs dontkill frame tty-name)
   ;; This is run from timers and process-filters, i.e. "asynchronously".
   ;; But w.r.t the user, this is not really asynchronous since the timer
   ;; is run after 0s and the process-filter is run in response to the
   ;; user running `emacsclient'.  So it is OK to override the
-  ;; inhibit-quit flag, which is good since `commands' (as well as
+  ;; inhibit-quit flag, which is good since `evalexprs' (as well as
   ;; find-file-noselect via the major-mode) can run arbitrary code,
   ;; including code that needs to wait.
   (with-local-quit
     (condition-case err
         (let ((buffers (server-visit-files files proc nowait)))
           (mapc 'funcall (nreverse commands))
+          (let ((server-eval-args-left (nreverse evalexprs)))
+            (while server-eval-args-left
+              (server-eval-and-print (pop server-eval-args-left) proc)))
 	  ;; If we were told only to open a new client, obey
 	  ;; `initial-buffer-choice' if it specifies a file
           ;; or a function.
-          (unless (or files commands)
+          (unless (or files commands evalexprs)
             (let ((buf
                    (cond ((stringp initial-buffer-choice)
 			  (find-file-noselect initial-buffer-choice))
diff --git a/lisp/startup.el b/lisp/startup.el
index 7f601668369..f2c84751211 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -120,7 +120,10 @@ command-switch-alist
     "List of command-line args not yet processed.
 This is a convenience alias, so that one can write (pop argv)
 inside of --eval command line arguments in order to access
-following arguments."))
+following arguments.
+
+See also `server-eval-args-left' for a similar variable which
+works for invocations of \"emacsclient --eval\"."))
 (internal-make-var-non-special 'argv)
 
 (defvar command-line-args-left nil
-- 
2.41.0


  reply	other threads:[~2023-09-23 20:24 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <80d8aeb0-c9f1-410f-b83d-60f83ca5b3af@email.android.com>
2023-09-14 14:57 ` bug#65902: 29.0.92; emacsclient-mail.desktop fails due to complicated escaping Eli Zaretskii
2023-09-14 15:10   ` Spencer Baugh
2023-09-15  6:29     ` Eli Zaretskii
2023-09-22  1:36       ` sbaugh
2023-09-22  6:36         ` Eli Zaretskii
2023-09-23 20:24           ` sbaugh [this message]
2023-09-24  5:18             ` Eli Zaretskii
2023-09-24 14:20               ` sbaugh
2023-10-21 15:20                 ` sbaugh
2023-10-22  5:27                   ` Eli Zaretskii
2023-10-22 14:15                     ` sbaugh
2023-10-22 16:09                       ` Andreas Schwab
2023-10-22 19:53                         ` sbaugh
2023-10-23 16:38                           ` Andreas Schwab
2023-10-23 16:52                           ` Jim Porter
2023-10-24 16:27                             ` sbaugh
2023-10-29 12:20                               ` Eli Zaretskii
2023-10-22  5:39                   ` Jim Porter
2023-09-22  7:05         ` Stefan Kangas
2023-09-22  7:14           ` Eli Zaretskii
2023-09-22  9:29             ` Andreas Schwab
2023-09-22 11:32               ` Eli Zaretskii
2023-09-22 12:37                 ` Andreas Schwab
2023-09-22 12:56                   ` Eli Zaretskii
2023-09-22 13:23                     ` Andreas Schwab
2023-09-22 14:51                       ` Eli Zaretskii
2023-09-22 14:52                         ` Andreas Schwab
     [not found] <fe2cc764-86c6-4840-80b7-8f3a3778b374@email.android.com>
2023-09-13 14:50 ` Eli Zaretskii
2023-09-13 15:01   ` Andreas Schwab
2023-09-13 15:23   ` Spencer Baugh
2023-09-13 16:19     ` Jim Porter
2023-09-13 19:13     ` Eli Zaretskii
2023-09-13 19:33       ` Jim Porter
2023-09-13 20:00         ` Spencer Baugh
2023-09-13 20:16           ` Jim Porter
2023-09-14  5:10         ` Eli Zaretskii
2023-09-14 11:03           ` sbaugh
2023-09-14 11:18             ` sbaugh
2023-09-14 11:35             ` sbaugh
2023-09-14 13:36             ` Eli Zaretskii
2023-09-14 14:04               ` Spencer Baugh
2023-09-14 14:31                 ` Eli Zaretskii
2023-09-14 19:16               ` Jim Porter
2023-09-15  5:33                 ` Eli Zaretskii
2023-09-16 13:43           ` Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-16 14:02             ` Eli Zaretskii
2023-09-16 15:54               ` Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-13  2:24 sbaugh
2023-09-13  2:30 ` sbaugh
2023-09-13  3:46   ` Jim Porter
2023-09-13  8:00     ` Robert Pluim
2023-09-13 13:06       ` Eli Zaretskii
2023-09-13 14:22         ` Robert Pluim
2023-09-13 12:41     ` Eli Zaretskii
2023-09-13 12:57     ` sbaugh
2023-09-13 12:41   ` Eli Zaretskii
2023-09-13 13:01     ` sbaugh
2023-09-13 13:26       ` Eli Zaretskii
2023-09-16 13:30         ` Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87zg1cprix.fsf@catern.com \
    --to=sbaugh@catern.com \
    --cc=65902@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=jporterbugs@gmail.com \
    --cc=sbaugh@janestreet.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).