]> crepu.dev Git - config.git/blob - djavu-asus/emacs/elpa/jabber-20230715.456/jabber-events.el
c12649ff788d512dda147a5979967d429673babb
[config.git] / djavu-asus / emacs / elpa / jabber-20230715.456 / jabber-events.el
1 ;;; jabber-events.el --- Message events (JEP-0022) implementation -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2005, 2008 Magnus Henoch
4
5 ;; Author: Magnus Henoch <mange@freemail.hu>
6
7 ;; This file is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 2, or (at your option)
10 ;; any later version.
11
12 ;; This file 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
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GNU Emacs; see the file COPYING. If not, write to
19 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 ;; Boston, MA 02111-1307, USA.
21
22 (require 'cl-lib)
23
24 (defgroup jabber-events nil
25 "Message events and notifications."
26 :group 'jabber)
27
28 ;;; INCOMING
29 ;;; Code for requesting event notifications from others and handling
30 ;;; them.
31
32 (defcustom jabber-events-request-these '(offline
33 delivered
34 displayed
35 composing)
36 "Request these kinds of event notifications from others."
37 :type '(set (const :tag "Delivered to offline storage" offline)
38 (const :tag "Delivered to user's client" delivered)
39 (const :tag "Displayed to user" displayed)
40 (const :tag "User is typing a reply" composing))
41 :group 'jabber-events)
42
43 (defvar jabber-events-composing-p nil
44 "Is the other person composing a message?")
45 (make-variable-buffer-local 'jabber-events-composing-p)
46
47 (defvar jabber-events-arrived nil
48 "In what way has the message reached the recipient?
49 Possible values are nil (no information available), offline
50 \(queued for delivery when recipient is online), delivered
51 \(message has reached the client) and displayed (user is
52 probably reading the message).")
53 (make-variable-buffer-local 'jabber-events-arrived)
54
55 (defvar jabber-events-message ""
56 "Human-readable presentation of event information.")
57 (make-variable-buffer-local 'jabber-events-message)
58
59 (defun jabber-events-update-message ()
60 (setq jabber-events-message
61 (concat (cdr (assq jabber-events-arrived
62 '((offline . "In offline storage")
63 (delivered . "Delivered")
64 (displayed . "Displayed"))))
65 (when jabber-events-composing-p
66 " (typing a message)"))))
67
68 (add-hook 'jabber-chat-send-hooks 'jabber-events-when-sending)
69 (defun jabber-events-when-sending (text id)
70 (setq jabber-events-arrived nil)
71 (jabber-events-update-message)
72 `((x ((xmlns . "jabber:x:event"))
73 ,@(mapcar #'list jabber-events-request-these))))
74
75 ;;; OUTGOING
76 ;;; Code for handling requests for event notifications and providing
77 ;;; them, modulo user preferences.
78
79 (defcustom jabber-events-confirm-delivered t
80 "Send delivery confirmation if requested?"
81 :group 'jabber-events
82 :type 'boolean)
83
84 (defcustom jabber-events-confirm-displayed t
85 "Send display confirmation if requested?"
86 :group 'jabber-events
87 :type 'boolean)
88
89 (defcustom jabber-events-confirm-composing t
90 "Send notifications about typing a reply?"
91 :group 'jabber-events
92 :type 'boolean)
93
94 (defvar jabber-events-requested ()
95 "List of events requested.")
96 (make-variable-buffer-local 'jabber-events-requested)
97
98 (defvar jabber-events-last-id nil
99 "Id of last message received, or nil if none.")
100 (make-variable-buffer-local 'jabber-events-last-id)
101
102 (defvar jabber-events-delivery-confirmed nil
103 "Has delivery confirmation been sent?")
104 (make-variable-buffer-local 'jabber-events-delivery-confirmed)
105
106 (defvar jabber-events-display-confirmed nil
107 "Has display confirmation been sent?")
108 (make-variable-buffer-local 'jabber-events-display-confirmed)
109
110 (defvar jabber-events-composing-sent nil
111 "Has composing notification been sent?
112 It can be sent and cancelled several times.")
113
114 (add-hook 'window-configuration-change-hook
115 'jabber-events-confirm-display)
116 (defun jabber-events-confirm-display ()
117 "Send display confirmation if appropriate.
118 That is, if user allows it, if the other user requested it,
119 and it hasn't been sent before."
120 (walk-windows #'jabber-events-confirm-display-in-window))
121
122 (defun jabber-events-confirm-display-in-window (window)
123 (with-current-buffer (window-buffer window)
124 (when (and jabber-events-confirm-displayed
125 (not jabber-events-display-confirmed)
126 (memq 'displayed jabber-events-requested)
127 ;; XXX: if jabber-events-requested is non-nil, how can
128 ;; jabber-chatting-with be nil? See
129 ;; http://sourceforge.net/tracker/index.php?func=detail&aid=1872560&group_id=88346&atid=586350
130 jabber-chatting-with
131 ;; don't send to bare jids
132 (jabber-jid-resource jabber-chatting-with))
133 (jabber-send-sexp
134 jabber-buffer-connection
135 `(message
136 ((to . ,jabber-chatting-with))
137 (x ((xmlns . "jabber:x:event"))
138 (displayed)
139 (id () ,jabber-events-last-id))))
140 (setq jabber-events-display-confirmed t))))
141
142 (defun jabber-events-after-change ()
143 (let ((composing-now (not (= (point-max) jabber-point-insert))))
144 (when (and jabber-events-confirm-composing
145 jabber-chatting-with
146 (not (eq composing-now jabber-events-composing-sent)))
147 (jabber-send-sexp
148 jabber-buffer-connection
149 `(message
150 ((to . ,jabber-chatting-with))
151 (x ((xmlns . "jabber:x:event"))
152 ,@(if composing-now '((composing)) nil)
153 (id () ,jabber-events-last-id))))
154 (setq jabber-events-composing-sent composing-now))))
155
156 ;;; COMMON
157
158 ;; Add function last in chain, so a chat buffer is already created.
159 (add-to-list 'jabber-message-chain 'jabber-handle-incoming-message-events t)
160
161 (defun jabber-handle-incoming-message-events (jc xml-data)
162 (when (and (not (jabber-muc-message-p xml-data))
163 (get-buffer (jabber-chat-get-buffer (jabber-xml-get-attribute xml-data 'from))))
164 (with-current-buffer (jabber-chat-get-buffer (jabber-xml-get-attribute xml-data 'from))
165 (let ((x (cl-find "jabber:x:event"
166 (jabber-xml-get-children xml-data 'x)
167 :key #'(lambda (x) (jabber-xml-get-attribute x 'xmlns))
168 :test #'string=)))
169 (cond
170 ;; If we get an error message, we shouldn't report any
171 ;; events, as the requests are mirrored from us.
172 ((string= (jabber-xml-get-attribute xml-data 'type) "error")
173 (remove-hook 'post-command-hook 'jabber-events-after-change t)
174 (setq jabber-events-requested nil))
175
176 ;; If there's a body, it's not an incoming message event.
177 ((jabber-xml-get-children xml-data 'body)
178 ;; User is done composing, obviously.
179 (setq jabber-events-composing-p nil)
180 (jabber-events-update-message)
181
182 ;; Reset variables
183 (setq jabber-events-display-confirmed nil)
184 (setq jabber-events-delivery-confirmed nil)
185
186 ;; User requests message events
187 (setq jabber-events-requested
188 ;; There might be empty strings in the XML data,
189 ;; which car chokes on. Having nil values in
190 ;; the list won't hurt, therefore car-safe.
191 (mapcar #'car-safe
192 (jabber-xml-node-children x)))
193 (setq jabber-events-last-id (jabber-xml-get-attribute
194 xml-data 'id))
195
196 ;; Send notifications we already know about
197 (cl-flet ((send-notification
198 (type)
199 (jabber-send-sexp
200 jc
201 `(message
202 ((to . ,(jabber-xml-get-attribute xml-data 'from)))
203 (x ((xmlns . "jabber:x:event"))
204 (,type)
205 (id () ,jabber-events-last-id))))))
206 ;; Send delivery confirmation if appropriate
207 (when (and jabber-events-confirm-delivered
208 (memq 'delivered jabber-events-requested))
209 (send-notification 'delivered)
210 (setq jabber-events-delivery-confirmed t))
211
212 ;; Send display confirmation if appropriate
213 (when (and jabber-events-confirm-displayed
214 (get-buffer-window (current-buffer) 'visible)
215 (memq 'displayed jabber-events-requested))
216 (send-notification 'displayed)
217 (setq jabber-events-display-confirmed t))
218
219 ;; Set up hooks for composition notification
220 (when (and jabber-events-confirm-composing
221 (memq 'composing jabber-events-requested))
222 (add-hook 'post-command-hook 'jabber-events-after-change
223 nil t))))
224 (t
225 ;; So it has no body. If it's a message event,
226 ;; the <x/> node should be the only child of the
227 ;; message, and it should contain an <id/> node.
228 ;; We check the latter.
229 (when (and x (jabber-xml-get-children x 'id))
230 ;; Currently we don't care about the <id/> node.
231
232 ;; There's only one node except for the id.
233 (unless
234 (cl-dolist (possible-node '(offline delivered displayed))
235 (when (jabber-xml-get-children x possible-node)
236 (setq jabber-events-arrived possible-node)
237 (jabber-events-update-message)
238 (cl-return t)))
239 ;; Or maybe even zero, which is a negative composing node.
240 (setq jabber-events-composing-p
241 (not (null (jabber-xml-get-children x 'composing))))
242 (jabber-events-update-message)))))))))
243
244 (provide 'jabber-events)
245 ;; arch-tag: 7b6e61fe-a9b3-11d9-afca-000a95c2fcd0