2004-02-25 21:42:02 +00:00
|
|
|
;; jabber-presence.el - roster and presence bookkeeping
|
|
|
|
|
2008-01-13 18:05:20 +00:00
|
|
|
;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu
|
2004-02-25 21:42:02 +00:00
|
|
|
;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net
|
|
|
|
|
|
|
|
;; This file is a part of jabber.el.
|
|
|
|
|
|
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
;; the Free Software Foundation; either version 2 of the License, or
|
|
|
|
;; (at your option) any later version.
|
|
|
|
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
|
|
;; along with this program; if not, write to the Free Software
|
|
|
|
;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
(require 'jabber-core)
|
|
|
|
(require 'jabber-iq)
|
2004-03-29 20:07:52 +00:00
|
|
|
(require 'jabber-alert)
|
|
|
|
(require 'jabber-util)
|
2004-09-13 12:49:49 +00:00
|
|
|
(require 'jabber-menu)
|
2004-10-26 20:05:11 +00:00
|
|
|
(require 'jabber-muc)
|
2004-02-25 21:42:02 +00:00
|
|
|
|
2006-03-09 00:08:39 +00:00
|
|
|
(defvar jabber-presence-element-functions nil
|
|
|
|
"List of functions returning extra elements for <presence/> stanzas.
|
2007-02-20 14:13:34 +00:00
|
|
|
Each function takes one argument, the connection, and returns a
|
|
|
|
possibly empty list of extra child element of the <presence/>
|
|
|
|
stanza.")
|
2006-03-09 00:08:39 +00:00
|
|
|
|
2009-02-15 14:33:53 +00:00
|
|
|
(defvar jabber-presence-history ()
|
|
|
|
"Keeps track of previously used presence status types")
|
|
|
|
|
2004-02-25 21:42:02 +00:00
|
|
|
(add-to-list 'jabber-iq-set-xmlns-alist
|
2007-02-05 21:59:02 +00:00
|
|
|
(cons "jabber:iq:roster" (function (lambda (jc x) (jabber-process-roster jc x nil)))))
|
|
|
|
(defun jabber-process-roster (jc xml-data closure-data)
|
2004-02-25 21:42:02 +00:00
|
|
|
"process an incoming roster infoquery result
|
|
|
|
CLOSURE-DATA should be 'initial if initial roster push, nil otherwise."
|
2007-02-05 21:59:02 +00:00
|
|
|
(let ((roster (plist-get (fsm-get-state-data jc) :roster))
|
|
|
|
(from (jabber-xml-get-attribute xml-data 'from))
|
2004-02-25 21:42:02 +00:00
|
|
|
(type (jabber-xml-get-attribute xml-data 'type))
|
2007-02-05 21:59:02 +00:00
|
|
|
(id (jabber-xml-get-attribute xml-data 'id))
|
|
|
|
(username (plist-get (fsm-get-state-data jc) :username))
|
|
|
|
(server (plist-get (fsm-get-state-data jc) :server))
|
|
|
|
(resource (plist-get (fsm-get-state-data jc) :resource))
|
|
|
|
new-items changed-items deleted-items)
|
|
|
|
;; Perform sanity check on "from" attribute: it should be either absent
|
2013-09-06 09:46:51 +00:00
|
|
|
;; match our own JID, or match the server's JID (the latter is what
|
|
|
|
;; Facebook does).
|
2004-02-25 21:42:02 +00:00
|
|
|
(if (not (or (null from)
|
2013-09-06 09:46:51 +00:00
|
|
|
(string= from server)
|
2007-02-05 21:59:02 +00:00
|
|
|
(string= from (concat username "@" server))
|
|
|
|
(string= from (concat username "@" server "/" resource))))
|
2013-09-06 09:46:51 +00:00
|
|
|
(message "Roster push with invalid \"from\": \"%s\" (expected \"%s\", \"%s@%s\" or \"%s@%s/%s\")"
|
2007-09-19 09:06:45 +00:00
|
|
|
from
|
2013-09-06 09:46:51 +00:00
|
|
|
server username server username server resource)
|
2004-02-25 21:42:02 +00:00
|
|
|
|
|
|
|
(dolist (item (jabber-xml-get-children (car (jabber-xml-get-children xml-data 'query)) 'item))
|
|
|
|
(let (roster-item
|
2004-05-01 14:35:45 +00:00
|
|
|
(jid (jabber-jid-symbol (jabber-xml-get-attribute item 'jid))))
|
2004-02-25 21:42:02 +00:00
|
|
|
|
|
|
|
;; If subscripton="remove", contact is to be removed from roster
|
2007-02-05 21:59:02 +00:00
|
|
|
(if (string= (jabber-xml-get-attribute item 'subscription) "remove")
|
|
|
|
(progn
|
2014-09-30 19:08:32 +00:00
|
|
|
(if (jabber-jid-rostername jid)
|
|
|
|
(message "%s (%s) removed from roster" (jabber-jid-rostername jid) jid)
|
|
|
|
(message "%s removed from roster" jid))
|
2007-02-05 21:59:02 +00:00
|
|
|
(push jid deleted-items))
|
|
|
|
|
|
|
|
;; Find contact if already in roster
|
|
|
|
(setq roster-item (car (memq jid roster)))
|
|
|
|
|
|
|
|
(if roster-item
|
|
|
|
(push roster-item changed-items)
|
|
|
|
;; If not found, create a new roster item.
|
2012-06-02 10:59:44 +00:00
|
|
|
(unless (eq closure-data 'initial)
|
2014-09-30 19:08:32 +00:00
|
|
|
(if (jabber-xml-get-attribute item 'name)
|
|
|
|
(message "%s (%s) added to roster" (jabber-xml-get-attribute item 'name) jid)
|
|
|
|
(message "%s added to roster" jid)))
|
2007-02-05 21:59:02 +00:00
|
|
|
(setq roster-item jid)
|
|
|
|
(push roster-item new-items))
|
|
|
|
|
2008-01-13 18:13:15 +00:00
|
|
|
;; If this is an initial push, we want to forget
|
|
|
|
;; everything we knew about this contact before - e.g. if
|
|
|
|
;; the contact was online when we disconnected and offline
|
|
|
|
;; when we reconnect, we don't want to see stale presence
|
|
|
|
;; information. This assumes that no contacts are shared
|
|
|
|
;; between accounts.
|
|
|
|
(when (eq closure-data 'initial)
|
|
|
|
(setplist roster-item nil))
|
|
|
|
|
2007-02-05 21:59:02 +00:00
|
|
|
;; Now, get all data associated with the contact.
|
|
|
|
(put roster-item 'name (jabber-xml-get-attribute item 'name))
|
|
|
|
(put roster-item 'subscription (jabber-xml-get-attribute item 'subscription))
|
|
|
|
(put roster-item 'ask (jabber-xml-get-attribute item 'ask))
|
|
|
|
|
|
|
|
;; Since roster items can't be changed incrementally, we
|
|
|
|
;; save the original XML to be able to modify it, instead of
|
|
|
|
;; having to reproduce it. This is for forwards
|
|
|
|
;; compatibility.
|
|
|
|
(put roster-item 'xml item)
|
|
|
|
|
|
|
|
(put roster-item 'groups
|
|
|
|
(mapcar (lambda (foo) (nth 2 foo))
|
|
|
|
(jabber-xml-get-children item 'group)))))))
|
|
|
|
;; This is the function that does the actual updating and
|
|
|
|
;; redrawing of the roster.
|
|
|
|
(jabber-roster-update jc new-items changed-items deleted-items)
|
2009-04-10 21:20:21 +00:00
|
|
|
|
2004-02-25 21:42:02 +00:00
|
|
|
(if (and id (string= type "set"))
|
2007-09-17 12:26:16 +00:00
|
|
|
(jabber-send-iq jc nil "result" nil
|
2006-07-09 16:35:30 +00:00
|
|
|
nil nil nil nil id)))
|
|
|
|
|
2007-02-05 21:59:02 +00:00
|
|
|
;; After initial roster push, run jabber-post-connect-hooks. We do
|
2006-07-09 16:35:30 +00:00
|
|
|
;; it here and not before since we want to have the entire roster
|
|
|
|
;; before we receive any presence stanzas.
|
|
|
|
(when (eq closure-data 'initial)
|
2007-02-05 21:59:02 +00:00
|
|
|
(run-hook-with-args 'jabber-post-connect-hooks jc)))
|
2004-02-25 21:42:02 +00:00
|
|
|
|
2014-01-22 21:27:50 +00:00
|
|
|
(defun jabber-initial-roster-failure (jc xml-data _closure-data)
|
|
|
|
;; If the initial roster request fails, let's report it, but run
|
|
|
|
;; jabber-post-connect-hooks anyway. According to the spec, there
|
|
|
|
;; is nothing exceptional about the server not returning a roster.
|
|
|
|
(jabber-report-success jc xml-data "Initial roster retrieval")
|
|
|
|
(run-hook-with-args 'jabber-post-connect-hooks jc))
|
|
|
|
|
2004-02-25 21:42:02 +00:00
|
|
|
(add-to-list 'jabber-presence-chain 'jabber-process-presence)
|
2007-02-05 21:59:02 +00:00
|
|
|
(defun jabber-process-presence (jc xml-data)
|
2004-02-25 21:42:02 +00:00
|
|
|
"process incoming presence tags"
|
2007-02-05 21:59:02 +00:00
|
|
|
;; XXX: use JC argument
|
|
|
|
(let ((roster (plist-get (fsm-get-state-data jc) :roster))
|
|
|
|
(from (jabber-xml-get-attribute xml-data 'from))
|
2004-02-25 21:42:02 +00:00
|
|
|
(to (jabber-xml-get-attribute xml-data 'to))
|
|
|
|
(type (jabber-xml-get-attribute xml-data 'type))
|
2004-10-26 20:05:11 +00:00
|
|
|
(presence-show (car (jabber-xml-node-children
|
|
|
|
(car (jabber-xml-get-children xml-data 'show)))))
|
|
|
|
(presence-status (car (jabber-xml-node-children
|
|
|
|
(car (jabber-xml-get-children xml-data 'status)))))
|
2004-02-25 21:42:02 +00:00
|
|
|
(error (car (jabber-xml-get-children xml-data 'error)))
|
2004-03-03 18:30:39 +00:00
|
|
|
(priority (string-to-number (or (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'priority))))
|
|
|
|
"0"))))
|
2004-02-25 21:42:02 +00:00
|
|
|
(cond
|
|
|
|
((string= type "subscribe")
|
2007-02-05 21:59:02 +00:00
|
|
|
(run-with-idle-timer 0.01 nil #'jabber-process-subscription-request jc from presence-status))
|
2004-10-26 20:05:11 +00:00
|
|
|
|
|
|
|
((jabber-muc-presence-p xml-data)
|
2007-02-05 21:59:02 +00:00
|
|
|
(jabber-muc-process-presence jc xml-data))
|
2004-10-26 20:05:11 +00:00
|
|
|
|
2004-02-25 21:42:02 +00:00
|
|
|
(t
|
2005-02-26 11:32:10 +00:00
|
|
|
;; XXX: Think about what to do about out-of-roster presences.
|
|
|
|
(let ((buddy (jabber-jid-symbol from)))
|
2007-02-05 21:59:02 +00:00
|
|
|
(if (memq buddy roster)
|
2004-02-25 21:42:02 +00:00
|
|
|
(let* ((oldstatus (get buddy 'show))
|
|
|
|
(resource (or (jabber-jid-resource from) ""))
|
|
|
|
(resource-plist (cdr (assoc resource
|
|
|
|
(get buddy 'resources))))
|
|
|
|
newstatus)
|
|
|
|
(cond
|
2007-12-09 00:55:34 +00:00
|
|
|
((and (string= resource "") (member type '("unavailable" "error")))
|
|
|
|
;; 'unavailable' or 'error' from bare JID means that all resources
|
|
|
|
;; are offline.
|
|
|
|
(setq resource-plist nil)
|
|
|
|
(setq newstatus (if (string= type "error") "error" nil))
|
|
|
|
(let ((new-message (if error
|
|
|
|
(jabber-parse-error error)
|
|
|
|
presence-status)))
|
|
|
|
;; erase any previous information
|
|
|
|
(put buddy 'resources nil)
|
|
|
|
(put buddy 'connected nil)
|
|
|
|
(put buddy 'show newstatus)
|
|
|
|
(put buddy 'status new-message)))
|
|
|
|
|
2004-02-25 21:42:02 +00:00
|
|
|
((string= type "unavailable")
|
|
|
|
(setq resource-plist
|
|
|
|
(plist-put resource-plist 'connected nil))
|
|
|
|
(setq resource-plist
|
|
|
|
(plist-put resource-plist 'show nil))
|
|
|
|
(setq resource-plist
|
2004-10-26 20:05:11 +00:00
|
|
|
(plist-put resource-plist 'status
|
2006-03-04 00:33:12 +00:00
|
|
|
presence-status)))
|
2004-02-25 21:42:02 +00:00
|
|
|
|
|
|
|
((string= type "error")
|
|
|
|
(setq newstatus "error")
|
|
|
|
(setq resource-plist
|
|
|
|
(plist-put resource-plist 'connected nil))
|
|
|
|
(setq resource-plist
|
|
|
|
(plist-put resource-plist 'show "error"))
|
|
|
|
(setq resource-plist
|
2004-10-26 20:05:11 +00:00
|
|
|
(plist-put resource-plist 'status
|
|
|
|
(if error
|
|
|
|
(jabber-parse-error error)
|
2006-03-04 00:33:12 +00:00
|
|
|
presence-status))))
|
2004-02-25 21:42:02 +00:00
|
|
|
((or
|
|
|
|
(string= type "unsubscribe")
|
|
|
|
(string= type "subscribed")
|
|
|
|
(string= type "unsubscribed"))
|
|
|
|
;; Do nothing, except letting the user know. The Jabber protocol
|
|
|
|
;; places all this complexity on the server.
|
|
|
|
(setq newstatus type))
|
|
|
|
(t
|
|
|
|
(setq resource-plist
|
|
|
|
(plist-put resource-plist 'connected t))
|
|
|
|
(setq resource-plist
|
|
|
|
(plist-put resource-plist 'show (or presence-show "")))
|
|
|
|
(setq resource-plist
|
2004-10-26 20:05:11 +00:00
|
|
|
(plist-put resource-plist 'status
|
2006-03-04 00:33:12 +00:00
|
|
|
presence-status))
|
2004-02-25 21:42:02 +00:00
|
|
|
(setq resource-plist
|
|
|
|
(plist-put resource-plist 'priority priority))
|
|
|
|
(setq newstatus (or presence-show ""))))
|
|
|
|
|
2007-12-09 00:55:34 +00:00
|
|
|
(when resource-plist
|
|
|
|
;; this is for `assoc-set!' in guile
|
|
|
|
(if (assoc resource (get buddy 'resources))
|
|
|
|
(setcdr (assoc resource (get buddy 'resources)) resource-plist)
|
|
|
|
(put buddy 'resources (cons (cons resource resource-plist) (get buddy 'resources))))
|
|
|
|
(jabber-prioritize-resources buddy))
|
2004-02-25 21:42:02 +00:00
|
|
|
|
2008-03-04 07:23:27 +00:00
|
|
|
(fsm-send jc (cons :roster-update buddy))
|
2007-02-05 21:59:02 +00:00
|
|
|
|
2004-12-23 16:58:17 +00:00
|
|
|
(dolist (hook '(jabber-presence-hooks jabber-alert-presence-hooks))
|
2004-12-25 10:52:38 +00:00
|
|
|
(run-hook-with-args hook
|
2004-12-23 16:58:17 +00:00
|
|
|
buddy
|
|
|
|
oldstatus
|
|
|
|
newstatus
|
2006-03-04 00:33:12 +00:00
|
|
|
(plist-get resource-plist 'status)
|
2009-04-10 21:20:21 +00:00
|
|
|
(funcall jabber-alert-presence-message-function
|
2004-12-23 16:58:17 +00:00
|
|
|
buddy
|
|
|
|
oldstatus
|
|
|
|
newstatus
|
2006-03-04 00:33:12 +00:00
|
|
|
(plist-get resource-plist 'status)))))))))))
|
2004-02-25 21:42:02 +00:00
|
|
|
|
2007-02-05 21:59:02 +00:00
|
|
|
(defun jabber-process-subscription-request (jc from presence-status)
|
2004-02-25 21:42:02 +00:00
|
|
|
"process an incoming subscription request"
|
2017-01-27 05:04:29 +00:00
|
|
|
(with-current-buffer (jabber-chat-create-buffer jc from nil)
|
2007-09-14 23:14:03 +00:00
|
|
|
(ewoc-enter-last jabber-chat-ewoc (list :subscription-request presence-status :time (current-time)))
|
|
|
|
|
|
|
|
(dolist (hook '(jabber-presence-hooks jabber-alert-presence-hooks))
|
|
|
|
(run-hook-with-args hook (jabber-jid-symbol from) nil "subscribe" presence-status (funcall jabber-alert-presence-message-function (jabber-jid-symbol from) nil "subscribe" presence-status)))))
|
|
|
|
|
|
|
|
(defun jabber-subscription-accept-mutual (&rest ignored)
|
2007-10-26 14:04:42 +00:00
|
|
|
(message "Subscription accepted; reciprocal subscription request sent")
|
2007-09-14 23:14:03 +00:00
|
|
|
(jabber-subscription-reply "subscribed" "subscribe"))
|
|
|
|
|
|
|
|
(defun jabber-subscription-accept-one-way (&rest ignored)
|
2007-10-26 14:04:42 +00:00
|
|
|
(message "Subscription accepted")
|
2007-09-14 23:14:03 +00:00
|
|
|
(jabber-subscription-reply "subscribed"))
|
|
|
|
|
|
|
|
(defun jabber-subscription-decline (&rest ignored)
|
2007-10-26 14:04:42 +00:00
|
|
|
(message "Subscription declined")
|
2007-09-14 23:14:03 +00:00
|
|
|
(jabber-subscription-reply "unsubscribed"))
|
|
|
|
|
|
|
|
(defun jabber-subscription-reply (&rest types)
|
|
|
|
(let ((to (jabber-jid-user jabber-chatting-with)))
|
|
|
|
(dolist (type types)
|
|
|
|
(jabber-send-sexp jabber-buffer-connection `(presence ((to . ,to) (type . ,type)))))))
|
2004-02-25 21:42:02 +00:00
|
|
|
|
|
|
|
(defun jabber-prioritize-resources (buddy)
|
|
|
|
"Set connected, show and status properties for BUDDY from highest-priority resource."
|
|
|
|
(let ((resource-alist (get buddy 'resources))
|
|
|
|
(highest-priority nil))
|
|
|
|
;; Reset to nil at first, for cases (a) resource-alist is nil
|
|
|
|
;; and (b) all resources are disconnected.
|
|
|
|
(put buddy 'connected nil)
|
|
|
|
(put buddy 'show nil)
|
|
|
|
(put buddy 'status nil)
|
2004-03-09 19:20:53 +00:00
|
|
|
(mapc #'(lambda (resource)
|
|
|
|
(let* ((resource-plist (cdr resource))
|
|
|
|
(priority (plist-get resource-plist 'priority)))
|
|
|
|
(if (plist-get resource-plist 'connected)
|
|
|
|
(when (or (null highest-priority)
|
|
|
|
(and priority
|
|
|
|
(> priority highest-priority)))
|
|
|
|
;; if no priority specified, interpret as zero
|
|
|
|
(setq highest-priority (or priority 0))
|
|
|
|
(put buddy 'connected (plist-get resource-plist 'connected))
|
|
|
|
(put buddy 'show (plist-get resource-plist 'show))
|
2004-08-07 17:29:02 +00:00
|
|
|
(put buddy 'status (plist-get resource-plist 'status))
|
|
|
|
(put buddy 'resource (car resource)))
|
2004-03-09 19:20:53 +00:00
|
|
|
|
|
|
|
;; if we have not found a connected resource yet, but this
|
|
|
|
;; disconnected resource has a status message, display it.
|
|
|
|
(when (not (get buddy 'connected))
|
|
|
|
(if (plist-get resource-plist 'status)
|
|
|
|
(put buddy 'status (plist-get resource-plist 'status)))
|
|
|
|
(if (plist-get resource-plist 'show)
|
|
|
|
(put buddy 'show (plist-get resource-plist 'show)))))))
|
2004-02-25 21:42:02 +00:00
|
|
|
resource-alist)))
|
|
|
|
|
|
|
|
(defun jabber-count-connected-resources (buddy)
|
|
|
|
"Return the number of connected resources for BUDDY."
|
|
|
|
(let ((resource-alist (get buddy 'resources))
|
|
|
|
(count 0))
|
|
|
|
(dolist (resource resource-alist)
|
|
|
|
(if (plist-get (cdr resource) 'connected)
|
|
|
|
(setq count (1+ count))))
|
|
|
|
count))
|
|
|
|
|
2008-06-17 14:51:40 +00:00
|
|
|
;;;###autoload
|
2004-02-25 21:42:02 +00:00
|
|
|
(defun jabber-send-presence (show status priority)
|
2007-02-05 21:59:02 +00:00
|
|
|
"Set presence for all accounts."
|
2009-04-10 21:20:21 +00:00
|
|
|
(interactive
|
|
|
|
(list
|
|
|
|
(completing-read "show: " '("" "away" "xa" "dnd" "chat")
|
|
|
|
nil t nil 'jabber-presence-history)
|
|
|
|
(jabber-read-with-input-method "status message: " *jabber-current-status*
|
|
|
|
'*jabber-status-history*)
|
|
|
|
(read-string "priority: " (int-to-string (if *jabber-current-priority*
|
|
|
|
*jabber-current-priority*
|
|
|
|
jabber-default-priority)))))
|
|
|
|
|
|
|
|
(setq *jabber-current-show* show *jabber-current-status* status)
|
|
|
|
(setq *jabber-current-priority*
|
|
|
|
(if (numberp priority) priority (string-to-number priority)))
|
|
|
|
|
2007-12-09 23:19:18 +00:00
|
|
|
(let (subelements-map)
|
|
|
|
;; For each connection, we use a different set of subelements. We
|
|
|
|
;; cache them, to only generate them once.
|
|
|
|
|
|
|
|
;; Ordinary presence, with no specified recipient
|
2007-02-05 21:59:02 +00:00
|
|
|
(dolist (jc jabber-connections)
|
2007-02-20 14:13:34 +00:00
|
|
|
(let ((subelements (jabber-presence-children jc)))
|
2013-04-07 02:34:56 +00:00
|
|
|
(push (cons jc subelements) subelements-map)
|
2008-01-13 18:05:20 +00:00
|
|
|
(jabber-send-sexp-if-connected jc `(presence () ,@subelements))))
|
2009-04-10 21:20:21 +00:00
|
|
|
|
2007-12-09 23:19:18 +00:00
|
|
|
;; Then send presence to groupchats
|
2009-04-10 21:20:21 +00:00
|
|
|
(dolist (gc *jabber-active-groupchats*)
|
|
|
|
(let* ((buffer (get-buffer (jabber-muc-get-buffer (car gc))))
|
2007-12-09 23:19:18 +00:00
|
|
|
(jc (when buffer
|
|
|
|
(buffer-local-value 'jabber-buffer-connection buffer)))
|
|
|
|
(subelements (cdr (assq jc subelements-map))))
|
|
|
|
(when jc
|
2010-09-03 21:09:11 +00:00
|
|
|
(jabber-send-sexp-if-connected
|
|
|
|
jc `(presence ((to . ,(concat (car gc) "/" (cdr gc))))
|
|
|
|
,@subelements))))))
|
2009-04-10 21:20:21 +00:00
|
|
|
|
2004-02-25 21:42:02 +00:00
|
|
|
(jabber-display-roster))
|
|
|
|
|
2007-02-20 14:13:34 +00:00
|
|
|
(defun jabber-presence-children (jc)
|
2006-10-31 16:31:52 +00:00
|
|
|
"Return the children for a <presence/> stanza."
|
|
|
|
`(,(when (> (length *jabber-current-status*) 0)
|
|
|
|
`(status () ,*jabber-current-status*))
|
|
|
|
,(when (> (length *jabber-current-show*) 0)
|
|
|
|
`(show () ,*jabber-current-show*))
|
2008-06-17 14:46:23 +00:00
|
|
|
,(when *jabber-current-priority*
|
|
|
|
`(priority () ,(number-to-string *jabber-current-priority*)))
|
2007-02-20 14:13:34 +00:00
|
|
|
,@(apply 'append (mapcar (lambda (f)
|
|
|
|
(funcall f jc))
|
|
|
|
jabber-presence-element-functions))))
|
2006-10-31 16:31:52 +00:00
|
|
|
|
2007-03-20 11:49:41 +00:00
|
|
|
(defun jabber-send-directed-presence (jc jid type)
|
2008-03-02 16:36:38 +00:00
|
|
|
"Send a directed presence stanza to JID.
|
|
|
|
TYPE is one of:
|
|
|
|
\"online\", \"away\", \"xa\", \"dnd\", \"chatty\":
|
|
|
|
Appear as present with the given status.
|
|
|
|
\"unavailable\":
|
|
|
|
Appear as offline.
|
|
|
|
\"probe\":
|
|
|
|
Ask the contact's server for updated presence.
|
|
|
|
\"subscribe\":
|
|
|
|
Ask for subscription to contact's presence.
|
|
|
|
(see also `jabber-send-subscription-request')
|
|
|
|
\"unsubscribe\":
|
|
|
|
Cancel your subscription to contact's presence.
|
|
|
|
\"subscribed\":
|
|
|
|
Accept contact's request for presence subscription.
|
|
|
|
(this is usually done within a chat buffer)
|
|
|
|
\"unsubscribed\":
|
|
|
|
Cancel contact's subscription to your presence."
|
2006-11-17 18:32:11 +00:00
|
|
|
(interactive
|
2007-03-20 11:49:41 +00:00
|
|
|
(list (jabber-read-account)
|
|
|
|
(jabber-read-jid-completing "Send directed presence to: ")
|
2006-11-17 18:32:11 +00:00
|
|
|
(completing-read "Type (default is online): "
|
|
|
|
'(("online")
|
|
|
|
("away")
|
|
|
|
("xa")
|
|
|
|
("dnd")
|
|
|
|
("chatty")
|
|
|
|
("probe")
|
2008-03-02 16:36:38 +00:00
|
|
|
("unavailable")
|
|
|
|
("subscribe")
|
|
|
|
("unsubscribe")
|
|
|
|
("subscribed")
|
|
|
|
("unsubscribed"))
|
2009-02-15 14:33:53 +00:00
|
|
|
nil t nil 'jabber-presence-history "online")))
|
2006-11-17 18:32:11 +00:00
|
|
|
(cond
|
2009-04-10 21:20:21 +00:00
|
|
|
((member type '("probe" "unavailable"
|
2008-03-02 16:36:38 +00:00
|
|
|
"subscribe" "unsubscribe"
|
|
|
|
"subscribed" "unsubscribed"))
|
2007-03-20 11:49:41 +00:00
|
|
|
(jabber-send-sexp jc `(presence ((to . ,jid)
|
|
|
|
(type . ,type)))))
|
2006-11-17 18:32:11 +00:00
|
|
|
|
|
|
|
(t
|
|
|
|
(let ((*jabber-current-show*
|
|
|
|
(if (string= type "online")
|
|
|
|
""
|
|
|
|
type))
|
|
|
|
(*jabber-current-status* nil))
|
2007-03-20 11:49:41 +00:00
|
|
|
(jabber-send-sexp jc `(presence ((to . ,jid))
|
|
|
|
,@(jabber-presence-children jc)))))))
|
2006-11-17 18:32:11 +00:00
|
|
|
|
2006-07-01 08:02:20 +00:00
|
|
|
(defun jabber-send-away-presence (&optional status)
|
2005-06-23 18:17:43 +00:00
|
|
|
"Set status to away.
|
2006-07-01 08:02:20 +00:00
|
|
|
With prefix argument, ask for status message."
|
2009-04-10 22:15:24 +00:00
|
|
|
(interactive
|
|
|
|
(list
|
|
|
|
(when current-prefix-arg
|
|
|
|
(jabber-read-with-input-method
|
|
|
|
"status message: " *jabber-current-status* '*jabber-status-history*))))
|
|
|
|
(jabber-send-presence "away" (if status status *jabber-current-status*)
|
|
|
|
*jabber-current-priority*))
|
2005-06-23 18:17:43 +00:00
|
|
|
|
2009-04-10 22:15:24 +00:00
|
|
|
;; XXX code duplication!
|
2006-07-01 08:02:20 +00:00
|
|
|
(defun jabber-send-xa-presence (&optional status)
|
2005-06-23 18:17:43 +00:00
|
|
|
"Send extended away presence.
|
2006-07-01 08:02:20 +00:00
|
|
|
With prefix argument, ask for status message."
|
2009-04-10 22:15:24 +00:00
|
|
|
(interactive
|
|
|
|
(list
|
|
|
|
(when current-prefix-arg
|
|
|
|
(jabber-read-with-input-method
|
|
|
|
"status message: " *jabber-current-status* '*jabber-status-history*))))
|
|
|
|
(jabber-send-presence "xa" (if status status *jabber-current-status*)
|
|
|
|
*jabber-current-priority*))
|
2005-06-23 18:17:43 +00:00
|
|
|
|
2008-06-17 14:52:21 +00:00
|
|
|
;;;###autoload
|
2009-04-10 22:15:24 +00:00
|
|
|
(defun jabber-send-default-presence (&optional ignore)
|
2004-09-12 10:56:08 +00:00
|
|
|
"Send default presence.
|
2009-04-10 22:15:24 +00:00
|
|
|
Default presence is specified by `jabber-default-show',
|
|
|
|
`jabber-default-status', and `jabber-default-priority'."
|
2004-09-12 10:56:08 +00:00
|
|
|
(interactive)
|
2008-11-21 12:51:50 +00:00
|
|
|
(jabber-send-presence
|
2009-04-10 22:15:24 +00:00
|
|
|
jabber-default-show jabber-default-status jabber-default-priority))
|
2004-09-12 10:56:08 +00:00
|
|
|
|
2009-04-10 22:15:24 +00:00
|
|
|
(defun jabber-send-current-presence (&optional ignore)
|
2008-03-27 16:09:13 +00:00
|
|
|
"(Re-)send current presence.
|
|
|
|
That is, if presence has already been sent, use current settings,
|
2009-04-10 22:15:24 +00:00
|
|
|
otherwise send defaults (see `jabber-send-default-presence')."
|
2008-03-27 16:09:13 +00:00
|
|
|
(interactive)
|
|
|
|
(if *jabber-current-show*
|
2009-04-10 22:15:24 +00:00
|
|
|
(jabber-send-presence *jabber-current-show* *jabber-current-status*
|
|
|
|
*jabber-current-priority*)
|
2008-03-27 16:09:13 +00:00
|
|
|
(jabber-send-default-presence)))
|
|
|
|
|
2009-04-10 22:15:24 +00:00
|
|
|
(add-to-list 'jabber-jid-roster-menu (cons "Send subscription request"
|
|
|
|
'jabber-send-subscription-request))
|
2007-02-05 21:59:02 +00:00
|
|
|
(defun jabber-send-subscription-request (jc to &optional request)
|
2009-04-10 22:15:24 +00:00
|
|
|
"send a subscription request to jid, showing him your request
|
|
|
|
text, if specified"
|
2007-02-05 21:59:02 +00:00
|
|
|
(interactive (list (jabber-read-account)
|
|
|
|
(jabber-read-jid-completing "to: ")
|
2004-02-25 21:42:02 +00:00
|
|
|
(jabber-read-with-input-method "request: ")))
|
2007-02-05 21:59:02 +00:00
|
|
|
(jabber-send-sexp jc
|
2009-04-10 21:20:21 +00:00
|
|
|
`(presence
|
2006-08-29 11:06:46 +00:00
|
|
|
((to . ,to)
|
|
|
|
(type . "subscribe"))
|
|
|
|
,@(when (and request (> (length request) 0))
|
|
|
|
(list `(status () ,request))))))
|
2004-02-25 21:42:02 +00:00
|
|
|
|
2008-09-19 21:07:32 +00:00
|
|
|
(defvar jabber-roster-group-history nil
|
|
|
|
"History of entered roster groups")
|
|
|
|
|
2004-03-02 13:08:25 +00:00
|
|
|
(add-to-list 'jabber-jid-roster-menu
|
|
|
|
(cons "Add/modify roster entry" 'jabber-roster-change))
|
2007-02-05 21:59:02 +00:00
|
|
|
(defun jabber-roster-change (jc jid name groups)
|
2004-03-02 13:08:25 +00:00
|
|
|
"Add or change a roster item."
|
2004-10-26 20:05:11 +00:00
|
|
|
(interactive (let* ((jid (jabber-jid-symbol
|
|
|
|
(jabber-read-jid-completing "Add/change JID: ")))
|
2008-09-19 21:07:32 +00:00
|
|
|
(account (jabber-read-account))
|
2004-03-02 13:08:25 +00:00
|
|
|
(name (get jid 'name))
|
2008-09-19 21:07:32 +00:00
|
|
|
(groups (get jid 'groups))
|
|
|
|
(all-groups
|
|
|
|
(apply #'append
|
|
|
|
(mapcar
|
|
|
|
(lambda (j) (get j 'groups))
|
|
|
|
(plist-get (fsm-get-state-data account) :roster)))))
|
|
|
|
(when (string< emacs-version "22")
|
|
|
|
;; Older emacsen want the completion table to be an alist...
|
|
|
|
(setq all-groups (mapcar #'list all-groups)))
|
|
|
|
(list account
|
2007-02-05 21:59:02 +00:00
|
|
|
jid (jabber-read-with-input-method (format "Name: (default `%s') " name) nil nil name)
|
2008-09-19 21:07:32 +00:00
|
|
|
(delete ""
|
2009-04-10 21:20:21 +00:00
|
|
|
(completing-read-multiple
|
2008-09-19 21:07:32 +00:00
|
|
|
(format
|
|
|
|
"Groups, comma-separated: (default %s) "
|
|
|
|
(if groups
|
|
|
|
(mapconcat #'identity groups ",")
|
|
|
|
"none"))
|
|
|
|
all-groups
|
|
|
|
nil nil nil
|
|
|
|
'jabber-roster-group-history
|
|
|
|
(mapconcat #'identity groups ",")
|
|
|
|
t)))))
|
2004-03-02 13:08:25 +00:00
|
|
|
;; If new fields are added to the roster XML structure in a future standard,
|
|
|
|
;; they will be clobbered by this function.
|
2007-02-05 21:59:02 +00:00
|
|
|
;; XXX: specify account
|
2009-04-10 21:20:21 +00:00
|
|
|
(jabber-send-iq jc nil "set"
|
2004-03-02 13:08:25 +00:00
|
|
|
(list 'query (list (cons 'xmlns "jabber:iq:roster"))
|
2010-01-22 21:25:18 +00:00
|
|
|
(append
|
|
|
|
(list 'item (append
|
2004-03-02 13:08:25 +00:00
|
|
|
(list (cons 'jid (symbol-name jid)))
|
|
|
|
(if (and name (> (length name) 0))
|
2010-01-22 21:25:18 +00:00
|
|
|
(list (cons 'name name)))))
|
|
|
|
(mapcar #'(lambda (x) `(group () ,x))
|
2009-04-10 21:20:21 +00:00
|
|
|
groups)))
|
2004-03-02 13:08:25 +00:00
|
|
|
#'jabber-report-success "Roster item change"
|
|
|
|
#'jabber-report-success "Roster item change"))
|
|
|
|
|
|
|
|
(add-to-list 'jabber-jid-roster-menu
|
|
|
|
(cons "Delete roster entry" 'jabber-roster-delete))
|
2007-02-05 21:59:02 +00:00
|
|
|
(defun jabber-roster-delete (jc jid)
|
|
|
|
(interactive (list (jabber-read-account)
|
|
|
|
(jabber-read-jid-completing "Delete from roster: ")))
|
|
|
|
(jabber-send-iq jc nil "set"
|
2004-03-02 13:08:25 +00:00
|
|
|
`(query ((xmlns . "jabber:iq:roster"))
|
|
|
|
(item ((jid . ,jid)
|
|
|
|
(subscription . "remove"))))
|
|
|
|
#'jabber-report-success "Roster item removal"
|
|
|
|
#'jabber-report-success "Roster item removal"))
|
|
|
|
|
2004-10-03 19:53:54 +00:00
|
|
|
(defun jabber-roster-delete-jid-at-point ()
|
|
|
|
"Delete JID at point from roster.
|
|
|
|
Signal an error if there is no JID at point."
|
|
|
|
(interactive)
|
|
|
|
(let ((jid-at-point (get-text-property (point)
|
2007-02-05 21:59:02 +00:00
|
|
|
'jabber-jid))
|
|
|
|
(account (get-text-property (point) 'jabber-account)))
|
|
|
|
(if (and jid-at-point account
|
2010-01-14 23:55:32 +00:00
|
|
|
(or jabber-silent-mode (yes-or-no-p (format "Really delete %s from roster? " jid-at-point))))
|
2007-02-05 21:59:02 +00:00
|
|
|
(jabber-roster-delete account jid-at-point)
|
2004-10-03 19:53:54 +00:00
|
|
|
(error "No contact at point"))))
|
|
|
|
|
2009-04-16 21:45:59 +00:00
|
|
|
(defun jabber-roster-delete-group-from-jids (jc jids group)
|
|
|
|
"Delete group `group' from all JIDs"
|
|
|
|
(interactive)
|
|
|
|
(dolist (jid jids)
|
|
|
|
(jabber-roster-change
|
|
|
|
jc jid (get jid 'name)
|
|
|
|
(remove-if-not (lambda (g) (not (string= g group)))
|
|
|
|
(get jid 'groups)))))
|
|
|
|
|
2009-04-16 22:02:55 +00:00
|
|
|
(defun jabber-roster-edit-group-from-jids (jc jids group)
|
|
|
|
"Edit group `group' from all JIDs"
|
|
|
|
(interactive)
|
|
|
|
(let ((new-group
|
|
|
|
(jabber-read-with-input-method
|
|
|
|
(format "New group: (default `%s') " group) nil nil group)))
|
|
|
|
(dolist (jid jids)
|
|
|
|
(jabber-roster-change
|
|
|
|
jc jid (get jid 'name)
|
|
|
|
(remove-duplicates
|
|
|
|
(mapcar
|
|
|
|
(lambda (g) (if (string= g group)
|
|
|
|
new-group
|
|
|
|
g))
|
|
|
|
(get jid 'groups))
|
|
|
|
:test 'string=)))))
|
|
|
|
|
2009-04-16 21:45:59 +00:00
|
|
|
|
2004-02-25 21:42:02 +00:00
|
|
|
(provide 'jabber-presence)
|
2004-04-15 23:15:21 +00:00
|
|
|
|
|
|
|
;;; arch-tag: b8616d4c-dde8-423e-86c7-da7b4928afc3
|