1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-04-27 16:51:06 -07:00

Relay body and attachments within Android e-mails to message-mailto

* java/org/gnu/emacs/EmacsOpenActivity.java (onCreate): Infer
e-mail body and subject from its parameters and convey this
information to message-mailto.

* lisp/gnus/message.el (message-mailto): New arguments SUBJECT,
BODY and FILE-ATTACHMENTS.
(message-mailto-1): Insert these arguments as appropriate.
This commit is contained in:
Po Lu 2023-10-19 16:19:18 +08:00
parent 77755706f0
commit e84e0cfb38
2 changed files with 153 additions and 12 deletions

View file

@ -55,6 +55,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.util.Log;
@ -67,6 +68,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
public final class EmacsOpenActivity extends Activity
implements DialogInterface.OnClickListener,
DialogInterface.OnCancelListener
@ -396,6 +399,7 @@ public final class EmacsOpenActivity extends Activity
Finally, display any error message, transfer the focus to an
Emacs frame, and finish the activity. */
@SuppressWarnings ("deprecation") /* getParcelableExtra */
@Override
public void
onCreate (Bundle savedInstanceState)
@ -407,6 +411,11 @@ public final class EmacsOpenActivity extends Activity
ParcelFileDescriptor fd;
byte[] names;
String errorBlurb, scheme;
String subjectString, textString, attachmentString;
CharSequence tem;
String tem1;
StringBuilder builder;
List<Parcelable> list;
super.onCreate (savedInstanceState);
@ -425,6 +434,7 @@ public final class EmacsOpenActivity extends Activity
if (action.equals ("android.intent.action.VIEW")
|| action.equals ("android.intent.action.EDIT")
|| action.equals ("android.intent.action.PICK")
|| action.equals ("android.intent.action.SEND")
|| action.equals ("android.intent.action.SENDTO"))
{
/* Obtain the URI of the action. */
@ -452,8 +462,110 @@ public final class EmacsOpenActivity extends Activity
/* Escape the special characters $ and " before enclosing
the string within the `message-mailto' wrapper. */
fileName = uri.toString ();
fileName.replace ("\"", "\\\"").replace ("$", "\\$");
fileName = "(message-mailto \"" + fileName + "\")";
fileName = (fileName
.replace ("\\", "\\\\")
.replace ("\"", "\\\"")
.replace ("$", "\\$"));
fileName = "(message-mailto \"" + fileName + "\" ";
/* Parse the intent itself to ascertain if any
non-standard subject, body, or something else of the
like is set. Such fields, non-standard as they are,
yield to fields provided within the URL itself; refer
to message-mailto. */
textString = attachmentString = subjectString = "()";
tem = intent.getCharSequenceExtra (Intent.EXTRA_SUBJECT);
if (tem != null)
subjectString = ("\"" + (tem.toString ()
.replace ("\\", "\\\\")
.replace ("\"", "\\\"")
.replace ("$", "\\$"))
+ "\" ");
tem = intent.getCharSequenceExtra (Intent.EXTRA_TEXT);
if (tem != null)
textString = ("\"" + (tem.toString ()
.replace ("\\", "\\\\")
.replace ("\"", "\\\"")
.replace ("$", "\\$"))
+ "\" ");
/* Producing a list of attachments is prey to two
mannerisms of the system: in the first instance, these
attachments are content URIs which don't allude to
their content types; and in the second instance, they
are either a list of such URIs or one individual URI,
subject to the type of the intent itself. */
if (Intent.ACTION_SEND.equals (action))
{
/* The attachment in this case is a single content
URI. */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
uri = intent.getParcelableExtra (Intent.EXTRA_STREAM,
Uri.class);
else
uri = intent.getParcelableExtra (Intent.EXTRA_STREAM);
if (uri != null
&& (scheme = uri.getScheme ()) != null
&& scheme.equals ("content"))
{
tem1 = EmacsService.buildContentName (uri);
attachmentString = ("'(\"" + (tem1.replace ("\\", "\\\\")
.replace ("\"", "\\\"")
.replace ("$", "\\$"))
+ "\")");
}
}
else
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
list
= intent.getParcelableArrayListExtra (Intent.EXTRA_STREAM,
Parcelable.class);
else
list
= intent.getParcelableArrayListExtra (Intent.EXTRA_STREAM);
if (list != null)
{
builder = new StringBuilder ("'(");
for (Parcelable parcelable : list)
{
if (!(parcelable instanceof Uri))
continue;
uri = (Uri) parcelable;
if (uri != null
&& (scheme = uri.getScheme ()) != null
&& scheme.equals ("content"))
{
tem1 = EmacsService.buildContentName (uri);
builder.append ("\"");
builder.append (tem1.replace ("\\", "\\\\")
.replace ("\"", "\\\"")
.replace ("$", "\\$"));
builder.append ("\"");
}
}
builder.append (")");
attachmentString = builder.toString ();
}
}
fileName += subjectString;
fileName += textString;
fileName += attachmentString;
fileName += ")";
/* Execute emacsclient in order to execute this code. */
currentActivity = this;

