diff options
Diffstat (limited to 'lisp/erc')
| -rw-r--r-- | lisp/erc/erc-backend.el | 44 | ||||
| -rw-r--r-- | lisp/erc/erc-networks.el | 694 | ||||
| -rw-r--r-- | lisp/erc/erc.el | 239 |
3 files changed, 867 insertions, 110 deletions
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 305422195b3..6fb581ca7c9 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el | |||
| @@ -196,11 +196,9 @@ escapes removed.") | |||
| 196 | "Mapping of server buffers to their specific ping timer.") | 196 | "Mapping of server buffers to their specific ping timer.") |
| 197 | 197 | ||
| 198 | (defvar-local erc-server-connected nil | 198 | (defvar-local erc-server-connected nil |
| 199 | "Non-nil if the current buffer has been used by ERC to establish | 199 | "Non-nil if the current buffer belongs to an active IRC connection. |
| 200 | an IRC connection. | 200 | To determine whether an underlying transport is connected, use the |
| 201 | 201 | function `erc-server-process-alive' instead.") | |
| 202 | If you wish to determine whether an IRC connection is currently | ||
| 203 | active, use the `erc-server-process-alive' function instead.") | ||
| 204 | 202 | ||
| 205 | (defvar-local erc-server-reconnect-count 0 | 203 | (defvar-local erc-server-reconnect-count 0 |
| 206 | "Number of times we have failed to reconnect to the current server.") | 204 | "Number of times we have failed to reconnect to the current server.") |
| @@ -602,7 +600,11 @@ Make sure you are in an ERC buffer when running this." | |||
| 602 | (erc-open erc-session-server erc-session-port erc-server-current-nick | 600 | (erc-open erc-session-server erc-session-port erc-server-current-nick |
| 603 | erc-session-user-full-name t erc-session-password | 601 | erc-session-user-full-name t erc-session-password |
| 604 | nil nil nil erc-session-client-certificate | 602 | nil nil nil erc-session-client-certificate |
| 605 | erc-session-username))))) | 603 | erc-session-username |
| 604 | (erc-networks--id-given erc-networks--id)) | ||
| 605 | (unless (with-suppressed-warnings ((obsolete erc-reuse-buffers)) | ||
| 606 | erc-reuse-buffers) | ||
| 607 | (cl-assert (not (eq buffer (current-buffer))))))))) | ||
| 606 | 608 | ||
| 607 | (defun erc-server-delayed-reconnect (buffer) | 609 | (defun erc-server-delayed-reconnect (buffer) |
| 608 | (if (buffer-live-p buffer) | 610 | (if (buffer-live-p buffer) |
| @@ -1336,7 +1338,11 @@ add things to `%s' instead." | |||
| 1336 | nick erc-session-user-full-name | 1338 | nick erc-session-user-full-name |
| 1337 | nil nil | 1339 | nil nil |
| 1338 | (list chnl) chnl | 1340 | (list chnl) chnl |
| 1339 | erc-server-process)) | 1341 | erc-server-process |
| 1342 | nil | ||
| 1343 | erc-session-username | ||
| 1344 | (erc-networks--id-given | ||
| 1345 | erc-networks--id))) | ||
| 1340 | (when buffer | 1346 | (when buffer |
| 1341 | (set-buffer buffer) | 1347 | (set-buffer buffer) |
| 1342 | (with-suppressed-warnings | 1348 | (with-suppressed-warnings |
| @@ -1427,19 +1433,27 @@ add things to `%s' instead." | |||
| 1427 | ;; sent to the correct nick. also add to bufs, since the user will want | 1433 | ;; sent to the correct nick. also add to bufs, since the user will want |
| 1428 | ;; to see the nick change in the query, and if it's a newly begun query, | 1434 | ;; to see the nick change in the query, and if it's a newly begun query, |
| 1429 | ;; erc-channel-users won't contain it | 1435 | ;; erc-channel-users won't contain it |
| 1430 | (erc-buffer-filter | 1436 | ;; |
| 1431 | (lambda () | 1437 | ;; Possibly still relevant: bug#12002 |
| 1432 | (when (equal (erc-default-target) nick) | 1438 | (when-let ((buf (erc-get-buffer nick erc-server-process)) |
| 1433 | (setq erc-default-recipients (cons nn (cdr erc-default-recipients)) | 1439 | (tgt (erc--target-from-string nn))) |
| 1434 | erc--target (erc--target-from-string nn)) | 1440 | (with-current-buffer buf |
| 1435 | (rename-buffer nn t) ; bug#12002 | 1441 | (setq erc-default-recipients (cons nn (cdr erc-default-recipients)) |
| 1436 | (erc-update-mode-line) | 1442 | erc--target tgt)) |
| 1437 | (cl-pushnew (current-buffer) bufs)))) | 1443 | (with-current-buffer (erc-get-buffer-create erc-session-server |
| 1444 | erc-session-port nil tgt | ||
| 1445 | (erc-networks--id-given | ||
| 1446 | erc-networks--id)) | ||
| 1447 | ;; Current buffer is among bufs | ||
| 1448 | (erc-update-mode-line))) | ||
| 1438 | (erc-update-user-nick nick nn host nil nil login) | 1449 | (erc-update-user-nick nick nn host nil nil login) |
| 1439 | (cond | 1450 | (cond |
| 1440 | ((string= nick (erc-current-nick)) | 1451 | ((string= nick (erc-current-nick)) |
| 1441 | (cl-pushnew (erc-server-buffer) bufs) | 1452 | (cl-pushnew (erc-server-buffer) bufs) |
| 1442 | (erc-set-current-nick nn) | 1453 | (erc-set-current-nick nn) |
| 1454 | ;; Rename session, possibly rename server buf and all targets | ||
| 1455 | (when (erc-network) | ||
| 1456 | (erc-networks--id-reload erc-networks--id proc parsed)) | ||
| 1443 | (erc-update-mode-line) | 1457 | (erc-update-mode-line) |
| 1444 | (setq erc-nick-change-attempt-count 0) | 1458 | (setq erc-nick-change-attempt-count 0) |
| 1445 | (setq erc-default-nicks (if (consp erc-nick) erc-nick (list erc-nick))) | 1459 | (setq erc-default-nicks (if (consp erc-nick) erc-nick (list erc-nick))) |
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 58223f37cf7..091b8aa92d7 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el | |||
| @@ -731,6 +731,466 @@ MATCHER is used to find a corresponding network to a server while | |||
| 731 | (defvar-local erc-network nil | 731 | (defvar-local erc-network nil |
| 732 | "The name of the network you are connected to (a symbol).") | 732 | "The name of the network you are connected to (a symbol).") |
| 733 | 733 | ||
| 734 | |||
| 735 | ;;;; Identifying session context | ||
| 736 | |||
| 737 | ;; This section is concerned with identifying and managing the | ||
| 738 | ;; relationship between an IRC connection and its unique identity on a | ||
| 739 | ;; given network (as seen by that network's nick-granting system). | ||
| 740 | ;; This relationship is quasi-permanent and transcends IRC connections | ||
| 741 | ;; and Emacs sessions. As of mid 2022, only nicknames matter, and | ||
| 742 | ;; whether a user is authenticated does not directly impact network | ||
| 743 | ;; identity from a client's perspective. However, ERC must be | ||
| 744 | ;; equipped to adapt should this ever change. And while a connection | ||
| 745 | ;; is normally associated with exactly one nick, some networks (or | ||
| 746 | ;; intermediaries) may allow multiple clients to control the same nick | ||
| 747 | ;; by combining instance activity into a single logical client. ERC | ||
| 748 | ;; must be limber enough to handle such situations. | ||
| 749 | |||
| 750 | (defvar-local erc-networks--id nil | ||
| 751 | "Server-local instance of its namesake struct. | ||
| 752 | Also shared among all target buffers for a given connection. See | ||
| 753 | \\[describe-symbol] `erc-networks--id' for more.") | ||
| 754 | |||
| 755 | (cl-defstruct erc-networks--id | ||
| 756 | "Persistent identifying info for a network presence. | ||
| 757 | |||
| 758 | Here, \"presence\" refers to some local state representing a | ||
| 759 | client's existence on a network. Some clients refer to this as a | ||
| 760 | \"context\" or a \"net-id\". The management of this state | ||
| 761 | involves tracking associated buffers and what they're displaying. | ||
| 762 | Since a presence can outlast physical connections and survive | ||
| 763 | changes in back-end transports (and even outlive Emacs sessions), | ||
| 764 | its identity must be resilient. | ||
| 765 | |||
| 766 | Essential to this notion of an enduring existence on a network is | ||
| 767 | ensuring recovery from the loss of a server buffer. Thus, any | ||
| 768 | useful identifier must be shared among server and target buffers | ||
| 769 | to allow for reassociation. Beyond that, it must ideally be | ||
| 770 | derivable from the same set of connection parameters. See the | ||
| 771 | constructor `erc-networks--id-create' for more info." | ||
| 772 | (ts nil :type float :read-only t :documentation "Creation timestamp.") | ||
| 773 | (symbol nil :type symbol :documentation "ID as a symbol.")) | ||
| 774 | |||
| 775 | (cl-defstruct (erc-networks--id-fixed | ||
| 776 | (:include erc-networks--id) | ||
| 777 | (:constructor erc-networks--id-fixed-create | ||
| 778 | (given &aux (ts (float-time)) (symbol given))))) | ||
| 779 | |||
| 780 | (cl-defstruct (erc-networks--id-qualifying | ||
| 781 | (:include erc-networks--id) | ||
| 782 | (:constructor erc-networks--id-qualifying-create | ||
| 783 | (&aux | ||
| 784 | (ts (float-time)) | ||
| 785 | (parts (erc-networks--id-qualifying-init-parts)) | ||
| 786 | (symbol (erc-networks--id-qualifying-init-symbol | ||
| 787 | parts)) | ||
| 788 | (len 1)))) | ||
| 789 | "A session context composed of hierarchical connection parameters. | ||
| 790 | Two identifiers are considered equivalent when their non-empty | ||
| 791 | `parts' slots compare equal. Related identifiers share a common | ||
| 792 | prefix of `parts' taken from connection parameters (given or | ||
| 793 | discovered). An identifier's unique `symbol', intended for | ||
| 794 | display purposes, is created by concatenating the shortest common | ||
| 795 | prefix among its relatives. For example, related presences [b a | ||
| 796 | r d o] and [b a z a r] would have symbols b/a/r and b/a/z | ||
| 797 | respectively. The separator is given by `erc-networks--id-sep'." | ||
| 798 | (parts nil :type sequence ; a vector of atoms | ||
| 799 | :documentation "Sequence of identifying components.") | ||
| 800 | (len 0 :type integer | ||
| 801 | :documentation "Length of active `parts' interval.")) | ||
| 802 | |||
| 803 | ;; For now, please use this instead of `erc-networks--id-fixed-p'. | ||
| 804 | (cl-defgeneric erc-networks--id-given (net-id) | ||
| 805 | "Return the preassigned identifier for a network presence, if any. | ||
| 806 | This may have originated from an `:id' arg to entry-point commands | ||
| 807 | `erc-tls' or `erc'.") | ||
| 808 | |||
| 809 | (cl-defmethod erc-networks--id-given ((_ erc-networks--id)) | ||
| 810 | nil) | ||
| 811 | |||
| 812 | (cl-defmethod erc-networks--id-given ((nid erc-networks--id-fixed)) | ||
| 813 | (erc-networks--id-symbol nid)) | ||
| 814 | |||
| 815 | (cl-generic-define-context-rewriter erc-obsolete-var (var spec) | ||
| 816 | `((with-suppressed-warnings ((obsolete ,var)) ,var) ,spec)) | ||
| 817 | |||
| 818 | ;; As a catch-all, derive the symbol from the unquoted printed repr. | ||
| 819 | (cl-defgeneric erc-networks--id-create (id) | ||
| 820 | "Invoke an appropriate constructor for an `erc-networks--id' object." | ||
| 821 | (erc-networks--id-fixed-create (intern (format "%s" id)))) | ||
| 822 | |||
| 823 | ;; When a given ID is a symbol, trust it unequivocally. | ||
| 824 | (cl-defmethod erc-networks--id-create ((id symbol)) | ||
| 825 | (erc-networks--id-fixed-create id)) | ||
| 826 | |||
| 827 | ;; Otherwise, use an adaptive name derived from network params. | ||
| 828 | (cl-defmethod erc-networks--id-create ((_ null)) | ||
| 829 | (erc-networks--id-qualifying-create)) | ||
| 830 | |||
| 831 | ;; But honor an explicitly set `erc-rename-buffers' (compat). | ||
| 832 | (cl-defmethod erc-networks--id-create | ||
| 833 | ((_ null) &context (erc-obsolete-var erc-rename-buffers null)) | ||
| 834 | (erc-networks--id-fixed-create (intern (buffer-name)))) | ||
| 835 | |||
| 836 | ;; But honor an explicitly set `erc-reuse-buffers' (compat). | ||
| 837 | (cl-defmethod erc-networks--id-create | ||
| 838 | ((_ null) &context (erc-obsolete-var erc-reuse-buffers null)) | ||
| 839 | (erc-networks--id-fixed-create (intern (buffer-name)))) | ||
| 840 | |||
| 841 | (cl-defmethod erc-networks--id-create | ||
| 842 | ((_ symbol) &context (erc-obsolete-var erc-reuse-buffers null)) | ||
| 843 | (erc-networks--id-fixed-create (intern (buffer-name)))) | ||
| 844 | |||
| 845 | (cl-defgeneric erc-networks--id-on-connect (net-id) | ||
| 846 | "Update NET-ID `erc-networks--id' after connection params known. | ||
| 847 | This is typically during or just after MOTD.") | ||
| 848 | |||
| 849 | (cl-defmethod erc-networks--id-on-connect ((_ erc-networks--id)) | ||
| 850 | nil) | ||
| 851 | |||
| 852 | (cl-defmethod erc-networks--id-on-connect ((id erc-networks--id-qualifying)) | ||
| 853 | (erc-networks--id-qualifying-update id (erc-networks--id-qualifying-create))) | ||
| 854 | |||
| 855 | (cl-defgeneric erc-networks--id-equal-p (self other) | ||
| 856 | "Return non-nil when two network identities exhibit underlying equality. | ||
| 857 | SELF and OTHER are `erc-networks--id' struct instances. This | ||
| 858 | should normally be used only for ID recovery or merging, after | ||
| 859 | which no two identities should be `equal' (timestamps aside) that | ||
| 860 | aren't also `eq'.") | ||
| 861 | |||
| 862 | (cl-defmethod erc-networks--id-equal-p ((self erc-networks--id) | ||
| 863 | (other erc-networks--id)) | ||
| 864 | (eq self other)) | ||
| 865 | |||
| 866 | (cl-defmethod erc-networks--id-equal-p ((a erc-networks--id-fixed) | ||
| 867 | (b erc-networks--id-fixed)) | ||
| 868 | (or (eq a b) (eq (erc-networks--id-symbol a) (erc-networks--id-symbol b)))) | ||
| 869 | |||
| 870 | (cl-defmethod erc-networks--id-equal-p ((a erc-networks--id-qualifying) | ||
| 871 | (b erc-networks--id-qualifying)) | ||
| 872 | (or (eq a b) (equal (erc-networks--id-qualifying-parts a) | ||
| 873 | (erc-networks--id-qualifying-parts b)))) | ||
| 874 | |||
| 875 | ;; ERASE-ME: if some future extension were to come along offering | ||
| 876 | ;; additional members, e.g., [Libera.Chat "bob" laptop], it'd likely | ||
| 877 | ;; be cleaner to create a new struct type descending from | ||
| 878 | ;; `erc-networks--id-qualifying' than to convert this function into a | ||
| 879 | ;; generic. However, the latter would be simpler because it'd just | ||
| 880 | ;; require something like &context (erc-v3-device erc-v3--device-t). | ||
| 881 | |||
| 882 | (defun erc-networks--id-qualifying-init-parts () | ||
| 883 | "Return opaque list of atoms to serve as canonical identifier." | ||
| 884 | (when-let ((network (erc-network)) | ||
| 885 | (nick (erc-current-nick))) | ||
| 886 | (vector network (erc-downcase nick)))) | ||
| 887 | |||
| 888 | (defvar erc-networks--id-sep "/" | ||
| 889 | "Separator for joining `erc-networks--id-qualifying-parts' into a net ID.") | ||
| 890 | |||
| 891 | (defun erc-networks--id-qualifying-init-symbol (elts &optional len) | ||
| 892 | "Return symbol appropriate for network context identified by ELTS. | ||
| 893 | Use leading interval of length LEN as contributing components. | ||
| 894 | Combine them with string separator `erc-networks--id-sep'." | ||
| 895 | (when elts | ||
| 896 | (unless len | ||
| 897 | (setq len 1)) | ||
| 898 | (intern (mapconcat (lambda (s) (prin1-to-string s t)) | ||
| 899 | (seq-subseq elts 0 len) | ||
| 900 | erc-networks--id-sep)))) | ||
| 901 | |||
| 902 | (defun erc-networks--id-qualifying-grow-id (nid) | ||
| 903 | "Grow NID by one component or return nil when at capacity." | ||
| 904 | (unless (= (length (erc-networks--id-qualifying-parts nid)) | ||
| 905 | (erc-networks--id-qualifying-len nid)) | ||
| 906 | (setf (erc-networks--id-symbol nid) | ||
| 907 | (erc-networks--id-qualifying-init-symbol | ||
| 908 | (erc-networks--id-qualifying-parts nid) | ||
| 909 | (cl-incf (erc-networks--id-qualifying-len nid)))))) | ||
| 910 | |||
| 911 | (defun erc-networks--id-qualifying-reset-id (nid) | ||
| 912 | "Restore NID to its initial state." | ||
| 913 | (setf (erc-networks--id-qualifying-len nid) 1 | ||
| 914 | (erc-networks--id-symbol nid) | ||
| 915 | (erc-networks--id-qualifying-init-symbol | ||
| 916 | (erc-networks--id-qualifying-parts nid)))) | ||
| 917 | |||
| 918 | (defun erc-networks--id-qualifying-prefix-length (nid-a nid-b) | ||
| 919 | "Return length of common initial prefix of NID-A and NID-B. | ||
| 920 | Return nil when no such sequence exists (instead of zero)." | ||
| 921 | (when-let* ((a (erc-networks--id-qualifying-parts nid-a)) | ||
| 922 | (b (erc-networks--id-qualifying-parts nid-b)) | ||
| 923 | (n (min (length a) (length b))) | ||
| 924 | ((> n 0)) | ||
| 925 | ((equal (elt a 0) (elt b 0))) | ||
| 926 | (i 1)) | ||
| 927 | (while (and (< i n) | ||
| 928 | (equal (elt a i) | ||
| 929 | (elt b i))) | ||
| 930 | (cl-incf i)) | ||
| 931 | i)) | ||
| 932 | |||
| 933 | (defun erc-networks--id-qualifying-update (dest source &rest overrides) | ||
| 934 | "Update DEST from SOURCE in place. | ||
| 935 | Copy slots into DEST from SOURCE and recompute ID. Both SOURCE | ||
| 936 | and DEST must be `erc-networks--id' objects. OVERRIDES is an | ||
| 937 | optional plist of SLOT VAL pairs." | ||
| 938 | (setf (erc-networks--id-qualifying-parts dest) | ||
| 939 | (or (plist-get overrides :parts) | ||
| 940 | (erc-networks--id-qualifying-parts source)) | ||
| 941 | (erc-networks--id-qualifying-len dest) | ||
| 942 | (or (plist-get overrides :len) | ||
| 943 | (erc-networks--id-qualifying-len source)) | ||
| 944 | (erc-networks--id-symbol dest) | ||
| 945 | (or (plist-get overrides :symbol) | ||
| 946 | (erc-networks--id-qualifying-init-symbol | ||
| 947 | (erc-networks--id-qualifying-parts dest) | ||
| 948 | (erc-networks--id-qualifying-len dest))))) | ||
| 949 | |||
| 950 | (cl-defgeneric erc-networks--id-reload (_nid &optional _proc _parsed) | ||
| 951 | "Handle an update to the current network identity. | ||
| 952 | If provided, PROC should be the current `erc-server-process' and | ||
| 953 | PARSED the current `erc-response'. NID is an `erc-networks--id' | ||
| 954 | object." | ||
| 955 | nil) | ||
| 956 | |||
| 957 | (cl-defmethod erc-networks--id-reload ((nid erc-networks--id-qualifying) | ||
| 958 | &optional proc parsed) | ||
| 959 | "Refresh identity after an `erc-networks--id-qualifying-parts'update." | ||
| 960 | (erc-networks--id-qualifying-update nid (erc-networks--id-qualifying-create) | ||
| 961 | :len | ||
| 962 | (erc-networks--id-qualifying-len nid)) | ||
| 963 | (erc-networks--rename-server-buffer (or proc erc-server-process) parsed) | ||
| 964 | (erc-networks--shrink-ids-and-buffer-names-any) | ||
| 965 | (erc-with-all-buffers-of-server | ||
| 966 | erc-server-process #'erc--default-target | ||
| 967 | (when-let* ((new-name (erc-networks--reconcile-buffer-names erc--target | ||
| 968 | nid)) | ||
| 969 | ((not (equal (buffer-name) new-name)))) | ||
| 970 | (rename-buffer new-name 'unique)))) | ||
| 971 | |||
| 972 | (cl-defgeneric erc-networks--id-ensure-comparable (self other) | ||
| 973 | "Take measures to ensure two net identities are in comparable states.") | ||
| 974 | |||
| 975 | (cl-defmethod erc-networks--id-ensure-comparable ((_ erc-networks--id) | ||
| 976 | (_ erc-networks--id)) | ||
| 977 | nil) | ||
| 978 | |||
| 979 | (cl-defmethod erc-networks--id-ensure-comparable | ||
| 980 | ((nid erc-networks--id-qualifying) (other erc-networks--id-qualifying)) | ||
| 981 | "Grow NID along with that of the current buffer. | ||
| 982 | Rename the current buffer if its NID has grown." | ||
| 983 | (when-let ((n (erc-networks--id-qualifying-prefix-length other nid))) | ||
| 984 | (while (and (<= (erc-networks--id-qualifying-len nid) n) | ||
| 985 | (erc-networks--id-qualifying-grow-id nid))) | ||
| 986 | ;; Grow and rename a visited buffer and all its targets | ||
| 987 | (when (and (> (erc-networks--id-qualifying-len nid) | ||
| 988 | (erc-networks--id-qualifying-len other)) | ||
| 989 | (erc-networks--id-qualifying-grow-id other)) | ||
| 990 | ;; Rename NID's buffers using current ID | ||
| 991 | (erc-buffer-filter (lambda () | ||
| 992 | (when (eq erc-networks--id other) | ||
| 993 | (erc-networks--maybe-update-buffer-name))))))) | ||
| 994 | |||
| 995 | (defun erc-networks--id-sort-buffers (buffers) | ||
| 996 | "Return a list of target BUFFERS, newest to oldest." | ||
| 997 | (sort buffers | ||
| 998 | (lambda (a b) | ||
| 999 | (> (with-current-buffer a (erc-networks--id-ts erc-networks--id)) | ||
| 1000 | (with-current-buffer b (erc-networks--id-ts erc-networks--id)))))) | ||
| 1001 | |||
| 1002 | |||
| 1003 | ;;;; Buffer association | ||
| 1004 | |||
| 1005 | (cl-defgeneric erc-networks--shrink-ids-and-buffer-names () | ||
| 1006 | nil) ; concrete default implementation for non-eliding IDs | ||
| 1007 | |||
| 1008 | (defun erc-networks--refresh-buffer-names (identity &optional omit) | ||
| 1009 | "Ensure all colliding buffers for network IDENTITY have suffixes. | ||
| 1010 | Then rename current buffer appropriately. Don't consider buffer OMIT | ||
| 1011 | when determining collisions." | ||
| 1012 | (if (erc-networks--examine-targets identity erc--target | ||
| 1013 | #'ignore | ||
| 1014 | (lambda () | ||
| 1015 | (unless (or (not omit) (eq (current-buffer) omit)) | ||
| 1016 | (erc-networks--ensure-unique-target-buffer-name) | ||
| 1017 | t))) | ||
| 1018 | (erc-networks--ensure-unique-target-buffer-name) | ||
| 1019 | (rename-buffer (erc--target-string erc--target) 'unique))) | ||
| 1020 | |||
| 1021 | ;; This currently doesn't equalize related identities that may have | ||
| 1022 | ;; become mismatched because that shouldn't happen after a connection | ||
| 1023 | ;; is up (other than for a brief moment while renicking or similar, | ||
| 1024 | ;; when states are inconsistent). | ||
| 1025 | (defun erc-networks--shrink-ids-and-buffer-names-any (&rest omit) | ||
| 1026 | (let (grown) | ||
| 1027 | ;; Gather all grown identities. | ||
| 1028 | (erc-buffer-filter | ||
| 1029 | (lambda () | ||
| 1030 | (when (and erc-networks--id | ||
| 1031 | (erc-networks--id-qualifying-p erc-networks--id) | ||
| 1032 | (not (memq (current-buffer) omit)) | ||
| 1033 | (not (memq erc-networks--id grown)) | ||
| 1034 | (> (erc-networks--id-qualifying-len erc-networks--id) 1)) | ||
| 1035 | (push erc-networks--id grown)))) | ||
| 1036 | ;; Check for other identities with shared prefix. If none exists, | ||
| 1037 | ;; and an identity is overlong, shrink it. | ||
| 1038 | (dolist (nid grown) | ||
| 1039 | (let ((skip (not (null omit)))) | ||
| 1040 | (catch 'found | ||
| 1041 | (if (cdr grown) | ||
| 1042 | (dolist (other grown) | ||
| 1043 | (unless (eq nid other) | ||
| 1044 | (setq skip nil) | ||
| 1045 | (when (erc-networks--id-qualifying-prefix-length nid other) | ||
| 1046 | (throw 'found (setq skip t))))) | ||
| 1047 | (setq skip nil))) | ||
| 1048 | (unless (or skip (< (erc-networks--id-qualifying-len nid) 2)) | ||
| 1049 | (erc-networks--id-qualifying-reset-id nid) | ||
| 1050 | (erc-buffer-filter | ||
| 1051 | (lambda () | ||
| 1052 | (when (and (eq erc-networks--id nid) | ||
| 1053 | (not (memq (current-buffer) omit))) | ||
| 1054 | (if erc--target | ||
| 1055 | (erc-networks--refresh-buffer-names nid omit) | ||
| 1056 | (erc-networks--maybe-update-buffer-name)))))))))) | ||
| 1057 | |||
| 1058 | (cl-defmethod erc-networks--shrink-ids-and-buffer-names | ||
| 1059 | (&context (erc-networks--id erc-networks--id-qualifying)) | ||
| 1060 | (erc-networks--shrink-ids-and-buffer-names-any (current-buffer))) | ||
| 1061 | |||
| 1062 | (defun erc-networks-rename-surviving-target-buffer () | ||
| 1063 | "Maybe drop qualifying suffix from fellow target-buffer's name. | ||
| 1064 | But only do so when there's a single survivor with a target | ||
| 1065 | matching that of the dying buffer." | ||
| 1066 | (when-let* | ||
| 1067 | (((with-suppressed-warnings ((obsolete erc-reuse-buffers)) | ||
| 1068 | erc-reuse-buffers)) | ||
| 1069 | (target erc--target) | ||
| 1070 | ;; Buffer name includes ID suffix | ||
| 1071 | ((not (string= (erc--target-symbol target) ; string= t "t" -> t | ||
| 1072 | (erc-downcase (buffer-name))))) | ||
| 1073 | (buf (current-buffer)) | ||
| 1074 | ;; All buffers, not just those belonging to same process | ||
| 1075 | (others (erc-buffer-filter | ||
| 1076 | (lambda () | ||
| 1077 | (and-let* ((erc--target) | ||
| 1078 | ((not (eq buf (current-buffer)))) | ||
| 1079 | ((eq (erc--target-symbol target) | ||
| 1080 | (erc--target-symbol erc--target)))))))) | ||
| 1081 | ((not (cdr others)))) | ||
| 1082 | (with-current-buffer (car others) | ||
| 1083 | (rename-buffer (erc--target-string target))))) | ||
| 1084 | |||
| 1085 | (defun erc-networks-shrink-ids-and-buffer-names () | ||
| 1086 | "Recompute network IDs and buffer names, ignoring the current buffer. | ||
| 1087 | Only do so when an IRC connection's context supports qualified | ||
| 1088 | naming. Do not discriminate based on whether a buffer's | ||
| 1089 | connection is active." | ||
| 1090 | (erc-networks--shrink-ids-and-buffer-names)) | ||
| 1091 | |||
| 1092 | (defun erc-networks--examine-targets (identity target on-dupe on-collision) | ||
| 1093 | "Visit all ERC target buffers with the same TARGET. | ||
| 1094 | Call ON-DUPE when a buffer's identity belongs to a network | ||
| 1095 | IDENTITY or \"should\" after reconciliation. Call ON-COLLISION | ||
| 1096 | otherwise. Neither function should accept any args. Expect | ||
| 1097 | TARGET to be an `erc--target' object." | ||
| 1098 | (declare (indent 2)) | ||
| 1099 | (let ((announced erc-server-announced-name)) | ||
| 1100 | (erc-buffer-filter | ||
| 1101 | (lambda () | ||
| 1102 | (when (and erc--target (eq (erc--target-symbol erc--target) | ||
| 1103 | (erc--target-symbol target))) | ||
| 1104 | (let ((oursp (if (erc--target-channel-local-p target) | ||
| 1105 | (equal announced erc-server-announced-name) | ||
| 1106 | (erc-networks--id-equal-p identity erc-networks--id)))) | ||
| 1107 | (funcall (if oursp on-dupe on-collision)))))))) | ||
| 1108 | |||
| 1109 | (defconst erc-networks--qualified-sep "@" | ||
| 1110 | "Separator used for naming a target buffer.") | ||
| 1111 | |||
| 1112 | (defun erc-networks--construct-target-buffer-name (target) | ||
| 1113 | "Return TARGET@suffix." | ||
| 1114 | (concat (erc--target-string target) | ||
| 1115 | (if (with-suppressed-warnings ((obsolete erc-reuse-buffers)) | ||
| 1116 | erc-reuse-buffers) | ||
| 1117 | erc-networks--qualified-sep "/") | ||
| 1118 | (cond | ||
| 1119 | ((not (with-suppressed-warnings ((obsolete erc-reuse-buffers)) | ||
| 1120 | erc-reuse-buffers)) | ||
| 1121 | (cadr (split-string | ||
| 1122 | (symbol-name (erc-networks--id-symbol erc-networks--id)) | ||
| 1123 | "/"))) | ||
| 1124 | ((erc--target-channel-local-p target) erc-server-announced-name) | ||
| 1125 | (t (symbol-name (erc-networks--id-symbol erc-networks--id)))))) | ||
| 1126 | |||
| 1127 | (defun erc-networks--ensure-unique-target-buffer-name () | ||
| 1128 | (when-let* ((new-name (erc-networks--construct-target-buffer-name | ||
| 1129 | erc--target)) | ||
| 1130 | ((not (equal (buffer-name) new-name)))) | ||
| 1131 | (rename-buffer new-name 'unique))) | ||
| 1132 | |||
| 1133 | (defun erc-networks--ensure-unique-server-buffer-name () | ||
| 1134 | (when-let* ((new-name (symbol-name (erc-networks--id-symbol | ||
| 1135 | erc-networks--id))) | ||
| 1136 | ((not (equal (buffer-name) new-name)))) | ||
| 1137 | (rename-buffer new-name 'unique))) | ||
| 1138 | |||
| 1139 | (defun erc-networks--maybe-update-buffer-name () | ||
| 1140 | "Update current buffer name to reflect display ID if necessary." | ||
| 1141 | (if erc--target | ||
| 1142 | (erc-networks--ensure-unique-target-buffer-name) | ||
| 1143 | (erc-networks--ensure-unique-server-buffer-name))) | ||
| 1144 | |||
| 1145 | (defun erc-networks--reconcile-buffer-names (target nid) | ||
| 1146 | "Reserve preferred buffer name for TARGET and network identifier. | ||
| 1147 | Expect TARGET to be an `erc--target' instance. Guarantee that at | ||
| 1148 | most one existing buffer has the same `erc-networks--id' and a | ||
| 1149 | case-mapped target, i.e., `erc--target-symbol'. If other buffers | ||
| 1150 | with equivalent targets exist, rename them to TARGET@their-NID | ||
| 1151 | and return TARGET@our-NID. Otherwise return TARGET as a string. | ||
| 1152 | When multiple buffers for TARGET exist for the current NID, | ||
| 1153 | rename them with <n> suffixes going from newest to oldest." | ||
| 1154 | (let* (existing ; Former selves or unexpected dupes (for now allow > 1) | ||
| 1155 | ;; Renamed ERC buffers on other networks matching target | ||
| 1156 | (namesakes (erc-networks--examine-targets nid target | ||
| 1157 | (lambda () (push (current-buffer) existing) nil) | ||
| 1158 | ;; Append network ID as TARGET@NID, | ||
| 1159 | ;; possibly qualifying to achieve uniqueness. | ||
| 1160 | (lambda () | ||
| 1161 | (unless (erc--target-channel-local-p erc--target) | ||
| 1162 | (erc-networks--id-ensure-comparable | ||
| 1163 | nid erc-networks--id)) | ||
| 1164 | (erc-networks--ensure-unique-target-buffer-name) | ||
| 1165 | t))) | ||
| 1166 | ;; Must follow ^ because NID may have been modified | ||
| 1167 | (name (if (or namesakes (not (with-suppressed-warnings | ||
| 1168 | ((obsolete erc-reuse-buffers)) | ||
| 1169 | erc-reuse-buffers))) | ||
| 1170 | (erc-networks--construct-target-buffer-name target) | ||
| 1171 | (erc--target-string target))) | ||
| 1172 | placeholder) | ||
| 1173 | ;; If we don't exist, claim name temporarily while renaming others | ||
| 1174 | (when-let* (namesakes | ||
| 1175 | (ex (get-buffer name)) | ||
| 1176 | ((not (memq ex existing))) | ||
| 1177 | (temp-name (generate-new-buffer-name (format "*%s*" name)))) | ||
| 1178 | (setq existing (remq ex existing)) | ||
| 1179 | (with-current-buffer ex | ||
| 1180 | (rename-buffer temp-name) | ||
| 1181 | (setq placeholder (get-buffer-create name)) | ||
| 1182 | (rename-buffer name 'unique))) | ||
| 1183 | (unless (with-suppressed-warnings ((obsolete erc-reuse-buffers)) | ||
| 1184 | erc-reuse-buffers) | ||
| 1185 | (when (string-suffix-p ">" name) | ||
| 1186 | (setq name (substring name 0 -3)))) | ||
| 1187 | (dolist (ex (erc-networks--id-sort-buffers existing)) | ||
| 1188 | (with-current-buffer ex | ||
| 1189 | (rename-buffer name 'unique))) | ||
| 1190 | (when placeholder (kill-buffer placeholder)) | ||
| 1191 | name)) | ||
| 1192 | |||
| 1193 | |||
| 734 | ;; Functions: | 1194 | ;; Functions: |
| 735 | 1195 | ||
| 736 | ;;;###autoload | 1196 | ;;;###autoload |
| @@ -739,6 +1199,7 @@ MATCHER is used to find a corresponding network to a server while | |||
| 739 | Use the server parameter NETWORK if provided, otherwise parse the | 1199 | Use the server parameter NETWORK if provided, otherwise parse the |
| 740 | server name and search for a match in `erc-networks-alist'." | 1200 | server name and search for a match in `erc-networks-alist'." |
| 741 | ;; The server made it easy for us and told us the name of the NETWORK | 1201 | ;; The server made it easy for us and told us the name of the NETWORK |
| 1202 | (declare (obsolete "maybe see `erc-networks--determine'" "29.1")) | ||
| 742 | (let ((network-name (cdr (assoc "NETWORK" erc-server-parameters)))) | 1203 | (let ((network-name (cdr (assoc "NETWORK" erc-server-parameters)))) |
| 743 | (if network-name | 1204 | (if network-name |
| 744 | (intern network-name) | 1205 | (intern network-name) |
| @@ -761,23 +1222,242 @@ server name and search for a match in `erc-networks-alist'." | |||
| 761 | 1222 | ||
| 762 | (defun erc-set-network-name (_proc _parsed) | 1223 | (defun erc-set-network-name (_proc _parsed) |
| 763 | "Set `erc-network' to the value returned by `erc-determine-network'." | 1224 | "Set `erc-network' to the value returned by `erc-determine-network'." |
| 1225 | (declare (obsolete "maybe see `erc-networks--set-name'" "29.1")) | ||
| 764 | (unless erc-server-connected | 1226 | (unless erc-server-connected |
| 765 | (setq erc-network (erc-determine-network))) | 1227 | (setq erc-network (with-suppressed-warnings |
| 1228 | ((obsolete erc-determine-network)) | ||
| 1229 | (erc-determine-network)))) | ||
| 1230 | nil) | ||
| 1231 | |||
| 1232 | (defconst erc-networks--name-missing-sentinel (gensym "Unknown ") | ||
| 1233 | "Value to cover rare case of a literal NETWORK=nil.") | ||
| 1234 | |||
| 1235 | (defun erc-networks--determine () | ||
| 1236 | "Return the name of the network as a symbol. | ||
| 1237 | Search `erc-networks-alist' for a known entity matching | ||
| 1238 | `erc-server-announced-name'. If that fails, use the display name | ||
| 1239 | given by the `RPL_ISUPPORT' NETWORK parameter." | ||
| 1240 | (or (cl-loop for (name matcher) in erc-networks-alist | ||
| 1241 | when (and matcher (string-match (concat matcher "\\'") | ||
| 1242 | erc-server-announced-name)) | ||
| 1243 | return name) | ||
| 1244 | (and-let* ((vanity (erc--get-isupport-entry 'NETWORK 'single)) | ||
| 1245 | ((intern vanity)))) | ||
| 1246 | erc-networks--name-missing-sentinel)) | ||
| 1247 | |||
| 1248 | (defun erc-networks--set-name (_proc parsed) | ||
| 1249 | "Set `erc-network' to the value returned by `erc-networks--determine'. | ||
| 1250 | Signal an error when the network cannot be determined." | ||
| 1251 | ;; Always update (possibly clobber) current value, if any. | ||
| 1252 | (let ((name (erc-networks--determine))) | ||
| 1253 | (when (eq name erc-networks--name-missing-sentinel) | ||
| 1254 | ;; This can happen theoretically, e.g., if you're editing some | ||
| 1255 | ;; settings interactively on a proxy service that impersonates IRC | ||
| 1256 | ;; but aren't being proxied through to a real network. The | ||
| 1257 | ;; service may send a 422 but no NETWORK param (or *any* 005s). | ||
| 1258 | (let ((m (concat "Failed to determine network. Please set entry for " | ||
| 1259 | erc-server-announced-name " in `erc-network-alist'."))) | ||
| 1260 | (erc-display-error-notice parsed m) | ||
| 1261 | (erc-error "Failed to determine network"))) ; beep | ||
| 1262 | (setq erc-network name)) | ||
| 1263 | nil) | ||
| 1264 | |||
| 1265 | ;; This lives here in this file because all the other "on connect" | ||
| 1266 | ;; MOTD stuff ended up here (but perhaps that needs to change). | ||
| 1267 | |||
| 1268 | (defun erc-networks--ensure-announced (_ parsed) | ||
| 1269 | "Set a fallback `erc-server-announced-name' if still unset. | ||
| 1270 | Copy source (prefix) from MOTD-ish message as a last resort." | ||
| 1271 | ;; The 004 handler never ran; see 2004-03-10 Diane Murray in change log | ||
| 1272 | (unless erc-server-announced-name | ||
| 1273 | (erc-display-error-notice parsed "Failed to determine server name.") | ||
| 1274 | (erc-display-error-notice | ||
| 1275 | parsed (concat "If this was unexpected, consider reporting it via " | ||
| 1276 | (substitute-command-keys "\\[erc-bug]") ".")) | ||
| 1277 | (setq erc-server-announced-name (erc-response.sender parsed))) | ||
| 766 | nil) | 1278 | nil) |
| 767 | 1279 | ||
| 768 | (defun erc-unset-network-name (_nick _ip _reason) | 1280 | (defun erc-unset-network-name (_nick _ip _reason) |
| 769 | "Set `erc-network' to nil." | 1281 | "Set `erc-network' to nil." |
| 1282 | (declare (obsolete "`erc-network' is now effectively read-only" "29.1")) | ||
| 770 | (setq erc-network nil) | 1283 | (setq erc-network nil) |
| 771 | nil) | 1284 | nil) |
| 772 | 1285 | ||
| 1286 | ;; TODO add note in Commentary saying that this module is considered a | ||
| 1287 | ;; core module and that it's as much about buffer naming and network | ||
| 1288 | ;; identity as anything else. | ||
| 1289 | |||
| 1290 | (defun erc-networks--insert-transplanted-content (content) | ||
| 1291 | (let ((inhibit-read-only t) | ||
| 1292 | (buffer-undo-list t)) | ||
| 1293 | (save-excursion | ||
| 1294 | (save-restriction | ||
| 1295 | (widen) | ||
| 1296 | (goto-char (point-min)) | ||
| 1297 | (insert-before-markers content))))) | ||
| 1298 | |||
| 1299 | ;; This should run whenever a network identity is updated. | ||
| 1300 | |||
| 1301 | (defun erc-networks--reclaim-orphaned-target-buffers (new-proc nid announced) | ||
| 1302 | "Visit disowned buffers for same NID and associate with NEW-PROC. | ||
| 1303 | ANNOUNCED is the server's reported host name." | ||
| 1304 | (erc-buffer-filter | ||
| 1305 | (lambda () | ||
| 1306 | (when (and erc--target | ||
| 1307 | (not erc-server-connected) | ||
| 1308 | (erc-networks--id-equal-p erc-networks--id nid) | ||
| 1309 | (or (not (erc--target-channel-local-p erc--target)) | ||
| 1310 | (string= erc-server-announced-name announced))) | ||
| 1311 | ;; If a target buffer exists for the current process, kill this | ||
| 1312 | ;; stale one after transplanting its content; else reinstate. | ||
| 1313 | (if-let ((existing (erc-get-buffer | ||
| 1314 | (erc--target-string erc--target) new-proc))) | ||
| 1315 | (progn | ||
| 1316 | (widen) | ||
| 1317 | (let ((content (buffer-substring (point-min) | ||
| 1318 | erc-insert-marker))) | ||
| 1319 | (kill-buffer) ; allow target-buf renaming hook to run | ||
| 1320 | (with-current-buffer existing | ||
| 1321 | (erc-networks--ensure-unique-target-buffer-name) | ||
| 1322 | (erc-networks--insert-transplanted-content content)))) | ||
| 1323 | (setq erc-server-process new-proc | ||
| 1324 | erc-server-connected t | ||
| 1325 | erc-networks--id nid)))))) | ||
| 1326 | |||
| 1327 | (defun erc-networks--copy-over-server-buffer-contents (existing name) | ||
| 1328 | "Kill off existing server buffer after copying its contents. | ||
| 1329 | Must be called from the replacement buffer." | ||
| 1330 | ;; ERC expects `erc-open' to be idempotent when setting up local | ||
| 1331 | ;; vars and other context properties for a new identity. Thus, it's | ||
| 1332 | ;; unlikely we'll have to copy anything else over besides text. And | ||
| 1333 | ;; no reconciling of user tables, etc. happens during a normal | ||
| 1334 | ;; reconnect, so we should be fine just sticking to text. (Right?) | ||
| 1335 | (let ((text (with-current-buffer existing | ||
| 1336 | ;; This `erc-networks--id' should be | ||
| 1337 | ;; `erc-networks--id-equal-p' to caller's network | ||
| 1338 | ;; identity and older if not eq. | ||
| 1339 | ;; | ||
| 1340 | ;; `erc-server-process' should be set but dead | ||
| 1341 | ;; and eq `get-buffer-process' unless latter nil | ||
| 1342 | (delete-process erc-server-process) | ||
| 1343 | (buffer-substring (point-min) erc-insert-marker))) | ||
| 1344 | erc-kill-server-hook | ||
| 1345 | erc-kill-buffer-hook) | ||
| 1346 | (erc-networks--insert-transplanted-content text) | ||
| 1347 | (kill-buffer name))) | ||
| 1348 | |||
| 1349 | ;; This stands alone for testing purposes | ||
| 1350 | |||
| 1351 | (defun erc-networks--update-server-identity () | ||
| 1352 | "Maybe grow or replace the current network identity. | ||
| 1353 | If a dupe is found, adopt its identity by overwriting ours. | ||
| 1354 | Otherwise, take steps to ensure it can effectively be compared to | ||
| 1355 | ours, now and into the future. Note that target buffers are | ||
| 1356 | considered as well because server buffers are often killed." | ||
| 1357 | (let* ((identity erc-networks--id) | ||
| 1358 | (buffer (current-buffer)) | ||
| 1359 | (f (lambda () | ||
| 1360 | (unless (or (eq (current-buffer) buffer) | ||
| 1361 | (eq erc-networks--id identity)) | ||
| 1362 | (if (erc-networks--id-equal-p identity erc-networks--id) | ||
| 1363 | (throw 'buffer erc-networks--id) | ||
| 1364 | (erc-networks--id-ensure-comparable identity | ||
| 1365 | erc-networks--id) | ||
| 1366 | nil)))) | ||
| 1367 | (found (catch 'buffer (erc-buffer-filter f)))) | ||
| 1368 | (when found | ||
| 1369 | (setq erc-networks--id found)))) | ||
| 1370 | |||
| 1371 | ;; These steps should only run when initializing a newly connected | ||
| 1372 | ;; server buffer, whereas `erc-networks--rename-server-buffer' can run | ||
| 1373 | ;; mid-session, after an identity's core components have changed. | ||
| 1374 | |||
| 1375 | (defun erc-networks--init-identity (_proc _parsed) | ||
| 1376 | "Update identity with real network name." | ||
| 1377 | ;; Initialize identity for real now that we know the network | ||
| 1378 | (cl-assert erc-network) | ||
| 1379 | (unless (erc-networks--id-symbol erc-networks--id) ; unless just reconnected | ||
| 1380 | (erc-networks--id-on-connect erc-networks--id)) | ||
| 1381 | ;; Find duplicate identities or other conflicting ones and act | ||
| 1382 | ;; accordingly. | ||
| 1383 | (erc-networks--update-server-identity) | ||
| 1384 | ;; | ||
| 1385 | nil) | ||
| 1386 | |||
| 1387 | (defun erc-networks--rename-server-buffer (new-proc &optional _parsed) | ||
| 1388 | "Rename a server buffer based on its network identity. | ||
| 1389 | Assume that the current buffer is a server buffer, either one | ||
| 1390 | with a newly established connection whose identity has just been | ||
| 1391 | fully fleshed out, or an existing one whose identity has just | ||
| 1392 | been updated. Either way, assume the current identity is ready | ||
| 1393 | to serve as a canonical identifier. | ||
| 1394 | |||
| 1395 | When a server buffer already exists with the chosen name, copy | ||
| 1396 | over its contents and kill it. However, when its process is | ||
| 1397 | still alive, kill off the current buffer. This can happen, for | ||
| 1398 | example, after a perceived loss in network connectivity turns out | ||
| 1399 | to be a false alarm. If `erc-reuse-buffers' is nil, let | ||
| 1400 | `generate-new-buffer-name' do the actual renaming." | ||
| 1401 | (cl-assert (eq new-proc erc-server-process)) | ||
| 1402 | (cl-assert (erc-networks--id-symbol erc-networks--id)) | ||
| 1403 | ;; Always look for targets to reassociate because original server | ||
| 1404 | ;; buffer may have been deleted. | ||
| 1405 | (erc-networks--reclaim-orphaned-target-buffers new-proc erc-networks--id | ||
| 1406 | erc-server-announced-name) | ||
| 1407 | (let* ((name (symbol-name (erc-networks--id-symbol erc-networks--id))) | ||
| 1408 | ;; When this ends up being the current buffer, either we have | ||
| 1409 | ;; a "given" ID or the buffer was reused on reconnecting. | ||
| 1410 | (existing (get-buffer name))) | ||
| 1411 | (cond ((or (not existing) | ||
| 1412 | (erc-networks--id-given erc-networks--id) | ||
| 1413 | (eq existing (current-buffer))) | ||
| 1414 | (rename-buffer name)) | ||
| 1415 | ;; Abort on accidental reconnect or failure to pass :id param for | ||
| 1416 | ;; avoidable collisions. | ||
| 1417 | ((erc-server-process-alive existing) | ||
| 1418 | (kill-local-variable 'erc-network) | ||
| 1419 | (delete-process new-proc) | ||
| 1420 | (erc-display-error-notice nil (format "Buffer %s still connected" | ||
| 1421 | name)) | ||
| 1422 | (erc-set-active-buffer existing)) | ||
| 1423 | ;; Copy over old buffer's contents and kill it | ||
| 1424 | ((with-suppressed-warnings ((obsolete erc-reuse-buffers)) | ||
| 1425 | erc-reuse-buffers) | ||
| 1426 | (erc-networks--copy-over-server-buffer-contents existing name) | ||
| 1427 | (rename-buffer name)) | ||
| 1428 | (t (rename-buffer (generate-new-buffer-name name))))) | ||
| 1429 | nil) | ||
| 1430 | |||
| 1431 | ;; Soju v0.4.0 only sends ISUPPORT on upstream reconnect, so this | ||
| 1432 | ;; doesn't apply. ZNC 1.8.2, however, still sends the entire burst. | ||
| 1433 | (defconst erc-networks--bouncer-targets '(*status bouncerserv) | ||
| 1434 | "Case-mapped symbols matching known bouncer service-bot targets.") | ||
| 1435 | |||
| 1436 | (defun erc-networks-on-MOTD-end (proc parsed) | ||
| 1437 | "Call on-connect functions with server PROC and PARSED message. | ||
| 1438 | This must run before `erc-server-connected' is set." | ||
| 1439 | (when erc-server-connected | ||
| 1440 | (unless (erc-buffer-filter (lambda () | ||
| 1441 | (and erc--target | ||
| 1442 | (memq (erc--target-symbol erc--target) | ||
| 1443 | erc-networks--bouncer-targets))) | ||
| 1444 | proc) | ||
| 1445 | (let ((m (concat "Unexpected state detected. Please report via " | ||
| 1446 | (substitute-command-keys "\\[erc-bug]") "."))) | ||
| 1447 | (erc-display-error-notice parsed m)))) | ||
| 1448 | |||
| 1449 | ;; For now, retain compatibility with erc-server-NNN-functions. | ||
| 1450 | (or (erc-networks--ensure-announced proc parsed) | ||
| 1451 | (erc-networks--set-name proc parsed) | ||
| 1452 | (erc-networks--init-identity proc parsed) | ||
| 1453 | (erc-networks--rename-server-buffer proc parsed))) | ||
| 1454 | |||
| 773 | (define-erc-module networks nil | 1455 | (define-erc-module networks nil |
| 774 | "Provide data about IRC networks." | 1456 | "Provide data about IRC networks." |
| 775 | ((add-hook 'erc-server-375-functions #'erc-set-network-name) | 1457 | ((add-hook 'erc-server-376-functions #'erc-networks-on-MOTD-end) |
| 776 | (add-hook 'erc-server-422-functions #'erc-set-network-name) | 1458 | (add-hook 'erc-server-422-functions #'erc-networks-on-MOTD-end)) |
| 777 | (add-hook 'erc-disconnected-hook #'erc-unset-network-name)) | 1459 | ((remove-hook 'erc-server-376-functions #'erc-networks-on-MOTD-end) |
| 778 | ((remove-hook 'erc-server-375-functions #'erc-set-network-name) | 1460 | (remove-hook 'erc-server-422-functions #'erc-networks-on-MOTD-end))) |
| 779 | (remove-hook 'erc-server-422-functions #'erc-set-network-name) | ||
| 780 | (remove-hook 'erc-disconnected-hook #'erc-unset-network-name))) | ||
| 781 | 1461 | ||
| 782 | (defun erc-ports-list (ports) | 1462 | (defun erc-ports-list (ports) |
| 783 | "Return a list of PORTS. | 1463 | "Return a list of PORTS. |
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 9f17816b8d4..18a353ae494 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el | |||
| @@ -134,6 +134,8 @@ | |||
| 134 | (defvar erc--server-last-reconnect-count) | 134 | (defvar erc--server-last-reconnect-count) |
| 135 | (defvar erc--server-reconnecting) | 135 | (defvar erc--server-reconnecting) |
| 136 | (defvar erc-channel-members-changed-hook) | 136 | (defvar erc-channel-members-changed-hook) |
| 137 | (defvar erc-network) | ||
| 138 | (defvar erc-networks--id) | ||
| 137 | (defvar erc-server-367-functions) | 139 | (defvar erc-server-367-functions) |
| 138 | (defvar erc-server-announced-name) | 140 | (defvar erc-server-announced-name) |
| 139 | (defvar erc-server-connect-function) | 141 | (defvar erc-server-connect-function) |
| @@ -210,12 +212,21 @@ parameters and authentication." | |||
| 210 | :set (lambda (sym val) | 212 | :set (lambda (sym val) |
| 211 | (set sym (if (functionp val) (funcall val) val)))) | 213 | (set sym (if (functionp val) (funcall val) val)))) |
| 212 | 214 | ||
| 213 | (defcustom erc-rename-buffers nil | 215 | (defcustom erc-rename-buffers t |
| 214 | "Non-nil means rename buffers with network name, if available." | 216 | "Non-nil means rename buffers with network name, if available." |
| 215 | :version "24.5" | 217 | :version "24.5" |
| 216 | :group 'erc | 218 | :group 'erc |
| 217 | :type 'boolean) | 219 | :type 'boolean) |
| 218 | 220 | ||
| 221 | ;; For the sake of compatibility, an ID will be created on the user's | ||
| 222 | ;; behalf when `erc-rename-buffers' is nil and one wasn't provided. | ||
| 223 | ;; The name will simply be that of the buffer, usually SERVER:PORT. | ||
| 224 | ;; This violates the policy of treating provided IDs as gospel, but | ||
| 225 | ;; it'll have to do for now. | ||
| 226 | |||
| 227 | (make-obsolete-variable 'erc-rename-buffers | ||
| 228 | "old behavior when t now permanent" "29.1") | ||
| 229 | |||
| 219 | (defvar erc-password nil | 230 | (defvar erc-password nil |
| 220 | "Password to use when authenticating to an IRC server. | 231 | "Password to use when authenticating to an IRC server. |
| 221 | It is not strictly necessary to provide this, since ERC will | 232 | It is not strictly necessary to provide this, since ERC will |
| @@ -1660,6 +1671,14 @@ effect when `erc-join-buffer' is set to `frame'." | |||
| 1660 | (erc-channel-p (erc-default-target)))) | 1671 | (erc-channel-p (erc-default-target)))) |
| 1661 | (t nil))) | 1672 | (t nil))) |
| 1662 | 1673 | ||
| 1674 | ;; For the sake of compatibility, a historical quirk concerning this | ||
| 1675 | ;; option, when nil, has been preserved: all buffers are suffixed with | ||
| 1676 | ;; the original dialed host name, which is usually something like | ||
| 1677 | ;; irc.libera.chat. Collisions are handled by adding a uniquifying | ||
| 1678 | ;; numeric suffix of the form <N>. Note that channel reassociation | ||
| 1679 | ;; behavior involving this option (when nil) was inverted in 28.1 (ERC | ||
| 1680 | ;; 5.4 and 5.4.1). This was regrettable and has since been undone. | ||
| 1681 | |||
| 1663 | (defcustom erc-reuse-buffers t | 1682 | (defcustom erc-reuse-buffers t |
| 1664 | "If nil, create new buffers on joining a channel/query. | 1683 | "If nil, create new buffers on joining a channel/query. |
| 1665 | If non-nil, a new buffer will only be created when you join | 1684 | If non-nil, a new buffer will only be created when you join |
| @@ -1669,6 +1688,9 @@ the existing buffers will be reused." | |||
| 1669 | :group 'erc-buffers | 1688 | :group 'erc-buffers |
| 1670 | :type 'boolean) | 1689 | :type 'boolean) |
| 1671 | 1690 | ||
| 1691 | (make-obsolete-variable 'erc-reuse-buffers | ||
| 1692 | "old behavior when t now permanent" "29.1") | ||
| 1693 | |||
| 1672 | (defun erc-normalize-port (port) | 1694 | (defun erc-normalize-port (port) |
| 1673 | "Normalize the port specification PORT to integer form. | 1695 | "Normalize the port specification PORT to integer form. |
| 1674 | PORT may be an integer, a string or a symbol. If it is a string or a | 1696 | PORT may be an integer, a string or a symbol. If it is a string or a |
| @@ -1704,55 +1726,61 @@ symbol, it may have these values: | |||
| 1704 | "Check whether ports A and B are equal." | 1726 | "Check whether ports A and B are equal." |
| 1705 | (= (erc-normalize-port a) (erc-normalize-port b))) | 1727 | (= (erc-normalize-port a) (erc-normalize-port b))) |
| 1706 | 1728 | ||
| 1707 | (defun erc-generate-new-buffer-name (server port target) | 1729 | (defun erc-generate-new-buffer-name (server port target &optional tgt-info id) |
| 1708 | "Create a new buffer name based on the arguments." | 1730 | "Determine the name of an ERC buffer. |
| 1709 | (when (numberp port) (setq port (number-to-string port))) | 1731 | When TGT-INFO is nil, assume this is a server buffer. If ID is non-nil, |
| 1710 | (let* ((buf-name (or target | 1732 | return ID as a string unless a buffer already exists with a live server |
| 1711 | (let ((name (concat server ":" port))) | 1733 | process, in which case signal an error. When ID is nil, return a |
| 1712 | (when (> (length name) 1) | 1734 | temporary name based on SERVER and PORT to be replaced with the network |
| 1713 | name)) | 1735 | name when discovered (see `erc-networks--rename-server-buffer'). Allow |
| 1714 | ;; This fallback should in fact never happen. | 1736 | either SERVER or PORT (but not both) to be nil to accommodate oddball |
| 1715 | "*erc-server-buffer*")) | 1737 | `erc-server-connect-function's. |
| 1716 | (full-buf-name (concat buf-name "/" server)) | 1738 | |
| 1717 | (dup-buf-name (buffer-name (car (erc-channel-list nil)))) | 1739 | When TGT-INFO is non-nil, expect its string field to match the redundant |
| 1718 | buffer-name) | 1740 | param TARGET (retained for compatibility). Whenever possibly, prefer |
| 1719 | ;; Reuse existing buffers, but not if the buffer is a connected server | 1741 | returning TGT-INFO's string unmodified. But when a case-insensitive |
| 1720 | ;; buffer and not if its associated with a different server than the | 1742 | collision prevents that, return target@ID when ID is non-nil or |
| 1721 | ;; current ERC buffer. | 1743 | target@network otherwise after renaming the conflicting buffer in the |
| 1722 | ;; If buf-name is taken by a different connection (or by something !erc) | 1744 | same manner." |
| 1723 | ;; then see if "buf-name/server" meets the same criteria. | 1745 | (when target ; compat |
| 1724 | (if (and dup-buf-name (string-match-p (concat buf-name "/") dup-buf-name)) | 1746 | (setq tgt-info (erc--target-from-string target))) |
| 1725 | (setq buffer-name full-buf-name) ; ERC buffer with full name already exists. | 1747 | (if tgt-info |
| 1726 | (dolist (candidate (list buf-name full-buf-name)) | 1748 | (let* ((esid (erc-networks--id-symbol erc-networks--id)) |
| 1727 | (if (and (not buffer-name) | 1749 | (name (if esid |
| 1728 | erc-reuse-buffers | 1750 | (erc-networks--reconcile-buffer-names tgt-info |
| 1729 | (or (not (get-buffer candidate)) | 1751 | erc-networks--id) |
| 1730 | ;; Looking for a server buffer, so there's no target. | 1752 | (erc--target-string tgt-info)))) |
| 1731 | (and (not target) | 1753 | (if (and esid (with-suppressed-warnings ((obsolete erc-reuse-buffers)) |
| 1732 | (with-current-buffer (get-buffer candidate) | 1754 | erc-reuse-buffers)) |
| 1733 | (and (erc-server-buffer-p) | 1755 | name |
| 1734 | (not (erc-server-process-alive))))) | 1756 | (generate-new-buffer-name name))) |
| 1735 | ;; Channel buffer; check that it's from the right server. | 1757 | (if (and (with-suppressed-warnings ((obsolete erc-reuse-buffers)) |
| 1736 | (and target | 1758 | erc-reuse-buffers) |
| 1737 | (with-current-buffer (get-buffer candidate) | 1759 | id) |
| 1738 | (and (string= erc-session-server server) | 1760 | (progn |
| 1739 | (erc-port-equal erc-session-port port)))))) | 1761 | (when-let* ((buf (get-buffer (symbol-name id))) |
| 1740 | (setq buffer-name candidate) | 1762 | ((erc-server-process-alive buf))) |
| 1741 | (when (and (not buffer-name) (get-buffer buf-name) erc-reuse-buffers) | 1763 | (user-error "Session with ID %S already exists" id)) |
| 1742 | ;; A new buffer will be created with the name buf-name/server, rename | 1764 | (symbol-name id)) |
| 1743 | ;; the existing name-duplicated buffer with the same format as well. | 1765 | (generate-new-buffer-name (if (and server port) |
| 1744 | (with-current-buffer (get-buffer buf-name) | 1766 | (if (with-suppressed-warnings |
| 1745 | (when (derived-mode-p 'erc-mode) ; ensure it's an erc buffer | 1767 | ((obsolete erc-reuse-buffers)) |
| 1746 | (rename-buffer | 1768 | erc-reuse-buffers) |
| 1747 | (concat buf-name "/" (or erc-session-server erc-server-announced-name))))))))) | 1769 | (format "%s:%s" server port) |
| 1748 | ;; If buffer-name is unset, neither candidate worked out for us, | 1770 | (format "%s:%s/%s" server port server)) |
| 1749 | ;; fallback to the old <N> uniquification method: | 1771 | (or server port)))))) |
| 1750 | (or buffer-name (generate-new-buffer-name full-buf-name)))) | 1772 | |
| 1751 | 1773 | (defun erc-get-buffer-create (server port target &optional tgt-info id) | |
| 1752 | (defun erc-get-buffer-create (server port target) | ||
| 1753 | "Create a new buffer based on the arguments." | 1774 | "Create a new buffer based on the arguments." |
| 1754 | (get-buffer-create (erc-generate-new-buffer-name server port target))) | 1775 | (when target ; compat |
| 1755 | 1776 | (setq tgt-info (erc--target-from-string target))) | |
| 1777 | (if (and erc--server-reconnecting | ||
| 1778 | (not tgt-info) | ||
| 1779 | (with-suppressed-warnings ((obsolete erc-reuse-buffers)) | ||
| 1780 | erc-reuse-buffers)) | ||
| 1781 | (current-buffer) | ||
| 1782 | (get-buffer-create | ||
| 1783 | (erc-generate-new-buffer-name server port nil tgt-info id)))) | ||
| 1756 | 1784 | ||
| 1757 | (defun erc-member-ignore-case (string list) | 1785 | (defun erc-member-ignore-case (string list) |
| 1758 | "Return non-nil if STRING is a member of LIST. | 1786 | "Return non-nil if STRING is a member of LIST. |
| @@ -2094,7 +2122,7 @@ removed from the list will be disabled." | |||
| 2094 | 2122 | ||
| 2095 | (defun erc-open (&optional server port nick full-name | 2123 | (defun erc-open (&optional server port nick full-name |
| 2096 | connect passwd tgt-list channel process | 2124 | connect passwd tgt-list channel process |
| 2097 | client-certificate user) | 2125 | client-certificate user id) |
| 2098 | "Connect to SERVER on PORT as NICK with USER and FULL-NAME. | 2126 | "Connect to SERVER on PORT as NICK with USER and FULL-NAME. |
| 2099 | 2127 | ||
| 2100 | If CONNECT is non-nil, connect to the server. Otherwise assume | 2128 | If CONNECT is non-nil, connect to the server. Otherwise assume |
| @@ -2111,11 +2139,17 @@ of the client certificate itself to use when connecting over TLS, | |||
| 2111 | or t, which means that `auth-source' will be queried for the | 2139 | or t, which means that `auth-source' will be queried for the |
| 2112 | private key and the certificate. | 2140 | private key and the certificate. |
| 2113 | 2141 | ||
| 2142 | When non-nil, ID should be a symbol for identifying the connection. | ||
| 2143 | |||
| 2114 | Returns the buffer for the given server or channel." | 2144 | Returns the buffer for the given server or channel." |
| 2115 | (let ((buffer (erc-get-buffer-create server port channel)) | 2145 | (let* ((target (and channel (erc--target-from-string channel))) |
| 2116 | (old-buffer (current-buffer)) | 2146 | (buffer (erc-get-buffer-create server port nil target id)) |
| 2117 | old-point | 2147 | (old-buffer (current-buffer)) |
| 2118 | (continued-session (and erc-reuse-buffers erc--server-reconnecting))) | 2148 | old-point |
| 2149 | (continued-session (and erc--server-reconnecting | ||
| 2150 | (with-suppressed-warnings | ||
| 2151 | ((obsolete erc-reuse-buffers)) | ||
| 2152 | erc-reuse-buffers)))) | ||
| 2119 | (when connect (run-hook-with-args 'erc-before-connect server port nick)) | 2153 | (when connect (run-hook-with-args 'erc-before-connect server port nick)) |
| 2120 | (erc-update-modules) | 2154 | (erc-update-modules) |
| 2121 | (set-buffer buffer) | 2155 | (set-buffer buffer) |
| @@ -2145,7 +2179,9 @@ Returns the buffer for the given server or channel." | |||
| 2145 | (set-marker erc-insert-marker (point)) | 2179 | (set-marker erc-insert-marker (point)) |
| 2146 | ;; stack of default recipients | 2180 | ;; stack of default recipients |
| 2147 | (setq erc-default-recipients tgt-list) | 2181 | (setq erc-default-recipients tgt-list) |
| 2148 | (setq erc--target (and channel (erc--target-from-string channel))) | 2182 | (when target |
| 2183 | (setq erc--target target | ||
| 2184 | erc-network (erc-network))) | ||
| 2149 | (setq erc-server-current-nick nil) | 2185 | (setq erc-server-current-nick nil) |
| 2150 | ;; Initialize erc-server-users and erc-channel-users | 2186 | ;; Initialize erc-server-users and erc-channel-users |
| 2151 | (if connect | 2187 | (if connect |
| @@ -2184,6 +2220,10 @@ Returns the buffer for the given server or channel." | |||
| 2184 | :require '(:secret)))) | 2220 | :require '(:secret)))) |
| 2185 | ;; client certificate (only useful if connecting over TLS) | 2221 | ;; client certificate (only useful if connecting over TLS) |
| 2186 | (setq erc-session-client-certificate client-certificate) | 2222 | (setq erc-session-client-certificate client-certificate) |
| 2223 | (setq erc-networks--id (if connect | ||
| 2224 | (erc-networks--id-create id) | ||
| 2225 | (buffer-local-value 'erc-networks--id | ||
| 2226 | old-buffer))) | ||
| 2187 | ;; debug output buffer | 2227 | ;; debug output buffer |
| 2188 | (setq erc-dbuf | 2228 | (setq erc-dbuf |
| 2189 | (when erc-log-p | 2229 | (when erc-log-p |
| @@ -2322,7 +2362,8 @@ parameters SERVER and NICK." | |||
| 2322 | (nick (erc-compute-nick)) | 2362 | (nick (erc-compute-nick)) |
| 2323 | (user (erc-compute-user)) | 2363 | (user (erc-compute-user)) |
| 2324 | password | 2364 | password |
| 2325 | (full-name (erc-compute-full-name))) | 2365 | (full-name (erc-compute-full-name)) |
| 2366 | id) | ||
| 2326 | "ERC is a powerful, modular, and extensible IRC client. | 2367 | "ERC is a powerful, modular, and extensible IRC client. |
| 2327 | This function is the main entry point for ERC. | 2368 | This function is the main entry point for ERC. |
| 2328 | 2369 | ||
| @@ -2335,6 +2376,7 @@ Non-interactively, it takes the keyword arguments | |||
| 2335 | (user (erc-compute-user)) | 2376 | (user (erc-compute-user)) |
| 2336 | password | 2377 | password |
| 2337 | (full-name (erc-compute-full-name)) | 2378 | (full-name (erc-compute-full-name)) |
| 2379 | id | ||
| 2338 | 2380 | ||
| 2339 | That is, if called with | 2381 | That is, if called with |
| 2340 | 2382 | ||
| @@ -2342,9 +2384,13 @@ That is, if called with | |||
| 2342 | 2384 | ||
| 2343 | then the server and full-name will be set to those values, | 2385 | then the server and full-name will be set to those values, |
| 2344 | whereas `erc-compute-port' and `erc-compute-nick' will be invoked | 2386 | whereas `erc-compute-port' and `erc-compute-nick' will be invoked |
| 2345 | for the values of the other parameters." | 2387 | for the values of the other parameters. |
| 2388 | |||
| 2389 | When present, ID should be an opaque object used to identify the | ||
| 2390 | connection unequivocally. This is rarely needed and not available | ||
| 2391 | interactively." | ||
| 2346 | (interactive (erc-select-read-args)) | 2392 | (interactive (erc-select-read-args)) |
| 2347 | (erc-open server port nick full-name t password nil nil nil nil user)) | 2393 | (erc-open server port nick full-name t password nil nil nil nil user id)) |
| 2348 | 2394 | ||
| 2349 | ;;;###autoload | 2395 | ;;;###autoload |
| 2350 | (defalias 'erc-select #'erc) | 2396 | (defalias 'erc-select #'erc) |
| @@ -2357,7 +2403,8 @@ for the values of the other parameters." | |||
| 2357 | (user (erc-compute-user)) | 2403 | (user (erc-compute-user)) |
| 2358 | password | 2404 | password |
| 2359 | (full-name (erc-compute-full-name)) | 2405 | (full-name (erc-compute-full-name)) |
| 2360 | client-certificate) | 2406 | client-certificate |
| 2407 | id) | ||
| 2361 | "ERC is a powerful, modular, and extensible IRC client. | 2408 | "ERC is a powerful, modular, and extensible IRC client. |
| 2362 | This function is the main entry point for ERC over TLS. | 2409 | This function is the main entry point for ERC over TLS. |
| 2363 | 2410 | ||
| @@ -2371,6 +2418,7 @@ Non-interactively, it takes the keyword arguments | |||
| 2371 | password | 2418 | password |
| 2372 | (full-name (erc-compute-full-name)) | 2419 | (full-name (erc-compute-full-name)) |
| 2373 | client-certificate | 2420 | client-certificate |
| 2421 | id | ||
| 2374 | 2422 | ||
| 2375 | That is, if called with | 2423 | That is, if called with |
| 2376 | 2424 | ||
| @@ -2393,12 +2441,18 @@ Example usage: | |||
| 2393 | (erc-tls :server \"irc.libera.chat\" :port 6697 | 2441 | (erc-tls :server \"irc.libera.chat\" :port 6697 |
| 2394 | :client-certificate | 2442 | :client-certificate |
| 2395 | \\='(\"/home/bandali/my-cert.key\" | 2443 | \\='(\"/home/bandali/my-cert.key\" |
| 2396 | \"/home/bandali/my-cert.crt\"))" | 2444 | \"/home/bandali/my-cert.crt\")) |
| 2445 | |||
| 2446 | When present, ID should be an opaque object for identifying the | ||
| 2447 | connection unequivocally. (In most cases, this would be a string or a | ||
| 2448 | symbol composed of letters from the Latin alphabet.) This option is | ||
| 2449 | generally unneeded, however. See info node `(erc) Connecting' for use | ||
| 2450 | cases. Not available interactively." | ||
| 2397 | (interactive (let ((erc-default-port erc-default-port-tls)) | 2451 | (interactive (let ((erc-default-port erc-default-port-tls)) |
| 2398 | (erc-select-read-args))) | 2452 | (erc-select-read-args))) |
| 2399 | (let ((erc-server-connect-function 'erc-open-tls-stream)) | 2453 | (let ((erc-server-connect-function 'erc-open-tls-stream)) |
| 2400 | (erc-open server port nick full-name t password | 2454 | (erc-open server port nick full-name t password |
| 2401 | nil nil nil client-certificate user))) | 2455 | nil nil nil client-certificate user id))) |
| 2402 | 2456 | ||
| 2403 | (defun erc-open-tls-stream (name buffer host port &rest parameters) | 2457 | (defun erc-open-tls-stream (name buffer host port &rest parameters) |
| 2404 | "Open an TLS stream to an IRC server. | 2458 | "Open an TLS stream to an IRC server. |
| @@ -2463,13 +2517,20 @@ The buffer is created if it doesn't exist. | |||
| 2463 | 2517 | ||
| 2464 | If OUTBOUND is non-nil, STRING is being sent to the IRC server and | 2518 | If OUTBOUND is non-nil, STRING is being sent to the IRC server and |
| 2465 | appears in face `erc-input-face' in the buffer. Lines must already | 2519 | appears in face `erc-input-face' in the buffer. Lines must already |
| 2466 | contain CRLF endings. Peer is identified by the most precise label | 2520 | contain CRLF endings. A peer is identified by the most precise label |
| 2467 | available at run time, starting with the network name, followed by the | 2521 | available, starting with the session ID followed by the server-reported |
| 2468 | announced host name, and falling back to the dialed <server>:<port>." | 2522 | hostname, and falling back to the dialed <server>:<port> pair. |
| 2523 | |||
| 2524 | When capturing logs for multiple peers and sorting them into buckets, | ||
| 2525 | such inconsistent labeling may pose a problem until the MOTD is | ||
| 2526 | received. Setting a fixed `erc-networks--id' can serve as a | ||
| 2527 | workaround." | ||
| 2469 | (when erc-debug-irc-protocol | 2528 | (when erc-debug-irc-protocol |
| 2470 | (let ((esid (or (and (erc-network) (erc-network-name)) | 2529 | (let ((esid (if-let ((erc-networks--id) |
| 2471 | erc-server-announced-name | 2530 | (esid (erc-networks--id-symbol erc-networks--id))) |
| 2472 | (format "%s:%s" erc-session-server erc-session-port))) | 2531 | (symbol-name esid) |
| 2532 | (or erc-server-announced-name | ||
| 2533 | (format "%s:%s" erc-session-server erc-session-port)))) | ||
| 2473 | (ts (when erc-debug-irc-protocol-time-format | 2534 | (ts (when erc-debug-irc-protocol-time-format |
| 2474 | (format-time-string erc-debug-irc-protocol-time-format)))) | 2535 | (format-time-string erc-debug-irc-protocol-time-format)))) |
| 2475 | (with-current-buffer (get-buffer-create "*erc-protocol*") | 2536 | (with-current-buffer (get-buffer-create "*erc-protocol*") |
| @@ -3866,7 +3927,8 @@ the message given by REASON." | |||
| 3866 | (when process | 3927 | (when process |
| 3867 | (delete-process process)) | 3928 | (delete-process process)) |
| 3868 | (erc-server-reconnect) | 3929 | (erc-server-reconnect) |
| 3869 | (with-suppressed-warnings ((obsolete erc-server-reconnecting)) | 3930 | (with-suppressed-warnings ((obsolete erc-server-reconnecting) |
| 3931 | ((obsolete erc-reuse-buffers))) | ||
| 3870 | (if erc-reuse-buffers | 3932 | (if erc-reuse-buffers |
| 3871 | (progn (cl-assert (not erc--server-reconnecting)) | 3933 | (progn (cl-assert (not erc--server-reconnecting)) |
| 3872 | (cl-assert (not erc-server-reconnecting))) | 3934 | (cl-assert (not erc-server-reconnecting))) |
| @@ -6626,21 +6688,13 @@ This should be a string with substitution variables recognized by | |||
| 6626 | "Return the network or the current target and network combined. | 6688 | "Return the network or the current target and network combined. |
| 6627 | If the name of the network is not available, then use the | 6689 | If the name of the network is not available, then use the |
| 6628 | shortened server name instead." | 6690 | shortened server name instead." |
| 6629 | (let ((network-name (or (and (fboundp 'erc-network-name) (erc-network-name)) | 6691 | (if-let ((erc--target) |
| 6630 | (erc-shorten-server-name | 6692 | (name (if-let ((esid (erc-networks--id-symbol erc-networks--id))) |
| 6631 | (or erc-server-announced-name | 6693 | (symbol-name esid) |
| 6632 | erc-session-server))))) | 6694 | (erc-shorten-server-name (or erc-server-announced-name |
| 6633 | (when (and network-name (symbolp network-name)) | 6695 | erc-session-server))))) |
| 6634 | (setq network-name (symbol-name network-name))) | 6696 | (concat (erc--target-string erc--target) "@" name) |
| 6635 | (cond ((erc-default-target) | 6697 | (buffer-name))) |
| 6636 | (concat (erc-string-no-properties (erc-default-target)) | ||
| 6637 | "@" network-name)) | ||
| 6638 | ((and network-name | ||
| 6639 | (not (get-buffer network-name))) | ||
| 6640 | (when erc-rename-buffers | ||
| 6641 | (rename-buffer network-name)) | ||
| 6642 | network-name) | ||
| 6643 | (t (buffer-name (current-buffer)))))) | ||
| 6644 | 6698 | ||
| 6645 | (defun erc-format-away-status () | 6699 | (defun erc-format-away-status () |
| 6646 | "Return a formatted `erc-mode-line-away-status-format' if `erc-away' is non-nil." | 6700 | "Return a formatted `erc-mode-line-away-status-format' if `erc-away' is non-nil." |
| @@ -7060,20 +7114,29 @@ See also `format-spec'." | |||
| 7060 | ;; FIXME: Don't set the hook globally! | 7114 | ;; FIXME: Don't set the hook globally! |
| 7061 | (add-hook 'kill-buffer-hook #'erc-kill-buffer-function) | 7115 | (add-hook 'kill-buffer-hook #'erc-kill-buffer-function) |
| 7062 | 7116 | ||
| 7063 | (defcustom erc-kill-server-hook '(erc-kill-server) | 7117 | (defcustom erc-kill-server-hook '(erc-kill-server |
| 7064 | "Invoked whenever a server buffer is killed via `kill-buffer'." | 7118 | erc-networks-shrink-ids-and-buffer-names) |
| 7119 | "Invoked whenever a live server buffer is killed via `kill-buffer'." | ||
| 7120 | :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA | ||
| 7065 | :group 'erc-hooks | 7121 | :group 'erc-hooks |
| 7066 | :type 'hook) | 7122 | :type 'hook) |
| 7067 | 7123 | ||
| 7068 | (defcustom erc-kill-channel-hook '(erc-kill-channel) | 7124 | (defcustom erc-kill-channel-hook |
| 7125 | '(erc-kill-channel | ||
| 7126 | erc-networks-shrink-ids-and-buffer-names | ||
| 7127 | erc-networks-rename-surviving-target-buffer) | ||
| 7069 | "Invoked whenever a channel-buffer is killed via `kill-buffer'." | 7128 | "Invoked whenever a channel-buffer is killed via `kill-buffer'." |
| 7129 | :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA | ||
| 7070 | :group 'erc-hooks | 7130 | :group 'erc-hooks |
| 7071 | :type 'hook) | 7131 | :type 'hook) |
| 7072 | 7132 | ||
| 7073 | (defcustom erc-kill-buffer-hook nil | 7133 | (defcustom erc-kill-buffer-hook |
| 7074 | "Hook run whenever a non-server or channel buffer is killed. | 7134 | '(erc-networks-shrink-ids-and-buffer-names |
| 7135 | erc-networks-rename-surviving-target-buffer) | ||
| 7136 | "Hook run whenever a query buffer is killed. | ||
| 7075 | 7137 | ||
| 7076 | See also `kill-buffer'." | 7138 | See also `kill-buffer'." |
| 7139 | :package-version '(ERC . "5.4.1") ; FIXME increment upon publishing to ELPA | ||
| 7077 | :group 'erc-hooks | 7140 | :group 'erc-hooks |
| 7078 | :type 'hook) | 7141 | :type 'hook) |
| 7079 | 7142 | ||