* lisp/net/rcirc.el (rcirc-markup-urls): Check if rcirc-url-regexp is nil.
[bpt/emacs.git] / lisp / net / rcirc.el
index 41e0954..0d02688 100644 (file)
@@ -4,7 +4,7 @@
 
 ;; Author: Ryan Yeske <rcyeske@gmail.com>
 ;; Maintainers: Ryan Yeske <rcyeske@gmail.com>,
-;;              Deniz Dogan <deniz.a.m.dogan@gmail.com>
+;;              Deniz Dogan <deniz@dogan.se>
 ;; Keywords: comm
 
 ;; This file is part of GNU Emacs.
   :group 'applications)
 
 (defcustom rcirc-server-alist
-  '(("irc.freenode.net" :channels ("#rcirc")))
+  '(("irc.freenode.net" :channels ("#rcirc")
+     ;; Don't use the TLS port by default, in case gnutls is not available.
+     ;; :port 7000 :encryption tls
+     ))
   "An alist of IRC connections to establish when running `rcirc'.
 Each element looks like (SERVER-NAME PARAMETERS).
 
@@ -95,14 +98,22 @@ used.
 
 VALUE must be a list of strings describing which channels to join
 when connecting to this server.  If absent, no channels will be
-connected to automatically."
+connected to automatically.
+
+`:encryption'
+
+VALUE must be `plain' (the default) for unencrypted connections, or `tls'
+for connections using SSL/TLS."
   :type '(alist :key-type string
-               :value-type (plist :options ((:nick string)
-                                            (:port integer)
-                                            (:user-name string)
-                                            (:password string)
-                                            (:full-name string)
-                                            (:channels (repeat string)))))
+               :value-type (plist :options
+                                   ((:nick string)
+                                    (:port integer)
+                                    (:user-name string)
+                                    (:password string)
+                                    (:full-name string)
+                                    (:channels (repeat string))
+                                    (:encryption (choice (const tls)
+                                                         (const plain))))))
   :group 'rcirc)
 
 (defcustom rcirc-default-port 6667
@@ -441,10 +452,14 @@ If ARG is non-nil, instead prompt for connection parameters."
                                                (plist-get server-plist
                                                           :channels)
                                                " "))
-                       "[, ]+" t)))
+                       "[, ]+" t))
+             (encryption
+              (intern (completing-read "Encryption (default plain): "
+                                       '("plain" "tls")
+                                       nil t nil nil "plain"))))
        (rcirc-connect server port nick user-name
                       rcirc-default-full-name
-                      channels password))
+                      channels password encryption))
     ;; connect to servers in `rcirc-server-alist'
     (let (connected-servers)
       (dolist (c rcirc-server-alist)
@@ -456,7 +471,8 @@ If ARG is non-nil, instead prompt for connection parameters."
              (full-name (or (plist-get (cdr c) :full-name)
                             rcirc-default-full-name))
              (channels (plist-get (cdr c) :channels))
-              (password (plist-get (cdr c) :password)))
+              (password (plist-get (cdr c) :password))
+              (encryption (plist-get (cdr c) :encryption)))
          (when server
            (let (connected)
              (dolist (p (rcirc-process-list))
@@ -465,7 +481,7 @@ If ARG is non-nil, instead prompt for connection parameters."
              (if (not connected)
                  (condition-case e
                      (rcirc-connect server port nick user-name
-                                    full-name channels password)
+                                    full-name channels password encryption)
                    (quit (message "Quit connecting to %s" server)))
                (with-current-buffer (process-buffer connected)
                  (setq connected-servers
@@ -491,13 +507,14 @@ If ARG is non-nil, instead prompt for connection parameters."
 (defvar rcirc-server nil)              ; server provided by server
 (defvar rcirc-server-name nil)         ; server name given by 001 response
 (defvar rcirc-timeout-timer nil)
+(defvar rcirc-user-authenticated nil)
 (defvar rcirc-user-disconnect nil)
 (defvar rcirc-connecting nil)
 (defvar rcirc-process nil)
 
 ;;;###autoload
 (defun rcirc-connect (server &optional port nick user-name
-                             full-name startup-channels password)
+                             full-name startup-channels password encryption)
   (save-excursion
     (message "Connecting to %s..." server)
     (let* ((inhibit-eol-conversion)
@@ -510,7 +527,9 @@ If ARG is non-nil, instead prompt for connection parameters."
           (user-name (or user-name rcirc-default-user-name))
           (full-name (or full-name rcirc-default-full-name))
           (startup-channels startup-channels)
-           (process (make-network-process :name server :host server :service port-number)))
+           (process (open-network-stream
+                     server nil server port-number
+                     :type (or encryption 'plain))))
       ;; set up process
       (set-process-coding-system process 'raw-text 'raw-text)
       (switch-to-buffer (rcirc-generate-new-buffer-name process nil))
@@ -518,32 +537,23 @@ If ARG is non-nil, instead prompt for connection parameters."
       (rcirc-mode process nil)
       (set-process-sentinel process 'rcirc-sentinel)
       (set-process-filter process 'rcirc-filter)
-      (make-local-variable 'rcirc-process)
-      (setq rcirc-process process)
-      (make-local-variable 'rcirc-server)
-      (setq rcirc-server server)
-      (make-local-variable 'rcirc-server-name)
-      (setq rcirc-server-name server)  ; update when we get 001 response
-      (make-local-variable 'rcirc-buffer-alist)
-      (setq rcirc-buffer-alist nil)
-      (make-local-variable 'rcirc-nick-table)
-      (setq rcirc-nick-table (make-hash-table :test 'equal))
-      (make-local-variable 'rcirc-nick)
-      (setq rcirc-nick nick)
-      (make-local-variable 'rcirc-process-output)
-      (setq rcirc-process-output nil)
-      (make-local-variable 'rcirc-startup-channels)
-      (setq rcirc-startup-channels startup-channels)
-      (make-local-variable 'rcirc-last-server-message-time)
-      (setq rcirc-last-server-message-time (current-time))
-      (make-local-variable 'rcirc-timeout-timer)
-      (setq rcirc-timeout-timer nil)
-      (make-local-variable 'rcirc-user-disconnect)
-      (setq rcirc-user-disconnect nil)
-      (make-local-variable 'rcirc-user-authenticated)
-      (setq rcirc-user-authenticated nil)
-      (make-local-variable 'rcirc-connecting)
-      (setq rcirc-connecting t)
+
+      (set (make-local-variable 'rcirc-process) process)
+      (set (make-local-variable 'rcirc-server) server)
+      (set (make-local-variable 'rcirc-server-name) server) ; Update when we get 001 response.
+      (set (make-local-variable 'rcirc-buffer-alist) nil)
+      (set (make-local-variable 'rcirc-nick-table)
+           (make-hash-table :test 'equal))
+      (set (make-local-variable 'rcirc-nick) nick)
+      (set (make-local-variable 'rcirc-process-output) nil)
+      (set (make-local-variable 'rcirc-startup-channels) startup-channels)
+      (set (make-local-variable 'rcirc-last-server-message-time)
+           (current-time))
+
+      (set (make-local-variable 'rcirc-timeout-timer) nil)
+      (set (make-local-variable 'rcirc-user-disconnect) nil)
+      (set (make-local-variable 'rcirc-user-authenticated) nil)
+      (set (make-local-variable 'rcirc-connecting) t)
 
       (add-hook 'auto-save-hook 'rcirc-log-write)
 
@@ -721,11 +731,14 @@ Function is called with PROCESS, COMMAND, SENDER, ARGS and LINE.")
                (mapconcat 'identity (cdr args) " ")
               (not (member response rcirc-responses-no-activity))))
 
+(defun rcirc--connection-open-p (process)
+  (memq (process-status process) '(run open)))
+
 (defun rcirc-send-string (process string)
   "Send PROCESS a STRING plus a newline."
   (let ((string (concat (encode-coding-string string rcirc-encode-coding-system)
                         "\n")))
-    (unless (eq (process-status process) 'open)
+    (unless (rcirc--connection-open-p process)
       (error "Network connection to %s is not open"
              (process-name process)))
     (rcirc-debug process string)
@@ -828,18 +841,21 @@ The list is updated automatically by `defun-rcirc-command'.")
 
 (defun rcirc-completion-at-point ()
   "Function used for `completion-at-point-functions' in `rcirc-mode'."
-  (let* ((beg (save-excursion
-               (if (re-search-backward " " rcirc-prompt-end-marker t)
-                   (1+ (point))
-                 rcirc-prompt-end-marker)))
-        (table (if (and (= beg rcirc-prompt-end-marker)
-                        (eq (char-after beg) ?/))
-                   (delete-dups
-                    (nconc
-                     (sort (copy-sequence rcirc-client-commands) 'string-lessp)
-                     (sort (copy-sequence rcirc-server-commands) 'string-lessp)))
-                 (rcirc-channel-nicks (rcirc-buffer-process) rcirc-target))))
-    (list beg (point) table)))
+  (and (rcirc-looking-at-input)
+       (let* ((beg (save-excursion
+                    (if (re-search-backward " " rcirc-prompt-end-marker t)
+                        (1+ (point))
+                      rcirc-prompt-end-marker)))
+             (table (if (and (= beg rcirc-prompt-end-marker)
+                             (eq (char-after beg) ?/))
+                        (delete-dups
+                         (nconc (sort (copy-sequence rcirc-client-commands)
+                                      'string-lessp)
+                                (sort (copy-sequence rcirc-server-commands)
+                                      'string-lessp)))
+                      (rcirc-channel-nicks (rcirc-buffer-process)
+                                           rcirc-target))))
+        (list beg (point) table))))
 
 (defvar rcirc-completions nil)
 (defvar rcirc-completion-start nil)
@@ -848,6 +864,8 @@ The list is updated automatically by `defun-rcirc-command'.")
   "Cycle through completions from list of nicks in channel or IRC commands.
 IRC command completion is performed only if '/' is the first input char."
   (interactive)
+  (unless (rcirc-looking-at-input)
+    (error "Point not located after rcirc prompt"))
   (if (eq last-command this-command)
       (setq rcirc-completions
            (append (cdr rcirc-completions) (list (car rcirc-completions))))
@@ -855,9 +873,10 @@ IRC command completion is performed only if '/' is the first input char."
          (table (rcirc-completion-at-point)))
       (setq rcirc-completion-start (car table))
       (setq rcirc-completions
-           (all-completions (buffer-substring rcirc-completion-start
-                                              (cadr table))
-                            (nth 2 table)))))
+           (and rcirc-completion-start
+                (all-completions (buffer-substring rcirc-completion-start
+                                                   (cadr table))
+                                 (nth 2 table))))))
   (let ((completion (car rcirc-completions)))
     (when completion
       (delete-region rcirc-completion-start (point))
@@ -871,12 +890,12 @@ IRC command completion is performed only if '/' is the first input char."
 (defun set-rcirc-decode-coding-system (coding-system)
   "Set the decode coding system used in this channel."
   (interactive "zCoding system for incoming messages: ")
-  (setq rcirc-decode-coding-system coding-system))
+  (set (make-local-variable 'rcirc-decode-coding-system) coding-system))
 
 (defun set-rcirc-encode-coding-system (coding-system)
   "Set the encode coding system used in this channel."
   (interactive "zCoding system for outgoing messages: ")
-  (setq rcirc-encode-coding-system coding-system))
+  (set (make-local-variable 'rcirc-encode-coding-system) coding-system))
 
 (defvar rcirc-mode-map
   (let ((map (make-sparse-keymap)))
@@ -893,7 +912,6 @@ IRC command completion is performed only if '/' is the first input char."
     (define-key map (kbd "C-c C-m") 'rcirc-cmd-msg)
     (define-key map (kbd "C-c C-r") 'rcirc-cmd-nick) ; rename
     (define-key map (kbd "C-c C-o") 'rcirc-omit-mode)
-    (define-key map (kbd "M-o") 'rcirc-omit-mode)
     (define-key map (kbd "C-c C-p") 'rcirc-cmd-part)
     (define-key map (kbd "C-c C-q") 'rcirc-cmd-query)
     (define-key map (kbd "C-c C-t") 'rcirc-cmd-topic)
@@ -942,27 +960,18 @@ This number is independent of the number of lines in the buffer.")
   (setq major-mode 'rcirc-mode)
   (setq mode-line-process nil)
 
-  (make-local-variable 'rcirc-input-ring)
-  (setq rcirc-input-ring (make-ring rcirc-input-ring-size))
-  (make-local-variable 'rcirc-server-buffer)
-  (setq rcirc-server-buffer (process-buffer process))
-  (make-local-variable 'rcirc-target)
-  (setq rcirc-target target)
-  (make-local-variable 'rcirc-topic)
-  (setq rcirc-topic nil)
-  (make-local-variable 'rcirc-last-post-time)
-  (setq rcirc-last-post-time (current-time))
-  (make-local-variable 'fill-paragraph-function)
-  (setq fill-paragraph-function 'rcirc-fill-paragraph)
-  (make-local-variable 'rcirc-recent-quit-alist)
-  (setq rcirc-recent-quit-alist nil)
-  (make-local-variable 'rcirc-current-line)
-  (setq rcirc-current-line 0)
-
-  (make-local-variable 'rcirc-short-buffer-name)
-  (setq rcirc-short-buffer-name nil)
-  (make-local-variable 'rcirc-urls)
-  (setq use-hard-newlines t)
+  (set (make-local-variable 'rcirc-input-ring)
+       (make-ring rcirc-input-ring-size))
+  (set (make-local-variable 'rcirc-server-buffer) (process-buffer process))
+  (set (make-local-variable 'rcirc-target) target)
+  (set (make-local-variable 'rcirc-topic) nil)
+  (set (make-local-variable 'rcirc-last-post-time) (current-time))
+  (set (make-local-variable 'fill-paragraph-function) 'rcirc-fill-paragraph)
+  (set (make-local-variable 'rcirc-recent-quit-alist) nil)
+  (set (make-local-variable 'rcirc-current-line) 0)
+
+  (set (make-local-variable 'rcirc-short-buffer-name) nil)
+  (set (make-local-variable 'rcirc-urls) nil)
 
   ;; setup for omitting responses
   (setq buffer-invisibility-spec '())
@@ -972,28 +981,23 @@ This number is independent of the number of lines in the buffer.")
                                        ?. 'font-lock-keyword-face)))
                            (make-vector 3 glyph)))
 
-  (make-local-variable 'rcirc-decode-coding-system)
-  (make-local-variable 'rcirc-encode-coding-system)
   (dolist (i rcirc-coding-system-alist)
     (let ((chan (if (consp (car i)) (caar i) (car i)))
          (serv (if (consp (car i)) (cdar i) "")))
       (when (and (string-match chan (or target ""))
                 (string-match serv (rcirc-server-name process)))
-       (setq rcirc-decode-coding-system (if (consp (cdr i)) (cadr i) (cdr i))
-             rcirc-encode-coding-system (if (consp (cdr i)) (cddr i) (cdr i))))))
+       (set (make-local-variable 'rcirc-decode-coding-system)
+             (if (consp (cdr i)) (cadr i) (cdr i)))
+        (set (make-local-variable 'rcirc-encode-coding-system)
+             (if (consp (cdr i)) (cddr i) (cdr i))))))
 
   ;; setup the prompt and markers
-  (make-local-variable 'rcirc-prompt-start-marker)
-  (setq rcirc-prompt-start-marker (make-marker))
-  (set-marker rcirc-prompt-start-marker (point-max))
-  (make-local-variable 'rcirc-prompt-end-marker)
-  (setq rcirc-prompt-end-marker (make-marker))
-  (set-marker rcirc-prompt-end-marker (point-max))
+  (set (make-local-variable 'rcirc-prompt-start-marker) (point-max-marker))
+  (set (make-local-variable 'rcirc-prompt-end-marker) (point-max-marker))
   (rcirc-update-prompt)
   (goto-char rcirc-prompt-end-marker)
-  (make-local-variable 'overlay-arrow-position)
-  (setq overlay-arrow-position (make-marker))
-  (set-marker overlay-arrow-position nil)
+
+  (set (make-local-variable 'overlay-arrow-position) (make-marker))
 
   ;; if the user changes the major mode or kills the buffer, there is
   ;; cleanup work to do
@@ -1089,7 +1093,7 @@ Logfiles are kept in `rcirc-log-directory'."
   (let ((buffer (current-buffer)))
     (rcirc-clear-activity buffer)
     (when (and (rcirc-buffer-process)
-              (eq (process-status (rcirc-buffer-process)) 'open))
+              (rcirc--connection-open-p (rcirc-buffer-process)))
       (with-rcirc-server-buffer
        (setq rcirc-buffer-alist
             (rassq-delete-all buffer rcirc-buffer-alist)))
@@ -1216,6 +1220,8 @@ Create the buffer if it doesn't exist."
                             (concat command " :" args)))))))
 
 (defvar rcirc-parent-buffer nil)
+(make-variable-buffer-local 'rcirc-parent-buffer)
+(put 'rcirc-parent-buffer 'permanent-local t)
 (defvar rcirc-window-configuration nil)
 (defun rcirc-edit-multiline ()
   "Move current edit to a dedicated buffer."
@@ -1251,8 +1257,6 @@ Create the buffer if it doesn't exist."
   :keymap rcirc-multiline-minor-mode-map
   :global nil
   :group 'rcirc
-  (make-local-variable 'rcirc-parent-buffer)
-  (put 'rcirc-parent-buffer 'permanent-local t)
   (setq fill-column rcirc-max-message-length))
 
 (defun rcirc-multiline-minor-submit ()
@@ -1836,6 +1840,8 @@ Uninteresting lines are those whose responses are listed in
 (defun rcirc-switch-to-server-buffer ()
   "Switch to the server buffer associated with current channel buffer."
   (interactive)
+  (unless (buffer-live-p rcirc-server-buffer)
+    (error "No such buffer"))
   (switch-to-buffer rcirc-server-buffer))
 
 (defun rcirc-jump-to-first-unread-line ()
@@ -2388,7 +2394,8 @@ keywords when no KEYWORD is given."
        (rcirc-record-activity (current-buffer) 'nick)))))
 
 (defun rcirc-markup-urls (sender response)
-  (while (re-search-forward rcirc-url-regexp nil t)
+  (while (and rcirc-url-regexp ;; nil means disable URL catching
+              (re-search-forward rcirc-url-regexp nil t))
     (let ((start (match-beginning 0))
          (end (match-end 0)))
       (rcirc-add-face start end 'rcirc-url)
@@ -2447,10 +2454,17 @@ keywords when no KEYWORD is given."
     (setq rcirc-nick (car args))
     (rcirc-update-prompt)
     (if rcirc-auto-authenticate-flag
-        (if rcirc-authenticate-before-join
+        (if (and rcirc-authenticate-before-join
+                ;; We have to ensure that there's an authentication
+                ;; entry for that server.  Else,
+                ;; rcirc-authenticated-hook won't be triggered, and
+                ;; autojoin won't happen at all.
+                (let (auth-required)
+                  (dolist (s rcirc-authinfo auth-required)
+                    (when (string-match (car s) rcirc-server-name)
+                      (setq auth-required t)))))
             (progn
-              (with-rcirc-process-buffer process
-                (add-hook 'rcirc-authenticated-hook 'rcirc-join-channels-post-auth t t))
+             (add-hook 'rcirc-authenticated-hook 'rcirc-join-channels-post-auth t t)
               (rcirc-authenticate))
           (rcirc-authenticate)
           (rcirc-join-channels process rcirc-startup-channels))
@@ -2515,7 +2529,7 @@ the only argument."
                (and ;; quakenet
                 (string= sender "Q")
                 (string= target rcirc-nick)
-                (string-match message "\\`You are now logged in as .+\\.\\'")))
+                (string-match "\\`You are now logged in as .+\\.\\'" message)))
           (setq rcirc-user-authenticated t)
           (run-hook-with-args 'rcirc-authenticated-hook process)
           (remove-hook 'rcirc-authenticated-hook 'rcirc-join-channels-post-auth t))))))
@@ -2728,10 +2742,13 @@ the only argument."
 
 (defun rcirc-handler-353 (process sender args text)
   "RPL_NAMREPLY"
-  (let ((channel (caddr args)))
+  (let ((channel (nth 2 args))
+       (names (or (nth 3 args) "")))
     (mapc (lambda (nick)
             (rcirc-put-nick-channel process nick channel))
-          (split-string (cadddr args) " " t))
+          (split-string names " " t))
+    ;; create a temporary buffer to insert the names into
+    ;; rcirc-handler-366 (RPL_ENDOFNAMES) will handle it
     (with-current-buffer (rcirc-get-temp-buffer-create process channel)
       (goto-char (point-max))
       (insert (car (last args)) " "))))