>From 8b659e704a6b39b586168a6851923fcfd6035d8e Mon Sep 17 00:00:00 2001 From: Kai Tetzlaff Date: Mon, 28 Feb 2022 11:08:07 +0100 Subject: [PATCH 1/6] Fix bug in sieve-manage--append-to-log and do some refactoring - simplify buffer creation and setup for process and log buffers - handle all encoding tasks in `sieve-manage-send' (and thus simplify `sieve-manage-putscript') - add/update doc-strings - update some comments * lisp/net/sieve-manage.el (sieve-manage-coding-system-for-read) (sieve-manage-coding-system-for-write): Remove unused constants. (sieve-manage-encode): Change misleading argument name (utf8-string -> str). (sieve-manage--coding-system): New constant. (sieve-manage-encode): Use `sieve-manage--coding-system', rename arguments, update doc string. (sieve-manage--set-buffer-maybe-append-text): New function. (sieve-manage-open-server): Change :coding property of `open-network-stream' from 'raw-text-unix to 'binary. (sieve-manage--append-to-log): Use `sieve-manage--set-buffer-maybe-append-text' to fix log buffer creation. (sieve-manage-decode) (sieve-manage-make-process-buffer): Use `sieve-manage--set-buffer-maybe-append-text'. (sieve-manage-send): Handle all encoding steps (including the 'literal-c2s' encoding previously done in `sieve-manage-putscript'). (sieve-manage-putscript): Move all encoding steps to `sieve-manage-send'. --- lisp/net/sieve-manage.el | 117 ++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 38 deletions(-) diff --git a/lisp/net/sieve-manage.el b/lisp/net/sieve-manage.el index 5bee4f4c4ad..bc8ba25f400 100644 --- a/lisp/net/sieve-manage.el +++ b/lisp/net/sieve-manage.el @@ -58,7 +58,7 @@ ;; ;; References: ;; -;; draft-martin-managesieve-02.txt, +;; RFC5804, ;; "A Protocol for Remotely Managing Sieve Scripts", ;; by Tim Martin. ;; @@ -145,6 +145,15 @@ sieve-manage-ignore-starttls :type 'boolean) ;; Internal variables: +(defconst sieve-manage--coding-system 'utf-8-unix + "Use \\='utf-8-unix coding system for (network) communication. + +Defines the coding system used for the internal (process, log) +buffers and the network stream created to communicate with the +managesieve server. Using \\='utf-8-unix encoding corresponds to +the use of UTF-8 in RFC5804 (managesieve). The explicit use of +\\='-unix\\=' avoids EOL conversions (and thus keeps CRLF (\"\\r\\n\") +sequences intact).") (defconst sieve-manage-local-variables '(sieve-manage-server sieve-manage-port @@ -154,8 +163,6 @@ sieve-manage-local-variables sieve-manage-client-eol sieve-manage-server-eol sieve-manage-capability)) -(defconst sieve-manage-coding-system-for-read 'binary) -(defconst sieve-manage-coding-system-for-write 'binary) (defvar sieve-manage-stream nil) (defvar sieve-manage-auth nil) (defvar sieve-manage-server nil) @@ -167,20 +174,45 @@ sieve-manage-process (defvar sieve-manage-capability nil) ;; Internal utility functions +(defun sieve-manage--set-buffer-maybe-append-text (buffer-name + &rest args) + "Append ARGS to buffer named BUFFER-NAME and return buffer. + +To be used with process and log buffers. When the buffer doesn't +exist, it gets created and configure as follows: +- set coding system to 'sieve-manage--coding-system', +- set buffer to single-byte mode, +- set `after-change-functions' to nil to avoid those + functions messing with buffer content, +- disable undo (to save a bit of memory and improve + performance). + +ARGS can be a nil, a string or a list of strings. If no +ARGS are provided, the content of buffer will not be +modified." + (let* ((existing-buffer (get-buffer buffer-name)) + (buffer (or existing-buffer + (get-buffer-create buffer-name)))) + (with-current-buffer buffer + (unless existing-buffer + (set-buffer-file-coding-system sieve-manage--coding-system) + (set-buffer-multibyte nil) + (setq-local after-change-functions nil) + (buffer-disable-undo)) + (when args + (goto-char (point-max)) + (apply #'insert args))) + buffer)) + (defun sieve-manage--append-to-log (&rest args) - "Append ARGS to sieve-manage log buffer. + "Append ARGS to `sieve-manage-log' buffer. -ARGS can be a string or a list of strings. -The buffer to use for logging is specifified via -`sieve-manage-log'. If it is nil, logging is disabled." +If `sieve-manage-log' is nil, logging is disabled. See also +`sieve-manage--set-buffer-maybe-append-text'." (when sieve-manage-log - (with-current-buffer (or (get-buffer sieve-manage-log) - (with-current-buffer - (get-buffer-create sieve-manage-log) - (set-buffer-multibyte nil) - (buffer-disable-undo))) - (goto-char (point-max)) - (apply #'insert args)))) + (apply #'sieve-manage--set-buffer-maybe-append-text + sieve-manage-log + args))) (defun sieve-manage--message (format-string &rest args) "Wrapper around `message' which also logs to sieve manage log. @@ -202,28 +234,28 @@ sieve-manage--error (sieve-manage--append-to-log msg "\n") (error msg))) -(defun sieve-manage-encode (utf8-string) - "Convert UTF8-STRING to managesieve protocol octets." - (encode-coding-string utf8-string 'raw-text t)) +(defun sieve-manage-encode (str) + "Convert STR to managesieve protocol octets." + (encode-coding-string str sieve-manage--coding-system t)) (defun sieve-manage-decode (octets &optional buffer) - "Convert managesieve protocol OCTETS to utf-8 string. + "Convert managesieve protocol OCTETS to UTF-8 string. If optional BUFFER is non-nil, insert decoded string into BUFFER." (when octets ;; eol type unix is required to preserve "\r\n" - (decode-coding-string octets 'utf-8-unix t buffer))) + (decode-coding-string octets + sieve-manage--coding-system + t buffer))) (defun sieve-manage-make-process-buffer () - (with-current-buffer - (generate-new-buffer (format " *sieve %s:%s*" - sieve-manage-server - sieve-manage-port)) - (mapc #'make-local-variable sieve-manage-local-variables) - (set-buffer-multibyte nil) - (setq-local after-change-functions nil) - (buffer-disable-undo) - (current-buffer))) + (let ((buffer (sieve-manage--set-buffer-maybe-append-text + (format " *sieve %s:%s*" + sieve-manage-server + sieve-manage-port)))) + (with-current-buffer buffer + (mapc #'make-local-variable sieve-manage-local-variables)) + buffer)) (defun sieve-manage-erase (&optional p buffer) (with-current-buffer (or buffer (current-buffer)) @@ -244,8 +276,7 @@ sieve-manage-open-server (open-network-stream "SIEVE" buffer server port :type stream - ;; eol type unix is required to preserve "\r\n" - :coding 'raw-text-unix + :coding 'binary :capability-command "CAPABILITY\r\n" :end-of-command "^\\(OK\\|NO\\).*\n" :success "^OK.*\n" @@ -480,9 +511,7 @@ sieve-manage-havespace (defun sieve-manage-putscript (name content &optional buffer) (with-current-buffer (or buffer (current-buffer)) - (sieve-manage-send (format "PUTSCRIPT \"%s\" {%d+}%s%s" name - (length (sieve-manage-encode content)) - sieve-manage-client-eol content)) + (sieve-manage-send (format "PUTSCRIPT \"%s\"" name) content) (sieve-manage-parse-okno))) (defun sieve-manage-deletescript (name &optional buffer) @@ -609,11 +638,23 @@ sieve-manage-parse-listscripts data rsp))) -(defun sieve-manage-send (cmdstr) - (setq cmdstr (sieve-manage-encode - (concat cmdstr sieve-manage-client-eol))) - (sieve-manage--append-to-log cmdstr) - (process-send-string sieve-manage-process cmdstr)) +(defun sieve-manage-send (command &optional payload-str) + "Send COMMAND with optional PAYLOAD-STR. + +If non-nil, PAYLOAD-STR will be appended to COMMAND using the +\\='literal-s2c\\' representation according to RFC5804." + (let ((encoded (when payload-str (sieve-manage-encode payload-str))) + literal-c2s cmdstr) + (when encoded + (setq literal-c2s (format " {%d+}%s%s" + (length encoded) + sieve-manage-client-eol + encoded))) + (setq cmdstr (concat (sieve-manage-encode command) + literal-c2s + sieve-manage-client-eol)) + (sieve-manage--append-to-log cmdstr) + (process-send-string sieve-manage-process cmdstr))) (provide 'sieve-manage) -- 2.39.0