lisp/gnus/sieve-manage.el (sieve-manage-authenticator-alist): Update the sieve port...
[bpt/emacs.git] / lisp / gnus / sieve-manage.el
CommitLineData
53964682 1;;; sieve-manage.el --- Implementation of the managesieve protocol in elisp
e84b4b86 2
ab422c4d 3;; Copyright (C) 2001-2013 Free Software Foundation, Inc.
23f87bed
MB
4
5;; Author: Simon Josefsson <simon@josefsson.org>
6
7;; This file is part of GNU Emacs.
8
5e809f55 9;; GNU Emacs is free software: you can redistribute it and/or modify
23f87bed 10;; it under the terms of the GNU General Public License as published by
5e809f55
GM
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
23f87bed
MB
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
5e809f55 16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23f87bed
MB
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
5e809f55 20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23f87bed
MB
21
22;;; Commentary:
23
24;; This library provides an elisp API for the managesieve network
25;; protocol.
26;;
01c52d31
MB
27;; It uses the SASL library for authentication, which means it
28;; supports DIGEST-MD5, CRAM-MD5, SCRAM-MD5, NTLM, PLAIN and LOGIN
29;; methods. STARTTLS is not well tested, but should be easy to get to
30;; work if someone wants.
23f87bed
MB
31;;
32;; The API should be fairly obvious for anyone familiar with the
33;; managesieve protocol, interface functions include:
34;;
35;; `sieve-manage-open'
36;; open connection to managesieve server, returning a buffer to be
37;; used by all other API functions.
38;;
39;; `sieve-manage-opened'
40;; check if a server is open or not
41;;
42;; `sieve-manage-close'
43;; close a server connection.
44;;
23f87bed
MB
45;; `sieve-manage-listscripts'
46;; `sieve-manage-deletescript'
47;; `sieve-manage-getscript'
48;; performs managesieve protocol actions
49;;
50;; and that's it. Example of a managesieve session in *scratch*:
51;;
fd9ba500
JD
52;; (with-current-buffer (sieve-manage-open "mail.example.com")
53;; (sieve-manage-authenticate)
54;; (sieve-manage-listscripts))
23f87bed 55;;
fd9ba500 56;; => ((active . "main") "vacation")
23f87bed
MB
57;;
58;; References:
59;;
60;; draft-martin-managesieve-02.txt,
61;; "A Protocol for Remotely Managing Sieve Scripts",
62;; by Tim Martin.
63;;
64;; Release history:
65;;
66;; 2001-10-31 Committed to Oort Gnus.
67;; 2002-07-27 Added DELETESCRIPT. Suggested by Ned Ludd.
01c52d31 68;; 2002-08-03 Use SASL library.
23f87bed
MB
69
70;;; Code:
71
f0b7f5a8 72;; For Emacs <22.2 and XEmacs.
1d1df709
GM
73(eval-and-compile
74 (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
87035689
MB
75
76(if (locate-library "password-cache")
77 (require 'password-cache)
78 (require 'password))
79
01c52d31 80(eval-when-compile
1d8ff0c6 81 (require 'cl) ; caddr
01c52d31
MB
82 (require 'sasl)
83 (require 'starttls))
8abf1b22
GM
84(autoload 'sasl-find-mechanism "sasl")
85(autoload 'starttls-open-stream "starttls")
b8e0f0cd 86(autoload 'auth-source-search "auth-source")
23f87bed
MB
87
88;; User customizable variables:
89
90(defgroup sieve-manage nil
91 "Low-level Managesieve protocol issues."
92 :group 'mail
93 :prefix "sieve-")
94
95(defcustom sieve-manage-log "*sieve-manage-log*"
96 "Name of buffer for managesieve session trace."
d0859c9a
MB
97 :type 'string
98 :group 'sieve-manage)
23f87bed 99
23f87bed
MB
100(defcustom sieve-manage-server-eol "\r\n"
101 "The EOL string sent from the server."
d0859c9a
MB
102 :type 'string
103 :group 'sieve-manage)
23f87bed
MB
104
105(defcustom sieve-manage-client-eol "\r\n"
106 "The EOL string we send to the server."
d0859c9a
MB
107 :type 'string
108 :group 'sieve-manage)
23f87bed
MB
109
110(defcustom sieve-manage-streams '(network starttls shell)
d0859c9a
MB
111 "Priority of streams to consider when opening connection to server."
112 :group 'sieve-manage)
23f87bed
MB
113
114(defcustom sieve-manage-stream-alist
115 '((network sieve-manage-network-p sieve-manage-network-open)
116 (shell sieve-manage-shell-p sieve-manage-shell-open)
117 (starttls sieve-manage-starttls-p sieve-manage-starttls-open))
118 "Definition of network streams.
119
120\(NAME CHECK OPEN)
121
122NAME names the stream, CHECK is a function returning non-nil if the
123server support the stream and OPEN is a function for opening the
d0859c9a
MB
124stream."
125 :group 'sieve-manage)
23f87bed 126
01c52d31
MB
127(defcustom sieve-manage-authenticators '(digest-md5
128 cram-md5
129 scram-md5
130 ntlm
131 plain
132 login)
d0859c9a
MB
133 "Priority of authenticators to consider when authenticating to server."
134 :group 'sieve-manage)
23f87bed
MB
135
136(defcustom sieve-manage-authenticator-alist
137 '((cram-md5 sieve-manage-cram-md5-p sieve-manage-cram-md5-auth)
01c52d31
MB
138 (digest-md5 sieve-manage-digest-md5-p sieve-manage-digest-md5-auth)
139 (scram-md5 sieve-manage-scram-md5-p sieve-manage-scram-md5-auth)
140 (ntlm sieve-manage-ntlm-p sieve-manage-ntlm-auth)
141 (plain sieve-manage-plain-p sieve-manage-plain-auth)
142 (login sieve-manage-login-p sieve-manage-login-auth))
23f87bed
MB
143 "Definition of authenticators.
144
145\(NAME CHECK AUTHENTICATE)
146
147NAME names the authenticator. CHECK is a function returning non-nil if
148the server support the authenticator and AUTHENTICATE is a function
d0859c9a
MB
149for doing the actual authentication."
150 :group 'sieve-manage)
23f87bed 151
4afd650a 152(defcustom sieve-manage-default-port "sieve"
6b7df8d3 153 "Default port number or service name for managesieve protocol."
4afd650a
JD
154 :type '(choice integer string)
155 :version "24.4"
d0859c9a 156 :group 'sieve-manage)
23f87bed 157
562f5ce5
G
158(defcustom sieve-manage-default-stream 'network
159 "Default stream type to use for `sieve-manage'.
160Must be a name of a stream in `sieve-manage-stream-alist'."
2bed3f04 161 :version "24.1"
562f5ce5
G
162 :type 'symbol
163 :group 'sieve-manage)
164
23f87bed
MB
165;; Internal variables:
166
167(defconst sieve-manage-local-variables '(sieve-manage-server
168 sieve-manage-port
169 sieve-manage-auth
170 sieve-manage-stream
23f87bed
MB
171 sieve-manage-process
172 sieve-manage-client-eol
173 sieve-manage-server-eol
174 sieve-manage-capability))
23f87bed
MB
175(defconst sieve-manage-coding-system-for-read 'binary)
176(defconst sieve-manage-coding-system-for-write 'binary)
177(defvar sieve-manage-stream nil)
178(defvar sieve-manage-auth nil)
179(defvar sieve-manage-server nil)
180(defvar sieve-manage-port nil)
23f87bed
MB
181(defvar sieve-manage-state 'closed
182 "Managesieve state.
183Valid states are `closed', `initial', `nonauth', and `auth'.")
184(defvar sieve-manage-process nil)
185(defvar sieve-manage-capability nil)
186
187;; Internal utility functions
188
765d4319 189(defmacro sieve-manage-disable-multibyte ()
23f87bed 190 "Enable multibyte in the current buffer."
765d4319
KY
191 (unless (featurep 'xemacs)
192 '(set-buffer-multibyte nil)))
23f87bed 193
23f87bed
MB
194(defun sieve-manage-erase (&optional p buffer)
195 (let ((buffer (or buffer (current-buffer))))
196 (and sieve-manage-log
197 (with-current-buffer (get-buffer-create sieve-manage-log)
198 (sieve-manage-disable-multibyte)
199 (buffer-disable-undo)
200 (goto-char (point-max))
201 (insert-buffer-substring buffer (with-current-buffer buffer
202 (point-min))
203 (or p (with-current-buffer buffer
204 (point-max)))))))
205 (delete-region (point-min) (or p (point-max))))
206
207(defun sieve-manage-open-1 (buffer)
208 (with-current-buffer buffer
209 (sieve-manage-erase)
210 (setq sieve-manage-state 'initial
211 sieve-manage-process
212 (condition-case ()
213 (funcall (nth 2 (assq sieve-manage-stream
214 sieve-manage-stream-alist))
215 "sieve" buffer sieve-manage-server sieve-manage-port)
216 ((error quit) nil)))
217 (when sieve-manage-process
218 (while (and (eq sieve-manage-state 'initial)
219 (memq (process-status sieve-manage-process) '(open run)))
220 (message "Waiting for response from %s..." sieve-manage-server)
221 (accept-process-output sieve-manage-process 1))
222 (message "Waiting for response from %s...done" sieve-manage-server)
223 (and (memq (process-status sieve-manage-process) '(open run))
224 sieve-manage-process))))
225
226;; Streams
227
228(defun sieve-manage-network-p (buffer)
229 t)
230
231(defun sieve-manage-network-open (name buffer server port)
232 (let* ((port (or port sieve-manage-default-port))
233 (coding-system-for-read sieve-manage-coding-system-for-read)
234 (coding-system-for-write sieve-manage-coding-system-for-write)
235 (process (open-network-stream name buffer server port)))
236 (when process
237 (while (and (memq (process-status process) '(open run))
238 (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
239 (goto-char (point-min))
240 (not (sieve-manage-parse-greeting-1)))
241 (accept-process-output process 1)
242 (sit-for 1))
243 (sieve-manage-erase nil buffer)
244 (when (memq (process-status process) '(open run))
245 process))))
246
e3e955fe 247(defun sieve-manage-starttls-p (buffer)
23f87bed
MB
248 (condition-case ()
249 (progn
250 (require 'starttls)
251 (call-process "starttls"))
252 (error nil)))
253
e3e955fe 254(defun sieve-manage-starttls-open (name buffer server port)
23f87bed
MB
255 (let* ((port (or port sieve-manage-default-port))
256 (coding-system-for-read sieve-manage-coding-system-for-read)
257 (coding-system-for-write sieve-manage-coding-system-for-write)
258 (process (starttls-open-stream name buffer server port))
259 done)
260 (when process
261 (while (and (memq (process-status process) '(open run))
262 (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
263 (goto-char (point-min))
264 (not (sieve-manage-parse-greeting-1)))
265 (accept-process-output process 1)
266 (sit-for 1))
267 (sieve-manage-erase nil buffer)
268 (sieve-manage-send "STARTTLS")
269 (starttls-negotiate process))
270 (when (memq (process-status process) '(open run))
271 process)))
272
273;; Authenticators
01c52d31
MB
274(defun sieve-sasl-auth (buffer mech)
275 "Login to server using the SASL MECH method."
276 (message "sieve: Authenticating using %s..." mech)
1d8e1f78 277 (with-current-buffer buffer
b8e0f0cd
G
278 (let* ((auth-info (auth-source-search :host sieve-manage-server
279 :port "sieve"
a5057546
G
280 :max 1
281 :create t))
282 (user-name (or (plist-get (nth 0 auth-info) :user) ""))
283 (user-password (or (plist-get (nth 0 auth-info) :secret) ""))
b8e0f0cd
G
284 (user-password (if (functionp user-password)
285 (funcall user-password)
286 user-password))
1d8e1f78 287 (client (sasl-make-client (sasl-find-mechanism (list mech))
b8e0f0cd 288 user-name "sieve" sieve-manage-server))
1d8e1f78
JD
289 (sasl-read-passphrase
290 ;; We *need* to copy the password, because sasl will modify it
291 ;; somehow.
b8e0f0cd 292 `(lambda (prompt) ,(copy-sequence user-password)))
1d8e1f78
JD
293 (step (sasl-next-step client nil))
294 (tag (sieve-manage-send
295 (concat
296 "AUTHENTICATE \""
297 mech
298 "\""
299 (and (sasl-step-data step)
300 (concat
301 " \""
302 (base64-encode-string
303 (sasl-step-data step)
304 'no-line-break)
305 "\"")))))
306 data rsp)
307 (catch 'done
308 (while t
309 (setq rsp nil)
310 (goto-char (point-min))
311 (while (null (or (progn
312 (setq rsp (sieve-manage-is-string))
313 (if (not (and rsp (looking-at
314 sieve-manage-server-eol)))
315 (setq rsp nil)
316 (goto-char (match-end 0))
317 rsp))
318 (setq rsp (sieve-manage-is-okno))))
319 (accept-process-output sieve-manage-process 1)
320 (goto-char (point-min)))
321 (sieve-manage-erase)
322 (when (sieve-manage-ok-p rsp)
323 (when (and (cadr rsp)
324 (string-match "^SASL \"\\([^\"]+\\)\"" (cadr rsp)))
325 (sasl-step-set-data
326 step (base64-decode-string (match-string 1 (cadr rsp)))))
327 (if (and (setq step (sasl-next-step client step))
328 (setq data (sasl-step-data step)))
329 ;; We got data for server but it's finished
330 (error "Server not ready for SASL data: %s" data)
331 ;; The authentication process is finished.
332 (throw 'done t)))
333 (unless (stringp rsp)
334 (error "Server aborted SASL authentication: %s" (caddr rsp)))
335 (sasl-step-set-data step (base64-decode-string rsp))
336 (setq step (sasl-next-step client step))
337 (sieve-manage-send
338 (if (sasl-step-data step)
339 (concat "\""
340 (base64-encode-string (sasl-step-data step)
341 'no-line-break)
342 "\"")
343 ""))))
344 (message "sieve: Login using %s...done" mech))))
01c52d31
MB
345
346(defun sieve-manage-cram-md5-p (buffer)
347 (sieve-manage-capability "SASL" "CRAM-MD5" buffer))
348
349(defun sieve-manage-cram-md5-auth (buffer)
350 "Login to managesieve server using the CRAM-MD5 SASL method."
351 (sieve-sasl-auth buffer "CRAM-MD5"))
352
353(defun sieve-manage-digest-md5-p (buffer)
354 (sieve-manage-capability "SASL" "DIGEST-MD5" buffer))
355
356(defun sieve-manage-digest-md5-auth (buffer)
357 "Login to managesieve server using the DIGEST-MD5 SASL method."
358 (sieve-sasl-auth buffer "DIGEST-MD5"))
359
360(defun sieve-manage-scram-md5-p (buffer)
361 (sieve-manage-capability "SASL" "SCRAM-MD5" buffer))
362
363(defun sieve-manage-scram-md5-auth (buffer)
364 "Login to managesieve server using the SCRAM-MD5 SASL method."
365 (sieve-sasl-auth buffer "SCRAM-MD5"))
366
367(defun sieve-manage-ntlm-p (buffer)
368 (sieve-manage-capability "SASL" "NTLM" buffer))
369
370(defun sieve-manage-ntlm-auth (buffer)
371 "Login to managesieve server using the NTLM SASL method."
372 (sieve-sasl-auth buffer "NTLM"))
373
23f87bed
MB
374(defun sieve-manage-plain-p (buffer)
375 (sieve-manage-capability "SASL" "PLAIN" buffer))
376
377(defun sieve-manage-plain-auth (buffer)
378 "Login to managesieve server using the PLAIN SASL method."
01c52d31 379 (sieve-sasl-auth buffer "PLAIN"))
23f87bed 380
01c52d31
MB
381(defun sieve-manage-login-p (buffer)
382 (sieve-manage-capability "SASL" "LOGIN" buffer))
23f87bed 383
01c52d31
MB
384(defun sieve-manage-login-auth (buffer)
385 "Login to managesieve server using the LOGIN SASL method."
386 (sieve-sasl-auth buffer "LOGIN"))
23f87bed
MB
387
388;; Managesieve API
389
390(defun sieve-manage-open (server &optional port stream auth buffer)
391 "Open a network connection to a managesieve SERVER (string).
56fd9faa
JB
392Optional argument PORT is port number (integer) on remote server.
393Optional argument STREAM is any of `sieve-manage-streams' (a symbol).
394Optional argument AUTH indicates authenticator to use, see
395`sieve-manage-authenticators' for available authenticators.
396If nil, chooses the best stream the server is capable of.
397Optional argument BUFFER is buffer (buffer, or string naming buffer)
23f87bed 398to work in."
c4c15f02
GM
399 (or port (setq port sieve-manage-default-port))
400 (setq buffer (or buffer (format " *sieve* %s:%s" server port)))
23f87bed 401 (with-current-buffer (get-buffer-create buffer)
6ab3804a 402 (mapc 'make-local-variable sieve-manage-local-variables)
23f87bed
MB
403 (sieve-manage-disable-multibyte)
404 (buffer-disable-undo)
405 (setq sieve-manage-server (or server sieve-manage-server))
c4c15f02 406 (setq sieve-manage-port port)
23f87bed
MB
407 (setq sieve-manage-stream (or stream sieve-manage-stream))
408 (message "sieve: Connecting to %s..." sieve-manage-server)
409 (if (let ((sieve-manage-stream
410 (or sieve-manage-stream sieve-manage-default-stream)))
411 (sieve-manage-open-1 buffer))
412 ;; Choose stream.
413 (let (stream-changed)
414 (message "sieve: Connecting to %s...done" sieve-manage-server)
415 (when (null sieve-manage-stream)
416 (let ((streams sieve-manage-streams))
417 (while (setq stream (pop streams))
418 (if (funcall (nth 1 (assq stream
419 sieve-manage-stream-alist)) buffer)
420 (setq stream-changed
421 (not (eq (or sieve-manage-stream
422 sieve-manage-default-stream)
423 stream))
424 sieve-manage-stream stream
425 streams nil)))
426 (unless sieve-manage-stream
427 (error "Couldn't figure out a stream for server"))))
428 (when stream-changed
429 (message "sieve: Reconnecting with stream `%s'..."
430 sieve-manage-stream)
431 (sieve-manage-close buffer)
432 (if (sieve-manage-open-1 buffer)
433 (message "sieve: Reconnecting with stream `%s'...done"
434 sieve-manage-stream)
435 (message "sieve: Reconnecting with stream `%s'...failed"
436 sieve-manage-stream))
437 (setq sieve-manage-capability nil))
438 (if (sieve-manage-opened buffer)
439 ;; Choose authenticator
440 (when (and (null sieve-manage-auth)
441 (not (eq sieve-manage-state 'auth)))
442 (let ((auths sieve-manage-authenticators))
443 (while (setq auth (pop auths))
444 (if (funcall (nth 1 (assq
445 auth
446 sieve-manage-authenticator-alist))
447 buffer)
448 (setq sieve-manage-auth auth
449 auths nil)))
450 (unless sieve-manage-auth
451 (error "Couldn't figure out authenticator for server"))))))
452 (message "sieve: Connecting to %s...failed" sieve-manage-server))
453 (when (sieve-manage-opened buffer)
454 (sieve-manage-erase)
455 buffer)))
456
fd9ba500
JD
457(defun sieve-manage-authenticate (&optional buffer)
458 "Authenticate on server in BUFFER.
459Return `sieve-manage-state' value."
460 (with-current-buffer (or buffer (current-buffer))
461 (if (eq sieve-manage-state 'nonauth)
462 (when (funcall (nth 2 (assq sieve-manage-auth
463 sieve-manage-authenticator-alist))
464 (current-buffer))
465 (setq sieve-manage-state 'auth))
466 sieve-manage-state)))
467
23f87bed
MB
468(defun sieve-manage-opened (&optional buffer)
469 "Return non-nil if connection to managesieve server in BUFFER is open.
470If BUFFER is nil then the current buffer is used."
471 (and (setq buffer (get-buffer (or buffer (current-buffer))))
472 (buffer-live-p buffer)
473 (with-current-buffer buffer
474 (and sieve-manage-process
475 (memq (process-status sieve-manage-process) '(open run))))))
476
477(defun sieve-manage-close (&optional buffer)
478 "Close connection to managesieve server in BUFFER.
479If BUFFER is nil, the current buffer is used."
480 (with-current-buffer (or buffer (current-buffer))
481 (when (sieve-manage-opened)
482 (sieve-manage-send "LOGOUT")
483 (sit-for 1))
484 (when (and sieve-manage-process
485 (memq (process-status sieve-manage-process) '(open run)))
486 (delete-process sieve-manage-process))
487 (setq sieve-manage-process nil)
488 (sieve-manage-erase)
489 t))
490
23f87bed 491(defun sieve-manage-capability (&optional name value buffer)
6f7e2ffd
JD
492 "Check if capability NAME of server BUFFER match VALUE.
493If it does, return the server value of NAME. If not returns nil.
494If VALUE is nil, do not check VALUE and return server value.
495If NAME is nil, return the full server list of capabilities."
23f87bed
MB
496 (with-current-buffer (or buffer (current-buffer))
497 (if (null name)
498 sieve-manage-capability
6f7e2ffd
JD
499 (let ((server-value (cadr (assoc name sieve-manage-capability))))
500 (when (or (null value)
501 (and server-value
502 (string-match value server-value)))
503 server-value)))))
23f87bed
MB
504
505(defun sieve-manage-listscripts (&optional buffer)
506 (with-current-buffer (or buffer (current-buffer))
507 (sieve-manage-send "LISTSCRIPTS")
508 (sieve-manage-parse-listscripts)))
509
510(defun sieve-manage-havespace (name size &optional buffer)
511 (with-current-buffer (or buffer (current-buffer))
512 (sieve-manage-send (format "HAVESPACE \"%s\" %s" name size))
513 (sieve-manage-parse-okno)))
514
23f87bed
MB
515(defun sieve-manage-putscript (name content &optional buffer)
516 (with-current-buffer (or buffer (current-buffer))
517 (sieve-manage-send (format "PUTSCRIPT \"%s\" {%d+}%s%s" name
2136a8a7
SM
518 ;; Here we assume that the coding-system will
519 ;; replace each char with a single byte.
520 ;; This is always the case if `content' is
521 ;; a unibyte string.
522 (length content)
23f87bed
MB
523 sieve-manage-client-eol content))
524 (sieve-manage-parse-okno)))
525
526(defun sieve-manage-deletescript (name &optional buffer)
527 (with-current-buffer (or buffer (current-buffer))
528 (sieve-manage-send (format "DELETESCRIPT \"%s\"" name))
529 (sieve-manage-parse-okno)))
530
531(defun sieve-manage-getscript (name output-buffer &optional buffer)
532 (with-current-buffer (or buffer (current-buffer))
533 (sieve-manage-send (format "GETSCRIPT \"%s\"" name))
534 (let ((script (sieve-manage-parse-string)))
535 (sieve-manage-parse-crlf)
536 (with-current-buffer output-buffer
537 (insert script))
538 (sieve-manage-parse-okno))))
539
540(defun sieve-manage-setactive (name &optional buffer)
541 (with-current-buffer (or buffer (current-buffer))
542 (sieve-manage-send (format "SETACTIVE \"%s\"" name))
543 (sieve-manage-parse-okno)))
544
545;; Protocol parsing routines
546
547(defun sieve-manage-ok-p (rsp)
548 (string= (downcase (or (car-safe rsp) "")) "ok"))
549
550(defsubst sieve-manage-forward ()
551 (or (eobp) (forward-char)))
552
553(defun sieve-manage-is-okno ()
554 (when (looking-at (concat
555 "^\\(OK\\|NO\\)\\( (\\([^)]+\\))\\)?\\( \\(.*\\)\\)?"
556 sieve-manage-server-eol))
557 (let ((status (match-string 1))
558 (resp-code (match-string 3))
559 (response (match-string 5)))
560 (when response
561 (goto-char (match-beginning 5))
562 (setq response (sieve-manage-is-string)))
563 (list status resp-code response))))
564
565(defun sieve-manage-parse-okno ()
566 (let (rsp)
567 (while (null rsp)
568 (accept-process-output (get-buffer-process (current-buffer)) 1)
569 (goto-char (point-min))
570 (setq rsp (sieve-manage-is-okno)))
571 (sieve-manage-erase)
572 rsp))
573
574(defun sieve-manage-parse-capability-1 ()
575 "Accept a managesieve greeting."
576 (let (str)
577 (while (setq str (sieve-manage-is-string))
578 (if (eq (char-after) ? )
579 (progn
580 (sieve-manage-forward)
581 (push (list str (sieve-manage-is-string))
582 sieve-manage-capability))
583 (push (list str) sieve-manage-capability))
584 (forward-line)))
889e4d55 585 (when (re-search-forward (concat "^OK.*" sieve-manage-server-eol) nil t)
23f87bed
MB
586 (setq sieve-manage-state 'nonauth)))
587
588(defalias 'sieve-manage-parse-greeting-1 'sieve-manage-parse-capability-1)
589
590(defun sieve-manage-is-string ()
591 (cond ((looking-at "\"\\([^\"]+\\)\"")
592 (prog1
593 (match-string 1)
594 (goto-char (match-end 0))))
64763fe3 595 ((looking-at (concat "{\\([0-9]+\\+?\\)}" sieve-manage-server-eol))
23f87bed
MB
596 (let ((pos (match-end 0))
597 (len (string-to-number (match-string 1))))
598 (if (< (point-max) (+ pos len))
599 nil
600 (goto-char (+ pos len))
601 (buffer-substring pos (+ pos len)))))))
602
603(defun sieve-manage-parse-string ()
604 (let (rsp)
605 (while (null rsp)
606 (accept-process-output (get-buffer-process (current-buffer)) 1)
607 (goto-char (point-min))
608 (setq rsp (sieve-manage-is-string)))
609 (sieve-manage-erase (point))
610 rsp))
611
612(defun sieve-manage-parse-crlf ()
613 (when (looking-at sieve-manage-server-eol)
614 (sieve-manage-erase (match-end 0))))
615
616(defun sieve-manage-parse-listscripts ()
617 (let (tmp rsp data)
618 (while (null rsp)
619 (while (null (or (setq rsp (sieve-manage-is-okno))
620 (setq tmp (sieve-manage-is-string))))
621 (accept-process-output (get-buffer-process (current-buffer)) 1)
622 (goto-char (point-min)))
623 (when tmp
624 (while (not (looking-at (concat "\\( ACTIVE\\)?"
625 sieve-manage-server-eol)))
626 (accept-process-output (get-buffer-process (current-buffer)) 1)
627 (goto-char (point-min)))
628 (if (match-string 1)
629 (push (cons 'active tmp) data)
630 (push tmp data))
631 (goto-char (match-end 0))
632 (setq tmp nil)))
633 (sieve-manage-erase)
634 (if (sieve-manage-ok-p rsp)
635 data
636 rsp)))
637
638(defun sieve-manage-send (cmdstr)
639 (setq cmdstr (concat cmdstr sieve-manage-client-eol))
640 (and sieve-manage-log
641 (with-current-buffer (get-buffer-create sieve-manage-log)
642 (sieve-manage-disable-multibyte)
643 (buffer-disable-undo)
644 (goto-char (point-max))
645 (insert cmdstr)))
646 (process-send-string sieve-manage-process cmdstr))
647
648(provide 'sieve-manage)
649
23f87bed 650;; sieve-manage.el ends here