aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorTeodor Zlatanov2010-10-07 03:49:38 +0000
committerKatsumi Yamaoka2010-10-07 03:49:38 +0000
commitcbabe91fdce9313ffc3f72e0a828b86580661dac (patch)
treeb2e1089233cfae029b3f4d5ba5f545044bdecc0e /lisp
parent58d1ac6d6d7c7634b3ecb7e0cf3f0c67db319b9b (diff)
downloademacs-cbabe91fdce9313ffc3f72e0a828b86580661dac.tar.gz
emacs-cbabe91fdce9313ffc3f72e0a828b86580661dac.zip
gnus-int.el, gnus-util.el: Gnus hooks for the mark get/set operations.
gnus-sync.el: Update docs to explain state and plans. auth-source.el: Update docs with TODO items.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/gnus/ChangeLog13
-rw-r--r--lisp/gnus/auth-source.el440
-rw-r--r--lisp/gnus/gnus-int.el14
-rw-r--r--lisp/gnus/gnus-sync.el7
-rw-r--r--lisp/gnus/gnus-util.el5
5 files changed, 262 insertions, 217 deletions
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog
index 0ffc7599cba..11c2b70fc86 100644
--- a/lisp/gnus/ChangeLog
+++ b/lisp/gnus/ChangeLog
@@ -1,3 +1,16 @@
12010-10-07 Teodor Zlatanov <tzz@lifelogs.com>
2
3 * auth-source.el: Update docs with TODO items.
4
5 * gnus-sync.el: Update docs to explain state and plans.
6
7 * gnus-int.el (gnus-after-set-mark-hook, gnus-before-update-mark-hook):
8 Hooks for mark updates.
9 (gnus-request-set-mark, gnus-request-update-mark): Use them.
10
11 * gnus-util.el (gnus-run-hooks-with-args): Convenience function to run
12 hooks with arguments, which is needed for mark update hooks.
13
12010-10-06 Julien Danjou <julien@danjou.info> 142010-10-06 Julien Danjou <julien@danjou.info>
2 15
3 * sieve-manage.el: Update example in `Commentary'. 16 * sieve-manage.el: Update example in `Commentary'.
diff --git a/lisp/gnus/auth-source.el b/lisp/gnus/auth-source.el
index caead4fabfa..0b1d8eb57af 100644
--- a/lisp/gnus/auth-source.el
+++ b/lisp/gnus/auth-source.el
@@ -29,6 +29,14 @@
29 29
30;; See the auth.info Info documentation for details. 30;; See the auth.info Info documentation for details.
31 31
32;; TODO:
33
34;; - never decode the backend file unless it's necessary
35;; - a more generic way to match backends and search backend contents
36;; - absorb netrc.el and simplify it
37;; - protect passwords better
38;; - allow creating and changing netrc lines (not files) e.g. change a password
39
32;;; Code: 40;;; Code:
33 41
34(require 'gnus-util) 42(require 'gnus-util)
@@ -49,29 +57,29 @@
49 :group 'gnus) 57 :group 'gnus)
50 58
51(defcustom auth-source-protocols '((imap "imap" "imaps" "143" "993") 59(defcustom auth-source-protocols '((imap "imap" "imaps" "143" "993")
52 (pop3 "pop3" "pop" "pop3s" "110" "995") 60 (pop3 "pop3" "pop" "pop3s" "110" "995")
53 (ssh "ssh" "22") 61 (ssh "ssh" "22")
54 (sftp "sftp" "115") 62 (sftp "sftp" "115")
55 (smtp "smtp" "25")) 63 (smtp "smtp" "25"))
56 "List of authentication protocols and their names" 64 "List of authentication protocols and their names"
57 65
58 :group 'auth-source 66 :group 'auth-source
59 :version "23.2" ;; No Gnus 67 :version "23.2" ;; No Gnus
60 :type '(repeat :tag "Authentication Protocols" 68 :type '(repeat :tag "Authentication Protocols"
61 (cons :tag "Protocol Entry" 69 (cons :tag "Protocol Entry"
62 (symbol :tag "Protocol") 70 (symbol :tag "Protocol")
63 (repeat :tag "Names" 71 (repeat :tag "Names"
64 (string :tag "Name"))))) 72 (string :tag "Name")))))
65 73
66;;; generate all the protocols in a format Customize can use 74;;; generate all the protocols in a format Customize can use
67;;; TODO: generate on the fly from auth-source-protocols 75;;; TODO: generate on the fly from auth-source-protocols
68(defconst auth-source-protocols-customize 76(defconst auth-source-protocols-customize
69 (mapcar (lambda (a) 77 (mapcar (lambda (a)
70 (let ((p (car-safe a))) 78 (let ((p (car-safe a)))
71 (list 'const 79 (list 'const
72 :tag (upcase (symbol-name p)) 80 :tag (upcase (symbol-name p))
73 p))) 81 p)))
74 auth-source-protocols)) 82 auth-source-protocols))
75 83
76(defvar auth-source-cache (make-hash-table :test 'equal) 84(defvar auth-source-cache (make-hash-table :test 'equal)
77 "Cache for auth-source data") 85 "Cache for auth-source data")
@@ -94,11 +102,11 @@ If the value is a function, debug messages are logged by calling
94 that function using the same arguments as `message'." 102 that function using the same arguments as `message'."
95 :group 'auth-source 103 :group 'auth-source
96 :version "23.2" ;; No Gnus 104 :version "23.2" ;; No Gnus
97 :type `(choice 105 :type `(choice
98 :tag "auth-source debugging mode" 106 :tag "auth-source debugging mode"
99 (const :tag "Log using `message' to the *Messages* buffer" t) 107 (const :tag "Log using `message' to the *Messages* buffer" t)
100 (function :tag "Function that takes arguments like `message'") 108 (function :tag "Function that takes arguments like `message'")
101 (const :tag "Don't log anything" nil))) 109 (const :tag "Don't log anything" nil)))
102 110
103(defcustom auth-source-hide-passwords t 111(defcustom auth-source-hide-passwords t
104 "Whether auth-source should hide passwords in log messages. 112 "Whether auth-source should hide passwords in log messages.
@@ -108,7 +116,7 @@ Only relevant if `auth-source-debug' is not nil."
108 :type `boolean) 116 :type `boolean)
109 117
110(defcustom auth-sources '((:source "~/.authinfo.gpg") 118(defcustom auth-sources '((:source "~/.authinfo.gpg")
111 (:source "~/.authinfo")) 119 (:source "~/.authinfo"))
112 "List of authentication sources. 120 "List of authentication sources.
113 121
114The default will get login and password information from a .gpg 122The default will get login and password information from a .gpg
@@ -122,34 +130,34 @@ can get pretty complex."
122 :group 'auth-source 130 :group 'auth-source
123 :version "23.2" ;; No Gnus 131 :version "23.2" ;; No Gnus
124 :type `(repeat :tag "Authentication Sources" 132 :type `(repeat :tag "Authentication Sources"
125 (list :tag "Source definition" 133 (list :tag "Source definition"
126 (const :format "" :value :source) 134 (const :format "" :value :source)
127 (choice :tag "Authentication backend choice" 135 (choice :tag "Authentication backend choice"
128 (string :tag "Authentication Source (file)") 136 (string :tag "Authentication Source (file)")
129 (list :tag "secrets.el (Secret Service API/KWallet/GNOME Keyring)" 137 (list :tag "secrets.el (Secret Service API/KWallet/GNOME Keyring)"
130 (const :format "" :value :secrets) 138 (const :format "" :value :secrets)
131 (choice :tag "Collection to use" 139 (choice :tag "Collection to use"
132 (string :tag "Collection name") 140 (string :tag "Collection name")
133 (const :tag "Default" 'default) 141 (const :tag "Default" 'default)
134 (const :tag "Login" "login") 142 (const :tag "Login" "login")
135 (const :tag "Temporary" "session")))) 143 (const :tag "Temporary" "session"))))
136 (repeat :tag "Extra Parameters" :inline t 144 (repeat :tag "Extra Parameters" :inline t
137 (choice :tag "Extra parameter" 145 (choice :tag "Extra parameter"
138 (list :tag "Host (omit to match as a fallback)" 146 (list :tag "Host (omit to match as a fallback)"
139 (const :format "" :value :host) 147 (const :format "" :value :host)
140 (choice :tag "Host (machine) choice" 148 (choice :tag "Host (machine) choice"
141 (const :tag "Any" t) 149 (const :tag "Any" t)
142 (regexp :tag "Host (machine) regular expression"))) 150 (regexp :tag "Host (machine) regular expression")))
143 (list :tag "Protocol (omit to match as a fallback)" 151 (list :tag "Protocol (omit to match as a fallback)"
144 (const :format "" :value :protocol) 152 (const :format "" :value :protocol)
145 (choice :tag "Protocol" 153 (choice :tag "Protocol"
146 (const :tag "Any" t) 154 (const :tag "Any" t)
147 ,@auth-source-protocols-customize)) 155 ,@auth-source-protocols-customize))
148 (list :tag "User (omit to match as a fallback)" :inline t 156 (list :tag "User (omit to match as a fallback)" :inline t
149 (const :format "" :value :user) 157 (const :format "" :value :user)
150 (choice :tag "Personality or username" 158 (choice :tag "Personality or username"
151 (const :tag "Any" t) 159 (const :tag "Any" t)
152 (string :tag "Specific user name")))))))) 160 (string :tag "Specific user name"))))))))
153 161
154;; temp for debugging 162;; temp for debugging
155;; (unintern 'auth-source-protocols) 163;; (unintern 'auth-source-protocols)
@@ -176,21 +184,21 @@ can get pretty complex."
176 ;; we also check the value 184 ;; we also check the value
177 (when auth-source-debug 185 (when auth-source-debug
178 (let ((logger (if (functionp auth-source-debug) 186 (let ((logger (if (functionp auth-source-debug)
179 auth-source-debug 187 auth-source-debug
180 'message))) 188 'message)))
181 (apply logger msg)))) 189 (apply logger msg))))
182 190
183;; (auth-source-pick nil :host "any" :protocol 'imap :user "joe") 191;; (auth-source-pick nil :host "any" :protocol 'imap :user "joe")
184;; (auth-source-pick t :host "any" :protocol 'imap :user "joe") 192;; (auth-source-pick t :host "any" :protocol 'imap :user "joe")
185;; (setq auth-sources '((:source (:secrets default) :host t :protocol t :user "joe") 193;; (setq auth-sources '((:source (:secrets default) :host t :protocol t :user "joe")
186;; (:source (:secrets "session") :host t :protocol t :user "joe") 194;; (:source (:secrets "session") :host t :protocol t :user "joe")
187;; (:source (:secrets "login") :host t :protocol t) 195;; (:source (:secrets "login") :host t :protocol t)
188;; (:source "~/.authinfo.gpg" :host t :protocol t))) 196;; (:source "~/.authinfo.gpg" :host t :protocol t)))
189 197
190;; (setq auth-sources '((:source (:secrets default) :host t :protocol t :user "joe") 198;; (setq auth-sources '((:source (:secrets default) :host t :protocol t :user "joe")
191;; (:source (:secrets "session") :host t :protocol t :user "joe") 199;; (:source (:secrets "session") :host t :protocol t :user "joe")
192;; (:source (:secrets "login") :host t :protocol t) 200;; (:source (:secrets "login") :host t :protocol t)
193;; )) 201;; ))
194 202
195;; (setq auth-sources '((:source "~/.authinfo.gpg" :host t :protocol t))) 203;; (setq auth-sources '((:source "~/.authinfo.gpg" :host t :protocol t)))
196 204
@@ -200,11 +208,11 @@ If it is a Secret Service API, return the collection name, otherwise
200the file name." 208the file name."
201 (let ((source (plist-get entry :source))) 209 (let ((source (plist-get entry :source)))
202 (if (stringp source) 210 (if (stringp source)
203 source 211 source
204 ;; Secret Service API. 212 ;; Secret Service API.
205 (setq source (plist-get source :secrets)) 213 (setq source (plist-get source :secrets))
206 (when (eq source 'default) 214 (when (eq source 'default)
207 (setq source (or (secrets-get-alias "default") "login"))) 215 (setq source (or (secrets-get-alias "default") "login")))
208 (or source "session")))) 216 (or source "session"))))
209 217
210(defun auth-source-pick (&rest spec) 218(defun auth-source-pick (&rest spec)
@@ -214,124 +222,124 @@ Common keys are :host, :protocol, and :user. A value of t in
214SPEC means to always succeed in the match. A string value is 222SPEC means to always succeed in the match. A string value is
215matched as a regex." 223matched as a regex."
216 (let ((keys (loop for i below (length spec) by 2 collect (nth i spec))) 224 (let ((keys (loop for i below (length spec) by 2 collect (nth i spec)))
217 choices) 225 choices)
218 (dolist (choice (copy-tree auth-sources) choices) 226 (dolist (choice (copy-tree auth-sources) choices)
219 (let ((source (plist-get choice :source)) 227 (let ((source (plist-get choice :source))
220 (match t)) 228 (match t))
221 (when 229 (when
222 (and 230 (and
223 ;; Check existence of source. 231 ;; Check existence of source.
224 (if (consp source) 232 (if (consp source)
225 ;; Secret Service API. 233 ;; Secret Service API.
226 (member (auth-get-source choice) (secrets-list-collections)) 234 (member (auth-get-source choice) (secrets-list-collections))
227 ;; authinfo file. 235 ;; authinfo file.
228 (file-exists-p source)) 236 (file-exists-p source))
229 237
230 ;; Check keywords. 238 ;; Check keywords.
231 (dolist (k keys match) 239 (dolist (k keys match)
232 (let* ((v (plist-get spec k)) 240 (let* ((v (plist-get spec k))
233 (choicev (if (plist-member choice k) 241 (choicev (if (plist-member choice k)
234 (plist-get choice k) t))) 242 (plist-get choice k) t)))
235 (setq match 243 (setq match
236 (and match 244 (and match
237 (or 245 (or
238 ;; source always matches spec key 246 ;; source always matches spec key
239 (eq t choicev) 247 (eq t choicev)
240 ;; source key gives regex to match against spec 248 ;; source key gives regex to match against spec
241 (and (stringp choicev) (string-match choicev v)) 249 (and (stringp choicev) (string-match choicev v))
242 ;; source key gives symbol to match against spec 250 ;; source key gives symbol to match against spec
243 (and (symbolp choicev) (eq choicev v)))))))) 251 (and (symbolp choicev) (eq choicev v))))))))
244 252
245 (add-to-list 'choices choice 'append)))))) 253 (add-to-list 'choices choice 'append))))))
246 254
247(defun auth-source-retrieve (mode entry &rest spec) 255(defun auth-source-retrieve (mode entry &rest spec)
248 "Retrieve MODE credentials according to SPEC from ENTRY." 256 "Retrieve MODE credentials according to SPEC from ENTRY."
249 (catch 'no-password 257 (catch 'no-password
250 (let ((host (plist-get spec :host)) 258 (let ((host (plist-get spec :host))
251 (user (plist-get spec :user)) 259 (user (plist-get spec :user))
252 (prot (plist-get spec :protocol)) 260 (prot (plist-get spec :protocol))
253 (source (plist-get entry :source)) 261 (source (plist-get entry :source))
254 result) 262 result)
255 (cond 263 (cond
256 ;; Secret Service API. 264 ;; Secret Service API.
257 ((consp source) 265 ((consp source)
258 (let ((coll (auth-get-source entry)) 266 (let ((coll (auth-get-source entry))
259 item) 267 item)
260 ;; Loop over candidates with a matching host attribute. 268 ;; Loop over candidates with a matching host attribute.
261 (dolist (elt (secrets-search-items coll :host host) item) 269 (dolist (elt (secrets-search-items coll :host host) item)
262 (when (and (or (not user) 270 (when (and (or (not user)
263 (string-equal 271 (string-equal
264 user (secrets-get-attribute coll elt :user))) 272 user (secrets-get-attribute coll elt :user)))
265 (or (not prot) 273 (or (not prot)
266 (string-equal 274 (string-equal
267 prot (secrets-get-attribute coll elt :protocol)))) 275 prot (secrets-get-attribute coll elt :protocol))))
268 (setq item elt) 276 (setq item elt)
269 (return elt))) 277 (return elt)))
270 ;; Compose result. 278 ;; Compose result.
271 (when item 279 (when item
272 (setq result 280 (setq result
273 (mapcar (lambda (m) 281 (mapcar (lambda (m)
274 (if (string-equal "password" m) 282 (if (string-equal "password" m)
275 (or (secrets-get-secret coll item) 283 (or (secrets-get-secret coll item)
276 ;; When we do not find a password, 284 ;; When we do not find a password,
277 ;; we return nil anyway. 285 ;; we return nil anyway.
278 (throw 'no-password nil)) 286 (throw 'no-password nil))
279 (or (secrets-get-attribute coll item :user) 287 (or (secrets-get-attribute coll item :user)
280 user))) 288 user)))
281 (if (consp mode) mode (list mode))))) 289 (if (consp mode) mode (list mode)))))
282 (if (consp mode) result (car result)))) 290 (if (consp mode) result (car result))))
283 ;; Anything else is netrc. 291 ;; Anything else is netrc.
284 (t 292 (t
285 (let ((search (list source (list host) (list (format "%s" prot)) 293 (let ((search (list source (list host) (list (format "%s" prot))
286 (auth-source-protocol-defaults prot)))) 294 (auth-source-protocol-defaults prot))))
287 (setq result 295 (setq result
288 (mapcar (lambda (m) 296 (mapcar (lambda (m)
289 (if (string-equal "password" m) 297 (if (string-equal "password" m)
290 (or (apply 298 (or (apply
291 'netrc-machine-user-or-password m search) 299 'netrc-machine-user-or-password m search)
292 ;; When we do not find a password, we 300 ;; When we do not find a password, we
293 ;; return nil anyway. 301 ;; return nil anyway.
294 (throw 'no-password nil)) 302 (throw 'no-password nil))
295 (or (apply 303 (or (apply
296 'netrc-machine-user-or-password m search) 304 'netrc-machine-user-or-password m search)
297 user))) 305 user)))
298 (if (consp mode) mode (list mode))))) 306 (if (consp mode) mode (list mode)))))
299 (if (consp mode) result (car result))))))) 307 (if (consp mode) result (car result)))))))
300 308
301(defun auth-source-create (mode entry &rest spec) 309(defun auth-source-create (mode entry &rest spec)
302 "Create interactively credentials according to SPEC in ENTRY. 310 "Create interactively credentials according to SPEC in ENTRY.
303Return structure as specified by MODE." 311Return structure as specified by MODE."
304 (let* ((host (plist-get spec :host)) 312 (let* ((host (plist-get spec :host))
305 (user (plist-get spec :user)) 313 (user (plist-get spec :user))
306 (prot (plist-get spec :protocol)) 314 (prot (plist-get spec :protocol))
307 (source (plist-get entry :source)) 315 (source (plist-get entry :source))
308 (name (concat (if user (format "%s@" user)) 316 (name (concat (if user (format "%s@" user))
309 host 317 host
310 (if prot (format ":%s" prot)))) 318 (if prot (format ":%s" prot))))
311 result) 319 result)
312 (setq result 320 (setq result
313 (mapcar 321 (mapcar
314 (lambda (m) 322 (lambda (m)
315 (cons 323 (cons
316 m 324 m
317 (cond 325 (cond
318 ((equal "password" m) 326 ((equal "password" m)
319 (let ((passwd (read-passwd 327 (let ((passwd (read-passwd
320 (format "Password for %s on %s: " prot host)))) 328 (format "Password for %s on %s: " prot host))))
321 (cond 329 (cond
322 ;; Secret Service API. 330 ;; Secret Service API.
323 ((consp source) 331 ((consp source)
324 (apply 332 (apply
325 'secrets-create-item 333 'secrets-create-item
326 (auth-get-source entry) name passwd spec)) 334 (auth-get-source entry) name passwd spec))
327 (t)) ;; netrc not implemented yes. 335 (t)) ;; netrc not implemented yes.
328 passwd)) 336 passwd))
329 ((equal "login" m) 337 ((equal "login" m)
330 (or user 338 (or user
331 (read-string (format "User name for %s on %s: " prot host)))) 339 (read-string (format "User name for %s on %s: " prot host))))
332 (t 340 (t
333 "unknownuser")))) 341 "unknownuser"))))
334 (if (consp mode) mode (list mode)))) 342 (if (consp mode) mode (list mode))))
335 ;; Allow the source to save the data. 343 ;; Allow the source to save the data.
336 (cond 344 (cond
337 ((consp source) 345 ((consp source)
@@ -340,33 +348,33 @@ Return structure as specified by MODE."
340 (t 348 (t
341 ;; netrc interface. 349 ;; netrc interface.
342 (when (y-or-n-p (format "Do you want to save this password in %s? " 350 (when (y-or-n-p (format "Do you want to save this password in %s? "
343 source)) 351 source))
344 (netrc-store-data source host prot 352 (netrc-store-data source host prot
345 (or user (cdr (assoc "login" result))) 353 (or user (cdr (assoc "login" result)))
346 (cdr (assoc "password" result)))))) 354 (cdr (assoc "password" result))))))
347 (if (consp mode) 355 (if (consp mode)
348 (mapcar #'cdr result) 356 (mapcar #'cdr result)
349 (cdar result)))) 357 (cdar result))))
350 358
351(defun auth-source-delete (entry &rest spec) 359(defun auth-source-delete (entry &rest spec)
352 "Delete credentials according to SPEC in ENTRY." 360 "Delete credentials according to SPEC in ENTRY."
353 (let ((host (plist-get spec :host)) 361 (let ((host (plist-get spec :host))
354 (user (plist-get spec :user)) 362 (user (plist-get spec :user))
355 (prot (plist-get spec :protocol)) 363 (prot (plist-get spec :protocol))
356 (source (plist-get entry :source))) 364 (source (plist-get entry :source)))
357 (cond 365 (cond
358 ;; Secret Service API. 366 ;; Secret Service API.
359 ((consp source) 367 ((consp source)
360 (let ((coll (auth-get-source entry))) 368 (let ((coll (auth-get-source entry)))
361 ;; Loop over candidates with a matching host attribute. 369 ;; Loop over candidates with a matching host attribute.
362 (dolist (elt (secrets-search-items coll :host host)) 370 (dolist (elt (secrets-search-items coll :host host))
363 (when (and (or (not user) 371 (when (and (or (not user)
364 (string-equal 372 (string-equal
365 user (secrets-get-attribute coll elt :user))) 373 user (secrets-get-attribute coll elt :user)))
366 (or (not prot) 374 (or (not prot)
367 (string-equal 375 (string-equal
368 prot (secrets-get-attribute coll elt :protocol)))) 376 prot (secrets-get-attribute coll elt :protocol))))
369 (secrets-delete-item coll elt))))) 377 (secrets-delete-item coll elt)))))
370 (t)))) ;; netrc not implemented yes. 378 (t)))) ;; netrc not implemented yes.
371 379
372(defun auth-source-forget-user-or-password 380(defun auth-source-forget-user-or-password
@@ -416,57 +424,57 @@ MODE can be \"login\" or \"password\"."
416 "auth-source-user-or-password: get %s for %s (%s) + user=%s" 424 "auth-source-user-or-password: get %s for %s (%s) + user=%s"
417 mode host protocol username) 425 mode host protocol username)
418 (let* ((listy (listp mode)) 426 (let* ((listy (listp mode))
419 (mode (if listy mode (list mode))) 427 (mode (if listy mode (list mode)))
420 (cname (if username 428 (cname (if username
421 (format "%s %s:%s %s" mode host protocol username) 429 (format "%s %s:%s %s" mode host protocol username)
422 (format "%s %s:%s" mode host protocol))) 430 (format "%s %s:%s" mode host protocol)))
423 (search (list :host host :protocol protocol)) 431 (search (list :host host :protocol protocol))
424 (search (if username (append search (list :user username)) search)) 432 (search (if username (append search (list :user username)) search))
425 (found (if (not delete-existing) 433 (found (if (not delete-existing)
426 (gethash cname auth-source-cache) 434 (gethash cname auth-source-cache)
427 (remhash cname auth-source-cache) 435 (remhash cname auth-source-cache)
428 nil))) 436 nil)))
429 (if found 437 (if found
430 (progn 438 (progn
431 (auth-source-do-debug 439 (auth-source-do-debug
432 "auth-source-user-or-password: cached %s=%s for %s (%s) + %s" 440 "auth-source-user-or-password: cached %s=%s for %s (%s) + %s"
433 mode 441 mode
434 ;; don't show the password 442 ;; don't show the password
435 (if (and (member "password" mode) auth-source-hide-passwords) 443 (if (and (member "password" mode) auth-source-hide-passwords)
436 "SECRET" 444 "SECRET"
437 found) 445 found)
438 host protocol username) 446 host protocol username)
439 found) ; return the found data 447 found) ; return the found data
440 ;; else, if not found 448 ;; else, if not found
441 (let ((choices (apply 'auth-source-pick search))) 449 (let ((choices (apply 'auth-source-pick search)))
442 (dolist (choice choices) 450 (dolist (choice choices)
443 (if delete-existing 451 (if delete-existing
444 (apply 'auth-source-delete choice search) 452 (apply 'auth-source-delete choice search)
445 (setq found (apply 'auth-source-retrieve mode choice search))) 453 (setq found (apply 'auth-source-retrieve mode choice search)))
446 (and found (return found))) 454 (and found (return found)))
447 455
448 ;; We haven't found something, so we will create it interactively. 456 ;; We haven't found something, so we will create it interactively.
449 (when (and (not found) create-missing) 457 (when (and (not found) create-missing)
450 (setq found (apply 'auth-source-create 458 (setq found (apply 'auth-source-create
451 mode (if choices 459 mode (if choices
452 (car choices) 460 (car choices)
453 (car auth-sources)) 461 (car auth-sources))
454 search))) 462 search)))
455 463
456 ;; Cache the result. 464 ;; Cache the result.
457 (when found 465 (when found
458 (auth-source-do-debug 466 (auth-source-do-debug
459 "auth-source-user-or-password: found %s=%s for %s (%s) + %s" 467 "auth-source-user-or-password: found %s=%s for %s (%s) + %s"
460 mode 468 mode
461 ;; don't show the password 469 ;; don't show the password
462 (if (and (member "password" mode) auth-source-hide-passwords) 470 (if (and (member "password" mode) auth-source-hide-passwords)
463 "SECRET" found) 471 "SECRET" found)
464 host protocol username) 472 host protocol username)
465 (setq found (if listy found (car-safe found))) 473 (setq found (if listy found (car-safe found)))
466 (when auth-source-do-cache 474 (when auth-source-do-cache
467 (puthash cname found auth-source-cache))) 475 (puthash cname found auth-source-cache)))
468 476
469 found)))) 477 found))))
470 478
471(defun auth-source-protocol-defaults (protocol) 479(defun auth-source-protocol-defaults (protocol)
472 "Return a list of default ports and names for PROTOCOL." 480 "Return a list of default ports and names for PROTOCOL."
diff --git a/lisp/gnus/gnus-int.el b/lisp/gnus/gnus-int.el
index 33d020f2a1a..9ed52d8f8ed 100644
--- a/lisp/gnus/gnus-int.el
+++ b/lisp/gnus/gnus-int.el
@@ -41,6 +41,16 @@
41 :group 'gnus-start 41 :group 'gnus-start
42 :type 'hook) 42 :type 'hook)
43 43
44(defcustom gnus-after-set-mark-hook nil
45 "Hook called just after marks are set in a group."
46 :group 'gnus-start
47 :type 'hook)
48
49(defcustom gnus-before-update-mark-hook nil
50 "Hook called just before marks are updated in a group."
51 :group 'gnus-start
52 :type 'hook)
53
44(defcustom gnus-server-unopen-status nil 54(defcustom gnus-server-unopen-status nil
45 "The default status if the server is not able to open. 55 "The default status if the server is not able to open.
46If the server is covered by Gnus agent, the possible values are 56If the server is covered by Gnus agent, the possible values are
@@ -471,7 +481,8 @@ If FETCH-OLD, retrieve all headers (or some subset thereof) in the group."
471 action 481 action
472 (funcall (gnus-get-function gnus-command-method 'request-set-mark) 482 (funcall (gnus-get-function gnus-command-method 'request-set-mark)
473 (gnus-group-real-name group) action 483 (gnus-group-real-name group) action
474 (nth 1 gnus-command-method))))) 484 (nth 1 gnus-command-method))
485 (gnus-run-hook-with-args gnus-after-set-mark-hook group action))))
475 486
476(defun gnus-request-update-mark (group article mark) 487(defun gnus-request-update-mark (group article mark)
477 "Allow the back end to change the mark the user tries to put on an article." 488 "Allow the back end to change the mark the user tries to put on an article."
@@ -479,6 +490,7 @@ If FETCH-OLD, retrieve all headers (or some subset thereof) in the group."
479 (if (not (gnus-check-backend-function 490 (if (not (gnus-check-backend-function
480 'request-update-mark (car gnus-command-method))) 491 'request-update-mark (car gnus-command-method)))
481 mark 492 mark
493 (gnus-run-hook-with-args gnus-before-update-mark-hook group article mark)
482 (funcall (gnus-get-function gnus-command-method 'request-update-mark) 494 (funcall (gnus-get-function gnus-command-method 'request-update-mark)
483 (gnus-group-real-name group) article mark)))) 495 (gnus-group-real-name group) article mark))))
484 496
diff --git a/lisp/gnus/gnus-sync.el b/lisp/gnus/gnus-sync.el
index c0e52b6a8b2..8a492e8d2c3 100644
--- a/lisp/gnus/gnus-sync.el
+++ b/lisp/gnus/gnus-sync.el
@@ -24,6 +24,10 @@
24 24
25;; This is the gnus-sync.el package. 25;; This is the gnus-sync.el package.
26 26
27;; It's due for a rewrite using gnus-after-set-mark-hook and
28;; gnus-before-update-mark-hook. Until then please consider it
29;; experimental.
30
27;; Put this in your startup file (~/.gnus.el for instance) 31;; Put this in your startup file (~/.gnus.el for instance)
28 32
29;; possibilities for gnus-sync-backend: 33;; possibilities for gnus-sync-backend:
@@ -40,6 +44,9 @@
40 44
41;; - after gnus-sync-read, the message counts are wrong 45;; - after gnus-sync-read, the message counts are wrong
42 46
47;; - use gnus-after-set-mark-hook and gnus-before-update-mark-hook to
48;; catch the mark updates
49
43;;; Code: 50;;; Code:
44 51
45(eval-when-compile (require 'cl)) 52(eval-when-compile (require 'cl))
diff --git a/lisp/gnus/gnus-util.el b/lisp/gnus/gnus-util.el
index b3f73d71fd5..30bc72b2348 100644
--- a/lisp/gnus/gnus-util.el
+++ b/lisp/gnus/gnus-util.el
@@ -1290,6 +1290,11 @@ ARG is passed to the first function."
1290 (save-current-buffer 1290 (save-current-buffer
1291 (apply 'run-hooks funcs))) 1291 (apply 'run-hooks funcs)))
1292 1292
1293(defun gnus-run-hook-with-args (hook &rest args)
1294 "Does the same as `run-hook-with-args', but saves the current buffer."
1295 (save-current-buffer
1296 (apply 'run-hook-with-args hook args)))
1297
1293(defun gnus-run-mode-hooks (&rest funcs) 1298(defun gnus-run-mode-hooks (&rest funcs)
1294 "Run `run-mode-hooks' if it is available, otherwise `run-hooks'. 1299 "Run `run-mode-hooks' if it is available, otherwise `run-hooks'.
1295This function saves the current buffer." 1300This function saves the current buffer."