diff options
| author | Teodor Zlatanov | 2010-10-07 03:49:38 +0000 |
|---|---|---|
| committer | Katsumi Yamaoka | 2010-10-07 03:49:38 +0000 |
| commit | cbabe91fdce9313ffc3f72e0a828b86580661dac (patch) | |
| tree | b2e1089233cfae029b3f4d5ba5f545044bdecc0e /lisp | |
| parent | 58d1ac6d6d7c7634b3ecb7e0cf3f0c67db319b9b (diff) | |
| download | emacs-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/ChangeLog | 13 | ||||
| -rw-r--r-- | lisp/gnus/auth-source.el | 440 | ||||
| -rw-r--r-- | lisp/gnus/gnus-int.el | 14 | ||||
| -rw-r--r-- | lisp/gnus/gnus-sync.el | 7 | ||||
| -rw-r--r-- | lisp/gnus/gnus-util.el | 5 |
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 @@ | |||
| 1 | 2010-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 | |||
| 1 | 2010-10-06 Julien Danjou <julien@danjou.info> | 14 | 2010-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 | ||
| 114 | The default will get login and password information from a .gpg | 122 | The 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 | |||
| 200 | the file name." | 208 | the 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 | |||
| 214 | SPEC means to always succeed in the match. A string value is | 222 | SPEC means to always succeed in the match. A string value is |
| 215 | matched as a regex." | 223 | matched 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. |
| 303 | Return structure as specified by MODE." | 311 | Return 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. |
| 46 | If the server is covered by Gnus agent, the possible values are | 56 | If 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'. |
| 1295 | This function saves the current buffer." | 1300 | This function saves the current buffer." |