diff options
Diffstat (limited to 'lisp/gnus/auth-source.el')
| -rw-r--r-- | lisp/gnus/auth-source.el | 314 |
1 files changed, 201 insertions, 113 deletions
diff --git a/lisp/gnus/auth-source.el b/lisp/gnus/auth-source.el index 500de10b71c..e0bea324a25 100644 --- a/lisp/gnus/auth-source.el +++ b/lisp/gnus/auth-source.el | |||
| @@ -54,6 +54,8 @@ | |||
| 54 | (autoload 'secrets-list-collections "secrets") | 54 | (autoload 'secrets-list-collections "secrets") |
| 55 | (autoload 'secrets-search-items "secrets") | 55 | (autoload 'secrets-search-items "secrets") |
| 56 | 56 | ||
| 57 | (autoload 'rfc2104-hash "rfc2104") | ||
| 58 | |||
| 57 | (defvar secrets-enabled) | 59 | (defvar secrets-enabled) |
| 58 | 60 | ||
| 59 | (defgroup auth-source nil | 61 | (defgroup auth-source nil |
| @@ -286,6 +288,28 @@ If the value is not a list, symmetric encryption will be used." | |||
| 286 | msg)) | 288 | msg)) |
| 287 | 289 | ||
| 288 | 290 | ||
| 291 | ;;; (auth-source-read-char-choice "enter choice? " '(?a ?b ?q)) | ||
| 292 | (defun auth-source-read-char-choice (prompt choices) | ||
| 293 | "Read one of CHOICES by `read-char-choice', or `read-char'. | ||
| 294 | `dropdown-list' support is disabled because it doesn't work reliably. | ||
| 295 | Only one of CHOICES will be returned. The PROMPT is augmented | ||
| 296 | with \"[a/b/c] \" if CHOICES is '\(?a ?b ?c\)." | ||
| 297 | (when choices | ||
| 298 | (let* ((prompt-choices | ||
| 299 | (apply 'concat (loop for c in choices | ||
| 300 | collect (format "%c/" c)))) | ||
| 301 | (prompt-choices (concat "[" (substring prompt-choices 0 -1) "] ")) | ||
| 302 | (full-prompt (concat prompt prompt-choices)) | ||
| 303 | k) | ||
| 304 | |||
| 305 | (while (not (memq k choices)) | ||
| 306 | (setq k (cond | ||
| 307 | ((fboundp 'read-char-choice) | ||
| 308 | (read-char-choice full-prompt choices)) | ||
| 309 | (t (message "%s" full-prompt) | ||
| 310 | (setq k (read-char)))))) | ||
| 311 | k))) | ||
| 312 | |||
| 289 | ;; (auth-source-pick nil :host "any" :port 'imap :user "joe") | 313 | ;; (auth-source-pick nil :host "any" :port 'imap :user "joe") |
| 290 | ;; (auth-source-pick t :host "any" :port 'imap :user "joe") | 314 | ;; (auth-source-pick t :host "any" :port 'imap :user "joe") |
| 291 | ;; (setq auth-sources '((:source (:secrets default) :host t :port t :user "joe") | 315 | ;; (setq auth-sources '((:source (:secrets default) :host t :port t :user "joe") |
| @@ -393,7 +417,7 @@ parameters." | |||
| 393 | 417 | ||
| 394 | (defun* auth-source-search (&rest spec | 418 | (defun* auth-source-search (&rest spec |
| 395 | &key type max host user port secret | 419 | &key type max host user port secret |
| 396 | create delete | 420 | require create delete |
| 397 | &allow-other-keys) | 421 | &allow-other-keys) |
| 398 | "Search or modify authentication backends according to SPEC. | 422 | "Search or modify authentication backends according to SPEC. |
| 399 | 423 | ||
| @@ -487,6 +511,11 @@ should `catch' the backend-specific error as usual. Some | |||
| 487 | backends (netrc, at least) will prompt the user rather than throw | 511 | backends (netrc, at least) will prompt the user rather than throw |
| 488 | an error. | 512 | an error. |
| 489 | 513 | ||
| 514 | :require (A B C) means that only results that contain those | ||
| 515 | tokens will be returned. Thus for instance requiring :secret | ||
| 516 | will ensure that any results will actually have a :secret | ||
| 517 | property. | ||
| 518 | |||
| 490 | :delete t means to delete any found entries. nil by default. | 519 | :delete t means to delete any found entries. nil by default. |
| 491 | Use `auth-source-delete' in ELisp code instead of calling | 520 | Use `auth-source-delete' in ELisp code instead of calling |
| 492 | `auth-source-search' directly with this parameter. | 521 | `auth-source-search' directly with this parameter. |
| @@ -516,11 +545,17 @@ is a plist with keys :backend :host :port :user, plus any other | |||
| 516 | keys provided by the backend (notably :secret). But note the | 545 | keys provided by the backend (notably :secret). But note the |
| 517 | exception for :max 0, which see above. | 546 | exception for :max 0, which see above. |
| 518 | 547 | ||
| 548 | The token can hold a :save-function key. If you call that, the | ||
| 549 | user will be prompted to save the data to the backend. You can't | ||
| 550 | request that this should happen right after creation, because | ||
| 551 | `auth-source-search' has no way of knowing if the token is | ||
| 552 | actually useful. So the caller must arrange to call this function. | ||
| 553 | |||
| 519 | The token's :secret key can hold a function. In that case you | 554 | The token's :secret key can hold a function. In that case you |
| 520 | must call it to obtain the actual value." | 555 | must call it to obtain the actual value." |
| 521 | (let* ((backends (mapcar 'auth-source-backend-parse auth-sources)) | 556 | (let* ((backends (mapcar 'auth-source-backend-parse auth-sources)) |
| 522 | (max (or max 1)) | 557 | (max (or max 1)) |
| 523 | (ignored-keys '(:create :delete :max)) | 558 | (ignored-keys '(:require :create :delete :max)) |
| 524 | (keys (loop for i below (length spec) by 2 | 559 | (keys (loop for i below (length spec) by 2 |
| 525 | unless (memq (nth i spec) ignored-keys) | 560 | unless (memq (nth i spec) ignored-keys) |
| 526 | collect (nth i spec))) | 561 | collect (nth i spec))) |
| @@ -539,6 +574,10 @@ must call it to obtain the actual value." | |||
| 539 | (or (eq t create) (listp create)) t | 574 | (or (eq t create) (listp create)) t |
| 540 | "Invalid auth-source :create parameter (must be t or a list): %s %s") | 575 | "Invalid auth-source :create parameter (must be t or a list): %s %s") |
| 541 | 576 | ||
| 577 | (assert | ||
| 578 | (listp require) t | ||
| 579 | "Invalid auth-source :require parameter (must be a list): %s") | ||
| 580 | |||
| 542 | (setq filtered-backends (copy-sequence backends)) | 581 | (setq filtered-backends (copy-sequence backends)) |
| 543 | (dolist (backend backends) | 582 | (dolist (backend backends) |
| 544 | (dolist (key keys) | 583 | (dolist (key keys) |
| @@ -562,8 +601,9 @@ must call it to obtain the actual value." | |||
| 562 | spec | 601 | spec |
| 563 | ;; to exit early | 602 | ;; to exit early |
| 564 | max | 603 | max |
| 565 | ;; create and delete | 604 | ;; create is always nil here |
| 566 | nil delete)) | 605 | nil delete |
| 606 | require)) | ||
| 567 | 607 | ||
| 568 | (auth-source-do-debug | 608 | (auth-source-do-debug |
| 569 | "auth-source-search: found %d results (max %d) matching %S" | 609 | "auth-source-search: found %d results (max %d) matching %S" |
| @@ -577,9 +617,9 @@ must call it to obtain the actual value." | |||
| 577 | spec | 617 | spec |
| 578 | ;; to exit early | 618 | ;; to exit early |
| 579 | max | 619 | max |
| 580 | ;; create and delete | 620 | create delete |
| 581 | create delete)) | 621 | require)) |
| 582 | (auth-source-do-warn | 622 | (auth-source-do-debug |
| 583 | "auth-source-search: CREATED %d results (max %d) matching %S" | 623 | "auth-source-search: CREATED %d results (max %d) matching %S" |
| 584 | (length found) max spec)) | 624 | (length found) max spec)) |
| 585 | 625 | ||
| @@ -589,18 +629,19 @@ must call it to obtain the actual value." | |||
| 589 | 629 | ||
| 590 | found)) | 630 | found)) |
| 591 | 631 | ||
| 592 | (defun auth-source-search-backends (backends spec max create delete) | 632 | (defun auth-source-search-backends (backends spec max create delete require) |
| 593 | (let (matches) | 633 | (let (matches) |
| 594 | (dolist (backend backends) | 634 | (dolist (backend backends) |
| 595 | (when (> max (length matches)) ; when we need more matches... | 635 | (when (> max (length matches)) ; when we need more matches... |
| 596 | (let ((bmatches (apply | 636 | (let* ((bmatches (apply |
| 597 | (slot-value backend 'search-function) | 637 | (slot-value backend 'search-function) |
| 598 | :backend backend | 638 | :backend backend |
| 599 | ;; note we're overriding whatever the spec | 639 | ;; note we're overriding whatever the spec |
| 600 | ;; has for :create and :delete | 640 | ;; has for :require, :create, and :delete |
| 601 | :create create | 641 | :require require |
| 602 | :delete delete | 642 | :create create |
| 603 | spec))) | 643 | :delete delete |
| 644 | spec))) | ||
| 604 | (when bmatches | 645 | (when bmatches |
| 605 | (auth-source-do-trivia | 646 | (auth-source-do-trivia |
| 606 | "auth-source-search-backend: got %d (max %d) in %s:%s matching %S" | 647 | "auth-source-search-backend: got %d (max %d) in %s:%s matching %S" |
| @@ -713,7 +754,28 @@ while \(:host t) would find all host entries." | |||
| 713 | (return 'no))) | 754 | (return 'no))) |
| 714 | 'no)))) | 755 | 'no)))) |
| 715 | 756 | ||
| 716 | ;;; Backend specific parsing: netrc/authinfo backend | 757 | ;;; (auth-source-pick-first-password :host "z.lifelogs.com") |
| 758 | ;;; (auth-source-pick-first-password :port "imap") | ||
| 759 | (defun auth-source-pick-first-password (&rest spec) | ||
| 760 | "Pick the first secret found from applying SPEC to `auth-source-search'." | ||
| 761 | (let* ((result (nth 0 (apply 'auth-source-search (plist-put spec :max 1)))) | ||
| 762 | (secret (plist-get result :secret))) | ||
| 763 | |||
| 764 | (if (functionp secret) | ||
| 765 | (funcall secret) | ||
| 766 | secret))) | ||
| 767 | |||
| 768 | ;; (auth-source-format-prompt "test %u %h %p" '((?u "user") (?h "host"))) | ||
| 769 | (defun auth-source-format-prompt (prompt alist) | ||
| 770 | "Format PROMPT using %x (for any character x) specifiers in ALIST." | ||
| 771 | (dolist (cell alist) | ||
| 772 | (let ((c (nth 0 cell)) | ||
| 773 | (v (nth 1 cell))) | ||
| 774 | (when (and c v) | ||
| 775 | (setq prompt (replace-regexp-in-string (format "%%%c" c) | ||
| 776 | (format "%s" v) | ||
| 777 | prompt))))) | ||
| 778 | prompt) | ||
| 717 | 779 | ||
| 718 | (defun auth-source-ensure-strings (values) | 780 | (defun auth-source-ensure-strings (values) |
| 719 | (unless (listp values) | 781 | (unless (listp values) |
| @@ -724,12 +786,14 @@ while \(:host t) would find all host entries." | |||
| 724 | value)) | 786 | value)) |
| 725 | values)) | 787 | values)) |
| 726 | 788 | ||
| 789 | ;;; Backend specific parsing: netrc/authinfo backend | ||
| 790 | |||
| 727 | (defvar auth-source-netrc-cache nil) | 791 | (defvar auth-source-netrc-cache nil) |
| 728 | 792 | ||
| 729 | ;;; (auth-source-netrc-parse "~/.authinfo.gpg") | 793 | ;;; (auth-source-netrc-parse "~/.authinfo.gpg") |
| 730 | (defun* auth-source-netrc-parse (&rest | 794 | (defun* auth-source-netrc-parse (&rest |
| 731 | spec | 795 | spec |
| 732 | &key file max host user port delete | 796 | &key file max host user port delete require |
| 733 | &allow-other-keys) | 797 | &allow-other-keys) |
| 734 | "Parse FILE and return a list of all entries in the file. | 798 | "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." | 799 | Note that the MAX parameter is used so we can exit the parse early." |
| @@ -828,7 +892,15 @@ Note that the MAX parameter is used so we can exit the parse early." | |||
| 828 | (or | 892 | (or |
| 829 | (aget alist "port") | 893 | (aget alist "port") |
| 830 | (aget alist "protocol") | 894 | (aget alist "protocol") |
| 831 | t))) | 895 | t)) |
| 896 | (or | ||
| 897 | ;; the required list of keys is nil, or | ||
| 898 | (null require) | ||
| 899 | ;; every element of require is in the normalized list | ||
| 900 | (let ((normalized (nth 0 (auth-source-netrc-normalize | ||
| 901 | (list alist))))) | ||
| 902 | (loop for req in require | ||
| 903 | always (plist-get normalized req))))) | ||
| 832 | (decf max) | 904 | (decf max) |
| 833 | (push (nreverse alist) result) | 905 | (push (nreverse alist) result) |
| 834 | ;; to delete a line, we just comment it out | 906 | ;; to delete a line, we just comment it out |
| @@ -853,7 +925,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))) | 925 | (setq epa-file-encrypt-to auth-source-gpg-encrypt-to))) |
| 854 | 926 | ||
| 855 | ;; ask AFTER we've successfully opened the file | 927 | ;; ask AFTER we've successfully opened the file |
| 856 | (when (y-or-n-p (format "Save file %s? (%d modifications)" | 928 | (when (y-or-n-p (format "Save file %s? (%d deletions)" |
| 857 | file modified)) | 929 | file modified)) |
| 858 | (write-region (point-min) (point-max) file nil 'silent) | 930 | (write-region (point-min) (point-max) file nil 'silent) |
| 859 | (auth-source-do-debug | 931 | (auth-source-do-debug |
| @@ -893,7 +965,7 @@ Note that the MAX parameter is used so we can exit the parse early." | |||
| 893 | 965 | ||
| 894 | (defun* auth-source-netrc-search (&rest | 966 | (defun* auth-source-netrc-search (&rest |
| 895 | spec | 967 | spec |
| 896 | &key backend create delete | 968 | &key backend require create delete |
| 897 | type max host user port | 969 | type max host user port |
| 898 | &allow-other-keys) | 970 | &allow-other-keys) |
| 899 | "Given a property list SPEC, return search matches from the :backend. | 971 | "Given a property list SPEC, return search matches from the :backend. |
| @@ -905,6 +977,7 @@ See `auth-source-search' for details on SPEC." | |||
| 905 | (let ((results (auth-source-netrc-normalize | 977 | (let ((results (auth-source-netrc-normalize |
| 906 | (auth-source-netrc-parse | 978 | (auth-source-netrc-parse |
| 907 | :max max | 979 | :max max |
| 980 | :require require | ||
| 908 | :delete delete | 981 | :delete delete |
| 909 | :file (oref backend source) | 982 | :file (oref backend source) |
| 910 | :host (or host t) | 983 | :host (or host t) |
| @@ -933,17 +1006,6 @@ See `auth-source-search' for details on SPEC." | |||
| 933 | (nth 0 v) | 1006 | (nth 0 v) |
| 934 | v)) | 1007 | v)) |
| 935 | 1008 | ||
| 936 | ;; (auth-source-format-prompt "test %u %h %p" '((?u "user") (?h "host"))) | ||
| 937 | |||
| 938 | (defun auth-source-format-prompt (prompt alist) | ||
| 939 | "Format PROMPT using %x (for any character x) specifiers in ALIST." | ||
| 940 | (dolist (cell alist) | ||
| 941 | (let ((c (nth 0 cell)) | ||
| 942 | (v (nth 1 cell))) | ||
| 943 | (when (and c v) | ||
| 944 | (setq prompt (replace-regexp-in-string (format "%%%c" c) v prompt))))) | ||
| 945 | prompt) | ||
| 946 | |||
| 947 | ;;; (auth-source-search :host "nonesuch" :type 'netrc :max 1 :create t) | 1009 | ;;; (auth-source-search :host "nonesuch" :type 'netrc :max 1 :create t) |
| 948 | ;;; (auth-source-search :host "nonesuch" :type 'netrc :max 1 :create t :create-extra-keys '((A "default A") (B))) | 1010 | ;;; (auth-source-search :host "nonesuch" :type 'netrc :max 1 :create t :create-extra-keys '((A "default A") (B))) |
| 949 | 1011 | ||
| @@ -992,12 +1054,12 @@ See `auth-source-search' for details on SPEC." | |||
| 992 | (data (auth-source-netrc-element-or-first data)) | 1054 | (data (auth-source-netrc-element-or-first data)) |
| 993 | ;; this is the default to be offered | 1055 | ;; this is the default to be offered |
| 994 | (given-default (aget auth-source-creation-defaults r)) | 1056 | (given-default (aget auth-source-creation-defaults r)) |
| 995 | ;; the default supplementals are simple: for the user, | 1057 | ;; the default supplementals are simple: |
| 996 | ;; try (user-login-name), otherwise take given-default | 1058 | ;; for the user, try `given-default' and then (user-login-name); |
| 1059 | ;; otherwise take `given-default' | ||
| 997 | (default (cond | 1060 | (default (cond |
| 998 | ;; don't default the user name | 1061 | ((and (not given-default) (eq r 'user)) |
| 999 | ;; ((and (not given-default) (eq r 'user)) | 1062 | (user-login-name)) |
| 1000 | ;; (user-login-name)) | ||
| 1001 | (t given-default))) | 1063 | (t given-default))) |
| 1002 | (printable-defaults (list | 1064 | (printable-defaults (list |
| 1003 | (cons 'user | 1065 | (cons 'user |
| @@ -1020,10 +1082,10 @@ See `auth-source-search' for details on SPEC." | |||
| 1020 | "[any port]")))) | 1082 | "[any port]")))) |
| 1021 | (prompt (or (aget auth-source-creation-prompts r) | 1083 | (prompt (or (aget auth-source-creation-prompts r) |
| 1022 | (case r | 1084 | (case r |
| 1023 | ('secret "%p password for user %u, host %h: ") | 1085 | (secret "%p password for %u@%h: ") |
| 1024 | ('user "%p user name: ") | 1086 | (user "%p user name for %h: ") |
| 1025 | ('host "%p host name for user %u: ") | 1087 | (host "%p host name for user %u: ") |
| 1026 | ('port "%p port for user %u and host %h: ")) | 1088 | (port "%p port for %u@%h: ")) |
| 1027 | (format "Enter %s (%%u@%%h:%%p): " r))) | 1089 | (format "Enter %s (%%u@%%h:%%p): " r))) |
| 1028 | (prompt (auth-source-format-prompt | 1090 | (prompt (auth-source-format-prompt |
| 1029 | prompt | 1091 | prompt |
| @@ -1031,14 +1093,20 @@ See `auth-source-search' for details on SPEC." | |||
| 1031 | (?h ,(aget printable-defaults 'host)) | 1093 | (?h ,(aget printable-defaults 'host)) |
| 1032 | (?p ,(aget printable-defaults 'port)))))) | 1094 | (?p ,(aget printable-defaults 'port)))))) |
| 1033 | 1095 | ||
| 1034 | ;; store the data, prompting for the password if needed | 1096 | ;; Store the data, prompting for the password if needed. |
| 1035 | (setq data | 1097 | (setq data |
| 1036 | (cond | 1098 | (cond |
| 1037 | ((and (null data) (eq r 'secret)) | 1099 | ((and (null data) (eq r 'secret)) |
| 1038 | ;; special case prompt for passwords | 1100 | ;; Special case prompt for passwords. |
| 1039 | (read-passwd prompt)) | 1101 | (read-passwd prompt)) |
| 1040 | ((null data) | 1102 | ((null data) |
| 1041 | (read-string prompt default)) | 1103 | (when default |
| 1104 | (setq prompt | ||
| 1105 | (if (string-match ": *\\'" prompt) | ||
| 1106 | (concat (substring prompt 0 (match-beginning 0)) | ||
| 1107 | " (default " default "): ") | ||
| 1108 | (concat prompt "(default " default ") ")))) | ||
| 1109 | (read-string prompt nil nil default)) | ||
| 1042 | (t (or data default)))) | 1110 | (t (or data default)))) |
| 1043 | 1111 | ||
| 1044 | (when data | 1112 | (when data |
| @@ -1049,7 +1117,7 @@ See `auth-source-search' for details on SPEC." | |||
| 1049 | (lambda () data)) | 1117 | (lambda () data)) |
| 1050 | data)))) | 1118 | data)))) |
| 1051 | 1119 | ||
| 1052 | ;; when r is not an empty string... | 1120 | ;; When r is not an empty string... |
| 1053 | (when (and (stringp data) | 1121 | (when (and (stringp data) |
| 1054 | (< 0 (length data))) | 1122 | (< 0 (length data))) |
| 1055 | ;; this function is not strictly necessary but I think it | 1123 | ;; this function is not strictly necessary but I think it |
| @@ -1062,79 +1130,99 @@ See `auth-source-search' for details on SPEC." | |||
| 1062 | (if (zerop (length add)) "" " ") | 1130 | (if (zerop (length add)) "" " ") |
| 1063 | ;; remap auth-source tokens to netrc | 1131 | ;; remap auth-source tokens to netrc |
| 1064 | (case r | 1132 | (case r |
| 1065 | ('user "login") | 1133 | (user "login") |
| 1066 | ('host "machine") | 1134 | (host "machine") |
| 1067 | ('secret "password") | 1135 | (secret "password") |
| 1068 | ('port "port") ; redundant but clearer | 1136 | (port "port") ; redundant but clearer |
| 1069 | (t (symbol-name r))) | 1137 | (t (symbol-name r))) |
| 1070 | ;; the value will be printed in %S format | 1138 | ;; the value will be printed in %S format |
| 1071 | data)))) | 1139 | data)))) |
| 1072 | (setq add (concat add (funcall printer))))))) | 1140 | (setq add (concat add (funcall printer))))))) |
| 1073 | 1141 | ||
| 1074 | (with-temp-buffer | 1142 | (plist-put |
| 1075 | (when (file-exists-p file) | 1143 | artificial |
| 1076 | (insert-file-contents file)) | 1144 | :save-function |
| 1077 | (when auth-source-gpg-encrypt-to | 1145 | (lexical-let ((file file) |
| 1078 | ;; (see bug#7487) making `epa-file-encrypt-to' local to | 1146 | (add add)) |
| 1079 | ;; this buffer lets epa-file skip the key selection query | 1147 | (lambda () (auth-source-netrc-saver file add)))) |
| 1080 | ;; (see the `local-variable-p' check in | 1148 | |
| 1081 | ;; `epa-file-write-region'). | 1149 | (list artificial))) |
| 1082 | (unless (local-variable-p 'epa-file-encrypt-to (current-buffer)) | 1150 | |
| 1083 | (make-local-variable 'epa-file-encrypt-to)) | 1151 | ;;(funcall (plist-get (nth 0 (auth-source-search :host '("nonesuch2") :user "tzz" :port "imap" :create t :max 1)) :save-function)) |
| 1084 | (if (listp auth-source-gpg-encrypt-to) | 1152 | (defun auth-source-netrc-saver (file add) |
| 1085 | (setq epa-file-encrypt-to auth-source-gpg-encrypt-to))) | 1153 | "Save a line ADD in FILE, prompting along the way. |
| 1086 | (goto-char (point-max)) | 1154 | Respects `auth-source-save-behavior'. Uses |
| 1087 | 1155 | `auth-source-netrc-cache' to avoid prompting more than once." | |
| 1088 | ;; ask AFTER we've successfully opened the file | 1156 | (let* ((key (format "%s %s" file (rfc2104-hash 'md5 64 16 file add))) |
| 1089 | (let ((prompt (format "Save auth info to file %s? %s: " | 1157 | (cached (assoc key auth-source-netrc-cache))) |
| 1090 | file | 1158 | |
| 1091 | "y/n/N/e/?")) | 1159 | (if cached |
| 1092 | (done (not (eq auth-source-save-behavior 'ask))) | 1160 | (auth-source-do-trivia |
| 1093 | (bufname "*auth-source Help*") | 1161 | "auth-source-netrc-saver: found previous run for key %s, returning" |
| 1094 | k) | 1162 | key) |
| 1095 | (while (not done) | 1163 | (with-temp-buffer |
| 1096 | (message "%s" prompt) | 1164 | (when (file-exists-p file) |
| 1097 | (setq k (read-char)) | 1165 | (insert-file-contents file)) |
| 1098 | (case k | 1166 | (when auth-source-gpg-encrypt-to |
| 1099 | (?y (setq done t)) | 1167 | ;; (see bug#7487) making `epa-file-encrypt-to' local to |
| 1100 | (?? (save-excursion | 1168 | ;; this buffer lets epa-file skip the key selection query |
| 1101 | (with-output-to-temp-buffer bufname | 1169 | ;; (see the `local-variable-p' check in |
| 1102 | (princ | 1170 | ;; `epa-file-write-region'). |
| 1103 | (concat "(y)es, save\n" | 1171 | (unless (local-variable-p 'epa-file-encrypt-to (current-buffer)) |
| 1104 | "(n)o but use the info\n" | 1172 | (make-local-variable 'epa-file-encrypt-to)) |
| 1105 | "(N)o and don't ask to save again\n" | 1173 | (if (listp auth-source-gpg-encrypt-to) |
| 1106 | "(e)dit the line\n" | 1174 | (setq epa-file-encrypt-to auth-source-gpg-encrypt-to))) |
| 1107 | "(?) for help as you can see.\n")) | 1175 | ;; we want the new data to be found first, so insert at beginning |
| 1108 | (set-buffer standard-output) | 1176 | (goto-char (point-min)) |
| 1109 | (help-mode)))) | 1177 | |
| 1110 | (?n (setq add "" | 1178 | ;; Ask AFTER we've successfully opened the file. |
| 1111 | done t)) | 1179 | (let ((prompt (format "Save auth info to file %s? " file)) |
| 1112 | (?N (setq add "" | 1180 | (done (not (eq auth-source-save-behavior 'ask))) |
| 1113 | done t | 1181 | (bufname "*auth-source Help*") |
| 1114 | auth-source-save-behavior nil)) | 1182 | k) |
| 1115 | (?e (setq add (read-string "Line to add: " add))) | 1183 | (while (not done) |
| 1116 | (t nil))) | 1184 | (setq k (auth-source-read-char-choice prompt '(?y ?n ?N ?e ??))) |
| 1117 | 1185 | (case k | |
| 1118 | (when (get-buffer-window bufname) | 1186 | (?y (setq done t)) |
| 1119 | (delete-window (get-buffer-window bufname))) | 1187 | (?? (save-excursion |
| 1120 | 1188 | (with-output-to-temp-buffer bufname | |
| 1121 | ;; make sure the info is not saved | 1189 | (princ |
| 1122 | (when (null auth-source-save-behavior) | 1190 | (concat "(y)es, save\n" |
| 1123 | (setq add "")) | 1191 | "(n)o but use the info\n" |
| 1124 | 1192 | "(N)o and don't ask to save again\n" | |
| 1125 | (when (< 0 (length add)) | 1193 | "(e)dit the line\n" |
| 1126 | (progn | 1194 | "(?) for help as you can see.\n")) |
| 1127 | (unless (bolp) | 1195 | ;; Why? Doesn't with-output-to-temp-buffer already do |
| 1128 | (insert "\n")) | 1196 | ;; the exact same thing anyway? --Stef |
| 1129 | (insert add "\n") | 1197 | (set-buffer standard-output) |
| 1130 | (write-region (point-min) (point-max) file nil 'silent) | 1198 | (help-mode)))) |
| 1131 | (auth-source-do-warn | 1199 | (?n (setq add "" |
| 1132 | "auth-source-netrc-create: wrote 1 new line to %s" | 1200 | done t)) |
| 1133 | file) | 1201 | (?N (setq add "" |
| 1134 | nil)) | 1202 | done t |
| 1135 | 1203 | auth-source-save-behavior nil)) | |
| 1136 | (when (eq done t) | 1204 | (?e (setq add (read-string "Line to add: " add))) |
| 1137 | (list artificial)))))) | 1205 | (t nil))) |
| 1206 | |||
| 1207 | (when (get-buffer-window bufname) | ||
| 1208 | (delete-window (get-buffer-window bufname))) | ||
| 1209 | |||
| 1210 | ;; Make sure the info is not saved. | ||
| 1211 | (when (null auth-source-save-behavior) | ||
| 1212 | (setq add "")) | ||
| 1213 | |||
| 1214 | (when (< 0 (length add)) | ||
| 1215 | (progn | ||
| 1216 | (unless (bolp) | ||
| 1217 | (insert "\n")) | ||
| 1218 | (insert add "\n") | ||
| 1219 | (write-region (point-min) (point-max) file nil 'silent) | ||
| 1220 | (auth-source-do-debug | ||
| 1221 | "auth-source-netrc-create: wrote 1 new line to %s" | ||
| 1222 | file) | ||
| 1223 | (message "Saved new authentication information to %s" file) | ||
| 1224 | nil)))) | ||
| 1225 | (aput 'auth-source-netrc-cache key "ran")))) | ||
| 1138 | 1226 | ||
| 1139 | ;;; Backend specific parsing: Secrets API backend | 1227 | ;;; Backend specific parsing: Secrets API backend |
| 1140 | 1228 | ||