diff options
| author | Teodor Zlatanov | 2011-03-09 13:39:35 +0000 |
|---|---|---|
| committer | Katsumi Yamaoka | 2011-03-09 13:39:35 +0000 |
| commit | 733afdf4d9df952a2d06c40b067de3a62bceb26b (patch) | |
| tree | b097d2a39b6e6a8a9ce80a5f8262a09b36518cc1 | |
| parent | ee545c35d2e83306d50ec78a8d9173ab9011bce5 (diff) | |
| download | emacs-733afdf4d9df952a2d06c40b067de3a62bceb26b.tar.gz emacs-733afdf4d9df952a2d06c40b067de3a62bceb26b.zip | |
Merge changes made in Gnus trunk.
auth-source.el (auth-source-read-char-choice): New function to read a character choice using `dropdown-list', `read-char-choice', or `read-char'. It appends "[a/b/c] " to the prompt if the choices were '(?a ?b ?c). The `dropdown-list' support is disabled for now. Use `eval-when-compile' to load `dropdown-list'.
(auth-source-netrc-saver): Use it.
nnimap.el (nnimap-credentials): Keep the :save-function as the third parameter in the credentials.
(nnimap-open-connection-1): Use it after a successful login.
(nnimap-credentials): Add IMAP-specific user and password prompt.
auth-source.el (auth-source-search): Add :require parameter, taking a list. Document it and the :save-function return token. Pass :require down. Change the CREATED message from a warning to a debug statement.
(auth-source-search-backends): Pass :require down.
(auth-source-netrc-search): Pass :require down.
(auth-source-netrc-parse): Use :require, if it's given, as a filter. Change save prompt to indicate all modifications saved here are deletions.
(auth-source-netrc-create): Take user login name as default in user prompt. Move all the save functionality to a lexically bound function under the :save-function token in the returned list. Set up clearer default prompts for user, host, port, and secret.
(auth-source-netrc-saver): New function, intended to be wrapped for :save-function.
| -rw-r--r-- | doc/misc/ChangeLog | 5 | ||||
| -rw-r--r-- | doc/misc/auth.texi | 64 | ||||
| -rw-r--r-- | lisp/gnus/ChangeLog | 31 | ||||
| -rw-r--r-- | lisp/gnus/auth-source.el | 258 | ||||
| -rw-r--r-- | lisp/gnus/nnimap.el | 22 |
5 files changed, 277 insertions, 103 deletions
diff --git a/doc/misc/ChangeLog b/doc/misc/ChangeLog index 75674c7fd17..96a2576355a 100644 --- a/doc/misc/ChangeLog +++ b/doc/misc/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2011-03-08 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 2 | |||
| 3 | * auth.texi (Help for developers): Show example of using | ||
| 4 | `auth-source-search' with prompts and :save-function. | ||
| 5 | |||
| 1 | 2011-03-07 Antoine Levitt <antoine.levitt@gmail.com> | 6 | 2011-03-07 Antoine Levitt <antoine.levitt@gmail.com> |
| 2 | 7 | ||
| 3 | * message.texi (Message Buffers): Update default value of | 8 | * message.texi (Message Buffers): Update default value of |
diff --git a/doc/misc/auth.texi b/doc/misc/auth.texi index 23ac23dce5b..e16d7b49b63 100644 --- a/doc/misc/auth.texi +++ b/doc/misc/auth.texi | |||
| @@ -131,11 +131,11 @@ library encourages this confusion by accepting both, as you'll see | |||
| 131 | later. | 131 | later. |
| 132 | 132 | ||
| 133 | If you have problems with the search, set @code{auth-source-debug} to | 133 | If you have problems with the search, set @code{auth-source-debug} to |
| 134 | @code{t} and see what host, port, and user the library is checking in | 134 | @code{'trivia} and see what host, port, and user the library is |
| 135 | the @code{*Messages*} buffer. Ditto for any other problems, your | 135 | checking in the @code{*Messages*} buffer. Ditto for any other |
| 136 | first step is always to see what's being checked. The second step, of | 136 | problems, your first step is always to see what's being checked. The |
| 137 | course, is to write a blog entry about it and wait for the answer in | 137 | second step, of course, is to write a blog entry about it and wait for |
| 138 | the comments. | 138 | the answer in the comments. |
| 139 | 139 | ||
| 140 | You can customize the variable @code{auth-sources}. The following may | 140 | You can customize the variable @code{auth-sources}. The following may |
| 141 | be needed if you are using an older version of Emacs or if the | 141 | be needed if you are using an older version of Emacs or if the |
| @@ -232,6 +232,14 @@ TODO: how does it work generally, how does secrets.el work, some examples. | |||
| 232 | @node Help for developers | 232 | @node Help for developers |
| 233 | @chapter Help for developers | 233 | @chapter Help for developers |
| 234 | 234 | ||
| 235 | The auth-source library lets you control logging output easily. | ||
| 236 | |||
| 237 | @defvar auth-source-debug | ||
| 238 | Set this variable to 'trivia to see lots of output in *Messages*, or | ||
| 239 | set it to a function that behaves like @code{message} to do your own | ||
| 240 | logging. | ||
| 241 | @end defvar | ||
| 242 | |||
| 235 | The auth-source library only has a few functions for external use. | 243 | The auth-source library only has a few functions for external use. |
| 236 | 244 | ||
| 237 | @defun auth-source-search SPEC | 245 | @defun auth-source-search SPEC |
| @@ -240,6 +248,52 @@ TODO: how to include docstring? | |||
| 240 | 248 | ||
| 241 | @end defun | 249 | @end defun |
| 242 | 250 | ||
| 251 | Let's take a look at an example of using @code{auth-source-search} | ||
| 252 | from Gnus' @code{nnimap.el}. | ||
| 253 | |||
| 254 | @example | ||
| 255 | (defun nnimap-credentials (address ports) | ||
| 256 | (let* ((auth-source-creation-prompts | ||
| 257 | '((user . "IMAP user at %h: ") | ||
| 258 | (secret . "IMAP password for %u@@%h: "))) | ||
| 259 | (found (nth 0 (auth-source-search :max 1 | ||
| 260 | :host address | ||
| 261 | :port ports | ||
| 262 | :require '(:user :secret) | ||
| 263 | :create t)))) | ||
| 264 | (if found | ||
| 265 | (list (plist-get found :user) | ||
| 266 | (let ((secret (plist-get found :secret))) | ||
| 267 | (if (functionp secret) | ||
| 268 | (funcall secret) | ||
| 269 | secret)) | ||
| 270 | (plist-get found :save-function)) | ||
| 271 | nil))) | ||
| 272 | @end example | ||
| 273 | |||
| 274 | This call requires the user and password (secret) to be in the | ||
| 275 | results. It also requests that an entry be created if it doesn't | ||
| 276 | exist already. While the created entry is being assembled, the shown | ||
| 277 | prompts will be used to interact with the user. The caller can also | ||
| 278 | pass data in @code{auth-source-creation-defaults} to supply defaults | ||
| 279 | for any of the prompts. | ||
| 280 | |||
| 281 | Note that the password needs to be evaluated if it's a function. It's | ||
| 282 | wrapped in a function to provide some security. | ||
| 283 | |||
| 284 | Later, after a successful login, @code{nnimal.el} calls the | ||
| 285 | @code{:save-function} like so: | ||
| 286 | |||
| 287 | @example | ||
| 288 | (when (functionp (nth 2 credentials)) | ||
| 289 | (funcall (nth 2 credentials))) | ||
| 290 | @end example | ||
| 291 | |||
| 292 | Which will work whether the @code{:save-function} was provided or not. | ||
| 293 | @code{:save-function} will be provided only when a new entry was | ||
| 294 | created, so this effectively says ``after a successful login, save the | ||
| 295 | authentication information we just used, if it was newly created.'' | ||
| 296 | |||
| 243 | @defun auth-source-delete SPEC | 297 | @defun auth-source-delete SPEC |
| 244 | 298 | ||
| 245 | TODO: how to include docstring? | 299 | TODO: how to include docstring? |
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog index b30cfdcfcd3..aa1f013dd35 100644 --- a/lisp/gnus/ChangeLog +++ b/lisp/gnus/ChangeLog | |||
| @@ -1,3 +1,34 @@ | |||
| 1 | 2011-03-09 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 2 | |||
| 3 | * auth-source.el (auth-source-read-char-choice): New function to read a | ||
| 4 | character choice using `dropdown-list', `read-char-choice', or | ||
| 5 | `read-char'. It appends "[a/b/c] " to the prompt if the choices were | ||
| 6 | '(?a ?b ?c). The `dropdown-list' support is disabled for now. Use | ||
| 7 | `eval-when-compile' to load `dropdown-list'. | ||
| 8 | (auth-source-netrc-saver): Use it. | ||
| 9 | |||
| 10 | 2011-03-08 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 11 | |||
| 12 | * nnimap.el (nnimap-credentials): Keep the :save-function as the third | ||
| 13 | parameter in the credentials. | ||
| 14 | (nnimap-open-connection-1): Use it after a successful login. | ||
| 15 | (nnimap-credentials): Add IMAP-specific user and password prompt. | ||
| 16 | |||
| 17 | * auth-source.el (auth-source-search): Add :require parameter, taking a | ||
| 18 | list. Document it and the :save-function return token. Pass :require | ||
| 19 | down. Change the CREATED message from a warning to a debug statement. | ||
| 20 | (auth-source-search-backends): Pass :require down. | ||
| 21 | (auth-source-netrc-search): Pass :require down. | ||
| 22 | (auth-source-netrc-parse): Use :require, if it's given, as a filter. | ||
| 23 | Change save prompt to indicate all modifications saved here are | ||
| 24 | deletions. | ||
| 25 | (auth-source-netrc-create): Take user login name as default in user | ||
| 26 | prompt. Move all the save functionality to a lexically bound function | ||
| 27 | under the :save-function token in the returned list. Set up clearer | ||
| 28 | default prompts for user, host, port, and secret. | ||
| 29 | (auth-source-netrc-saver): New function, intended to be wrapped for | ||
| 30 | :save-function. | ||
| 31 | |||
| 1 | 2011-03-07 Lars Magne Ingebrigtsen <larsi@gnus.org> | 32 | 2011-03-07 Lars Magne Ingebrigtsen <larsi@gnus.org> |
| 2 | 33 | ||
| 3 | * shr.el (shr-table-horizontal-line): Change the defaults for the table | 34 | * shr.el (shr-table-horizontal-line): Change the defaults for the table |
diff --git a/lisp/gnus/auth-source.el b/lisp/gnus/auth-source.el index 500de10b71c..108871974a0 100644 --- a/lisp/gnus/auth-source.el +++ b/lisp/gnus/auth-source.el | |||
| @@ -44,7 +44,18 @@ | |||
| 44 | (require 'gnus-util) | 44 | (require 'gnus-util) |
| 45 | (require 'assoc) | 45 | (require 'assoc) |
| 46 | (eval-when-compile (require 'cl)) | 46 | (eval-when-compile (require 'cl)) |
| 47 | (require 'eieio) | 47 | (eval-when-compile (require 'dropdown-list nil t)) |
| 48 | (eval-and-compile | ||
| 49 | (or (ignore-errors (require 'eieio)) | ||
| 50 | ;; gnus-fallback-lib/ from gnus/lisp/gnus-fallback-lib | ||
| 51 | (ignore-errors | ||
| 52 | (let ((load-path (cons (expand-file-name | ||
| 53 | "gnus-fallback-lib/eieio" | ||
| 54 | (file-name-directory (locate-library "gnus"))) | ||
| 55 | load-path))) | ||
| 56 | (require 'eieio))) | ||
| 57 | (error | ||
| 58 | "eieio not found in `load-path' or gnus-fallback-lib/ directory."))) | ||
| 48 | 59 | ||
| 49 | (autoload 'secrets-create-item "secrets") | 60 | (autoload 'secrets-create-item "secrets") |
| 50 | (autoload 'secrets-delete-item "secrets") | 61 | (autoload 'secrets-delete-item "secrets") |
| @@ -286,6 +297,34 @@ If the value is not a list, symmetric encryption will be used." | |||
| 286 | msg)) | 297 | msg)) |
| 287 | 298 | ||
| 288 | 299 | ||
| 300 | ;;; (auth-source-read-char-choice "enter choice? " '(?a ?b ?q)) | ||
| 301 | (defun auth-source-read-char-choice (prompt choices) | ||
| 302 | "Read one of CHOICES by `read-char-choice', or `read-char'. | ||
| 303 | `dropdown-list' support is disabled because it doesn't work reliably. | ||
| 304 | Only one of CHOICES will be returned. The PROMPT is augmented | ||
| 305 | with \"[a/b/c] \" if CHOICES is '\(?a ?b ?c\)." | ||
| 306 | (when choices | ||
| 307 | (let* ((prompt-choices | ||
| 308 | (apply 'concat (loop for c in choices | ||
| 309 | collect (format "%c/" c)))) | ||
| 310 | (prompt-choices (concat "[" (substring prompt-choices 0 -1) "] ")) | ||
| 311 | (full-prompt (concat prompt prompt-choices)) | ||
| 312 | k) | ||
| 313 | |||
| 314 | (while (not (memq k choices)) | ||
| 315 | (setq k (cond | ||
| 316 | ((and nil (featurep 'dropdown-list)) | ||
| 317 | (let* ((blank (fill (copy-sequence prompt) ?.)) | ||
| 318 | (dlc (cons (format "%s %c" prompt (car choices)) | ||
| 319 | (loop for c in (cdr choices) | ||
| 320 | collect (format "%s %c" blank c))))) | ||
| 321 | (nth (dropdown-list dlc) choices))) | ||
| 322 | ((fboundp 'read-char-choice) | ||
| 323 | (read-char-choice full-prompt choices)) | ||
| 324 | (t (message "%s" full-prompt) | ||
| 325 | (setq k (read-char)))))) | ||
| 326 | k))) | ||
| 327 | |||
| 289 | ;; (auth-source-pick nil :host "any" :port 'imap :user "joe") | 328 | ;; (auth-source-pick nil :host "any" :port 'imap :user "joe") |
| 290 | ;; (auth-source-pick t :host "any" :port 'imap :user "joe") | 329 | ;; (auth-source-pick t :host "any" :port 'imap :user "joe") |
| 291 | ;; (setq auth-sources '((:source (:secrets default) :host t :port t :user "joe") | 330 | ;; (setq auth-sources '((:source (:secrets default) :host t :port t :user "joe") |
| @@ -393,7 +432,7 @@ parameters." | |||
| 393 | 432 | ||
| 394 | (defun* auth-source-search (&rest spec | 433 | (defun* auth-source-search (&rest spec |
| 395 | &key type max host user port secret | 434 | &key type max host user port secret |
| 396 | create delete | 435 | require create delete |
| 397 | &allow-other-keys) | 436 | &allow-other-keys) |
| 398 | "Search or modify authentication backends according to SPEC. | 437 | "Search or modify authentication backends according to SPEC. |
| 399 | 438 | ||
| @@ -487,6 +526,11 @@ should `catch' the backend-specific error as usual. Some | |||
| 487 | backends (netrc, at least) will prompt the user rather than throw | 526 | backends (netrc, at least) will prompt the user rather than throw |
| 488 | an error. | 527 | an error. |
| 489 | 528 | ||
| 529 | :require (A B C) means that only results that contain those | ||
| 530 | tokens will be returned. Thus for instance requiring :secret | ||
| 531 | will ensure that any results will actually have a :secret | ||
| 532 | property. | ||
| 533 | |||
| 490 | :delete t means to delete any found entries. nil by default. | 534 | :delete t means to delete any found entries. nil by default. |
| 491 | Use `auth-source-delete' in ELisp code instead of calling | 535 | Use `auth-source-delete' in ELisp code instead of calling |
| 492 | `auth-source-search' directly with this parameter. | 536 | `auth-source-search' directly with this parameter. |
| @@ -516,11 +560,17 @@ is a plist with keys :backend :host :port :user, plus any other | |||
| 516 | keys provided by the backend (notably :secret). But note the | 560 | keys provided by the backend (notably :secret). But note the |
| 517 | exception for :max 0, which see above. | 561 | exception for :max 0, which see above. |
| 518 | 562 | ||
| 563 | The token can hold a :save-function key. If you call that, the | ||
| 564 | user will be prompted to save the data to the backend. You can't | ||
| 565 | request that this should happen right after creation, because | ||
| 566 | `auth-source-search' has no way of knowing if the token is | ||
| 567 | actually useful. So the caller must arrange to call this function. | ||
| 568 | |||
| 519 | The token's :secret key can hold a function. In that case you | 569 | The token's :secret key can hold a function. In that case you |
| 520 | must call it to obtain the actual value." | 570 | must call it to obtain the actual value." |
| 521 | (let* ((backends (mapcar 'auth-source-backend-parse auth-sources)) | 571 | (let* ((backends (mapcar 'auth-source-backend-parse auth-sources)) |
| 522 | (max (or max 1)) | 572 | (max (or max 1)) |
| 523 | (ignored-keys '(:create :delete :max)) | 573 | (ignored-keys '(:require :create :delete :max)) |
| 524 | (keys (loop for i below (length spec) by 2 | 574 | (keys (loop for i below (length spec) by 2 |
| 525 | unless (memq (nth i spec) ignored-keys) | 575 | unless (memq (nth i spec) ignored-keys) |
| 526 | collect (nth i spec))) | 576 | collect (nth i spec))) |
| @@ -539,6 +589,10 @@ must call it to obtain the actual value." | |||
| 539 | (or (eq t create) (listp create)) t | 589 | (or (eq t create) (listp create)) t |
| 540 | "Invalid auth-source :create parameter (must be t or a list): %s %s") | 590 | "Invalid auth-source :create parameter (must be t or a list): %s %s") |
| 541 | 591 | ||
| 592 | (assert | ||
| 593 | (listp require) t | ||
| 594 | "Invalid auth-source :require parameter (must be a list): %s") | ||
| 595 | |||
| 542 | (setq filtered-backends (copy-sequence backends)) | 596 | (setq filtered-backends (copy-sequence backends)) |
| 543 | (dolist (backend backends) | 597 | (dolist (backend backends) |
| 544 | (dolist (key keys) | 598 | (dolist (key keys) |
| @@ -562,8 +616,9 @@ must call it to obtain the actual value." | |||
| 562 | spec | 616 | spec |
| 563 | ;; to exit early | 617 | ;; to exit early |
| 564 | max | 618 | max |
| 565 | ;; create and delete | 619 | ;; create is always nil here |
| 566 | nil delete)) | 620 | nil delete |
| 621 | require)) | ||
| 567 | 622 | ||
| 568 | (auth-source-do-debug | 623 | (auth-source-do-debug |
| 569 | "auth-source-search: found %d results (max %d) matching %S" | 624 | "auth-source-search: found %d results (max %d) matching %S" |
| @@ -577,9 +632,9 @@ must call it to obtain the actual value." | |||
| 577 | spec | 632 | spec |
| 578 | ;; to exit early | 633 | ;; to exit early |
| 579 | max | 634 | max |
| 580 | ;; create and delete | 635 | create delete |
| 581 | create delete)) | 636 | require)) |
| 582 | (auth-source-do-warn | 637 | (auth-source-do-debug |
| 583 | "auth-source-search: CREATED %d results (max %d) matching %S" | 638 | "auth-source-search: CREATED %d results (max %d) matching %S" |
| 584 | (length found) max spec)) | 639 | (length found) max spec)) |
| 585 | 640 | ||
| @@ -589,18 +644,19 @@ must call it to obtain the actual value." | |||
| 589 | 644 | ||
| 590 | found)) | 645 | found)) |
| 591 | 646 | ||
| 592 | (defun auth-source-search-backends (backends spec max create delete) | 647 | (defun auth-source-search-backends (backends spec max create delete require) |
| 593 | (let (matches) | 648 | (let (matches) |
| 594 | (dolist (backend backends) | 649 | (dolist (backend backends) |
| 595 | (when (> max (length matches)) ; when we need more matches... | 650 | (when (> max (length matches)) ; when we need more matches... |
| 596 | (let ((bmatches (apply | 651 | (let* ((bmatches (apply |
| 597 | (slot-value backend 'search-function) | 652 | (slot-value backend 'search-function) |
| 598 | :backend backend | 653 | :backend backend |
| 599 | ;; note we're overriding whatever the spec | 654 | ;; note we're overriding whatever the spec |
| 600 | ;; has for :create and :delete | 655 | ;; has for :require, :create, and :delete |
| 601 | :create create | 656 | :require require |
| 602 | :delete delete | 657 | :create create |
| 603 | spec))) | 658 | :delete delete |
| 659 | spec))) | ||
| 604 | (when bmatches | 660 | (when bmatches |
| 605 | (auth-source-do-trivia | 661 | (auth-source-do-trivia |
| 606 | "auth-source-search-backend: got %d (max %d) in %s:%s matching %S" | 662 | "auth-source-search-backend: got %d (max %d) in %s:%s matching %S" |
| @@ -729,7 +785,7 @@ while \(:host t) would find all host entries." | |||
| 729 | ;;; (auth-source-netrc-parse "~/.authinfo.gpg") | 785 | ;;; (auth-source-netrc-parse "~/.authinfo.gpg") |
| 730 | (defun* auth-source-netrc-parse (&rest | 786 | (defun* auth-source-netrc-parse (&rest |
| 731 | spec | 787 | spec |
| 732 | &key file max host user port delete | 788 | &key file max host user port delete require |
| 733 | &allow-other-keys) | 789 | &allow-other-keys) |
| 734 | "Parse FILE and return a list of all entries in the file. | 790 | "Parse FILE and return a list of all entries in the file. |
| 735 | Note that the MAX parameter is used so we can exit the parse early." | 791 | Note that the MAX parameter is used so we can exit the parse early." |
| @@ -828,7 +884,15 @@ Note that the MAX parameter is used so we can exit the parse early." | |||
| 828 | (or | 884 | (or |
| 829 | (aget alist "port") | 885 | (aget alist "port") |
| 830 | (aget alist "protocol") | 886 | (aget alist "protocol") |
| 831 | t))) | 887 | t)) |
| 888 | (or | ||
| 889 | ;; the required list of keys is nil, or | ||
| 890 | (null require) | ||
| 891 | ;; every element of require is in the normalized list | ||
| 892 | (let ((normalized (nth 0 (auth-source-netrc-normalize | ||
| 893 | (list alist))))) | ||
| 894 | (loop for req in require | ||
| 895 | always (plist-get normalized req))))) | ||
| 832 | (decf max) | 896 | (decf max) |
| 833 | (push (nreverse alist) result) | 897 | (push (nreverse alist) result) |
| 834 | ;; to delete a line, we just comment it out | 898 | ;; to delete a line, we just comment it out |
| @@ -853,7 +917,7 @@ Note that the MAX parameter is used so we can exit the parse early." | |||
| 853 | (setq epa-file-encrypt-to auth-source-gpg-encrypt-to))) | 917 | (setq epa-file-encrypt-to auth-source-gpg-encrypt-to))) |
| 854 | 918 | ||
| 855 | ;; ask AFTER we've successfully opened the file | 919 | ;; ask AFTER we've successfully opened the file |
| 856 | (when (y-or-n-p (format "Save file %s? (%d modifications)" | 920 | (when (y-or-n-p (format "Save file %s? (%d deletions)" |
| 857 | file modified)) | 921 | file modified)) |
| 858 | (write-region (point-min) (point-max) file nil 'silent) | 922 | (write-region (point-min) (point-max) file nil 'silent) |
| 859 | (auth-source-do-debug | 923 | (auth-source-do-debug |
| @@ -893,7 +957,7 @@ Note that the MAX parameter is used so we can exit the parse early." | |||
| 893 | 957 | ||
| 894 | (defun* auth-source-netrc-search (&rest | 958 | (defun* auth-source-netrc-search (&rest |
| 895 | spec | 959 | spec |
| 896 | &key backend create delete | 960 | &key backend require create delete |
| 897 | type max host user port | 961 | type max host user port |
| 898 | &allow-other-keys) | 962 | &allow-other-keys) |
| 899 | "Given a property list SPEC, return search matches from the :backend. | 963 | "Given a property list SPEC, return search matches from the :backend. |
| @@ -905,6 +969,7 @@ See `auth-source-search' for details on SPEC." | |||
| 905 | (let ((results (auth-source-netrc-normalize | 969 | (let ((results (auth-source-netrc-normalize |
| 906 | (auth-source-netrc-parse | 970 | (auth-source-netrc-parse |
| 907 | :max max | 971 | :max max |
| 972 | :require require | ||
| 908 | :delete delete | 973 | :delete delete |
| 909 | :file (oref backend source) | 974 | :file (oref backend source) |
| 910 | :host (or host t) | 975 | :host (or host t) |
| @@ -992,12 +1057,12 @@ See `auth-source-search' for details on SPEC." | |||
| 992 | (data (auth-source-netrc-element-or-first data)) | 1057 | (data (auth-source-netrc-element-or-first data)) |
| 993 | ;; this is the default to be offered | 1058 | ;; this is the default to be offered |
| 994 | (given-default (aget auth-source-creation-defaults r)) | 1059 | (given-default (aget auth-source-creation-defaults r)) |
| 995 | ;; the default supplementals are simple: for the user, | 1060 | ;; the default supplementals are simple: |
| 996 | ;; try (user-login-name), otherwise take given-default | 1061 | ;; for the user, try `given-default' and then (user-login-name); |
| 1062 | ;; otherwise take `given-default' | ||
| 997 | (default (cond | 1063 | (default (cond |
| 998 | ;; don't default the user name | 1064 | ((and (not given-default) (eq r 'user)) |
| 999 | ;; ((and (not given-default) (eq r 'user)) | 1065 | (user-login-name)) |
| 1000 | ;; (user-login-name)) | ||
| 1001 | (t given-default))) | 1066 | (t given-default))) |
| 1002 | (printable-defaults (list | 1067 | (printable-defaults (list |
| 1003 | (cons 'user | 1068 | (cons 'user |
| @@ -1020,10 +1085,10 @@ See `auth-source-search' for details on SPEC." | |||
| 1020 | "[any port]")))) | 1085 | "[any port]")))) |
| 1021 | (prompt (or (aget auth-source-creation-prompts r) | 1086 | (prompt (or (aget auth-source-creation-prompts r) |
| 1022 | (case r | 1087 | (case r |
| 1023 | ('secret "%p password for user %u, host %h: ") | 1088 | (secret "%p password for %u@%h: ") |
| 1024 | ('user "%p user name: ") | 1089 | (user "%p user name for %h: ") |
| 1025 | ('host "%p host name for user %u: ") | 1090 | (host "%p host name for user %u: ") |
| 1026 | ('port "%p port for user %u and host %h: ")) | 1091 | (port "%p port for %u@%h: ")) |
| 1027 | (format "Enter %s (%%u@%%h:%%p): " r))) | 1092 | (format "Enter %s (%%u@%%h:%%p): " r))) |
| 1028 | (prompt (auth-source-format-prompt | 1093 | (prompt (auth-source-format-prompt |
| 1029 | prompt | 1094 | prompt |
| @@ -1071,70 +1136,79 @@ See `auth-source-search' for details on SPEC." | |||
| 1071 | data)))) | 1136 | data)))) |
| 1072 | (setq add (concat add (funcall printer))))))) | 1137 | (setq add (concat add (funcall printer))))))) |
| 1073 | 1138 | ||
| 1074 | (with-temp-buffer | 1139 | (plist-put |
| 1075 | (when (file-exists-p file) | 1140 | artificial |
| 1076 | (insert-file-contents file)) | 1141 | :save-function |
| 1077 | (when auth-source-gpg-encrypt-to | 1142 | (lexical-let ((file file) |
| 1078 | ;; (see bug#7487) making `epa-file-encrypt-to' local to | 1143 | (add add)) |
| 1079 | ;; this buffer lets epa-file skip the key selection query | 1144 | (lambda () (auth-source-netrc-saver file add)))) |
| 1080 | ;; (see the `local-variable-p' check in | 1145 | |
| 1081 | ;; `epa-file-write-region'). | 1146 | (list artificial))) |
| 1082 | (unless (local-variable-p 'epa-file-encrypt-to (current-buffer)) | 1147 | |
| 1083 | (make-local-variable 'epa-file-encrypt-to)) | 1148 | ;;(funcall (plist-get (nth 0 (auth-source-search :host '("nonesuch") :user "tzz" :port "imap" :create t :max 1)) :save-function)) |
| 1084 | (if (listp auth-source-gpg-encrypt-to) | 1149 | (defun auth-source-netrc-saver (file add) |
| 1085 | (setq epa-file-encrypt-to auth-source-gpg-encrypt-to))) | 1150 | "Save a line ADD in FILE, prompting along the way. |
| 1086 | (goto-char (point-max)) | 1151 | Respects `auth-source-save-behavior'." |
| 1087 | 1152 | (with-temp-buffer | |
| 1088 | ;; ask AFTER we've successfully opened the file | 1153 | (when (file-exists-p file) |
| 1089 | (let ((prompt (format "Save auth info to file %s? %s: " | 1154 | (insert-file-contents file)) |
| 1090 | file | 1155 | (when auth-source-gpg-encrypt-to |
| 1091 | "y/n/N/e/?")) | 1156 | ;; (see bug#7487) making `epa-file-encrypt-to' local to |
| 1092 | (done (not (eq auth-source-save-behavior 'ask))) | 1157 | ;; this buffer lets epa-file skip the key selection query |
| 1093 | (bufname "*auth-source Help*") | 1158 | ;; (see the `local-variable-p' check in |
| 1094 | k) | 1159 | ;; `epa-file-write-region'). |
| 1095 | (while (not done) | 1160 | (unless (local-variable-p 'epa-file-encrypt-to (current-buffer)) |
| 1096 | (message "%s" prompt) | 1161 | (make-local-variable 'epa-file-encrypt-to)) |
| 1097 | (setq k (read-char)) | 1162 | (if (listp auth-source-gpg-encrypt-to) |
| 1098 | (case k | 1163 | (setq epa-file-encrypt-to auth-source-gpg-encrypt-to))) |
| 1099 | (?y (setq done t)) | 1164 | ;; we want the new data to be found first, so insert at beginning |
| 1100 | (?? (save-excursion | 1165 | (goto-char (point-min)) |
| 1101 | (with-output-to-temp-buffer bufname | 1166 | |
| 1102 | (princ | 1167 | ;; ask AFTER we've successfully opened the file |
| 1103 | (concat "(y)es, save\n" | 1168 | (let ((prompt (format "Save auth info to file %s? " file)) |
| 1104 | "(n)o but use the info\n" | 1169 | (done (not (eq auth-source-save-behavior 'ask))) |
| 1105 | "(N)o and don't ask to save again\n" | 1170 | (bufname "*auth-source Help*") |
| 1106 | "(e)dit the line\n" | 1171 | k) |
| 1107 | "(?) for help as you can see.\n")) | 1172 | (while (not done) |
| 1173 | (setq k (auth-source-read-char-choice prompt '(?y ?n ?N ?e ??))) | ||
| 1174 | (case k | ||
| 1175 | (?y (setq done t)) | ||
| 1176 | (?? (save-excursion | ||
| 1177 | (with-output-to-temp-buffer bufname | ||
| 1178 | (princ | ||
| 1179 | (concat "(y)es, save\n" | ||
| 1180 | "(n)o but use the info\n" | ||
| 1181 | "(N)o and don't ask to save again\n" | ||
| 1182 | "(e)dit the line\n" | ||
| 1183 | "(?) for help as you can see.\n")) | ||
| 1108 | (set-buffer standard-output) | 1184 | (set-buffer standard-output) |
| 1109 | (help-mode)))) | 1185 | (help-mode)))) |
| 1110 | (?n (setq add "" | 1186 | (?n (setq add "" |
| 1111 | done t)) | 1187 | done t)) |
| 1112 | (?N (setq add "" | 1188 | (?N (setq add "" |
| 1113 | done t | 1189 | done t |
| 1114 | auth-source-save-behavior nil)) | 1190 | auth-source-save-behavior nil)) |
| 1115 | (?e (setq add (read-string "Line to add: " add))) | 1191 | (?e (setq add (read-string "Line to add: " add))) |
| 1116 | (t nil))) | 1192 | (t nil))) |
| 1117 | 1193 | ||
| 1118 | (when (get-buffer-window bufname) | 1194 | (when (get-buffer-window bufname) |
| 1119 | (delete-window (get-buffer-window bufname))) | 1195 | (delete-window (get-buffer-window bufname))) |
| 1120 | 1196 | ||
| 1121 | ;; make sure the info is not saved | 1197 | ;; make sure the info is not saved |
| 1122 | (when (null auth-source-save-behavior) | 1198 | (when (null auth-source-save-behavior) |
| 1123 | (setq add "")) | 1199 | (setq add "")) |
| 1124 | 1200 | ||
| 1125 | (when (< 0 (length add)) | 1201 | (when (< 0 (length add)) |
| 1126 | (progn | 1202 | (progn |
| 1127 | (unless (bolp) | 1203 | (unless (bolp) |
| 1128 | (insert "\n")) | 1204 | (insert "\n")) |
| 1129 | (insert add "\n") | 1205 | (insert add "\n") |
| 1130 | (write-region (point-min) (point-max) file nil 'silent) | 1206 | (write-region (point-min) (point-max) file nil 'silent) |
| 1131 | (auth-source-do-warn | 1207 | (auth-source-do-debug |
| 1132 | "auth-source-netrc-create: wrote 1 new line to %s" | 1208 | "auth-source-netrc-create: wrote 1 new line to %s" |
| 1133 | file) | 1209 | file) |
| 1134 | nil)) | 1210 | (message "Saved new authentication information to %s" file) |
| 1135 | 1211 | nil))))) | |
| 1136 | (when (eq done t) | ||
| 1137 | (list artificial)))))) | ||
| 1138 | 1212 | ||
| 1139 | ;;; Backend specific parsing: Secrets API backend | 1213 | ;;; Backend specific parsing: Secrets API backend |
| 1140 | 1214 | ||
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el index 638097abd7d..e76ead515c5 100644 --- a/lisp/gnus/nnimap.el +++ b/lisp/gnus/nnimap.el | |||
| @@ -279,16 +279,21 @@ textual parts.") | |||
| 279 | (current-buffer))) | 279 | (current-buffer))) |
| 280 | 280 | ||
| 281 | (defun nnimap-credentials (address ports) | 281 | (defun nnimap-credentials (address ports) |
| 282 | (let ((found (nth 0 (auth-source-search :max 1 | 282 | (let* ((auth-source-creation-prompts |
| 283 | :host address | 283 | '((user . "IMAP user at %h: ") |
| 284 | :port ports | 284 | (secret . "IMAP password for %u@%h: "))) |
| 285 | :create t)))) | 285 | (found (nth 0 (auth-source-search :max 1 |
| 286 | :host address | ||
| 287 | :port ports | ||
| 288 | :require '(:user :secret) | ||
| 289 | :create t)))) | ||
| 286 | (if found | 290 | (if found |
| 287 | (list (plist-get found :user) | 291 | (list (plist-get found :user) |
| 288 | (let ((secret (plist-get found :secret))) | 292 | (let ((secret (plist-get found :secret))) |
| 289 | (if (functionp secret) | 293 | (if (functionp secret) |
| 290 | (funcall secret) | 294 | (funcall secret) |
| 291 | secret))) | 295 | secret)) |
| 296 | (plist-get found :save-function)) | ||
| 292 | nil))) | 297 | nil))) |
| 293 | 298 | ||
| 294 | (defun nnimap-keepalive () | 299 | (defun nnimap-keepalive () |
| @@ -396,7 +401,12 @@ textual parts.") | |||
| 396 | (let ((nnimap-inhibit-logging t)) | 401 | (let ((nnimap-inhibit-logging t)) |
| 397 | (setq login-result | 402 | (setq login-result |
| 398 | (nnimap-login (car credentials) (cadr credentials)))) | 403 | (nnimap-login (car credentials) (cadr credentials)))) |
| 399 | (unless (car login-result) | 404 | (if (car login-result) |
| 405 | ;; save the credentials if a save function exists | ||
| 406 | ;; (such a function will only be passed if a new | ||
| 407 | ;; token was created) | ||
| 408 | (when (functionp (nth 2 credentials)) | ||
| 409 | (funcall (nth 2 credentials))) | ||
| 400 | ;; If the login failed, then forget the credentials | 410 | ;; If the login failed, then forget the credentials |
| 401 | ;; that are now possibly cached. | 411 | ;; that are now possibly cached. |
| 402 | (dolist (host (list (nnoo-current-server 'nnimap) | 412 | (dolist (host (list (nnoo-current-server 'nnimap) |