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