* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split @ 2023-05-05 13:13 Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-05 18:57 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-05 13:13 UTC (permalink / raw) To: 63311 [-- Attachment #1: Type: text/plain, Size: 606 bytes --] Hi, I'm trying to make sending mail over SMTP asynchronous. For this, I'm working on 'smtpmail-send-it'… but I think that that function does too much and is hard to reason about. This patch just splits 'smtpmail-send-it' work into three functions: prepare a mail and queue it or send it. There should be no change in functionality (it is mostly code refactoring). I've tested it a bit with sending and queueing and this seems to work correctly but this needs way more eyes and tests. BTW, does anyone know the purpose of 'errbuf': I see it is created then erased and then killed? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-smtpmail-send-it-split.patch --] [-- Type: text/x-patch, Size: 18239 bytes --] From 6481038443deae8bf4e309a641f5ce77717be712 Mon Sep 17 00:00:00 2001 From: Manuel Giraud <manuel@ledu-giraud.fr> Date: Fri, 5 May 2023 14:35:01 +0200 Subject: [PATCH] smtpmail-send-it split * lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function that prepares the mail with current buffer content. (smtpmail-queue-mail): New function to queue a mail (prepared by 'smtpmail-prepare-mail'). (smtpmail-send-mail): New function to send a mail (prepared by 'smtpmail-send-mail'). (smtpmail-send-it): Use all three previous functions. --- lisp/mail/smtpmail.el | 407 +++++++++++++++++++++--------------------- 1 file changed, 206 insertions(+), 201 deletions(-) diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el index 78688d170cc..7c61ca29de6 100644 --- a/lisp/mail/smtpmail.el +++ b/lisp/mail/smtpmail.el @@ -205,214 +205,219 @@ smtpmail-mail-address "Value to use for envelope-from address for mail from ambient buffer.") ;;; Functions +(defun smtpmail-prepare-mail (tembuf errbuf smtpmail-code-conv-from) + (let ((case-fold-search nil) + delimline + (mailbuf (current-buffer)) + ;; Examine this variable now, so that + ;; local binding in the mail buffer will take effect. + (smtpmail-mail-address + (save-restriction + ;; Only look at the headers when fetching the + ;; envelope address. + (message-narrow-to-headers) + (or (and mail-specify-envelope-from (mail-envelope-from)) + (let ((from (mail-fetch-field "from"))) + (and from + (cadr (mail-extract-address-components from)))) + (smtpmail-user-mail-address))))) + (with-current-buffer tembuf + (erase-buffer) + ;; Use the same `buffer-file-coding-system' as in the mail + ;; buffer, otherwise any `write-region' invocations (e.g., in + ;; mail-do-fcc below) will annoy with asking for a suitable + ;; encoding. + (set-buffer-file-coding-system smtpmail-code-conv-from nil t) + (insert-buffer-substring mailbuf) + (goto-char (point-max)) + ;; require one newline at the end. + (or (= (preceding-char) ?\n) + (insert ?\n)) + ;; Change header-delimiter to be what sendmail expects. + (mail-sendmail-undelimit-header) + (setq delimline (point-marker)) + (if mail-aliases + (expand-mail-aliases (point-min) delimline)) + (goto-char (point-min)) + ;; ignore any blank lines in the header + (while (and (re-search-forward "\n\n\n*" delimline t) + (< (point) delimline)) + (replace-match "\n")) + (let ((case-fold-search t)) + ;; We used to process Resent-... headers here, + ;; but it was not done properly, and the job + ;; is done correctly in `smtpmail-deduce-address-list'. + ;; Don't send out a blank subject line + (goto-char (point-min)) + (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) + (replace-match "") + ;; This one matches a Subject just before the header delimiter. + (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) + (= (match-end 0) delimline)) + (replace-match ""))) + ;; Put the "From:" field in unless for some odd reason + ;; they put one in themselves. + (goto-char (point-min)) + (if (not (re-search-forward "^From:" delimline t)) + (let* ((login smtpmail-mail-address) + (fullname (user-full-name))) + (cond ((eq mail-from-style 'angles) + (insert "From: " fullname) + (let ((fullname-start (+ (point-min) 6)) + (fullname-end (point-marker))) + (goto-char fullname-start) + ;; Look for a character that cannot appear unquoted + ;; according to RFC 822 or its successors. + (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" + fullname-end 1) + (progn + ;; Quote fullname, escaping specials. + (goto-char fullname-start) + (insert "\"") + (while (re-search-forward "[\"\\]" + fullname-end 1) + (replace-match "\\\\\\&" t)) + (insert "\"")))) + (insert " <" login ">\n")) + ((eq mail-from-style 'parens) + (insert "From: " login " (") + (let ((fullname-start (point))) + (insert fullname) + (let ((fullname-end (point-marker))) + (goto-char fullname-start) + ;; RFC 822 and its successors say \ and + ;; nonmatching parentheses must be + ;; escaped in comments. + ;; Escape every instance of ()\ ... + (while (re-search-forward "[()\\]" fullname-end 1) + (replace-match "\\\\\\&" t)) + ;; ... then undo escaping of matching parentheses, + ;; including matching nested parentheses. + (goto-char fullname-start) + (while (re-search-forward + "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" + fullname-end 1) + (replace-match "\\1(\\3)" t) + (goto-char fullname-start)))) + (insert ")\n")) + ((null mail-from-style) + (insert "From: " login "\n"))))) + ;; Insert a `Message-Id:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Message-Id:" delimline t) + (insert "Message-Id: " (message-make-message-id) "\n")) + ;; Insert a `Date:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Date:" delimline t) + (insert "Date: " (message-make-date) "\n")) + ;; Possibly add a MIME header for the current coding system + (let (charset) + (goto-char (point-min)) + (and (eq mail-send-nonascii 'mime) + (not (re-search-forward "^MIME-version:" delimline t)) + (progn (skip-chars-forward "\0-\177") + (/= (point) (point-max))) + smtpmail-code-conv-from + (setq charset + (coding-system-get smtpmail-code-conv-from + 'mime-charset)) + (goto-char delimline) + (insert "MIME-version: 1.0\n" + "Content-type: text/plain; charset=" + (symbol-name charset) + "\nContent-Transfer-Encoding: 8bit\n"))) + ;; Insert an extra newline if we need it to work around + ;; Sun's bug that swallows newlines. + (goto-char (1+ delimline)) + ;; Find and handle any Fcc fields. + (goto-char (point-min)) + (if (re-search-forward "^Fcc:" delimline t) + ;; Force `mail-do-fcc' to use the encoding of the mail + ;; buffer to encode outgoing messages on Fcc files. + (let ((coding-system-for-write + ;; mbox files must have Unix EOLs. + (coding-system-change-eol-conversion + smtpmail-code-conv-from 'unix))) + (mail-do-fcc delimline))) + (if mail-interactive + (with-current-buffer errbuf + (erase-buffer)))) + ;; Encode the header according to RFC2047. + (mail-encode-header (point-min) delimline) + ;; + (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) + (setq smtpmail-recipient-address-list + (smtpmail-deduce-address-list tembuf (point-min) delimline)) + (kill-buffer smtpmail-address-buffer) + + (smtpmail-do-bcc delimline)))) + +(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from) + (let* ((file-data + (expand-file-name + (format "%s_%i" + (format-time-string "%Y-%m-%d_%H:%M:%S") + (setq smtpmail-queue-counter + (1+ smtpmail-queue-counter))) + smtpmail-queue-dir)) + (file-data (convert-standard-filename file-data)) + (file-elisp (concat file-data ".el")) + (buffer-data (create-file-buffer file-data))) + (unless (file-exists-p smtpmail-queue-dir) + (make-directory smtpmail-queue-dir t)) + (with-current-buffer buffer-data + (erase-buffer) + (set-buffer-file-coding-system + ;; We will be reading the file with no-conversion in + ;; smtpmail-send-queued-mail below, so write it out + ;; with Unix EOLs. + (coding-system-change-eol-conversion + (or smtpmail-code-conv-from 'undecided) + 'unix) + nil t) + (insert-buffer-substring tembuf) + (write-file file-data) + (let ((coding-system-for-write 'utf-8)) + (with-temp-buffer + (insert "(setq ") + (dolist (var (cons 'smtpmail-recipient-address-list + ;; Perhaps store the server etc. + (and smtpmail-store-queue-variables + smtpmail--stored-queue-variables))) + (insert (format " %s %S\n" var (symbol-value var)))) + (insert ")\n") + (write-region (point-min) (point-max) file-elisp + nil 'silent))) + (write-region (concat file-data "\n") nil + (expand-file-name smtpmail-queue-index-file + smtpmail-queue-dir) + t 'silent)) + (kill-buffer buffer-data))) + +(defun smtpmail-send-mail (tembuf) + (if (not (null smtpmail-recipient-address-list)) + (when (setq result + (smtpmail-via-smtp + smtpmail-recipient-address-list tembuf)) + (error "Sending failed: %s" + (smtpmail--sanitize-error-message result))) + (error "Sending failed; no recipients"))) ;;;###autoload (defun smtpmail-send-it () (let ((errbuf (if mail-interactive (generate-new-buffer " smtpmail errors") 0)) - (tembuf (generate-new-buffer " smtpmail temp")) - (case-fold-search nil) - delimline - result - (mailbuf (current-buffer)) - ;; Examine this variable now, so that - ;; local binding in the mail buffer will take effect. - (smtpmail-mail-address - (save-restriction - ;; Only look at the headers when fetching the - ;; envelope address. - (message-narrow-to-headers) - (or (and mail-specify-envelope-from (mail-envelope-from)) - (let ((from (mail-fetch-field "from"))) - (and from - (cadr (mail-extract-address-components from)))) - (smtpmail-user-mail-address)))) - (smtpmail-code-conv-from - (if enable-multibyte-characters - (let ((sendmail-coding-system smtpmail-code-conv-from)) - (select-message-coding-system))))) + (tembuf (generate-new-buffer " smtpmail temp"))) (unwind-protect - (with-current-buffer tembuf - (erase-buffer) - ;; Use the same `buffer-file-coding-system' as in the mail - ;; buffer, otherwise any `write-region' invocations (e.g., in - ;; mail-do-fcc below) will annoy with asking for a suitable - ;; encoding. - (set-buffer-file-coding-system smtpmail-code-conv-from nil t) - (insert-buffer-substring mailbuf) - (goto-char (point-max)) - ;; require one newline at the end. - (or (= (preceding-char) ?\n) - (insert ?\n)) - ;; Change header-delimiter to be what sendmail expects. - (mail-sendmail-undelimit-header) - (setq delimline (point-marker)) - ;; (sendmail-synch-aliases) - (if mail-aliases - (expand-mail-aliases (point-min) delimline)) - (goto-char (point-min)) - ;; ignore any blank lines in the header - (while (and (re-search-forward "\n\n\n*" delimline t) - (< (point) delimline)) - (replace-match "\n")) - (let ((case-fold-search t)) - ;; We used to process Resent-... headers here, - ;; but it was not done properly, and the job - ;; is done correctly in `smtpmail-deduce-address-list'. - ;; Don't send out a blank subject line - (goto-char (point-min)) - (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) - (replace-match "") - ;; This one matches a Subject just before the header delimiter. - (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) - (= (match-end 0) delimline)) - (replace-match ""))) - ;; Put the "From:" field in unless for some odd reason - ;; they put one in themselves. - (goto-char (point-min)) - (if (not (re-search-forward "^From:" delimline t)) - (let* ((login smtpmail-mail-address) - (fullname (user-full-name))) - (cond ((eq mail-from-style 'angles) - (insert "From: " fullname) - (let ((fullname-start (+ (point-min) 6)) - (fullname-end (point-marker))) - (goto-char fullname-start) - ;; Look for a character that cannot appear unquoted - ;; according to RFC 822 or its successors. - (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" - fullname-end 1) - (progn - ;; Quote fullname, escaping specials. - (goto-char fullname-start) - (insert "\"") - (while (re-search-forward "[\"\\]" - fullname-end 1) - (replace-match "\\\\\\&" t)) - (insert "\"")))) - (insert " <" login ">\n")) - ((eq mail-from-style 'parens) - (insert "From: " login " (") - (let ((fullname-start (point))) - (insert fullname) - (let ((fullname-end (point-marker))) - (goto-char fullname-start) - ;; RFC 822 and its successors say \ and - ;; nonmatching parentheses must be - ;; escaped in comments. - ;; Escape every instance of ()\ ... - (while (re-search-forward "[()\\]" fullname-end 1) - (replace-match "\\\\\\&" t)) - ;; ... then undo escaping of matching parentheses, - ;; including matching nested parentheses. - (goto-char fullname-start) - (while (re-search-forward - "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" - fullname-end 1) - (replace-match "\\1(\\3)" t) - (goto-char fullname-start)))) - (insert ")\n")) - ((null mail-from-style) - (insert "From: " login "\n"))))) - ;; Insert a `Message-Id:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Message-Id:" delimline t) - (insert "Message-Id: " (message-make-message-id) "\n")) - ;; Insert a `Date:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Date:" delimline t) - (insert "Date: " (message-make-date) "\n")) - ;; Possibly add a MIME header for the current coding system - (let (charset) - (goto-char (point-min)) - (and (eq mail-send-nonascii 'mime) - (not (re-search-forward "^MIME-version:" delimline t)) - (progn (skip-chars-forward "\0-\177") - (/= (point) (point-max))) - smtpmail-code-conv-from - (setq charset - (coding-system-get smtpmail-code-conv-from - 'mime-charset)) - (goto-char delimline) - (insert "MIME-version: 1.0\n" - "Content-type: text/plain; charset=" - (symbol-name charset) - "\nContent-Transfer-Encoding: 8bit\n"))) - ;; Insert an extra newline if we need it to work around - ;; Sun's bug that swallows newlines. - (goto-char (1+ delimline)) - ;; Find and handle any Fcc fields. - (goto-char (point-min)) - (if (re-search-forward "^Fcc:" delimline t) - ;; Force `mail-do-fcc' to use the encoding of the mail - ;; buffer to encode outgoing messages on Fcc files. - (let ((coding-system-for-write - ;; mbox files must have Unix EOLs. - (coding-system-change-eol-conversion - smtpmail-code-conv-from 'unix))) - (mail-do-fcc delimline))) - (if mail-interactive - (with-current-buffer errbuf - (erase-buffer)))) - ;; Encode the header according to RFC2047. - (mail-encode-header (point-min) delimline) - ;; - (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) - (setq smtpmail-recipient-address-list - (smtpmail-deduce-address-list tembuf (point-min) delimline)) - (kill-buffer smtpmail-address-buffer) - - (smtpmail-do-bcc delimline) - ;; Send or queue - (if (not smtpmail-queue-mail) - (if (not (null smtpmail-recipient-address-list)) - (when (setq result - (smtpmail-via-smtp - smtpmail-recipient-address-list tembuf)) - (error "Sending failed: %s" - (smtpmail--sanitize-error-message result))) - (error "Sending failed; no recipients")) - (let* ((file-data - (expand-file-name - (format "%s_%i" - (format-time-string "%Y-%m-%d_%H:%M:%S") - (setq smtpmail-queue-counter - (1+ smtpmail-queue-counter))) - smtpmail-queue-dir)) - (file-data (convert-standard-filename file-data)) - (file-elisp (concat file-data ".el")) - (buffer-data (create-file-buffer file-data))) - (unless (file-exists-p smtpmail-queue-dir) - (make-directory smtpmail-queue-dir t)) - (with-current-buffer buffer-data - (erase-buffer) - (set-buffer-file-coding-system - ;; We will be reading the file with no-conversion in - ;; smtpmail-send-queued-mail below, so write it out - ;; with Unix EOLs. - (coding-system-change-eol-conversion - (or smtpmail-code-conv-from 'undecided) - 'unix) - nil t) - (insert-buffer-substring tembuf) - (write-file file-data) - (let ((coding-system-for-write 'utf-8)) - (with-temp-buffer - (insert "(setq ") - (dolist (var (cons 'smtpmail-recipient-address-list - ;; Perhaps store the server etc. - (and smtpmail-store-queue-variables - smtpmail--stored-queue-variables))) - (insert (format " %s %S\n" var (symbol-value var)))) - (insert ")\n") - (write-region (point-min) (point-max) file-elisp - nil 'silent))) - (write-region (concat file-data "\n") nil - (expand-file-name smtpmail-queue-index-file - smtpmail-queue-dir) - t 'silent)) - (kill-buffer buffer-data)))) + (let ((smtpmail-code-conv-from + (if enable-multibyte-characters + (let ((sendmail-coding-system smtpmail-code-conv-from)) + (select-message-coding-system))))) + (smtpmail-prepare-mail tembuf errbuf smtpmail-code-conv-from) + (if smtpmail-queue-mail + (smtpmail-queue-mail tembuf smtpmail-code-conv-from) + (smtpmail-send-mail tembuf))) (kill-buffer tembuf) (if (bufferp errbuf) (kill-buffer errbuf))))) -- 2.40.0 [-- Attachment #3: Type: text/plain, Size: 7350 bytes --] In GNU Emacs 30.0.50 (build 1, x86_64-unknown-openbsd7.3, cairo version 1.17.8) of 2023-05-05 built on computer Repository revision: f204c4a6cfa77fdbb2573b728110576e206b0b20 Repository branch: master Windowing system distributor 'The X.Org Foundation', version 11.0.12101006 System Description: OpenBSD computer 7.3 GENERIC.MP#1125 amd64 Configured using: 'configure --prefix=/home/manuel/emacs --bindir=/home/manuel/bin --with-x-toolkit=no --without-sound --without-compress-install CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib' Configured features: CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG JSON LCMS2 LIBOTF LIBXML2 MODULES NOTIFY KQUEUE OLDXMENU PDUMPER PNG RSVG SQLITE3 THREADS TIFF TREE_SITTER WEBP X11 XDBE XIM XINPUT2 XPM ZLIB Important settings: value of $LC_ALL: en_US.UTF-8 locale-coding-system: utf-8-unix Major mode: Magit Minor modes in effect: global-git-commit-mode: t magit-auto-revert-mode: t display-time-mode: t display-battery-mode: t server-mode: t shell-dirtrack-mode: t override-global-mode: t repeat-mode: t desktop-save-mode: t global-eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t buffer-read-only: t line-number-mode: t indent-tabs-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t Load-path shadows: /home/manuel/.emacs.d/elpa/ef-themes-0.11.0/theme-loaddefs hides /home/manuel/emacs/share/emacs/30.0.50/lisp/theme-loaddefs /home/manuel/.emacs.d/elpa/transient-0.3.7/transient hides /home/manuel/emacs/share/emacs/30.0.50/lisp/transient Features: (shadow goto-addr dabbrev emacsbug whitespace magit-patch misearch multi-isearch magit-extras face-remap magit-submodule magit-obsolete magit-blame magit-stash magit-reflog magit-bisect magit-push magit-pull magit-fetch magit-clone magit-remote magit-commit magit-sequence magit-notes magit-worktree magit-tag magit-merge magit-branch magit-reset magit-files magit-refs magit-status magit magit-repos magit-apply magit-wip magit-log which-func imenu magit-diff smerge-mode diff git-commit log-edit add-log magit-core magit-autorevert magit-margin magit-transient magit-process with-editor magit-mode transient magit-git magit-section magit-utils dash shr-color gnus-cite gnus-async gnus-bcklg gnus-ml gnus-topic mm-archive url-cache qp utf-7 imap rfc2104 nndoc nndraft nnmh nnfolder nnml gnus-agent gnus-srvr gnus-score score-mode nnvirtual nntp gnus-cache nnrss mm-url network-stream mailalias textsec uni-scripts idna-mapping ucs-normalize uni-confusable textsec-check sort mail-extr pulse tabify cus-edit cus-start cl-print smtpmail help-fns radix-tree vc-bzr vc-src vc-sccs vc-cvs vc-rcs log-view pcvs-util sh-script smie treesit executable vc-hg conf-mode view pascal vc mule-util hi-lock autorevert filenotify vc-git diff-mode vc-dispatcher vc-svn bug-reference paredit gnus-dired time battery cus-load exwm-randr xcb-randr exwm-config ido exwm exwm-input xcb-keysyms xcb-xkb exwm-manage exwm-floating xcb-cursor xcb-render exwm-layout exwm-workspace exwm-core xcb-ewmh xcb-icccm xcb xcb-xproto xcb-types xcb-debug server modus-operandi-theme modus-themes zone speed-type url-http url-auth url-gw nsm compat ytdious mingus libmpdee reporter edebug debug backtrace transmission color calc-bin calc-ext calc calc-loaddefs rect calc-macs supercite regi ebdb-message ebdb-gnus gnus-msg gnus-art mm-uu mml2015 mm-view mml-smime smime gnutls dig gnus-sum shr pixel-fill kinsoku url-file svg dom gnus-group gnus-undo gnus-start gnus-dbus gnus-cloud nnimap nnmail mail-source utf7 nnoo gnus-spec gnus-int gnus-range message sendmail yank-media puny rfc822 mml mml-sec epa epg rfc6068 epg-config mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 ietf-drums gmm-utils mailheader gnus-win gnus nnheader gnus-util mail-utils range mm-util mail-prsvr wid-edit ebdb-mua ebdb-com crm ebdb-format ebdb mailabbrev eieio-opt speedbar ezimage dframe find-func eieio-base pcase timezone visual-basic-mode cl web-mode derived disp-table erlang-start smart-tabs-mode skeleton cc-mode cc-fonts cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs slime-asdf grep slime-tramp tramp rx tramp-loaddefs trampver tramp-integration files-x tramp-compat xdg shell pcomplete parse-time iso8601 time-date ls-lisp format-spec slime-fancy slime-indentation slime-cl-indent cl-indent slime-trace-dialog slime-fontifying-fu slime-package-fu slime-references slime-compiler-notes-tree advice slime-scratch slime-presentations bridge slime-macrostep macrostep slime-mdot-fu slime-enclosing-context slime-fuzzy slime-fancy-trace slime-fancy-inspector slime-c-p-c slime-editing-commands slime-autodoc slime-repl slime-parse slime apropos compile text-property-search etags fileloop generator xref project arc-mode archive-mode noutline outline icons pp comint ansi-osc ansi-color ring hyperspec thingatpt slime-autoloads edmacro kmacro use-package-bind-key bind-key appt diary-lib diary-loaddefs cal-menu calendar cal-loaddefs dired-x dired-aux dired dired-loaddefs notifications dbus xml cl-extra help-mode use-package-core repeat easy-mmode desktop frameset rust-mode-autoloads speed-type-autoloads osm-autoloads ebdb-autoloads compat-autoloads magit-autoloads debbugs-autoloads git-commit-autoloads magit-section-autoloads ef-themes-autoloads with-editor-autoloads paredit-autoloads dash-autoloads ytdious-autoloads transmission-autoloads transient-autoloads exwm-autoloads hyperbole-autoloads detached-autoloads info package browse-url url url-proxy url-privacy url-expand url-methods url-history url-cookie generate-lisp-file url-domsuf url-util mailcap url-handlers url-parse auth-source cl-seq eieio eieio-core cl-macs password-cache json subr-x map byte-opt gv bytecomp byte-compile url-vars cl-loaddefs cl-lib rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads dbusbind kqueue lcms2 dynamic-setting system-font-setting font-render-setting cairo xinput2 x multi-tty make-network-process emacs) Memory information: ((conses 16 933133 308956) (symbols 48 55180 35) (strings 32 272198 12320) (string-bytes 1 8555283) (vectors 16 173055) (vector-slots 8 2925695 155806) (floats 8 544 5262) (intervals 56 18111 2469) (buffers 984 113)) -- Manuel Giraud ^ permalink raw reply related [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-05 13:13 bug#63311: 30.0.50; [PATCH] smtpmail-send-it split Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-05 18:57 ` Eli Zaretskii [not found] ` <874joq34bk.fsf@ledu-giraud.fr> 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-05-05 18:57 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > Date: Fri, 05 May 2023 15:13:32 +0200 > From: Manuel Giraud via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> > > BTW, does anyone know the purpose of 'errbuf': I see it is created then > erased and then killed? Looks like a left-over from when this function was written. It is basically a rewrite of sendmail-send-it, which does use that variable. ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <874joq34bk.fsf@ledu-giraud.fr>]
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split [not found] ` <874joq34bk.fsf@ledu-giraud.fr> @ 2023-05-06 6:20 ` Eli Zaretskii 2023-05-06 9:34 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-09 9:52 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 2 replies; 41+ messages in thread From: Eli Zaretskii @ 2023-05-06 6:20 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Date: Fri, 05 May 2023 22:34:39 +0200 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> Date: Fri, 05 May 2023 15:13:32 +0200 > >> From: Manuel Giraud via "Bug reports for GNU Emacs, > >> the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> > >> > >> BTW, does anyone know the purpose of 'errbuf': I see it is created then > >> erased and then killed? > > > > Looks like a left-over from when this function was written. It is > > basically a rewrite of sendmail-send-it, which does use that variable. > > Ok. Do you want me to upgrade this patch removing errbuf? Sure, that's a good cleanup. (And please use Reply All, to have this discussion recorded by the tracker.) ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-06 6:20 ` Eli Zaretskii @ 2023-05-06 9:34 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-09 9:52 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 0 replies; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-06 9:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 [-- Attachment #1: Type: text/plain, Size: 282 bytes --] Eli Zaretskii <eliz@gnu.org> writes: [...] >> Ok. Do you want me to upgrade this patch removing errbuf? > > Sure, that's a good cleanup. Ok. Here is the modified patch. > (And please use Reply All, to have this discussion recorded by the > tracker.) Sure. Sorry about that. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-smtpmail-send-it-split.patch --] [-- Type: text/x-patch, Size: 18269 bytes --] From dfcaa8d0b9ec3fa0087326bb06dcdda5895f7142 Mon Sep 17 00:00:00 2001 From: Manuel Giraud <manuel@ledu-giraud.fr> Date: Fri, 5 May 2023 14:35:01 +0200 Subject: [PATCH] smtpmail-send-it split * lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function that prepares the mail with current buffer content. (smtpmail-queue-mail): New function to queue a mail (prepared by 'smtpmail-prepare-mail'). (smtpmail-send-mail): New function to send a mail (prepared by 'smtpmail-send-mail'). (smtpmail-send-it): Use all three previous functions. While here, remove 'errbuf' leftovers. --- lisp/mail/smtpmail.el | 411 +++++++++++++++++++++--------------------- 1 file changed, 204 insertions(+), 207 deletions(-) diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el index 78688d170cc..2c23e97afd0 100644 --- a/lisp/mail/smtpmail.el +++ b/lisp/mail/smtpmail.el @@ -205,217 +205,214 @@ smtpmail-mail-address "Value to use for envelope-from address for mail from ambient buffer.") ;;; Functions +(defun smtpmail-prepare-mail (tembuf smtpmail-code-conv-from) + (let ((case-fold-search nil) + delimline + (mailbuf (current-buffer)) + ;; Examine this variable now, so that + ;; local binding in the mail buffer will take effect. + (smtpmail-mail-address + (save-restriction + ;; Only look at the headers when fetching the + ;; envelope address. + (message-narrow-to-headers) + (or (and mail-specify-envelope-from (mail-envelope-from)) + (let ((from (mail-fetch-field "from"))) + (and from + (cadr (mail-extract-address-components from)))) + (smtpmail-user-mail-address))))) + (with-current-buffer tembuf + (erase-buffer) + ;; Use the same `buffer-file-coding-system' as in the mail + ;; buffer, otherwise any `write-region' invocations (e.g., in + ;; mail-do-fcc below) will annoy with asking for a suitable + ;; encoding. + (set-buffer-file-coding-system smtpmail-code-conv-from nil t) + (insert-buffer-substring mailbuf) + (goto-char (point-max)) + ;; require one newline at the end. + (or (= (preceding-char) ?\n) + (insert ?\n)) + ;; Change header-delimiter to be what sendmail expects. + (mail-sendmail-undelimit-header) + (setq delimline (point-marker)) + (if mail-aliases + (expand-mail-aliases (point-min) delimline)) + (goto-char (point-min)) + ;; ignore any blank lines in the header + (while (and (re-search-forward "\n\n\n*" delimline t) + (< (point) delimline)) + (replace-match "\n")) + (let ((case-fold-search t)) + ;; We used to process Resent-... headers here, + ;; but it was not done properly, and the job + ;; is done correctly in `smtpmail-deduce-address-list'. + ;; Don't send out a blank subject line + (goto-char (point-min)) + (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) + (replace-match "") + ;; This one matches a Subject just before the header delimiter. + (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) + (= (match-end 0) delimline)) + (replace-match ""))) + ;; Put the "From:" field in unless for some odd reason + ;; they put one in themselves. + (goto-char (point-min)) + (if (not (re-search-forward "^From:" delimline t)) + (let* ((login smtpmail-mail-address) + (fullname (user-full-name))) + (cond ((eq mail-from-style 'angles) + (insert "From: " fullname) + (let ((fullname-start (+ (point-min) 6)) + (fullname-end (point-marker))) + (goto-char fullname-start) + ;; Look for a character that cannot appear unquoted + ;; according to RFC 822 or its successors. + (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" + fullname-end 1) + (progn + ;; Quote fullname, escaping specials. + (goto-char fullname-start) + (insert "\"") + (while (re-search-forward "[\"\\]" + fullname-end 1) + (replace-match "\\\\\\&" t)) + (insert "\"")))) + (insert " <" login ">\n")) + ((eq mail-from-style 'parens) + (insert "From: " login " (") + (let ((fullname-start (point))) + (insert fullname) + (let ((fullname-end (point-marker))) + (goto-char fullname-start) + ;; RFC 822 and its successors say \ and + ;; nonmatching parentheses must be + ;; escaped in comments. + ;; Escape every instance of ()\ ... + (while (re-search-forward "[()\\]" fullname-end 1) + (replace-match "\\\\\\&" t)) + ;; ... then undo escaping of matching parentheses, + ;; including matching nested parentheses. + (goto-char fullname-start) + (while (re-search-forward + "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" + fullname-end 1) + (replace-match "\\1(\\3)" t) + (goto-char fullname-start)))) + (insert ")\n")) + ((null mail-from-style) + (insert "From: " login "\n"))))) + ;; Insert a `Message-Id:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Message-Id:" delimline t) + (insert "Message-Id: " (message-make-message-id) "\n")) + ;; Insert a `Date:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Date:" delimline t) + (insert "Date: " (message-make-date) "\n")) + ;; Possibly add a MIME header for the current coding system + (let (charset) + (goto-char (point-min)) + (and (eq mail-send-nonascii 'mime) + (not (re-search-forward "^MIME-version:" delimline t)) + (progn (skip-chars-forward "\0-\177") + (/= (point) (point-max))) + smtpmail-code-conv-from + (setq charset + (coding-system-get smtpmail-code-conv-from + 'mime-charset)) + (goto-char delimline) + (insert "MIME-version: 1.0\n" + "Content-type: text/plain; charset=" + (symbol-name charset) + "\nContent-Transfer-Encoding: 8bit\n"))) + ;; Insert an extra newline if we need it to work around + ;; Sun's bug that swallows newlines. + (goto-char (1+ delimline)) + ;; Find and handle any Fcc fields. + (goto-char (point-min)) + (if (re-search-forward "^Fcc:" delimline t) + ;; Force `mail-do-fcc' to use the encoding of the mail + ;; buffer to encode outgoing messages on Fcc files. + (let ((coding-system-for-write + ;; mbox files must have Unix EOLs. + (coding-system-change-eol-conversion + smtpmail-code-conv-from 'unix))) + (mail-do-fcc delimline)))) + ;; Encode the header according to RFC2047. + (mail-encode-header (point-min) delimline) + ;; + (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) + (setq smtpmail-recipient-address-list + (smtpmail-deduce-address-list tembuf (point-min) delimline)) + (kill-buffer smtpmail-address-buffer) + + (smtpmail-do-bcc delimline)))) + +(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from) + (let* ((file-data + (expand-file-name + (format "%s_%i" + (format-time-string "%Y-%m-%d_%H:%M:%S") + (setq smtpmail-queue-counter + (1+ smtpmail-queue-counter))) + smtpmail-queue-dir)) + (file-data (convert-standard-filename file-data)) + (file-elisp (concat file-data ".el")) + (buffer-data (create-file-buffer file-data))) + (unless (file-exists-p smtpmail-queue-dir) + (make-directory smtpmail-queue-dir t)) + (with-current-buffer buffer-data + (erase-buffer) + (set-buffer-file-coding-system + ;; We will be reading the file with no-conversion in + ;; smtpmail-send-queued-mail below, so write it out + ;; with Unix EOLs. + (coding-system-change-eol-conversion + (or smtpmail-code-conv-from 'undecided) + 'unix) + nil t) + (insert-buffer-substring tembuf) + (write-file file-data) + (let ((coding-system-for-write 'utf-8)) + (with-temp-buffer + (insert "(setq ") + (dolist (var (cons 'smtpmail-recipient-address-list + ;; Perhaps store the server etc. + (and smtpmail-store-queue-variables + smtpmail--stored-queue-variables))) + (insert (format " %s %S\n" var (symbol-value var)))) + (insert ")\n") + (write-region (point-min) (point-max) file-elisp + nil 'silent))) + (write-region (concat file-data "\n") nil + (expand-file-name smtpmail-queue-index-file + smtpmail-queue-dir) + t 'silent)) + (kill-buffer buffer-data))) + +(defun smtpmail-send-mail (tembuf) + (if (not (null smtpmail-recipient-address-list)) + (when (setq result + (smtpmail-via-smtp + smtpmail-recipient-address-list tembuf)) + (error "Sending failed: %s" + (smtpmail--sanitize-error-message result))) + (error "Sending failed; no recipients"))) ;;;###autoload (defun smtpmail-send-it () - (let ((errbuf (if mail-interactive - (generate-new-buffer " smtpmail errors") - 0)) - (tembuf (generate-new-buffer " smtpmail temp")) - (case-fold-search nil) - delimline - result - (mailbuf (current-buffer)) - ;; Examine this variable now, so that - ;; local binding in the mail buffer will take effect. - (smtpmail-mail-address - (save-restriction - ;; Only look at the headers when fetching the - ;; envelope address. - (message-narrow-to-headers) - (or (and mail-specify-envelope-from (mail-envelope-from)) - (let ((from (mail-fetch-field "from"))) - (and from - (cadr (mail-extract-address-components from)))) - (smtpmail-user-mail-address)))) - (smtpmail-code-conv-from - (if enable-multibyte-characters - (let ((sendmail-coding-system smtpmail-code-conv-from)) - (select-message-coding-system))))) + (let ((tembuf (generate-new-buffer " smtpmail temp"))) (unwind-protect - (with-current-buffer tembuf - (erase-buffer) - ;; Use the same `buffer-file-coding-system' as in the mail - ;; buffer, otherwise any `write-region' invocations (e.g., in - ;; mail-do-fcc below) will annoy with asking for a suitable - ;; encoding. - (set-buffer-file-coding-system smtpmail-code-conv-from nil t) - (insert-buffer-substring mailbuf) - (goto-char (point-max)) - ;; require one newline at the end. - (or (= (preceding-char) ?\n) - (insert ?\n)) - ;; Change header-delimiter to be what sendmail expects. - (mail-sendmail-undelimit-header) - (setq delimline (point-marker)) - ;; (sendmail-synch-aliases) - (if mail-aliases - (expand-mail-aliases (point-min) delimline)) - (goto-char (point-min)) - ;; ignore any blank lines in the header - (while (and (re-search-forward "\n\n\n*" delimline t) - (< (point) delimline)) - (replace-match "\n")) - (let ((case-fold-search t)) - ;; We used to process Resent-... headers here, - ;; but it was not done properly, and the job - ;; is done correctly in `smtpmail-deduce-address-list'. - ;; Don't send out a blank subject line - (goto-char (point-min)) - (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) - (replace-match "") - ;; This one matches a Subject just before the header delimiter. - (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) - (= (match-end 0) delimline)) - (replace-match ""))) - ;; Put the "From:" field in unless for some odd reason - ;; they put one in themselves. - (goto-char (point-min)) - (if (not (re-search-forward "^From:" delimline t)) - (let* ((login smtpmail-mail-address) - (fullname (user-full-name))) - (cond ((eq mail-from-style 'angles) - (insert "From: " fullname) - (let ((fullname-start (+ (point-min) 6)) - (fullname-end (point-marker))) - (goto-char fullname-start) - ;; Look for a character that cannot appear unquoted - ;; according to RFC 822 or its successors. - (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" - fullname-end 1) - (progn - ;; Quote fullname, escaping specials. - (goto-char fullname-start) - (insert "\"") - (while (re-search-forward "[\"\\]" - fullname-end 1) - (replace-match "\\\\\\&" t)) - (insert "\"")))) - (insert " <" login ">\n")) - ((eq mail-from-style 'parens) - (insert "From: " login " (") - (let ((fullname-start (point))) - (insert fullname) - (let ((fullname-end (point-marker))) - (goto-char fullname-start) - ;; RFC 822 and its successors say \ and - ;; nonmatching parentheses must be - ;; escaped in comments. - ;; Escape every instance of ()\ ... - (while (re-search-forward "[()\\]" fullname-end 1) - (replace-match "\\\\\\&" t)) - ;; ... then undo escaping of matching parentheses, - ;; including matching nested parentheses. - (goto-char fullname-start) - (while (re-search-forward - "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" - fullname-end 1) - (replace-match "\\1(\\3)" t) - (goto-char fullname-start)))) - (insert ")\n")) - ((null mail-from-style) - (insert "From: " login "\n"))))) - ;; Insert a `Message-Id:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Message-Id:" delimline t) - (insert "Message-Id: " (message-make-message-id) "\n")) - ;; Insert a `Date:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Date:" delimline t) - (insert "Date: " (message-make-date) "\n")) - ;; Possibly add a MIME header for the current coding system - (let (charset) - (goto-char (point-min)) - (and (eq mail-send-nonascii 'mime) - (not (re-search-forward "^MIME-version:" delimline t)) - (progn (skip-chars-forward "\0-\177") - (/= (point) (point-max))) - smtpmail-code-conv-from - (setq charset - (coding-system-get smtpmail-code-conv-from - 'mime-charset)) - (goto-char delimline) - (insert "MIME-version: 1.0\n" - "Content-type: text/plain; charset=" - (symbol-name charset) - "\nContent-Transfer-Encoding: 8bit\n"))) - ;; Insert an extra newline if we need it to work around - ;; Sun's bug that swallows newlines. - (goto-char (1+ delimline)) - ;; Find and handle any Fcc fields. - (goto-char (point-min)) - (if (re-search-forward "^Fcc:" delimline t) - ;; Force `mail-do-fcc' to use the encoding of the mail - ;; buffer to encode outgoing messages on Fcc files. - (let ((coding-system-for-write - ;; mbox files must have Unix EOLs. - (coding-system-change-eol-conversion - smtpmail-code-conv-from 'unix))) - (mail-do-fcc delimline))) - (if mail-interactive - (with-current-buffer errbuf - (erase-buffer)))) - ;; Encode the header according to RFC2047. - (mail-encode-header (point-min) delimline) - ;; - (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) - (setq smtpmail-recipient-address-list - (smtpmail-deduce-address-list tembuf (point-min) delimline)) - (kill-buffer smtpmail-address-buffer) - - (smtpmail-do-bcc delimline) - ;; Send or queue - (if (not smtpmail-queue-mail) - (if (not (null smtpmail-recipient-address-list)) - (when (setq result - (smtpmail-via-smtp - smtpmail-recipient-address-list tembuf)) - (error "Sending failed: %s" - (smtpmail--sanitize-error-message result))) - (error "Sending failed; no recipients")) - (let* ((file-data - (expand-file-name - (format "%s_%i" - (format-time-string "%Y-%m-%d_%H:%M:%S") - (setq smtpmail-queue-counter - (1+ smtpmail-queue-counter))) - smtpmail-queue-dir)) - (file-data (convert-standard-filename file-data)) - (file-elisp (concat file-data ".el")) - (buffer-data (create-file-buffer file-data))) - (unless (file-exists-p smtpmail-queue-dir) - (make-directory smtpmail-queue-dir t)) - (with-current-buffer buffer-data - (erase-buffer) - (set-buffer-file-coding-system - ;; We will be reading the file with no-conversion in - ;; smtpmail-send-queued-mail below, so write it out - ;; with Unix EOLs. - (coding-system-change-eol-conversion - (or smtpmail-code-conv-from 'undecided) - 'unix) - nil t) - (insert-buffer-substring tembuf) - (write-file file-data) - (let ((coding-system-for-write 'utf-8)) - (with-temp-buffer - (insert "(setq ") - (dolist (var (cons 'smtpmail-recipient-address-list - ;; Perhaps store the server etc. - (and smtpmail-store-queue-variables - smtpmail--stored-queue-variables))) - (insert (format " %s %S\n" var (symbol-value var)))) - (insert ")\n") - (write-region (point-min) (point-max) file-elisp - nil 'silent))) - (write-region (concat file-data "\n") nil - (expand-file-name smtpmail-queue-index-file - smtpmail-queue-dir) - t 'silent)) - (kill-buffer buffer-data)))) - (kill-buffer tembuf) - (if (bufferp errbuf) - (kill-buffer errbuf))))) + (let ((smtpmail-code-conv-from + (if enable-multibyte-characters + (let ((sendmail-coding-system smtpmail-code-conv-from)) + (select-message-coding-system))))) + (smtpmail-prepare-mail tembuf smtpmail-code-conv-from) + (if smtpmail-queue-mail + (smtpmail-queue-mail tembuf smtpmail-code-conv-from) + (smtpmail-send-mail tembuf))) + (kill-buffer tembuf)))) ;;;###autoload (defun smtpmail-send-queued-mail () -- 2.40.0 [-- Attachment #3: Type: text/plain, Size: 18 bytes --] -- Manuel Giraud ^ permalink raw reply related [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-06 6:20 ` Eli Zaretskii 2023-05-06 9:34 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-09 9:52 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-10 11:47 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-09 9:52 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 [-- Attachment #1: Type: text/plain, Size: 86 bytes --] Hi, I forgot to "declare" 'result' in smtpmail-send-it. Here is an updated version. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-smtpmail-send-it-split.patch --] [-- Type: text/x-patch, Size: 18301 bytes --] From a7786a443abebe38acd968dcd7ea2c2f2364d4a0 Mon Sep 17 00:00:00 2001 From: Manuel Giraud <manuel@ledu-giraud.fr> Date: Fri, 5 May 2023 14:35:01 +0200 Subject: [PATCH] smtpmail-send-it split * lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function that prepares the mail with current buffer content. (smtpmail-queue-mail): New function to queue a mail (prepared by 'smtpmail-prepare-mail'). (smtpmail-send-mail): New function to send a mail (prepared by 'smtpmail-send-mail'). (smtpmail-send-it): Use all three previous functions. While here, remove 'errbuf' leftovers. --- lisp/mail/smtpmail.el | 412 +++++++++++++++++++++--------------------- 1 file changed, 205 insertions(+), 207 deletions(-) diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el index 78688d170cc..714f1e14eaf 100644 --- a/lisp/mail/smtpmail.el +++ b/lisp/mail/smtpmail.el @@ -205,217 +205,215 @@ smtpmail-mail-address "Value to use for envelope-from address for mail from ambient buffer.") ;;; Functions +(defun smtpmail-prepare-mail (tembuf smtpmail-code-conv-from) + (let ((case-fold-search nil) + delimline + (mailbuf (current-buffer)) + ;; Examine this variable now, so that + ;; local binding in the mail buffer will take effect. + (smtpmail-mail-address + (save-restriction + ;; Only look at the headers when fetching the + ;; envelope address. + (message-narrow-to-headers) + (or (and mail-specify-envelope-from (mail-envelope-from)) + (let ((from (mail-fetch-field "from"))) + (and from + (cadr (mail-extract-address-components from)))) + (smtpmail-user-mail-address))))) + (with-current-buffer tembuf + (erase-buffer) + ;; Use the same `buffer-file-coding-system' as in the mail + ;; buffer, otherwise any `write-region' invocations (e.g., in + ;; mail-do-fcc below) will annoy with asking for a suitable + ;; encoding. + (set-buffer-file-coding-system smtpmail-code-conv-from nil t) + (insert-buffer-substring mailbuf) + (goto-char (point-max)) + ;; require one newline at the end. + (or (= (preceding-char) ?\n) + (insert ?\n)) + ;; Change header-delimiter to be what sendmail expects. + (mail-sendmail-undelimit-header) + (setq delimline (point-marker)) + (if mail-aliases + (expand-mail-aliases (point-min) delimline)) + (goto-char (point-min)) + ;; ignore any blank lines in the header + (while (and (re-search-forward "\n\n\n*" delimline t) + (< (point) delimline)) + (replace-match "\n")) + (let ((case-fold-search t)) + ;; We used to process Resent-... headers here, + ;; but it was not done properly, and the job + ;; is done correctly in `smtpmail-deduce-address-list'. + ;; Don't send out a blank subject line + (goto-char (point-min)) + (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) + (replace-match "") + ;; This one matches a Subject just before the header delimiter. + (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) + (= (match-end 0) delimline)) + (replace-match ""))) + ;; Put the "From:" field in unless for some odd reason + ;; they put one in themselves. + (goto-char (point-min)) + (if (not (re-search-forward "^From:" delimline t)) + (let* ((login smtpmail-mail-address) + (fullname (user-full-name))) + (cond ((eq mail-from-style 'angles) + (insert "From: " fullname) + (let ((fullname-start (+ (point-min) 6)) + (fullname-end (point-marker))) + (goto-char fullname-start) + ;; Look for a character that cannot appear unquoted + ;; according to RFC 822 or its successors. + (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" + fullname-end 1) + (progn + ;; Quote fullname, escaping specials. + (goto-char fullname-start) + (insert "\"") + (while (re-search-forward "[\"\\]" + fullname-end 1) + (replace-match "\\\\\\&" t)) + (insert "\"")))) + (insert " <" login ">\n")) + ((eq mail-from-style 'parens) + (insert "From: " login " (") + (let ((fullname-start (point))) + (insert fullname) + (let ((fullname-end (point-marker))) + (goto-char fullname-start) + ;; RFC 822 and its successors say \ and + ;; nonmatching parentheses must be + ;; escaped in comments. + ;; Escape every instance of ()\ ... + (while (re-search-forward "[()\\]" fullname-end 1) + (replace-match "\\\\\\&" t)) + ;; ... then undo escaping of matching parentheses, + ;; including matching nested parentheses. + (goto-char fullname-start) + (while (re-search-forward + "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" + fullname-end 1) + (replace-match "\\1(\\3)" t) + (goto-char fullname-start)))) + (insert ")\n")) + ((null mail-from-style) + (insert "From: " login "\n"))))) + ;; Insert a `Message-Id:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Message-Id:" delimline t) + (insert "Message-Id: " (message-make-message-id) "\n")) + ;; Insert a `Date:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Date:" delimline t) + (insert "Date: " (message-make-date) "\n")) + ;; Possibly add a MIME header for the current coding system + (let (charset) + (goto-char (point-min)) + (and (eq mail-send-nonascii 'mime) + (not (re-search-forward "^MIME-version:" delimline t)) + (progn (skip-chars-forward "\0-\177") + (/= (point) (point-max))) + smtpmail-code-conv-from + (setq charset + (coding-system-get smtpmail-code-conv-from + 'mime-charset)) + (goto-char delimline) + (insert "MIME-version: 1.0\n" + "Content-type: text/plain; charset=" + (symbol-name charset) + "\nContent-Transfer-Encoding: 8bit\n"))) + ;; Insert an extra newline if we need it to work around + ;; Sun's bug that swallows newlines. + (goto-char (1+ delimline)) + ;; Find and handle any Fcc fields. + (goto-char (point-min)) + (if (re-search-forward "^Fcc:" delimline t) + ;; Force `mail-do-fcc' to use the encoding of the mail + ;; buffer to encode outgoing messages on Fcc files. + (let ((coding-system-for-write + ;; mbox files must have Unix EOLs. + (coding-system-change-eol-conversion + smtpmail-code-conv-from 'unix))) + (mail-do-fcc delimline)))) + ;; Encode the header according to RFC2047. + (mail-encode-header (point-min) delimline) + ;; + (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) + (setq smtpmail-recipient-address-list + (smtpmail-deduce-address-list tembuf (point-min) delimline)) + (kill-buffer smtpmail-address-buffer) + + (smtpmail-do-bcc delimline)))) + +(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from) + (let* ((file-data + (expand-file-name + (format "%s_%i" + (format-time-string "%Y-%m-%d_%H:%M:%S") + (setq smtpmail-queue-counter + (1+ smtpmail-queue-counter))) + smtpmail-queue-dir)) + (file-data (convert-standard-filename file-data)) + (file-elisp (concat file-data ".el")) + (buffer-data (create-file-buffer file-data))) + (unless (file-exists-p smtpmail-queue-dir) + (make-directory smtpmail-queue-dir t)) + (with-current-buffer buffer-data + (erase-buffer) + (set-buffer-file-coding-system + ;; We will be reading the file with no-conversion in + ;; smtpmail-send-queued-mail below, so write it out + ;; with Unix EOLs. + (coding-system-change-eol-conversion + (or smtpmail-code-conv-from 'undecided) + 'unix) + nil t) + (insert-buffer-substring tembuf) + (write-file file-data) + (let ((coding-system-for-write 'utf-8)) + (with-temp-buffer + (insert "(setq ") + (dolist (var (cons 'smtpmail-recipient-address-list + ;; Perhaps store the server etc. + (and smtpmail-store-queue-variables + smtpmail--stored-queue-variables))) + (insert (format " %s %S\n" var (symbol-value var)))) + (insert ")\n") + (write-region (point-min) (point-max) file-elisp + nil 'silent))) + (write-region (concat file-data "\n") nil + (expand-file-name smtpmail-queue-index-file + smtpmail-queue-dir) + t 'silent)) + (kill-buffer buffer-data))) + +(defun smtpmail-send-mail (tembuf) + (let (result) + (if (not (null smtpmail-recipient-address-list)) + (when (setq result + (smtpmail-via-smtp + smtpmail-recipient-address-list tembuf)) + (error "Sending failed: %s" + (smtpmail--sanitize-error-message result))) + (error "Sending failed; no recipients")))) ;;;###autoload (defun smtpmail-send-it () - (let ((errbuf (if mail-interactive - (generate-new-buffer " smtpmail errors") - 0)) - (tembuf (generate-new-buffer " smtpmail temp")) - (case-fold-search nil) - delimline - result - (mailbuf (current-buffer)) - ;; Examine this variable now, so that - ;; local binding in the mail buffer will take effect. - (smtpmail-mail-address - (save-restriction - ;; Only look at the headers when fetching the - ;; envelope address. - (message-narrow-to-headers) - (or (and mail-specify-envelope-from (mail-envelope-from)) - (let ((from (mail-fetch-field "from"))) - (and from - (cadr (mail-extract-address-components from)))) - (smtpmail-user-mail-address)))) - (smtpmail-code-conv-from - (if enable-multibyte-characters - (let ((sendmail-coding-system smtpmail-code-conv-from)) - (select-message-coding-system))))) + (let ((tembuf (generate-new-buffer " smtpmail temp"))) (unwind-protect - (with-current-buffer tembuf - (erase-buffer) - ;; Use the same `buffer-file-coding-system' as in the mail - ;; buffer, otherwise any `write-region' invocations (e.g., in - ;; mail-do-fcc below) will annoy with asking for a suitable - ;; encoding. - (set-buffer-file-coding-system smtpmail-code-conv-from nil t) - (insert-buffer-substring mailbuf) - (goto-char (point-max)) - ;; require one newline at the end. - (or (= (preceding-char) ?\n) - (insert ?\n)) - ;; Change header-delimiter to be what sendmail expects. - (mail-sendmail-undelimit-header) - (setq delimline (point-marker)) - ;; (sendmail-synch-aliases) - (if mail-aliases - (expand-mail-aliases (point-min) delimline)) - (goto-char (point-min)) - ;; ignore any blank lines in the header - (while (and (re-search-forward "\n\n\n*" delimline t) - (< (point) delimline)) - (replace-match "\n")) - (let ((case-fold-search t)) - ;; We used to process Resent-... headers here, - ;; but it was not done properly, and the job - ;; is done correctly in `smtpmail-deduce-address-list'. - ;; Don't send out a blank subject line - (goto-char (point-min)) - (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) - (replace-match "") - ;; This one matches a Subject just before the header delimiter. - (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) - (= (match-end 0) delimline)) - (replace-match ""))) - ;; Put the "From:" field in unless for some odd reason - ;; they put one in themselves. - (goto-char (point-min)) - (if (not (re-search-forward "^From:" delimline t)) - (let* ((login smtpmail-mail-address) - (fullname (user-full-name))) - (cond ((eq mail-from-style 'angles) - (insert "From: " fullname) - (let ((fullname-start (+ (point-min) 6)) - (fullname-end (point-marker))) - (goto-char fullname-start) - ;; Look for a character that cannot appear unquoted - ;; according to RFC 822 or its successors. - (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" - fullname-end 1) - (progn - ;; Quote fullname, escaping specials. - (goto-char fullname-start) - (insert "\"") - (while (re-search-forward "[\"\\]" - fullname-end 1) - (replace-match "\\\\\\&" t)) - (insert "\"")))) - (insert " <" login ">\n")) - ((eq mail-from-style 'parens) - (insert "From: " login " (") - (let ((fullname-start (point))) - (insert fullname) - (let ((fullname-end (point-marker))) - (goto-char fullname-start) - ;; RFC 822 and its successors say \ and - ;; nonmatching parentheses must be - ;; escaped in comments. - ;; Escape every instance of ()\ ... - (while (re-search-forward "[()\\]" fullname-end 1) - (replace-match "\\\\\\&" t)) - ;; ... then undo escaping of matching parentheses, - ;; including matching nested parentheses. - (goto-char fullname-start) - (while (re-search-forward - "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" - fullname-end 1) - (replace-match "\\1(\\3)" t) - (goto-char fullname-start)))) - (insert ")\n")) - ((null mail-from-style) - (insert "From: " login "\n"))))) - ;; Insert a `Message-Id:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Message-Id:" delimline t) - (insert "Message-Id: " (message-make-message-id) "\n")) - ;; Insert a `Date:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Date:" delimline t) - (insert "Date: " (message-make-date) "\n")) - ;; Possibly add a MIME header for the current coding system - (let (charset) - (goto-char (point-min)) - (and (eq mail-send-nonascii 'mime) - (not (re-search-forward "^MIME-version:" delimline t)) - (progn (skip-chars-forward "\0-\177") - (/= (point) (point-max))) - smtpmail-code-conv-from - (setq charset - (coding-system-get smtpmail-code-conv-from - 'mime-charset)) - (goto-char delimline) - (insert "MIME-version: 1.0\n" - "Content-type: text/plain; charset=" - (symbol-name charset) - "\nContent-Transfer-Encoding: 8bit\n"))) - ;; Insert an extra newline if we need it to work around - ;; Sun's bug that swallows newlines. - (goto-char (1+ delimline)) - ;; Find and handle any Fcc fields. - (goto-char (point-min)) - (if (re-search-forward "^Fcc:" delimline t) - ;; Force `mail-do-fcc' to use the encoding of the mail - ;; buffer to encode outgoing messages on Fcc files. - (let ((coding-system-for-write - ;; mbox files must have Unix EOLs. - (coding-system-change-eol-conversion - smtpmail-code-conv-from 'unix))) - (mail-do-fcc delimline))) - (if mail-interactive - (with-current-buffer errbuf - (erase-buffer)))) - ;; Encode the header according to RFC2047. - (mail-encode-header (point-min) delimline) - ;; - (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) - (setq smtpmail-recipient-address-list - (smtpmail-deduce-address-list tembuf (point-min) delimline)) - (kill-buffer smtpmail-address-buffer) - - (smtpmail-do-bcc delimline) - ;; Send or queue - (if (not smtpmail-queue-mail) - (if (not (null smtpmail-recipient-address-list)) - (when (setq result - (smtpmail-via-smtp - smtpmail-recipient-address-list tembuf)) - (error "Sending failed: %s" - (smtpmail--sanitize-error-message result))) - (error "Sending failed; no recipients")) - (let* ((file-data - (expand-file-name - (format "%s_%i" - (format-time-string "%Y-%m-%d_%H:%M:%S") - (setq smtpmail-queue-counter - (1+ smtpmail-queue-counter))) - smtpmail-queue-dir)) - (file-data (convert-standard-filename file-data)) - (file-elisp (concat file-data ".el")) - (buffer-data (create-file-buffer file-data))) - (unless (file-exists-p smtpmail-queue-dir) - (make-directory smtpmail-queue-dir t)) - (with-current-buffer buffer-data - (erase-buffer) - (set-buffer-file-coding-system - ;; We will be reading the file with no-conversion in - ;; smtpmail-send-queued-mail below, so write it out - ;; with Unix EOLs. - (coding-system-change-eol-conversion - (or smtpmail-code-conv-from 'undecided) - 'unix) - nil t) - (insert-buffer-substring tembuf) - (write-file file-data) - (let ((coding-system-for-write 'utf-8)) - (with-temp-buffer - (insert "(setq ") - (dolist (var (cons 'smtpmail-recipient-address-list - ;; Perhaps store the server etc. - (and smtpmail-store-queue-variables - smtpmail--stored-queue-variables))) - (insert (format " %s %S\n" var (symbol-value var)))) - (insert ")\n") - (write-region (point-min) (point-max) file-elisp - nil 'silent))) - (write-region (concat file-data "\n") nil - (expand-file-name smtpmail-queue-index-file - smtpmail-queue-dir) - t 'silent)) - (kill-buffer buffer-data)))) - (kill-buffer tembuf) - (if (bufferp errbuf) - (kill-buffer errbuf))))) + (let ((smtpmail-code-conv-from + (if enable-multibyte-characters + (let ((sendmail-coding-system smtpmail-code-conv-from)) + (select-message-coding-system))))) + (smtpmail-prepare-mail tembuf smtpmail-code-conv-from) + (if smtpmail-queue-mail + (smtpmail-queue-mail tembuf smtpmail-code-conv-from) + (smtpmail-send-mail tembuf))) + (kill-buffer tembuf)))) ;;;###autoload (defun smtpmail-send-queued-mail () -- 2.40.0 [-- Attachment #3: Type: text/plain, Size: 18 bytes --] -- Manuel Giraud ^ permalink raw reply related [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-09 9:52 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-10 11:47 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-11 13:28 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-10 11:47 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Hi Eli, My strategy after the previous patch is summed up by this function: --8<---------------cut here---------------start------------->8--- (defun smtpmail-async-send-it (cleanups) (let ((tembuf (generate-new-buffer " smtpmail temp")) (smtpmail-code-conv-from (if enable-multibyte-characters (let ((sendmail-coding-system smtpmail-code-conv-from)) (select-message-coding-system))))) (smtpmail-prepare-mail tembuf smtpmail-code-conv-from) (push #'(lambda () (kill-buffer tembuf)) cleanups) (make-thread #'(lambda () (smtpmail-send-mail tembuf) (mapc #'funcall cleanups))))) --8<---------------cut here---------------end--------------->8--- That is, I'd like carry around a 'cleanups' list that holds all the functions that needed to be called after the mail was sent. I then need to propagate this 'cleanups' parameter to callers of 'smtpmail-send-it'. The problem is that encounter code with the following form: --8<---------------cut here---------------start------------->8--- (unwind-protect (let (haha) (do) (many) (things) (smtpmail-send-it-or-one-of-its-caller) (run) (other) (stuff)) (kill-some-top-level-buffer)) --8<---------------cut here---------------end--------------->8--- I'm tempted to put '(run)(other)(stuff)(kill-some-top-level-buffer)' into the cleanups list and remove the unwind-protect but then if something goes wrong before sending the mail the '(kill-some-top-level-buffer)' part won't be called. OTOH, if I let the '(unwind-protect… (kill-some-top-level-buffer)' in place I could shoot myself in the foot with the code that use this buffer into the thread. So I guess, my question is how does one mix Lisp thread with unwind-protect? Best regards, -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-10 11:47 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-11 13:28 ` Eli Zaretskii 2023-05-11 20:59 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-05-11 13:28 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Wed, 10 May 2023 13:47:11 +0200 > > So I guess, my question is how does one mix Lisp thread with > unwind-protect? I'm not sure I understand why you need to. The two unwind-protect handlers will run at different times and most probably will need to unwind different stuff, although there could be overlap. So why is it a problem to have two separate unwind forms? ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-11 13:28 ` Eli Zaretskii @ 2023-05-11 20:59 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-12 5:41 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-11 20:59 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Wed, 10 May 2023 13:47:11 +0200 >> >> So I guess, my question is how does one mix Lisp thread with >> unwind-protect? > > I'm not sure I understand why you need to. The two unwind-protect > handlers will run at different times and most probably will need to > unwind different stuff, although there could be overlap. So why is it > a problem to have two separate unwind forms? I was not talking about two separate unwind forms. I was talking about *thread* and unwind. Here is a minimal example that exhibits my problem: --8<---------------cut here---------------start------------->8--- (setq-local lexical-binding t) (defun my-problem () (interactive) (let ((buf (generate-new-buffer "*foo*"))) (with-current-buffer buf (insert "secret message")) (unwind-protect (make-thread #'(lambda () (with-current-buffer buf (sit-for 10) (message (buffer-string))))) (kill-buffer buf)))) --8<---------------cut here---------------end--------------->8--- The thread won't have a chance to do its job since the buffer will already be dead. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-11 20:59 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12 5:41 ` Eli Zaretskii 2023-05-12 6:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-05-12 5:41 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Thu, 11 May 2023 22:59:20 +0200 > > (defun my-problem () > (interactive) > (let ((buf (generate-new-buffer "*foo*"))) > (with-current-buffer buf > (insert "secret message")) > (unwind-protect > (make-thread #'(lambda () > (with-current-buffer buf > (sit-for 10) > (message (buffer-string))))) > (kill-buffer buf)))) > --8<---------------cut here---------------end--------------->8--- > > The thread won't have a chance to do its job since the buffer will > already be dead. Of course. So you cannot do that, obviously. Cleanup that gets in the way of code you run in a thread must be done after thread-join returns, or when thread-live-p returns nil for the thread. Or use some other synchronization method. There could be several such threads alive at the same time, btw. In the unwind-protect handler of the main thread you can only do cleanup of stuff that the thread doesn't need, or if you are sure the thread was not started (due to some error that precludes the call to make-thread). I'm not aware of any other machinery we have for these cases. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-12 5:41 ` Eli Zaretskii @ 2023-05-12 6:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-12 7:09 ` Eli Zaretskii 2023-05-12 7:10 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 2 replies; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12 6:24 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Thu, 11 May 2023 22:59:20 +0200 >> >> (defun my-problem () >> (interactive) >> (let ((buf (generate-new-buffer "*foo*"))) >> (with-current-buffer buf >> (insert "secret message")) >> (unwind-protect >> (make-thread #'(lambda () >> (with-current-buffer buf >> (sit-for 10) >> (message (buffer-string))))) >> (kill-buffer buf)))) >> --8<---------------cut here---------------end--------------->8--- >> >> The thread won't have a chance to do its job since the buffer will >> already be dead. > > Of course. So you cannot do that, obviously. Cleanup that gets in > the way of code you run in a thread must be done after thread-join > returns, or when thread-live-p returns nil for the thread. Or use > some other synchronization method. There could be several such > threads alive at the same time, btw. > > In the unwind-protect handler of the main thread you can only do > cleanup of stuff that the thread doesn't need, or if you are sure the > thread was not started (due to some error that precludes the call to > make-thread). Thanks! So I could go with something like this: --8<---------------cut here---------------start------------->8--- (setq-local lexical-binding t) (defun eli-solution () (interactive) (let ((buf (generate-new-buffer "*foo*"))) (with-current-buffer buf (insert "secret message")) (let ((cleanup #'(lambda () (kill-buffer buf))) thread) (unwind-protect (setf thread (make-thread #'(lambda () (with-current-buffer buf (sit-for 10) (message (buffer-string)) (funcall cleanup))))) (unless (thread-live-p thread) (funcall cleanup)))))) --8<---------------cut here---------------end--------------->8--- BTW, do you know a more elisp way of defining a function than "(let ((f #'(lambda…))))" form? -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-12 6:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12 7:09 ` Eli Zaretskii 2023-05-12 7:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-12 7:10 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-05-12 7:09 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Fri, 12 May 2023 08:24:36 +0200 > > (setq-local lexical-binding t) > > (defun eli-solution () > (interactive) > (let ((buf (generate-new-buffer "*foo*"))) > (with-current-buffer buf > (insert "secret message")) > (let ((cleanup #'(lambda () (kill-buffer buf))) > thread) > (unwind-protect > (setf thread (make-thread #'(lambda () > (with-current-buffer buf > (sit-for 10) > (message (buffer-string)) > (funcall cleanup))))) > (unless (thread-live-p thread) > (funcall cleanup)))))) Yes, something like that. > BTW, do you know a more elisp way of defining a function than > "(let ((f #'(lambda…))))" form? I'm not sure I understand: what's not ELisp'y about that? And why not use defun instead? ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-12 7:09 ` Eli Zaretskii @ 2023-05-12 7:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-01 12:35 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12 7:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: [...] >> BTW, do you know a more elisp way of defining a function than >> "(let ((f #'(lambda…))))" form? > > I'm not sure I understand: what's not ELisp'y about that? I meant what is the most idiomatic. As Ruijie Yu said, there is also Common Lisp extensions that are cleaner but will also add a new dependency into "smtpmail.el" and "message.el". > And why not use defun instead? I'll try that. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-12 7:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 12:35 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-01 12:59 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 12:35 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 [-- Attachment #1: Type: text/plain, Size: 233 bytes --] Hi, I'm reviving this old bug report because I think I have made some progress. Here is a new patch that tries to send mail asynchronously. This seems to work for me but, of course, it needs testing, testing and even more testing. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-smtpmail-send-it-split-and-async.patch --] [-- Type: text/x-patch, Size: 18702 bytes --] From 1c105e1c70d290bc4e7dfe8180d1a210daa76f05 Mon Sep 17 00:00:00 2001 From: Manuel Giraud <manuel@ledu-giraud.fr> Date: Fri, 5 May 2023 14:35:01 +0200 Subject: [PATCH] smtpmail-send-it split and async * lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function that prepares the mail with current buffer content. (smtpmail-queue-mail): New function to queue a mail (prepared by 'smtpmail-prepare-mail'). (smtpmail-send-mail): New function to send a mail (prepared by 'smtpmail-send-mail'). (smtpmail-send-it): Use all three previous functions. Use a thread to async 'smtpmail-send-mail'. While here, remove 'errbuf' leftovers. --- lisp/mail/smtpmail.el | 421 +++++++++++++++++++++--------------------- 1 file changed, 213 insertions(+), 208 deletions(-) diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el index 78688d170cc..a69aa027c0a 100644 --- a/lisp/mail/smtpmail.el +++ b/lisp/mail/smtpmail.el @@ -205,217 +205,222 @@ smtpmail-mail-address "Value to use for envelope-from address for mail from ambient buffer.") ;;; Functions +(defun smtpmail-prepare-mail (tembuf smtpmail-code-conv-from) + (let ((case-fold-search nil) + delimline + (mailbuf (current-buffer)) + ;; Examine this variable now, so that + ;; local binding in the mail buffer will take effect. + (smtpmail-mail-address + (save-restriction + ;; Only look at the headers when fetching the + ;; envelope address. + (message-narrow-to-headers) + (or (and mail-specify-envelope-from (mail-envelope-from)) + (let ((from (mail-fetch-field "from"))) + (and from + (cadr (mail-extract-address-components from)))) + (smtpmail-user-mail-address))))) + (with-current-buffer tembuf + (erase-buffer) + ;; Use the same `buffer-file-coding-system' as in the mail + ;; buffer, otherwise any `write-region' invocations (e.g., in + ;; mail-do-fcc below) will annoy with asking for a suitable + ;; encoding. + (set-buffer-file-coding-system smtpmail-code-conv-from nil t) + (insert-buffer-substring mailbuf) + (goto-char (point-max)) + ;; require one newline at the end. + (or (= (preceding-char) ?\n) + (insert ?\n)) + ;; Change header-delimiter to be what sendmail expects. + (mail-sendmail-undelimit-header) + (setq delimline (point-marker)) + (if mail-aliases + (expand-mail-aliases (point-min) delimline)) + (goto-char (point-min)) + ;; ignore any blank lines in the header + (while (and (re-search-forward "\n\n\n*" delimline t) + (< (point) delimline)) + (replace-match "\n")) + (let ((case-fold-search t)) + ;; We used to process Resent-... headers here, + ;; but it was not done properly, and the job + ;; is done correctly in `smtpmail-deduce-address-list'. + ;; Don't send out a blank subject line + (goto-char (point-min)) + (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) + (replace-match "") + ;; This one matches a Subject just before the header delimiter. + (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) + (= (match-end 0) delimline)) + (replace-match ""))) + ;; Put the "From:" field in unless for some odd reason + ;; they put one in themselves. + (goto-char (point-min)) + (if (not (re-search-forward "^From:" delimline t)) + (let* ((login smtpmail-mail-address) + (fullname (user-full-name))) + (cond ((eq mail-from-style 'angles) + (insert "From: " fullname) + (let ((fullname-start (+ (point-min) 6)) + (fullname-end (point-marker))) + (goto-char fullname-start) + ;; Look for a character that cannot appear unquoted + ;; according to RFC 822 or its successors. + (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" + fullname-end 1) + (progn + ;; Quote fullname, escaping specials. + (goto-char fullname-start) + (insert "\"") + (while (re-search-forward "[\"\\]" + fullname-end 1) + (replace-match "\\\\\\&" t)) + (insert "\"")))) + (insert " <" login ">\n")) + ((eq mail-from-style 'parens) + (insert "From: " login " (") + (let ((fullname-start (point))) + (insert fullname) + (let ((fullname-end (point-marker))) + (goto-char fullname-start) + ;; RFC 822 and its successors say \ and + ;; nonmatching parentheses must be + ;; escaped in comments. + ;; Escape every instance of ()\ ... + (while (re-search-forward "[()\\]" fullname-end 1) + (replace-match "\\\\\\&" t)) + ;; ... then undo escaping of matching parentheses, + ;; including matching nested parentheses. + (goto-char fullname-start) + (while (re-search-forward + "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" + fullname-end 1) + (replace-match "\\1(\\3)" t) + (goto-char fullname-start)))) + (insert ")\n")) + ((null mail-from-style) + (insert "From: " login "\n"))))) + ;; Insert a `Message-Id:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Message-Id:" delimline t) + (insert "Message-Id: " (message-make-message-id) "\n")) + ;; Insert a `Date:' field if there isn't one yet. + (goto-char (point-min)) + (unless (re-search-forward "^Date:" delimline t) + (insert "Date: " (message-make-date) "\n")) + ;; Possibly add a MIME header for the current coding system + (let (charset) + (goto-char (point-min)) + (and (eq mail-send-nonascii 'mime) + (not (re-search-forward "^MIME-version:" delimline t)) + (progn (skip-chars-forward "\0-\177") + (/= (point) (point-max))) + smtpmail-code-conv-from + (setq charset + (coding-system-get smtpmail-code-conv-from + 'mime-charset)) + (goto-char delimline) + (insert "MIME-version: 1.0\n" + "Content-type: text/plain; charset=" + (symbol-name charset) + "\nContent-Transfer-Encoding: 8bit\n"))) + ;; Insert an extra newline if we need it to work around + ;; Sun's bug that swallows newlines. + (goto-char (1+ delimline)) + ;; Find and handle any Fcc fields. + (goto-char (point-min)) + (if (re-search-forward "^Fcc:" delimline t) + ;; Force `mail-do-fcc' to use the encoding of the mail + ;; buffer to encode outgoing messages on Fcc files. + (let ((coding-system-for-write + ;; mbox files must have Unix EOLs. + (coding-system-change-eol-conversion + smtpmail-code-conv-from 'unix))) + (mail-do-fcc delimline)))) + ;; Encode the header according to RFC2047. + (mail-encode-header (point-min) delimline) + ;; + (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) + (setq smtpmail-recipient-address-list + (smtpmail-deduce-address-list tembuf (point-min) delimline)) + (kill-buffer smtpmail-address-buffer) + + (smtpmail-do-bcc delimline)))) + +(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from) + (let* ((file-data + (expand-file-name + (format "%s_%i" + (format-time-string "%Y-%m-%d_%H:%M:%S") + (setq smtpmail-queue-counter + (1+ smtpmail-queue-counter))) + smtpmail-queue-dir)) + (file-data (convert-standard-filename file-data)) + (file-elisp (concat file-data ".el")) + (buffer-data (create-file-buffer file-data))) + (unless (file-exists-p smtpmail-queue-dir) + (make-directory smtpmail-queue-dir t)) + (with-current-buffer buffer-data + (erase-buffer) + (set-buffer-file-coding-system + ;; We will be reading the file with no-conversion in + ;; smtpmail-send-queued-mail below, so write it out + ;; with Unix EOLs. + (coding-system-change-eol-conversion + (or smtpmail-code-conv-from 'undecided) + 'unix) + nil t) + (insert-buffer-substring tembuf) + (write-file file-data) + (let ((coding-system-for-write 'utf-8)) + (with-temp-buffer + (insert "(setq ") + (dolist (var (cons 'smtpmail-recipient-address-list + ;; Perhaps store the server etc. + (and smtpmail-store-queue-variables + smtpmail--stored-queue-variables))) + (insert (format " %s %S\n" var (symbol-value var)))) + (insert ")\n") + (write-region (point-min) (point-max) file-elisp + nil 'silent))) + (write-region (concat file-data "\n") nil + (expand-file-name smtpmail-queue-index-file + smtpmail-queue-dir) + t 'silent)) + (kill-buffer buffer-data))) + +(defun smtpmail-send-mail (tembuf) + (let (result) + (if (not (null smtpmail-recipient-address-list)) + (when (setq result + (smtpmail-via-smtp + smtpmail-recipient-address-list tembuf)) + (error "Sending failed: %s" + (smtpmail--sanitize-error-message result))) + (error "Sending failed; no recipients")))) ;;;###autoload (defun smtpmail-send-it () - (let ((errbuf (if mail-interactive - (generate-new-buffer " smtpmail errors") - 0)) - (tembuf (generate-new-buffer " smtpmail temp")) - (case-fold-search nil) - delimline - result - (mailbuf (current-buffer)) - ;; Examine this variable now, so that - ;; local binding in the mail buffer will take effect. - (smtpmail-mail-address - (save-restriction - ;; Only look at the headers when fetching the - ;; envelope address. - (message-narrow-to-headers) - (or (and mail-specify-envelope-from (mail-envelope-from)) - (let ((from (mail-fetch-field "from"))) - (and from - (cadr (mail-extract-address-components from)))) - (smtpmail-user-mail-address)))) - (smtpmail-code-conv-from - (if enable-multibyte-characters - (let ((sendmail-coding-system smtpmail-code-conv-from)) - (select-message-coding-system))))) - (unwind-protect - (with-current-buffer tembuf - (erase-buffer) - ;; Use the same `buffer-file-coding-system' as in the mail - ;; buffer, otherwise any `write-region' invocations (e.g., in - ;; mail-do-fcc below) will annoy with asking for a suitable - ;; encoding. - (set-buffer-file-coding-system smtpmail-code-conv-from nil t) - (insert-buffer-substring mailbuf) - (goto-char (point-max)) - ;; require one newline at the end. - (or (= (preceding-char) ?\n) - (insert ?\n)) - ;; Change header-delimiter to be what sendmail expects. - (mail-sendmail-undelimit-header) - (setq delimline (point-marker)) - ;; (sendmail-synch-aliases) - (if mail-aliases - (expand-mail-aliases (point-min) delimline)) - (goto-char (point-min)) - ;; ignore any blank lines in the header - (while (and (re-search-forward "\n\n\n*" delimline t) - (< (point) delimline)) - (replace-match "\n")) - (let ((case-fold-search t)) - ;; We used to process Resent-... headers here, - ;; but it was not done properly, and the job - ;; is done correctly in `smtpmail-deduce-address-list'. - ;; Don't send out a blank subject line - (goto-char (point-min)) - (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t) - (replace-match "") - ;; This one matches a Subject just before the header delimiter. - (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t) - (= (match-end 0) delimline)) - (replace-match ""))) - ;; Put the "From:" field in unless for some odd reason - ;; they put one in themselves. - (goto-char (point-min)) - (if (not (re-search-forward "^From:" delimline t)) - (let* ((login smtpmail-mail-address) - (fullname (user-full-name))) - (cond ((eq mail-from-style 'angles) - (insert "From: " fullname) - (let ((fullname-start (+ (point-min) 6)) - (fullname-end (point-marker))) - (goto-char fullname-start) - ;; Look for a character that cannot appear unquoted - ;; according to RFC 822 or its successors. - (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" - fullname-end 1) - (progn - ;; Quote fullname, escaping specials. - (goto-char fullname-start) - (insert "\"") - (while (re-search-forward "[\"\\]" - fullname-end 1) - (replace-match "\\\\\\&" t)) - (insert "\"")))) - (insert " <" login ">\n")) - ((eq mail-from-style 'parens) - (insert "From: " login " (") - (let ((fullname-start (point))) - (insert fullname) - (let ((fullname-end (point-marker))) - (goto-char fullname-start) - ;; RFC 822 and its successors say \ and - ;; nonmatching parentheses must be - ;; escaped in comments. - ;; Escape every instance of ()\ ... - (while (re-search-forward "[()\\]" fullname-end 1) - (replace-match "\\\\\\&" t)) - ;; ... then undo escaping of matching parentheses, - ;; including matching nested parentheses. - (goto-char fullname-start) - (while (re-search-forward - "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" - fullname-end 1) - (replace-match "\\1(\\3)" t) - (goto-char fullname-start)))) - (insert ")\n")) - ((null mail-from-style) - (insert "From: " login "\n"))))) - ;; Insert a `Message-Id:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Message-Id:" delimline t) - (insert "Message-Id: " (message-make-message-id) "\n")) - ;; Insert a `Date:' field if there isn't one yet. - (goto-char (point-min)) - (unless (re-search-forward "^Date:" delimline t) - (insert "Date: " (message-make-date) "\n")) - ;; Possibly add a MIME header for the current coding system - (let (charset) - (goto-char (point-min)) - (and (eq mail-send-nonascii 'mime) - (not (re-search-forward "^MIME-version:" delimline t)) - (progn (skip-chars-forward "\0-\177") - (/= (point) (point-max))) - smtpmail-code-conv-from - (setq charset - (coding-system-get smtpmail-code-conv-from - 'mime-charset)) - (goto-char delimline) - (insert "MIME-version: 1.0\n" - "Content-type: text/plain; charset=" - (symbol-name charset) - "\nContent-Transfer-Encoding: 8bit\n"))) - ;; Insert an extra newline if we need it to work around - ;; Sun's bug that swallows newlines. - (goto-char (1+ delimline)) - ;; Find and handle any Fcc fields. - (goto-char (point-min)) - (if (re-search-forward "^Fcc:" delimline t) - ;; Force `mail-do-fcc' to use the encoding of the mail - ;; buffer to encode outgoing messages on Fcc files. - (let ((coding-system-for-write - ;; mbox files must have Unix EOLs. - (coding-system-change-eol-conversion - smtpmail-code-conv-from 'unix))) - (mail-do-fcc delimline))) - (if mail-interactive - (with-current-buffer errbuf - (erase-buffer)))) - ;; Encode the header according to RFC2047. - (mail-encode-header (point-min) delimline) - ;; - (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*")) - (setq smtpmail-recipient-address-list - (smtpmail-deduce-address-list tembuf (point-min) delimline)) - (kill-buffer smtpmail-address-buffer) - - (smtpmail-do-bcc delimline) - ;; Send or queue - (if (not smtpmail-queue-mail) - (if (not (null smtpmail-recipient-address-list)) - (when (setq result - (smtpmail-via-smtp - smtpmail-recipient-address-list tembuf)) - (error "Sending failed: %s" - (smtpmail--sanitize-error-message result))) - (error "Sending failed; no recipients")) - (let* ((file-data - (expand-file-name - (format "%s_%i" - (format-time-string "%Y-%m-%d_%H:%M:%S") - (setq smtpmail-queue-counter - (1+ smtpmail-queue-counter))) - smtpmail-queue-dir)) - (file-data (convert-standard-filename file-data)) - (file-elisp (concat file-data ".el")) - (buffer-data (create-file-buffer file-data))) - (unless (file-exists-p smtpmail-queue-dir) - (make-directory smtpmail-queue-dir t)) - (with-current-buffer buffer-data - (erase-buffer) - (set-buffer-file-coding-system - ;; We will be reading the file with no-conversion in - ;; smtpmail-send-queued-mail below, so write it out - ;; with Unix EOLs. - (coding-system-change-eol-conversion - (or smtpmail-code-conv-from 'undecided) - 'unix) - nil t) - (insert-buffer-substring tembuf) - (write-file file-data) - (let ((coding-system-for-write 'utf-8)) - (with-temp-buffer - (insert "(setq ") - (dolist (var (cons 'smtpmail-recipient-address-list - ;; Perhaps store the server etc. - (and smtpmail-store-queue-variables - smtpmail--stored-queue-variables))) - (insert (format " %s %S\n" var (symbol-value var)))) - (insert ")\n") - (write-region (point-min) (point-max) file-elisp - nil 'silent))) - (write-region (concat file-data "\n") nil - (expand-file-name smtpmail-queue-index-file - smtpmail-queue-dir) - t 'silent)) - (kill-buffer buffer-data)))) - (kill-buffer tembuf) - (if (bufferp errbuf) - (kill-buffer errbuf))))) + (let ((tembuf (generate-new-buffer " smtpmail temp")) + (smtpmail-code-conv-from + (if enable-multibyte-characters + (let ((sendmail-coding-system smtpmail-code-conv-from)) + (select-message-coding-system))))) + (smtpmail-prepare-mail tembuf smtpmail-code-conv-from) + (cond (smtpmail-queue-mail + (smtpmail-queue-mail tembuf smtpmail-code-conv-from) + (kill-buffer tembuf)) + (t + (let ((cleanup (lambda () (kill-buffer tembuf))) + thread) + (unwind-protect + (setf thread (make-thread (lambda () + (smtpmail-send-mail tembuf) + (funcall cleanup)))) + (unless (thread-live-p thread) + (funcall cleanup)))))))) ;;;###autoload (defun smtpmail-send-queued-mail () -- 2.42.0 [-- Attachment #3: Type: text/plain, Size: 18 bytes --] -- Manuel Giraud ^ permalink raw reply related [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-01 12:35 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 12:59 ` Eli Zaretskii 2023-11-01 18:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-01 12:59 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Wed, 01 Nov 2023 13:35:45 +0100 > > I'm reviving this old bug report because I think I have made some > progress. Here is a new patch that tries to send mail asynchronously. > This seems to work for me but, of course, it needs testing, testing and > even more testing. Thank you for working on this. I have several questions about it: . I'm not sure I understand how will the success/failure of sending be communicated back to the callers. Currently, when the sending succeeds, there's a message in echo-area, and if the message was a reply, then Emacs marks the original message as "have been replied to". How will this work with async sending? . What happens if sending fails for some reason? It could be that the problem is detected by smtpmail itself, or it could be that some low-level code signals an error -- what happens in both cases? . With which MUA are you testing this? . What happens if another message is sent while the previous one is still being sent? . What did you try to do in Emacs while the message was being sent, and did you see any problems with the foreground responsiveness? For that matter, how long did it take for the background thread to send the message? If that was short enough, like 1 sec or so, I suggest to test this with sending a larger message, like a message with a large attachment. That's because the most important situation where async sending is valuable is when it takes a long time to send a message, either because it's a large message or because the connection is slow or unreliable. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-01 12:59 ` Eli Zaretskii @ 2023-11-01 18:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-01 19:29 ` Eli Zaretskii 2023-11-03 2:31 ` Richard Stallman 0 siblings, 2 replies; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 18:06 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Wed, 01 Nov 2023 13:35:45 +0100 >> >> I'm reviving this old bug report because I think I have made some >> progress. Here is a new patch that tries to send mail asynchronously. >> This seems to work for me but, of course, it needs testing, testing and >> even more testing. > > Thank you for working on this. > > I have several questions about it: > > . I'm not sure I understand how will the success/failure of sending > be communicated back to the callers. Currently, when the sending > succeeds, there's a message in echo-area, and if the message was a > reply, then Emacs marks the original message as "have been replied > to". How will this work with async sending? The progress and "Sending email done" still shows in echo-area and *Messages* buffer but asynchronously. As for the "have been replied too" part, it happens right after 'C-c C-c' so a message that should error later down the line will be named as "*sent reply...": this is a problem. > . What happens if sending fails for some reason? It could be that > the problem is detected by smtpmail itself, or it could be that > some low-level code signals an error -- what happens in both > cases? Some errors should be handled in 'smtpmail-send-mail' and signal by calling (error). But other errors won't be. For instance, I tried to send a mail to a non existent address and I get no error whatsoever: the buffer is also called "*sent ...*" > . With which MUA are you testing this? I'm testing gnus and message-mode. > . What happens if another message is sent while the previous one is > still being sent? That I have tested. It works because the temporary buffer where everything takes place is generated by 'generate-new-buffer' which creates a unique name if needed. > . What did you try to do in Emacs while the message was being sent, > and did you see any problems with the foreground responsiveness? I did not do some intensive usage just moving to other buffers. I've not seen any problem with responsiveness. > For that matter, how long did it take for the background thread to > send the message? If that was short enough, like 1 sec or so, I > suggest to test this with sending a larger message, like a message > with a large attachment. That's because the most important > situation where async sending is valuable is when it takes a long > time to send a message, either because it's a large message or > because the connection is slow or unreliable. Yes I have tested with longer to send message otherwise I would not be able to see the asynchronous process. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-01 18:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 19:29 ` Eli Zaretskii 2023-11-01 19:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-03 2:31 ` Richard Stallman 1 sibling, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-01 19:29 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Wed, 01 Nov 2023 19:06:08 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > > . I'm not sure I understand how will the success/failure of sending > > be communicated back to the callers. Currently, when the sending > > succeeds, there's a message in echo-area, and if the message was a > > reply, then Emacs marks the original message as "have been replied > > to". How will this work with async sending? > > The progress and "Sending email done" still shows in echo-area and > *Messages* buffer but asynchronously. What happens if the foreground Lisp program displays something in the echo-area at that time? I'm asking because I don't think it's a good idea to show this from a background thread. > > . What happens if sending fails for some reason? It could be that > > the problem is detected by smtpmail itself, or it could be that > > some low-level code signals an error -- what happens in both > > cases? > > Some errors should be handled in 'smtpmail-send-mail' and signal by > calling (error). But other errors won't be. For instance, I tried to > send a mail to a non existent address and I get no error whatsoever: the > buffer is also called "*sent ...*" Signaling an error in a non-main thread causes the thread exit silently, with the error stored in a variable, so something should be done to show the error to the user. > > . What happens if another message is sent while the previous one is > > still being sent? > > That I have tested. It works because the temporary buffer where > everything takes place is generated by 'generate-new-buffer' which > creates a unique name if needed. So you have several threads sending at the same time? If so, what happens with their errors and success messages? > > For that matter, how long did it take for the background thread to > > send the message? If that was short enough, like 1 sec or so, I > > suggest to test this with sending a larger message, like a message > > with a large attachment. That's because the most important > > situation where async sending is valuable is when it takes a long > > time to send a message, either because it's a large message or > > because the connection is slow or unreliable. > > Yes I have tested with longer to send message otherwise I would not be > able to see the asynchronous process. If you don't see problems with responsiveness, this is encouraging. IME, such problems happen quite frequently, for example if you type during the time the background thread does its job. Thanks. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-01 19:29 ` Eli Zaretskii @ 2023-11-01 19:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-02 5:48 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 19:55 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Wed, 01 Nov 2023 19:06:08 +0100 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> > . I'm not sure I understand how will the success/failure of sending >> > be communicated back to the callers. Currently, when the sending >> > succeeds, there's a message in echo-area, and if the message was a >> > reply, then Emacs marks the original message as "have been replied >> > to". How will this work with async sending? >> >> The progress and "Sending email done" still shows in echo-area and >> *Messages* buffer but asynchronously. > > What happens if the foreground Lisp program displays something in the > echo-area at that time? I'm asking because I don't think it's a good > idea to show this from a background thread. Sorry I did not test this. But maybe when this starts working, we should consider removing the progress report for large messages. >> > . What happens if sending fails for some reason? It could be that >> > the problem is detected by smtpmail itself, or it could be that >> > some low-level code signals an error -- what happens in both >> > cases? >> >> Some errors should be handled in 'smtpmail-send-mail' and signal by >> calling (error). But other errors won't be. For instance, I tried to >> send a mail to a non existent address and I get no error whatsoever: the >> buffer is also called "*sent ...*" > > Signaling an error in a non-main thread causes the thread exit > silently, with the error stored in a variable, so something should be > done to show the error to the user. Yes, I have seen that and just learn about 'thread-signal'. >> > . What happens if another message is sent while the previous one is >> > still being sent? >> >> That I have tested. It works because the temporary buffer where >> everything takes place is generated by 'generate-new-buffer' which >> creates a unique name if needed. > > So you have several threads sending at the same time? If so, what > happens with their errors and success messages? Their was no errors because those sendings did not generate any. The success messages appeared in the *Messages* buffer. >> > For that matter, how long did it take for the background thread to >> > send the message? If that was short enough, like 1 sec or so, I >> > suggest to test this with sending a larger message, like a message >> > with a large attachment. That's because the most important >> > situation where async sending is valuable is when it takes a long >> > time to send a message, either because it's a large message or >> > because the connection is slow or unreliable. >> >> Yes I have tested with longer to send message otherwise I would not be >> able to see the asynchronous process. > > If you don't see problems with responsiveness, this is encouraging. > IME, such problems happen quite frequently, for example if you type > during the time the background thread does its job. Yes this is just a start and should be tested on normal/regular usage. As always, when I start working on this I rediscover that there is many housekeeping done afterward by the 'smtpmail-send-it' callers (marking as sent via mail,...): this should be taken into account too. So it may be encouraging but I think this is just a start. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-01 19:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-02 5:48 ` Eli Zaretskii 2023-11-02 10:44 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-02 5:48 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Wed, 01 Nov 2023 20:55:37 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> The progress and "Sending email done" still shows in echo-area and > >> *Messages* buffer but asynchronously. > > > > What happens if the foreground Lisp program displays something in the > > echo-area at that time? I'm asking because I don't think it's a good > > idea to show this from a background thread. > > Sorry I did not test this. But maybe when this starts working, we > should consider removing the progress report for large messages. I think when messages are sent in the background, there should be a different series of messages: one at the beginning, when the thread is launched, and one when the thread exits. Both of these should be output by the main thread, not the thread which sends. The sending progress messages will not be shown, since they are mostly useless anyway (if the user wants the sending to be in the background, it generally means he/she doesn't care much about the progress, since Emacs is not waiting for the sending to complete). If we need more detailed messages in some cases, we could have a special buffer which the user could then view if needed. > > So you have several threads sending at the same time? If so, what > > happens with their errors and success messages? > > Their was no errors because those sendings did not generate any. The > success messages appeared in the *Messages* buffer. One more reason to move the messages to the main thread, to avoid threads "fighting" for the echo area. > > If you don't see problems with responsiveness, this is encouraging. > > IME, such problems happen quite frequently, for example if you type > > during the time the background thread does its job. > > Yes this is just a start and should be tested on normal/regular usage. > As always, when I start working on this I rediscover that there is many > housekeeping done afterward by the 'smtpmail-send-it' callers (marking > as sent via mail,...): this should be taken into account too. So it may > be encouraging but I think this is just a start. Right, thanks. When this is available, I will probably become a heavy user of this feature. It should probably be an opt-in feature initially, so as to let people try it without disrupting their production workflows too much. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-02 5:48 ` Eli Zaretskii @ 2023-11-02 10:44 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-02 11:26 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-02 10:44 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: [...] > I think when messages are sent in the background, there should be a > different series of messages: one at the beginning, when the thread is > launched, and one when the thread exits. Both of these should be > output by the main thread, not the thread which sends. I think this is feasible for the message when the thread is launch but not for the final message: the main-thread would have to 'thread-join' on the sending thread and we'll lose the asynchronous behaviour, no? > The sending progress messages will not be shown, since they are mostly > useless anyway (if the user wants the sending to be in the background, > it generally means he/she doesn't care much about the progress, since > Emacs is not waiting for the sending to complete). If we need more > detailed messages in some cases, we could have a special buffer which > the user could then view if needed. Ok. [...] > Right, thanks. > > When this is available, I will probably become a heavy user of this > feature. It should probably be an opt-in feature initially, so as to > let people try it without disrupting their production workflows too > much. Yes, I think it should be opt-in. But such an option will also have ramifications in message.el, Gnus and surely more that I don't even know about. (BTW, do you have an idea for a name for such option?) -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-02 10:44 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-02 11:26 ` Eli Zaretskii 2023-11-05 14:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-02 11:26 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Thu, 02 Nov 2023 11:44:40 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > [...] > > > I think when messages are sent in the background, there should be a > > different series of messages: one at the beginning, when the thread is > > launched, and one when the thread exits. Both of these should be > > output by the main thread, not the thread which sends. > > I think this is feasible for the message when the thread is launch but > not for the final message: the main-thread would have to 'thread-join' > on the sending thread and we'll lose the asynchronous behaviour, no? That is not necessary. The background thread could add the message to some queue which the main thread could check from time to time. Or something similar. > > When this is available, I will probably become a heavy user of this > > feature. It should probably be an opt-in feature initially, so as to > > let people try it without disrupting their production workflows too > > much. > > Yes, I think it should be opt-in. But such an option will also have > ramifications in message.el, Gnus and surely more that I don't even know > about. Probably. (Another client is sendmail.el.) > (BTW, do you have an idea for a name for such option?) smtpmail-send-message-in-background ? ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-02 11:26 ` Eli Zaretskii @ 2023-11-05 14:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-05 15:46 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-05 14:24 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Hi Eli, I'm still struggling with making 'smtpmail-send-it' async. As I'm using message.el, I'm trying to make it work here. But message.el in written in such way that it is quite hard to make it work with a threaded 'smtpmail-send-it' call. And then, from a message buffer (with a quite large attachment), I've just evaluted the following: (make-thread #'message-send)... and everything went ok: - Emacs is still responsive: I could switch to other buffers, request the status of a VC handled file. - When the message is finally sent, the buffer is renamed accordingly and tagged as sent via mail. So my question is this one: instead of making 'smtpmail-send-it' threaded why not have a threaded version of toplevel commands (such as 'message-send')? We could hopefully do the same for sendmail.el. Of course, we should have it as opt-in behind customs (message-send-in-background and/or mail-send-in-background?) As for when something goes wrong and we end up in an 'error' call, maybe we should fix how 'error' behave inside a thread. What am I missing? -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-05 14:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-05 15:46 ` Eli Zaretskii 2023-11-05 16:12 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-05 15:46 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Sun, 05 Nov 2023 15:24:50 +0100 > > Hi Eli, > > I'm still struggling with making 'smtpmail-send-it' async. As I'm using > message.el, I'm trying to make it work here. But message.el in written > in such way that it is quite hard to make it work with a threaded > 'smtpmail-send-it' call. > > And then, from a message buffer (with a quite large attachment), I've > just evaluted the following: (make-thread #'message-send)... and > everything went ok: > - Emacs is still responsive: I could switch to other > buffers, request the status of a VC handled file. > > - When the message is finally sent, the buffer is renamed > accordingly and tagged as sent via mail. > > So my question is this one: instead of making 'smtpmail-send-it' > threaded why not have a threaded version of toplevel commands (such as > 'message-send')? We could hopefully do the same for sendmail.el. Of > course, we should have it as opt-in behind customs > (message-send-in-background and/or mail-send-in-background?) > > As for when something goes wrong and we end up in an 'error' call, maybe > we should fix how 'error' behave inside a thread. What am I missing? Nothing, AFAIU. Instead of making smtpmail-send-it optionally working asynchronously, it should be perfectly valid to have a separate function called, say, message-send-asynchronously, which would work with background threads and implement the same protocol as the other MUA's send-it functions do. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-05 15:46 ` Eli Zaretskii @ 2023-11-05 16:12 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-05 16:17 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-05 16:12 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: [...] >> As for when something goes wrong and we end up in an 'error' call, maybe >> we should fix how 'error' behave inside a thread. What am I missing? > > Nothing, AFAIU. Instead of making smtpmail-send-it optionally working > asynchronously, it should be perfectly valid to have a separate > function called, say, message-send-asynchronously, which would work > with background threads and implement the same protocol as the other > MUA's send-it functions do. Ok. But there is still the case where any 'error' call from a thread will end up in limbo, no? -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-05 16:12 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-05 16:17 ` Eli Zaretskii 2023-11-06 10:21 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-05 16:17 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Sun, 05 Nov 2023 17:12:03 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > > Nothing, AFAIU. Instead of making smtpmail-send-it optionally working > > asynchronously, it should be perfectly valid to have a separate > > function called, say, message-send-asynchronously, which would work > > with background threads and implement the same protocol as the other > > MUA's send-it functions do. > > Ok. But there is still the case where any 'error' call from a thread > will end up in limbo, no? The caller will need to fetch it and display it. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-05 16:17 ` Eli Zaretskii @ 2023-11-06 10:21 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-06 12:40 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 10:21 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Sun, 05 Nov 2023 17:12:03 +0100 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> > Nothing, AFAIU. Instead of making smtpmail-send-it optionally working >> > asynchronously, it should be perfectly valid to have a separate >> > function called, say, message-send-asynchronously, which would work >> > with background threads and implement the same protocol as the other >> > MUA's send-it functions do. >> >> Ok. But there is still the case where any 'error' call from a thread >> will end up in limbo, no? > > The caller will need to fetch it and display it. Yes but how would I do that. My idea was to left much code unmodified (with all 'error' calls in case something goes wrong). But how the 'main-thread' could fetch these errors. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-06 10:21 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 12:40 ` Eli Zaretskii 2023-11-06 15:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-06 12:40 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Mon, 06 Nov 2023 11:21:23 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> Ok. But there is still the case where any 'error' call from a thread > >> will end up in limbo, no? > > > > The caller will need to fetch it and display it. > > Yes but how would I do that. My idea was to left much code unmodified > (with all 'error' calls in case something goes wrong). But how the > 'main-thread' could fetch these errors. Using thread-last-error, or at least that's what I had in mind. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-06 12:40 ` Eli Zaretskii @ 2023-11-06 15:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-06 16:28 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 15:56 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Mon, 06 Nov 2023 11:21:23 +0100 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> >> Ok. But there is still the case where any 'error' call from a thread >> >> will end up in limbo, no? >> > >> > The caller will need to fetch it and display it. >> >> Yes but how would I do that. My idea was to left much code unmodified >> (with all 'error' calls in case something goes wrong). But how the >> 'main-thread' could fetch these errors. > > Using thread-last-error, or at least that's what I had in mind. It seems that 'thread-last-error' is global for all threads of Emacs so I don't it would work. Doesn't a thread record its error status and message? -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-06 15:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 16:28 ` Eli Zaretskii 2023-11-06 17:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-06 16:28 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Mon, 06 Nov 2023 16:56:33 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> Yes but how would I do that. My idea was to left much code unmodified > >> (with all 'error' calls in case something goes wrong). But how the > >> 'main-thread' could fetch these errors. > > > > Using thread-last-error, or at least that's what I had in mind. > > It seems that 'thread-last-error' is global for all threads of Emacs so > I don't it would work. Doesn't a thread record its error status and > message? Sorry, I don't understand what exactly you are asking and what you are saying. Yes, thread-last-error accesses a global storage, but I fail to see how this is a problem: if the main thread fetches the error in a timely fashion, it should still work. And if, for some reason, this is not good enough, we could come up with a more fine-grained mechanism. But first I'd like to see a description of a real problem with the existing mechanism: after all, it isn't expected that every single thread you launch will die due to an error, right? So the situation where a thread dies and we need to access its error should be relatively rare, and a global resource could still be adequate. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-06 16:28 ` Eli Zaretskii @ 2023-11-06 17:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-06 19:21 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 17:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Mon, 06 Nov 2023 16:56:33 +0100 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> >> Yes but how would I do that. My idea was to left much code unmodified >> >> (with all 'error' calls in case something goes wrong). But how the >> >> 'main-thread' could fetch these errors. >> > >> > Using thread-last-error, or at least that's what I had in mind. >> >> It seems that 'thread-last-error' is global for all threads of Emacs so >> I don't it would work. Doesn't a thread record its error status and >> message? > > Sorry, I don't understand what exactly you are asking and what you are > saying. > > Yes, thread-last-error accesses a global storage, but I fail to see > how this is a problem: if the main thread fetches the error in a > timely fashion, it should still work. And if, for some reason, this > is not good enough, we could come up with a more fine-grained > mechanism. But first I'd like to see a description of a real problem > with the existing mechanism: after all, it isn't expected that every > single thread you launch will die due to an error, right? So the > situation where a thread dies and we need to access its error should > be relatively rare, and a global resource could still be adequate. So just for recap, the idea is to have a command ('message-send-asynchronously' as you suggested) that will just be wrapper around 'message-send' and creates a thread to send the current buffer. Such a thread could be stored in a list and, by mean of a timer, the main-thread would sometimes look if this thread is dead. If it is dead and (thread-last-error) returns nil maybe we can conclude that everything went well. But if (thread-last-error) returns a message, it could be message from any other Emacs thread: what to do in such case? Or worse: the thread is dead, (thread-last-error) returns nil... but it was cleared from another part of Emacs. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-06 17:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 19:21 ` Eli Zaretskii 2023-11-06 20:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-06 19:21 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Mon, 06 Nov 2023 18:57:59 +0100 > > So just for recap, the idea is to have a command > ('message-send-asynchronously' as you suggested) that will just be > wrapper around 'message-send' and creates a thread to send the current > buffer. Such a thread could be stored in a list and, by mean of a > timer, the main-thread would sometimes look if this thread is dead. Something like that, yes. > If it is dead and (thread-last-error) returns nil maybe we can conclude > that everything went well. But if (thread-last-error) returns a > message, it could be message from any other Emacs thread: what to do in > such case? Display a message about the error. > Or worse: the thread is dead, (thread-last-error) returns > nil... but it was cleared from another part of Emacs. This means it exited successfully. We could also maintain a data structure where successfully-exiting threads will leave their success status together with some id of the message they sent -- unlike a thread that dies abruptly due to an error, a successful thread can store the information in the data structure before exiting. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-06 19:21 ` Eli Zaretskii @ 2023-11-06 20:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-07 3:26 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 20:55 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> If it is dead and (thread-last-error) returns nil maybe we can conclude >> that everything went well. But if (thread-last-error) returns a >> message, it could be message from any other Emacs thread: what to do in >> such case? > > Display a message about the error. I mean, the last error message could come from another thread not related in anyway to mail sending. No? >> Or worse: the thread is dead, (thread-last-error) returns >> nil... but it was cleared from another part of Emacs. > > This means it exited successfully. We could also maintain a data > structure where successfully-exiting threads will leave their success > status together with some id of the message they sent -- unlike a > thread that dies abruptly due to an error, a successful thread can > store the information in the data structure before exiting. Yes why not but then I'd have to modify internals of 'message-send': something I thought I could escape. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-06 20:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-07 3:26 ` Eli Zaretskii 2023-11-07 9:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-07 3:26 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Mon, 06 Nov 2023 21:55:49 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> If it is dead and (thread-last-error) returns nil maybe we can conclude > >> that everything went well. But if (thread-last-error) returns a > >> message, it could be message from any other Emacs thread: what to do in > >> such case? > > > > Display a message about the error. > > I mean, the last error message could come from another thread not > related in anyway to mail sending. No? It could, but why would there be other threads in this case? > >> Or worse: the thread is dead, (thread-last-error) returns > >> nil... but it was cleared from another part of Emacs. > > > > This means it exited successfully. We could also maintain a data > > structure where successfully-exiting threads will leave their success > > status together with some id of the message they sent -- unlike a > > thread that dies abruptly due to an error, a successful thread can > > store the information in the data structure before exiting. > > Yes why not but then I'd have to modify internals of 'message-send': > something I thought I could escape. I thought we were talking about a new function for this purpose, which would replace message-send, no? Then that new function could have this code. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-07 3:26 ` Eli Zaretskii @ 2023-11-07 9:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-07 12:12 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-07 9:06 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Manuel Giraud <manuel@ledu-giraud.fr> >> Cc: 63311@debbugs.gnu.org >> Date: Mon, 06 Nov 2023 21:55:49 +0100 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> >> If it is dead and (thread-last-error) returns nil maybe we can conclude >> >> that everything went well. But if (thread-last-error) returns a >> >> message, it could be message from any other Emacs thread: what to do in >> >> such case? >> > >> > Display a message about the error. >> >> I mean, the last error message could come from another thread not >> related in anyway to mail sending. No? > > It could, but why would there be other threads in this case? It seems that threads aren't used much in Emacs but isn't it dangerous to consider we're the only one using them? I don't if it would be easy but I think that it would be good to have a function like this: (thread-error thread) that would return the error message of the given thread like the global 'thread-last-error' does. >> >> Or worse: the thread is dead, (thread-last-error) returns >> >> nil... but it was cleared from another part of Emacs. >> > >> > This means it exited successfully. We could also maintain a data >> > structure where successfully-exiting threads will leave their success >> > status together with some id of the message they sent -- unlike a >> > thread that dies abruptly due to an error, a successful thread can >> > store the information in the data structure before exiting. >> >> Yes why not but then I'd have to modify internals of 'message-send': >> something I thought I could escape. > > I thought we were talking about a new function for this purpose, which > would replace message-send, no? Then that new function could have > this code. You're right it should be feasible inside this new function with something like that: --8<---------------cut here---------------start------------->8--- (make-thread #'(lambda () (if (message-send) (store-my-success) (store-my-failure)))) --8<---------------cut here---------------end--------------->8--- and then the main-thread will read those success or failure and act accordingly. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-07 9:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-07 12:12 ` Eli Zaretskii 2023-11-07 12:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-07 12:12 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Tue, 07 Nov 2023 10:06:58 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> I mean, the last error message could come from another thread not > >> related in anyway to mail sending. No? > > > > It could, but why would there be other threads in this case? > > It seems that threads aren't used much in Emacs but isn't it dangerous > to consider we're the only one using them? I don't if it would be easy > but I think that it would be good to have a function like this: > > (thread-error thread) > > that would return the error message of the given thread like the global > 'thread-last-error' does. Maybe. But we decided not to add this until there's a real need for it. Also, threads don't really have a unique ID, at least not easily, so there's more here than meets the eye... ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-07 12:12 ` Eli Zaretskii @ 2023-11-07 12:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-07 13:17 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-07 12:56 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 63311 Eli Zaretskii <eliz@gnu.org> writes: [...] >> that would return the error message of the given thread like the global >> 'thread-last-error' does. > > Maybe. But we decided not to add this until there's a real need for > it. Ok. > Also, threads don't really have a unique ID, at least not easily, > so there's more here than meets the eye... What do you mean by this? Where does this ID come from? -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-07 12:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-07 13:17 ` Eli Zaretskii 0 siblings, 0 replies; 41+ messages in thread From: Eli Zaretskii @ 2023-11-07 13:17 UTC (permalink / raw) To: Manuel Giraud; +Cc: 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: 63311@debbugs.gnu.org > Date: Tue, 07 Nov 2023 13:56:38 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > > Also, threads don't really have a unique ID, at least not easily, > > so there's more here than meets the eye... > > What do you mean by this? Where does this ID come from? From the underlying threads library, I think. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-01 18:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-01 19:29 ` Eli Zaretskii @ 2023-11-03 2:31 ` Richard Stallman 2023-11-03 7:18 ` Eli Zaretskii 1 sibling, 1 reply; 41+ messages in thread From: Richard Stallman @ 2023-11-03 2:31 UTC (permalink / raw) To: Manuel Giraud; +Cc: eliz, 63311 [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > The progress and "Sending email done" still shows in echo-area and > *Messages* buffer but asynchronously. I think that may prove confusing. What happens if you send a message, then edit the buffer and send again before that "done" message appears for the first? When the "done" message appears, can you tell which message was sent? -- Dr Richard Stallman (https://stallman.org) Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-03 2:31 ` Richard Stallman @ 2023-11-03 7:18 ` Eli Zaretskii 2023-11-03 13:49 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 41+ messages in thread From: Eli Zaretskii @ 2023-11-03 7:18 UTC (permalink / raw) To: rms; +Cc: 63311, manuel > From: Richard Stallman <rms@gnu.org> > Cc: eliz@gnu.org, 63311@debbugs.gnu.org > Date: Thu, 02 Nov 2023 22:31:35 -0400 > > > The progress and "Sending email done" still shows in echo-area and > > *Messages* buffer but asynchronously. > > I think that may prove confusing. What happens if you send a message, > then edit the buffer and send again before that "done" message appears > for the first? When the "done" message appears, can you tell which message > was sent? The messages should be displayed by the main thread when the sending thread finishes sending. And we probably need to rethink the text of the messages, to identify the message that was sent. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-03 7:18 ` Eli Zaretskii @ 2023-11-03 13:49 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-03 14:29 ` Eli Zaretskii 0 siblings, 1 reply; 41+ messages in thread From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-03 13:49 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rms, 63311 Eli Zaretskii <eliz@gnu.org> writes: >> From: Richard Stallman <rms@gnu.org> >> Cc: eliz@gnu.org, 63311@debbugs.gnu.org >> Date: Thu, 02 Nov 2023 22:31:35 -0400 >> >> > The progress and "Sending email done" still shows in echo-area and >> > *Messages* buffer but asynchronously. >> >> I think that may prove confusing. What happens if you send a message, >> then edit the buffer and send again before that "done" message appears >> for the first? When the "done" message appears, can you tell which message >> was sent? > > The messages should be displayed by the main thread when the sending > thread finishes sending. And we probably need to rethink the text of > the messages, to identify the message that was sent. Yes, of course. But I think we could do that at the very end of this work. -- Manuel Giraud ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-11-03 13:49 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-03 14:29 ` Eli Zaretskii 0 siblings, 0 replies; 41+ messages in thread From: Eli Zaretskii @ 2023-11-03 14:29 UTC (permalink / raw) To: Manuel Giraud; +Cc: rms, 63311 > From: Manuel Giraud <manuel@ledu-giraud.fr> > Cc: rms@gnu.org, 63311@debbugs.gnu.org > Date: Fri, 03 Nov 2023 14:49:40 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > > The messages should be displayed by the main thread when the sending > > thread finishes sending. And we probably need to rethink the text of > > the messages, to identify the message that was sent. > > Yes, of course. But I think we could do that at the very end of this > work. Agreed. ^ permalink raw reply [flat|nested] 41+ messages in thread
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split 2023-05-12 6:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-12 7:09 ` Eli Zaretskii @ 2023-05-12 7:10 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 0 replies; 41+ messages in thread From: Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12 7:10 UTC (permalink / raw) To: Manuel Giraud; +Cc: Eli Zaretskii, 63311 Manuel Giraud via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> writes: > BTW, do you know a more elisp way of defining a function than > "(let ((f #'(lambda…))))" form? First of all, I believe you can always get rid of the function quote because λ is a self-evaluating form. Not quite sure if `lexical-binding' makes a difference here though. Option 1: ```emacs-lisp (eval-when-compile (require 'cl-macs)) (cl-flet ((f (arg) 'expressions)) (f arg)) ``` Option 2: ```emacs-lisp (eval-when-compile (require 'cl-macs)) (cl-letf (((symbol-function 'f) (lambda (arg) 'expression))) (f arg)) ``` -- Best, RY ^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2023-11-07 13:17 UTC | newest] Thread overview: 41+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-05-05 13:13 bug#63311: 30.0.50; [PATCH] smtpmail-send-it split Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-05 18:57 ` Eli Zaretskii [not found] ` <874joq34bk.fsf@ledu-giraud.fr> 2023-05-06 6:20 ` Eli Zaretskii 2023-05-06 9:34 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-09 9:52 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-10 11:47 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-11 13:28 ` Eli Zaretskii 2023-05-11 20:59 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-12 5:41 ` Eli Zaretskii 2023-05-12 6:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-12 7:09 ` Eli Zaretskii 2023-05-12 7:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-01 12:35 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-01 12:59 ` Eli Zaretskii 2023-11-01 18:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-01 19:29 ` Eli Zaretskii 2023-11-01 19:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-02 5:48 ` Eli Zaretskii 2023-11-02 10:44 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-02 11:26 ` Eli Zaretskii 2023-11-05 14:24 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-05 15:46 ` Eli Zaretskii 2023-11-05 16:12 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-05 16:17 ` Eli Zaretskii 2023-11-06 10:21 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-06 12:40 ` Eli Zaretskii 2023-11-06 15:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-06 16:28 ` Eli Zaretskii 2023-11-06 17:57 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-06 19:21 ` Eli Zaretskii 2023-11-06 20:55 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-07 3:26 ` Eli Zaretskii 2023-11-07 9:06 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-07 12:12 ` Eli Zaretskii 2023-11-07 12:56 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-07 13:17 ` Eli Zaretskii 2023-11-03 2:31 ` Richard Stallman 2023-11-03 7:18 ` Eli Zaretskii 2023-11-03 13:49 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-11-03 14:29 ` Eli Zaretskii 2023-05-12 7:10 ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.