Subject: bug#65902: 29.0.92; emacsclient-mail.desktop fails due to complicated escaping

From: Spencer Baugh <[email-masked]>
Date: Thu, 14 Sep 2023 10:04:48 -0400

Eli Zaretskii <[email-masked]> writes:

>> From: [email-masked]
>> Date: Thu, 14 Sep 2023 11:03:44 +0000 (UTC)
>> Cc: Jim Porter <[email-masked]>, [email-masked],
>> 	[email-masked]
>> 
>> The issue is not really with the desktop file.  It's a generic problem:
>
> No, it isn't.  If it were, we'd have heard about it much sooner, and
> not because of the desktop files.
>
> What you are doing is representing a rare problem related to a niche
> feature is if it were a general one, by inventing use cases to justify
> that.  But if those use cases were important, people would have asked
> for them long ago.  They didn't.  Why? because --eval already exists.

No... these are real use cases that I personally have.  I have really
wanted this for a long time.  As I said in my original email, "I expect
this to also be useful in other places; the need to escape arbitrary
inputs before passing them to emacsclient is frequently annoying."

- I've wanted the ability to pass arbitrary data to Emacs through
  emacsclient since at least 2016, for other reasons:
  https://lists.gnu.org/archive/html/emacs-devel/2016-06/msg00051.html

- The fact that there is currently advice in org-protocol to implement
  this behavior means there are people who want it.  I'm sure the
  org-protocol authors really wanted to be able to avoid that advice,
  back when they developed it in 2009.  They didn't bother contributing
  a solution upstream back then, but why stop it from happening now?

- It would allow lazy loading of org-protocol as desired by the org devs
  https://list.orgmode.org/[email-masked]

- I'm working on a package which allows using Emacs to do
  completing-read over arbitrary strings passed in from the command
  line, as a replacement for the popular terminal software fzf.  Since
  this is completion over arbitrary strings, I need the ability to get
  those arbitrary strings into Emacs.

- There are numerous examples on the web of users trying and failing to
  get the quoting right to pass arguments to emacsclient; for example

  https://www.reddit.com/r/emacs/comments/hhbcg7/emacsclient_eval_with_command_line_arguments/
  this would become
  emacsclient --apply switch-to-buffer

  https://stackoverflow.com/questions/8848819/emacs-eval-ediff-1-2-how-to-put-this-line-in-to-shell-script
  this would become
  emacsclient --apply ediff

  No shell complexities required in either case.

>> > What about alternative solutions: use a shell script in the desktop
>> > files, and delegate to that script to solve the problem with quoting?
>> > Had anyone considered this strategy?  If not, why not?
>> 
>> Getting the quoting right is hard and complex, and even Emacs developers
>> have failed at it over multiple iterations, and when they fail it either
>> breaks or exposes a security vulnerability.
>
> Emacs developers make mistakes even in the simple regexps we have in
> our code.  That doesn't mean we should abandon regexps.  The solution
> for sending Lisp forms to the server exists, and the quoting, although
> tricky in some cases, is not rocket science to get right.

I think this (the current contents of emacsclient-mail.desktop):
sh -c "u=\\$(echo \\"\\$1\\" | sed 's/[\\\\\\"]/\\\\\\\\&/g'); exec
emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval
\\"(message-mailto \\\\\\"\\$u\\\\\\")\\"" sh %u

is in fact rocket science, and rocket science that needs to be repeated
by every user who wants to pass arbitrary strings to Emacs.

And keep in mind this mass of escaping *is currently broken*.

> I don't see
> why we would need another mechanism to do something similar with
> radically different syntax, a separate set of rules and restrictions
> that need to be documented, etc. etc.
>
>> This solution is far simpler
>
> That's an illusion.  There's nothing simple about it.  You are
> inventing a new mechanism for passing Lisp forms as something other
> than Lisp.

But I don't want to pass Lisp forms, that's the entire point.  I have
some arbitrary string which is *not* Lisp, and I want Emacs to *not*
parse it as Lisp.

> This has got to have issues into which we will bump sooner
> or later.  E.g., assume that two or more of the arguments to the
> function begins with single quote, as in
>
>   $ emacsclient --apply func arg1 'foo arg2 'bar
>
> Escape-quoting, here we come again!

That example works fine with --apply.  The call becomes:
(func "arg1" "'foo" "arg2" "'bar")
which is reliable and expected.

Maybe you're referring to how, if you run that command through a shell,
the shell interprets the single quotes as creating a string?  But that's
that's a separate issue, because:

- I don't plan to run any of my commands using --apply through a shell
  (which means they will require zero escaping or quoting whatsoever)

- Right now with --eval you have to do escaping for both the shell and
  Lisp.  With --apply you only have to do escaping for the shell, if you
  do use a shell, and if you don't use a shell you don't have to do
  anything.

I think it is simpler to reduce the amount of quoting and escaping from
"both Lisp and shell" to "just shell, and not even that if you don't use
a shell".