erc-join.el 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. ;;; erc-join.el --- autojoin channels on connect and reconnects
  2. ;; Copyright (C) 2002-2004, 2006-2015 Free Software Foundation, Inc.
  3. ;; Author: Alex Schroeder <alex@gnu.org>
  4. ;; Maintainer: emacs-devel@gnu.org
  5. ;; Keywords: irc
  6. ;; URL: http://www.emacswiki.org/cgi-bin/wiki.pl?ErcAutoJoin
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; This allows us to customize an `erc-autojoin-channels-alist'. As
  20. ;; we /JOIN and /PART channels, this alist is updated to reflect our
  21. ;; current setup, so that when we reconnect, we rejoin the same
  22. ;; channels. The alist can be customized, so that the customized
  23. ;; value will be used when we reconnect in our next Emacs session.
  24. ;;; Code:
  25. (require 'erc)
  26. (require 'auth-source)
  27. (defgroup erc-autojoin nil
  28. "Enable autojoining."
  29. :group 'erc)
  30. ;;;###autoload (autoload 'erc-autojoin-mode "erc-join" nil t)
  31. (define-erc-module autojoin nil
  32. "Makes ERC autojoin on connects and reconnects."
  33. ((add-hook 'erc-after-connect 'erc-autojoin-channels)
  34. (add-hook 'erc-nickserv-identified-hook 'erc-autojoin-after-ident)
  35. (add-hook 'erc-server-JOIN-functions 'erc-autojoin-add)
  36. (add-hook 'erc-server-PART-functions 'erc-autojoin-remove))
  37. ((remove-hook 'erc-after-connect 'erc-autojoin-channels)
  38. (remove-hook 'erc-nickserv-identified-hook 'erc-autojoin-after-ident)
  39. (remove-hook 'erc-server-JOIN-functions 'erc-autojoin-add)
  40. (remove-hook 'erc-server-PART-functions 'erc-autojoin-remove)))
  41. (defcustom erc-autojoin-channels-alist nil
  42. "Alist of channels to autojoin on IRC networks.
  43. Every element in the alist has the form (SERVER . CHANNELS).
  44. SERVER is a regexp matching the server, and channels is the
  45. list of channels to join.
  46. If the channel(s) require channel keys for joining, the passwords
  47. are found via auth-source. For instance, if you use ~/.authinfo
  48. as your auth-source backend, then put something like the
  49. following in that file:
  50. machine irc.example.net login \"#fsf\" password sEcReT
  51. Customize this variable to set the value for your first connect.
  52. Once you are connected and join and part channels, this alist
  53. keeps track of what channels you are on, and will join them
  54. again when you get disconnected. When you restart Emacs, however,
  55. those changes are lost, and the customization you saved the last
  56. time is used again."
  57. :group 'erc-autojoin
  58. :type '(repeat (cons :tag "Server"
  59. (regexp :tag "Name")
  60. (repeat :tag "Channels"
  61. (string :tag "Name")))))
  62. (defcustom erc-autojoin-timing 'connect
  63. "When ERC should attempt to autojoin a channel.
  64. If the value is `connect', autojoin immediately on connecting.
  65. If the value is `ident', autojoin after successful NickServ
  66. identification, or after `erc-autojoin-delay' seconds.
  67. Any other value means the same as `connect'."
  68. :group 'erc-autojoin
  69. :version "24.1"
  70. :type '(choice (const :tag "On Connection" connect)
  71. (const :tag "When Identified" ident)))
  72. (defcustom erc-autojoin-delay 30
  73. "Number of seconds to wait before attempting to autojoin channels.
  74. This only takes effect if `erc-autojoin-timing' is `ident'.
  75. If NickServ identification occurs before this delay expires, ERC
  76. autojoins immediately at that time."
  77. :group 'erc-autojoin
  78. :version "24.1"
  79. :type 'integer)
  80. (defcustom erc-autojoin-domain-only t
  81. "Truncate host name to the domain name when joining a server.
  82. If non-nil, and a channel on the server a.b.c is joined, then
  83. only b.c is used as the server for `erc-autojoin-channels-alist'.
  84. This is important for networks that redirect you to other
  85. servers, presumably in the same domain."
  86. :group 'erc-autojoin
  87. :type 'boolean)
  88. (defvar erc--autojoin-timer nil)
  89. (make-variable-buffer-local 'erc--autojoin-timer)
  90. (defun erc-autojoin-channels-delayed (server nick buffer)
  91. "Attempt to autojoin channels.
  92. This is called from a timer set up by `erc-autojoin-channels'."
  93. (if erc--autojoin-timer
  94. (setq erc--autojoin-timer
  95. (erc-cancel-timer erc--autojoin-timer)))
  96. (with-current-buffer buffer
  97. ;; Don't kick of another delayed autojoin or try to wait for
  98. ;; another ident response:
  99. (let ((erc-autojoin-delay -1)
  100. (erc-autojoin-timing 'connect))
  101. (erc-log "Delayed autojoin started (no ident success detected yet)")
  102. (erc-autojoin-channels server nick))))
  103. (defun erc-autojoin-after-ident (network nick)
  104. "Autojoin channels in `erc-autojoin-channels-alist'.
  105. This function is run from `erc-nickserv-identified-hook'."
  106. (if erc--autojoin-timer
  107. (setq erc--autojoin-timer
  108. (erc-cancel-timer erc--autojoin-timer)))
  109. (when (eq erc-autojoin-timing 'ident)
  110. (let ((server (or erc-server-announced-name erc-session-server))
  111. (joined (mapcar (lambda (buf)
  112. (with-current-buffer buf (erc-default-target)))
  113. (erc-channel-list erc-server-process))))
  114. ;; We may already be in these channels, e.g. because the
  115. ;; autojoin timer went off.
  116. (dolist (l erc-autojoin-channels-alist)
  117. (when (string-match (car l) server)
  118. (dolist (chan (cdr l))
  119. (unless (erc-member-ignore-case chan joined)
  120. (erc-server-join-channel server chan)))))))
  121. nil)
  122. (defun erc-autojoin-channels (server nick)
  123. "Autojoin channels in `erc-autojoin-channels-alist'."
  124. (if (eq erc-autojoin-timing 'ident)
  125. ;; Prepare the delayed autojoin timer, in case ident doesn't
  126. ;; happen within the allotted time limit:
  127. (when (> erc-autojoin-delay 0)
  128. (setq erc--autojoin-timer
  129. (run-with-timer erc-autojoin-delay nil
  130. 'erc-autojoin-channels-delayed
  131. server nick (current-buffer))))
  132. ;; `erc-autojoin-timing' is `connect':
  133. (dolist (l erc-autojoin-channels-alist)
  134. (when (string-match (car l) server)
  135. (dolist (chan (cdr l))
  136. (erc-server-join-channel server chan)))))
  137. ;; Return nil to avoid stomping on any other hook funcs.
  138. nil)
  139. (defun erc-server-join-channel (server channel)
  140. (let* ((secret (plist-get (nth 0 (auth-source-search
  141. :max 1
  142. :host server
  143. :port "irc"
  144. :user channel))
  145. :secret))
  146. (password (if (functionp secret)
  147. (funcall secret)
  148. secret)))
  149. (erc-server-send (concat "join " channel
  150. (if password
  151. (concat " " password)
  152. "")))))
  153. (defun erc-autojoin-add (proc parsed)
  154. "Add the channel being joined to `erc-autojoin-channels-alist'."
  155. (let* ((chnl (erc-response.contents parsed))
  156. (nick (car (erc-parse-user (erc-response.sender parsed))))
  157. (server (with-current-buffer (process-buffer proc)
  158. (or erc-server-announced-name erc-session-server))))
  159. (when (erc-current-nick-p nick)
  160. (when (and erc-autojoin-domain-only
  161. (string-match "[^.\n]+\\.\\([^.\n]+\\.[^.\n]+\\)$" server))
  162. (setq server (match-string 1 server)))
  163. (let ((elem (assoc server erc-autojoin-channels-alist)))
  164. (if elem
  165. (unless (member chnl (cdr elem))
  166. (setcdr elem (cons chnl (cdr elem))))
  167. (setq erc-autojoin-channels-alist
  168. (cons (list server chnl)
  169. erc-autojoin-channels-alist))))))
  170. ;; We must return nil to tell ERC to continue running the other
  171. ;; functions.
  172. nil)
  173. ;; (erc-parse-user "kensanata!~user@dclient217-162-233-228.hispeed.ch")
  174. (defun erc-autojoin-remove (proc parsed)
  175. "Remove the channel being left from `erc-autojoin-channels-alist'."
  176. (let* ((chnl (car (erc-response.command-args parsed)))
  177. (nick (car (erc-parse-user (erc-response.sender parsed))))
  178. (server (with-current-buffer (process-buffer proc)
  179. (or erc-server-announced-name erc-session-server))))
  180. (when (erc-current-nick-p nick)
  181. (when (and erc-autojoin-domain-only
  182. (string-match "[^.\n]+\\.\\([^.\n]+\\.[^.\n]+\\)$" server))
  183. (setq server (match-string 1 server)))
  184. (let ((elem (assoc server erc-autojoin-channels-alist)))
  185. (when elem
  186. (setcdr elem (delete chnl (cdr elem)))
  187. (unless (cdr elem)
  188. (setq erc-autojoin-channels-alist
  189. (delete elem erc-autojoin-channels-alist)))))))
  190. ;; We must return nil to tell ERC to continue running the other
  191. ;; functions.
  192. nil)
  193. (provide 'erc-join)
  194. ;;; erc-join.el ends here
  195. ;;
  196. ;; Local Variables:
  197. ;; indent-tabs-mode: t
  198. ;; tab-width: 8
  199. ;; End: