* etc/publicsuffix.txt: Update from source.
[bpt/emacs.git] / lisp / org / org-irc.el
CommitLineData
0fc0f178 1;;; org-irc.el --- Store links to IRC sessions
20908596 2;;
ba318903 3;; Copyright (C) 2008-2014 Free Software Foundation, Inc.
20908596 4;;
0fc0f178
CD
5;; Author: Philip Jackson <emacs@shellarchive.co.uk>
6;; Keywords: erc, irc, link, org
20908596 7;;
0fc0f178 8;; This file is part of GNU Emacs.
20908596 9;;
b1fc2b50 10;; GNU Emacs is free software: you can redistribute it and/or modify
0fc0f178 11;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
0fc0f178
CD
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
33306645 17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0fc0f178
CD
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
b1fc2b50 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
c1fbdbbb 22
0fc0f178 23;;; Commentary:
c1fbdbbb 24
20908596
CD
25;; This file implements links to an IRC session from within Org-mode.
26;; Org-mode loads this module by default - if this is not what you want,
27;; configure the variable `org-modules'.
0fc0f178 28;;
ce4fdcb9 29;; Please customize the variable `org-modules' to select
20908596
CD
30;; extensions you would like to use, and to deselect those which you don't
31;; want.
0fc0f178 32;;
20908596
CD
33;; Please note that at the moment only ERC is supported. Other clients
34;; shouldn't be difficult to add though.
0fc0f178
CD
35;;
36;; Then set `org-irc-link-to-logs' to non-nil if you would like a
37;; file:/ type link to be created to the current line in the logs or
38;; to t if you would like to create an irc:/ style link.
39;;
40;; Links within an org buffer might look like this:
41;;
42;; [[irc:/irc.freenode.net/#emacs/bob][chat with bob in #emacs on freenode]]
43;; [[irc:/irc.freenode.net/#emacs][#emacs on freenode]]
44;; [[irc:/irc.freenode.net/]]
45;;
46;; If, when the resulting link is visited, there is no connection to a
47;; requested server then one will be created.
0fc0f178 48
c1fbdbbb 49;;; Code:
0fc0f178
CD
50
51(require 'org)
20908596 52
33306645 53;; Declare the function form ERC that we use.
20908596
CD
54(declare-function erc-current-logfile "erc-log" (&optional buffer))
55(declare-function erc-prompt "erc" ())
56(declare-function erc-default-target "erc" ())
57(declare-function erc-channel-p "erc" (channel))
58(declare-function erc-buffer-filter "erc" (predicate &optional proc))
59(declare-function erc-server-buffer "erc" ())
60(declare-function erc-get-server-nickname-list "erc" ())
61(declare-function erc-cmd-JOIN "erc" (channel &optional key))
14e1337f 62(declare-function org-pop-to-buffer-same-window
e66ba1df 63 "org-compat" (&optional buffer-or-name norecord label))
0fc0f178
CD
64
65(defvar org-irc-client 'erc
20908596 66 "The IRC client to act on.")
0fc0f178 67(defvar org-irc-link-to-logs nil
20908596 68 "Non-nil will store a link to the logs, nil will store an irc: style link.")
0fc0f178 69
20908596
CD
70(defvar erc-default-port) ; dynamically scoped from erc.el
71(defvar erc-session-port) ; dynamically scoped form erc-backend.el
72(defvar erc-session-server) ; dynamically scoped form erc-backend.el
0fc0f178
CD
73
74;; Generic functions/config (extend these for other clients)
75
20908596 76(add-to-list 'org-store-link-functions 'org-irc-store-link)
0fc0f178
CD
77
78(org-add-link-type "irc" 'org-irc-visit nil)
79
80(defun org-irc-visit (link)
20908596 81 "Parse LINK and dispatch to the correct function based on the client found."
0fc0f178
CD
82 (let ((link (org-irc-parse-link link)))
83 (cond
8223b1d2
BG
84 ((eq org-irc-client 'erc)
85 (org-irc-visit-erc link))
86 (t
87 (error "ERC only known client")))))
0fc0f178
CD
88
89(defun org-irc-parse-link (link)
20908596
CD
90 "Parse an IRC LINK and return the attributes found.
91Parse a LINK that looks like server:port/chan/user (port, chan
e8cb0ef8 92and user being optional) and return any of the port, channel or user
20908596 93attributes that are found."
0fc0f178 94 (let* ((parts (split-string link "/" t))
33306645 95 (len (length parts)))
0fc0f178 96 (when (or (< len 1) (> len 3))
20908596 97 (error "Failed to parse link needed 1-3 parts, got %d" len))
0fc0f178
CD
98 (setcar parts (split-string (car parts) ":" t))
99 parts))
100
101;;;###autoload
102(defun org-irc-store-link ()
20908596 103 "Dispatch to the appropriate function to store a link to an IRC session."
0fc0f178 104 (cond
8223b1d2
BG
105 ((eq major-mode 'erc-mode)
106 (org-irc-erc-store-link))))
0fc0f178 107
136b74c5 108(defun org-irc-ellipsify-description (string &optional after)
20908596
CD
109 "Remove unnecessary white space from STRING and add ellipses if necessary.
110Strip starting and ending white space from STRING and replace any
111chars that the value AFTER with '...'"
0fc0f178 112 (let* ((after (number-to-string (or after 30)))
33306645
CD
113 (replace-map (list (cons "^[ \t]*" "")
114 (cons "[ \t]*$" "")
115 (cons (concat "^\\(.\\{" after
116 "\\}\\).*") "\\1..."))))
0fc0f178 117 (mapc (lambda (x)
33306645
CD
118 (when (string-match (car x) string)
119 (setq string (replace-match (cdr x) nil nil string))))
120 replace-map)
0fc0f178
CD
121 string))
122
123;; ERC specific functions
124
125(defun org-irc-erc-get-line-from-log (erc-line)
20908596
CD
126 "Find the best line to link to from the ERC logs given ERC-LINE as a start.
127If the user is on the ERC-prompt then search backward for the
128first non-blank line, otherwise return the current line. The
129result is a cons of the filename and search string."
0fc0f178 130 (erc-save-buffer-in-logs)
20908596 131 (require 'erc-log)
0fc0f178
CD
132 (with-current-buffer (find-file-noselect (erc-current-logfile))
133 (goto-char (point-max))
134 (list
135 (abbreviate-file-name buffer-file-name)
136 ;; can we get a '::' part?
137 (if (string= erc-line (erc-prompt))
33306645
CD
138 (progn
139 (goto-char (point-at-bol))
140 (when (search-backward-regexp "^[^ ]" nil t)
141 (buffer-substring-no-properties (point-at-bol)
142 (point-at-eol))))
8223b1d2
BG
143 (when (search-backward erc-line nil t)
144 (buffer-substring-no-properties (point-at-bol)
145 (point-at-eol)))))))
0fc0f178
CD
146
147(defun org-irc-erc-store-link ()
20908596
CD
148 "Store a link to the IRC log file or the session itself.
149Depending on the variable `org-irc-link-to-logs' store either a
150link to the log file for the current session or an irc: link to
0fc0f178 151the session itself."
20908596 152 (require 'erc-log)
0fc0f178
CD
153 (if org-irc-link-to-logs
154 (let* ((erc-line (buffer-substring-no-properties
33306645
CD
155 (point-at-bol) (point-at-eol)))
156 (parsed-line (org-irc-erc-get-line-from-log erc-line)))
157 (if (erc-logging-enabled nil)
158 (progn
159 (org-store-link-props
160 :type "file"
136b74c5 161 :description (concat "'" (org-irc-ellipsify-description
33306645
CD
162 (cadr parsed-line) 20)
163 "' from an IRC conversation")
164 :link (concat "file:" (car parsed-line) "::"
165 (cadr parsed-line)))
166 t)
8223b1d2
BG
167 (error "This ERC session is not being logged")))
168 (let* ((link-text (org-irc-get-erc-link))
169 (link (org-irc-parse-link link-text)))
170 (if link-text
171 (progn
172 (org-store-link-props
173 :type "irc"
174 :link (concat "irc:/" link-text)
175 :description (concat "irc session '" link-text "'")
176 :server (car (car link))
177 :port (or (string-to-number (cadr (pop link))) erc-default-port)
178 :nick (pop link))
179 t)
180 (error "Failed to create ('irc:/' style) ERC link")))))
0fc0f178
CD
181
182(defun org-irc-get-erc-link ()
20908596
CD
183 "Return an org compatible irc:/ link from an ERC buffer."
184 (let* ((session-port (if (numberp erc-session-port)
33306645 185 (number-to-string erc-session-port)
8223b1d2
BG
186 erc-session-port))
187 (link (concat erc-session-server ":" session-port)))
0fc0f178 188 (concat link "/"
33306645
CD
189 (if (and (erc-default-target)
190 (erc-channel-p (erc-default-target))
191 (car (get-text-property (point) 'erc-data)))
192 ;; we can get a nick
193 (let ((nick (car (get-text-property (point) 'erc-data))))
194 (concat (erc-default-target) "/" nick))
8223b1d2 195 (erc-default-target)))))
0fc0f178 196
20908596
CD
197(defun org-irc-get-current-erc-port ()
198 "Return the current port as a number.
199Return the current port number or, if none is set, return the ERC
200default."
201 (cond
8223b1d2
BG
202 ((stringp erc-session-port)
203 (string-to-number erc-session-port))
204 ((numberp erc-session-port)
205 erc-session-port)
206 (t
207 erc-default-port)))
20908596 208
0fc0f178 209(defun org-irc-visit-erc (link)
20908596
CD
210 "Visit an ERC buffer based on criteria found in LINK."
211 (require 'erc)
212 (require 'erc-log)
0fc0f178 213 (let* ((server (car (car link)))
33306645
CD
214 (port (or (string-to-number (cadr (pop link))) erc-default-port))
215 (server-buffer)
216 (buffer-list
217 (erc-buffer-filter
218 (lambda nil
219 (let ((tmp-server-buf (erc-server-buffer)))
220 (and tmp-server-buf
221 (with-current-buffer tmp-server-buf
222 (and
223 (eq (org-irc-get-current-erc-port) port)
224 (string= erc-session-server server)
225 (setq server-buffer tmp-server-buf)))))))))
0fc0f178 226 (if buffer-list
33306645
CD
227 (let ((chan-name (pop link)))
228 ;; if we got a channel name then switch to it or join it
229 (if chan-name
230 (let ((chan-buf (catch 'found
231 (dolist (x buffer-list)
232 (if (string= (buffer-name x) chan-name)
233 (throw 'found x))))))
234 (if chan-buf
235 (progn
e66ba1df 236 (org-pop-to-buffer-same-window chan-buf)
33306645
CD
237 ;; if we got a nick, and they're in the chan,
238 ;; then start a chat with them
239 (let ((nick (pop link)))
240 (when nick
241 (if (member nick (erc-get-server-nickname-list))
242 (progn
243 (goto-char (point-max))
244 (insert (concat nick ": ")))
8223b1d2
BG
245 (error "%s not found in %s" nick chan-name)))))
246 (progn
247 (org-pop-to-buffer-same-window server-buffer)
248 (erc-cmd-JOIN chan-name))))
249 (org-pop-to-buffer-same-window server-buffer)))
250 ;; no server match, make new connection
251 (erc-select :server server :port port))))
0fc0f178
CD
252
253(provide 'org-irc)
254
bdebdb64
BG
255;; Local variables:
256;; generated-autoload-file: "org-loaddefs.el"
257;; End:
258
0fc0f178 259;;; org-irc.el ends here