View file

@ -8971,32 +8971,61 @@ used to take the screenshot."
retval))
;;;###autoload
(defun message-mailto (&optional url)
(defun message-mailto (&optional url subject body file-attachments)
"Command to parse command line mailto: links.
This is meant to be used for MIME handlers: Setting the handler
for \"x-scheme-handler/mailto;\" to \"emacs -f message-mailto %u\"
will then start up Emacs ready to compose mail. For emacsclient use
emacsclient -e \\='(message-mailto \"%u\")'"
emacsclient -e \\='(message-mailto \"%u\")'
To facilitate the use of this function within window systems that
provide message subject, body and attachments independent of URL
itself, the arguments SUBJECT, BODY and FILE-ATTACHMENTS may also
provide alternative message subject and body text, which is
inserted in lieu of nothing if URL does not incorporate such
information itself, and a list of files to insert as attachments
to the E-mail."
(interactive)
;; <a href="mailto:someone@example.com?subject=This%20is%20the%20subject&cc=someone_else@example.com&body=This%20is%20the%20body">Send email</a>
(message-mail)
(message-mailto-1 (or url (pop command-line-args-left))))
(message-mailto-1 (or url (pop command-line-args-left))
subject body file-attachments))
(defun message-mailto-1 (url)
(let ((args (message-parse-mailto-url url)))
(defun message-mailto-1 (url &optional subject body file-attachments)
(let ((args (message-parse-mailto-url url))
(need-body nil) (need-subject nil))
(dolist (arg args)
(unless (equal (car arg) "body")
(message-position-on-field (capitalize (car arg)))
(insert (string-replace
"\r\n" "\n"
(mapconcat #'identity (reverse (cdr arg)) ", ")))))
(when (assoc "body" args)
(message-goto-body)
(dolist (body (cdr (assoc "body" args)))
(insert body "\n")))
(if (assoc "body" args)
(progn
(message-goto-body)
(dolist (body (cdr (assoc "body" args)))
(insert body "\n")))
(setq need-body t))
(if (assoc "subject" args)
(message-goto-body)
(message-goto-subject))))
(setq need-subject t)
(message-goto-subject))
;; If either one of need-subject and need-body is non-nil then
;; attempt to insert the absent information from an external
;; SUBJECT or BODY.
(when (or need-body need-subject)
(when (and need-body body)
(message-goto-body)
(insert body))
(when (and need-subject subject)
(message-goto-subject)
(insert subject)
(message-goto-body)))
;; Subsequently insert each attachment enumerated within
;; FILE-ATTACHMENTS.
(dolist (file file-attachments)
(mml-attach-file file nil 'attachment))))
(provide 'message)