1 ;; jabber-feature-neg.el - Feature Negotiation by JEP-0020
3 ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net
4 ;; Copyright (C) 2003, 2004 - Magnus Henoch - mange@freemail.hu
6 ;; This file is a part of jabber.el.
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2 of the License, or
11 ;; (at your option) any later version.
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program; if not, write to the Free Software
20 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 (require 'jabber-disco
)
25 (add-to-list 'jabber-advertised-features
"http://jabber.org/protocol/feature-neg")
27 (defun jabber-fn-parse (xml-data type
)
28 "Parse a Feature Negotiation request, return alist representation.
29 XML-DATA should have one child element, <x/>, in the jabber:x:data
32 TYPE is either 'request or 'response.
34 Returned alist has field name as key, and value is a list of offered
36 (let ((x (car (jabber-xml-get-children xml-data
'x
))))
38 (string= (jabber-xml-get-attribute x
'xmlns
) "jabber:x:data"))
39 (jabber-signal-error "modify" 'bad-request
"Malformed Feature Negotiation"))
42 (fields (jabber-xml-get-children x
'field
)))
43 (dolist (field fields
)
44 (let ((var (jabber-xml-get-attribute field
'var
))
45 (value (car (jabber-xml-get-children field
'value
)))
46 (options (jabber-xml-get-children field
'option
)))
51 (mapcar #'(lambda (option)
52 (car (jabber-xml-node-children
53 (car (jabber-xml-get-children
57 (jabber-xml-node-children value
))
59 (error "Incorrect Feature Negotiation type: %s" type
))))
64 (defun jabber-fn-encode (alist type
)
65 "Transform a feature alist into an <x/> node int the jabber:x:data namespace.
66 Note that this is not the reverse of `jabber-fn-parse'.
68 TYPE is either 'request or 'response."
69 (let ((requestp (eq type
'request
)))
70 `(x ((xmlns .
"jabber:x:data")
71 (type .
,(if requestp
"form" "submit")))
72 ,@(mapcar #'(lambda (field)
74 ((type .
"list-single")
79 `(option nil
(value nil
,option
)))
81 (list `(value nil
,(cadr field
))))))
84 (defun jabber-fn-intersection (mine theirs
)
85 "Find values acceptable to both parties.
87 MINE and THEIRS are alists, as returned by `jabber-fn-parse'.
89 An alist is returned, where the keys are the negotiated variables,
90 and the values are lists containing the preferred option. If
91 negotiation is impossible, an error is signalled. The errors are as
92 specified in JEP-0020, and not necessarily the ones of higher-level
95 (let ((vars (mapcar #'car mine
))
96 (their-vars (mapcar #'car theirs
)))
98 ;; are the same variables being negotiated?
99 (sort vars
'string-lessp
)
100 (sort their-vars
'string-lessp
)
101 (let ((mine-but-not-theirs (set-difference vars their-vars
:test
'string
=))
102 (theirs-but-not-mine (set-difference their-vars vars
:test
'string
=)))
103 (when mine-but-not-theirs
104 (jabber-signal-error "modify" 'not-acceptable
(car mine-but-not-theirs
)))
105 (when theirs-but-not-mine
106 (jabber-signal-error "cancel" 'feature-not-implemented
(car theirs-but-not-mine
))))
110 (let ((my-options (cdr (assoc var mine
)))
111 (their-options (cdr (assoc var theirs
))))
112 (let ((common-options (intersection my-options their-options
:test
'string
=)))
114 ;; we have a match; but which one to use?
115 ;; the first one will probably work
117 (cons (list var
(car common-options
))
120 (jabber-signal-error "modify" 'not-acceptable var
)))))
123 (provide 'jabber-feature-neg
)
125 ;;; arch-tag: 65b2cdcc-7a5f-476b-a613-84ec8e590186