From e84e0cfb38282921eadbf0e4a1e08466ab787235 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 19 Oct 2023 16:19:18 +0800 Subject: [PATCH] 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. --- java/org/gnu/emacs/EmacsOpenActivity.java | 116 +++++++++++++++++++++- lisp/gnus/message.el | 49 +++++++-- 2 files changed, 153 insertions(+), 12 deletions(-) diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java index 202b3c8c5dc..0c0da6acd1f 100644 --- a/java/org/gnu/emacs/EmacsOpenActivity.java +++ b/java/org/gnu/emacs/EmacsOpenActivity.java @@ -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 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; diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index 969589bb942..0071c02c081 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el @@ -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) ;; Send email (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) -- 2.39.2