xcapclient 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +89 -40
- data/lib/xcapclient/application.rb +23 -25
- data/lib/xcapclient/client.rb +26 -22
- data/lib/xcapclient/document.rb +30 -8
- data/lib/xcapclient/version.rb +2 -2
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= XCAPClient (version 1.
|
1
|
+
= XCAPClient (version 1.4.0)
|
2
2
|
|
3
3
|
* http://dev.sipdoc.net/projects/ruby-xcapclient/wiki/
|
4
4
|
* http://rubyforge.org/projects/xcapclient/
|
@@ -6,9 +6,9 @@
|
|
6
6
|
|
7
7
|
== Description
|
8
8
|
|
9
|
-
XCAP ({RFC 4825}[http://tools.ietf.org/html/rfc4825]) is a protocol on top of HTTP
|
9
|
+
XCAP ({RFC 4825}[http://tools.ietf.org/html/rfc4825]) is a protocol on top of HTTP allowing a client (usually built within a SIP user agent) to manipulate the content of XML documents stored in a server. These documents represent per user buddy list, presence authorization policy, media content (i.e. user avatar) and other kind of features.
|
10
10
|
|
11
|
-
XCAPClient library implements the XCAP protocol in client side, allowing the
|
11
|
+
Ruby XCAPClient library implements the XCAP protocol in client side, allowing the application to get, store, modify and delete XML documents (totally or partially) in the server.
|
12
12
|
|
13
13
|
|
14
14
|
== Features
|
@@ -60,36 +60,55 @@ A developer interested in this library should study the following documents:
|
|
60
60
|
==== Create a client
|
61
61
|
|
62
62
|
xcap_conf = {
|
63
|
-
:xcap_root => "https://xcap.myserver.org
|
63
|
+
:xcap_root => "https://xcap.myserver.org",
|
64
64
|
:user => "sip:me@mydomain.org",
|
65
|
-
:auth_user => "me",
|
66
65
|
:password => "xxxxxx",
|
67
66
|
:ssl_verify_cert => true
|
68
67
|
}
|
69
68
|
|
70
69
|
xcap_apps = {
|
71
|
-
"
|
72
|
-
:xmlns
|
73
|
-
:mime_type
|
74
|
-
:scope => :user,
|
75
|
-
:document_name => "index"
|
70
|
+
"resource-lists" => {
|
71
|
+
:xmlns => "urn:ietf:params:xml:ns:resource-lists",
|
72
|
+
:mime_type => "application/resource-lists+xml"
|
76
73
|
}
|
77
74
|
}
|
78
75
|
|
79
|
-
|
76
|
+
xcapclient = Client.new(xcap_conf, xcap_apps)
|
80
77
|
|
81
78
|
|
82
|
-
====
|
79
|
+
==== Create a XCAPClient::Document with name "index" for "resource-lists" application.
|
83
80
|
|
84
|
-
|
81
|
+
xcapclient.application("resource-lists").add_document("index")
|
85
82
|
|
83
|
+
It's the same as doing:
|
86
84
|
|
87
|
-
|
85
|
+
xcapclient.application("resource-lists").add_document("index", scope=nil, xui=nil)
|
86
|
+
|
87
|
+
As _scope_ is nil it's set to :users. As _xui_ is nil it's a document owned by our user.
|
88
|
+
|
89
|
+
|
90
|
+
==== Fetch the "index" document (auid "resource-lists") from the server
|
91
|
+
|
92
|
+
This works because the document we are interested in is the first one, so it's fetched:
|
93
|
+
|
94
|
+
xcapclient.get("resource-lists")
|
95
|
+
|
96
|
+
It's the same as doing:
|
97
|
+
|
98
|
+
xcapclient.get("resource-lists", "index")
|
99
|
+
|
100
|
+
We can also use a XCAPClient::Document object rather than a String (required when fetching 3rd party documents):
|
101
|
+
|
102
|
+
doc = xcapclient.application("resource-lists").document("index")
|
103
|
+
xcapclient.get("resource-lists", doc)
|
104
|
+
|
105
|
+
|
106
|
+
==== Fetch again the "resource-lists" document (now including the stored ETag)
|
88
107
|
|
89
108
|
By default, the methods accesing the XCAP server include the ETag if it's available. Since it was already got on the previous request, it's included in the new request. If the document has not been modified in the server by other client, the server replies "304 Not Modified" and the method generates a XCAPClient::XCAPClientError::HTTPDocumentNotModified exception.
|
90
109
|
|
91
110
|
begin
|
92
|
-
|
111
|
+
xcapclient.get("resource-lists")
|
93
112
|
rescue XCAPClientError::HTTPDocumentNotModified
|
94
113
|
puts "The document has not been modified in the server."
|
95
114
|
end
|
@@ -97,48 +116,78 @@ By default, the methods accesing the XCAP server include the ETag if it's availa
|
|
97
116
|
|
98
117
|
==== Replace the local document and upload it to the server
|
99
118
|
|
100
|
-
|
101
|
-
|
102
|
-
|
119
|
+
xcapclient.application("resource-lists").document.reset
|
120
|
+
xcapclient.application("resource-lists").document.plain = "<?xml version='1.0' encoding='UTF-8'?> ..."
|
121
|
+
|
122
|
+
xcapclient.put("resource-lists")
|
123
|
+
|
124
|
+
or:
|
125
|
+
|
126
|
+
xcapclient.put("resource-lists", "index")
|
127
|
+
|
128
|
+
or:
|
129
|
+
|
130
|
+
doc = xcapclient.application("resource-lists").document("index")
|
131
|
+
xcapclient.put("resource-lists", doc)
|
103
132
|
|
104
133
|
|
105
134
|
==== Delete the document in the server
|
106
135
|
|
107
|
-
|
136
|
+
xcapclient.delete("resource-lists")
|
137
|
+
|
138
|
+
|
139
|
+
==== Create a new document and upload it (a new "friends" document for "resource-lists" application)
|
140
|
+
|
141
|
+
friends_doc = xcapclient.application("resource-lists").add_document("friends")
|
142
|
+
friends_doc.plain = "<?xml version='1.0' encoding='UTF-8'?> ..."
|
143
|
+
|
144
|
+
xcapclient.put("resource-lists", friends_doc)
|
145
|
+
|
146
|
+
or:
|
147
|
+
|
148
|
+
xcapclient.put("resource-lists", "friends")
|
149
|
+
|
150
|
+
|
151
|
+
==== Fetch a node (with "uri" = "sip:alice@example.org")
|
152
|
+
|
153
|
+
xcapclient.get_node("resource-lists", "index",
|
154
|
+
'rl:resource-lists/rl:list[@name="mybuddies"]/rl:entry[@uri="sip:alice@example.org"]',
|
155
|
+
{"rl" => "urn:ietf:params:xml:ns:resource-lists"})
|
156
|
+
|
157
|
+
or using the application default namespace:
|
158
|
+
|
159
|
+
xcapclient.get_node("resource-lists", "index",
|
160
|
+
'resource-lists/list[@name="mybuddies"]/entry[@uri="sip:alice@example.org"]')
|
161
|
+
|
162
|
+
|
163
|
+
==== Add a new node (a new buddy)
|
108
164
|
|
165
|
+
xcapclient.put_node("resource-lists", "index",
|
166
|
+
'resource-lists/list[@name="mybuddies"]/entry[@uri="sip:bob@example.org"]',
|
167
|
+
'<entry uri="sip:bob@example.org"/>'
|
109
168
|
|
110
|
-
==== Create a new document and upload it (a new "vacation-rules" document for "pres-rules" application)
|
111
169
|
|
112
|
-
|
113
|
-
my_pres_rules_2.plain = "<?xml version='1.0' encoding='UTF-8'?> ..."
|
114
|
-
@xcapclient.put("pres-rules", my_pres_rules_2)
|
115
|
-
# or
|
116
|
-
@xcapclient.put("pres-rules", "vacation-rules")
|
170
|
+
==== Fetch a node attribute (the "uri" attribute of "sip:alice@example.org")
|
117
171
|
|
172
|
+
xcapclient.get_attribute("resource-lists", "index",
|
173
|
+
'resource-lists/list[@name="mybuddies"]/entry[@uri="sip:alice@example.org"]',
|
174
|
+
"uri")
|
118
175
|
|
119
|
-
|
176
|
+
It would return "sip:alice@example.org" as obvious.
|
120
177
|
|
121
|
-
@xcapclient.get_node("pres-rules", nil,
|
122
|
-
'cp:ruleset/cp:rule[@id="pres_whitelist"]/cp:conditions/cp:identity/cp:one[@id="sip:alice@example.org"]',
|
123
|
-
{"cp" => "urn:ietf:params:xml:ns:common-policy"})
|
124
178
|
|
179
|
+
==== Get a 3rd party document owned by a different user (different "xui") within the same XCAP server.
|
125
180
|
|
126
|
-
|
181
|
+
This is useful to implement shared contact lists or when fetching a OMA icon (avatar) of a different user (OMA icon is a XCAP document rather than a pure image).
|
127
182
|
|
128
|
-
|
129
|
-
'cp:ruleset/cp:rule[@id="pres_whitelist"]/cp:conditions/cp:identity/cp:one[@id="sip:bob@example.org"]',
|
130
|
-
'<cp:one id="sip:bob@example.org"/>',
|
131
|
-
{"cp"=>"urn:ietf:params:xml:ns:common-policy"})
|
183
|
+
shared_contact_list_doc = xcapclient.application("resource-lists").add_document("shared_contact_list", :users, "sip:bob@example.org")
|
132
184
|
|
133
|
-
|
185
|
+
In this case it's required to in indicate the document by a XCAPClient::Document object rather than a String:
|
134
186
|
|
135
|
-
|
136
|
-
'cp:ruleset/cp:rule[@id="pres_whitelist"]/cp:conditions/cp:identity/cp:one[@id="sip:alice@example.org"]',
|
137
|
-
"name",
|
138
|
-
{"cp" => "urn:ietf:params:xml:ns:common-policy"})
|
187
|
+
xcapclient.get("resource-lists", shared_contact_list_doc)
|
139
188
|
|
140
189
|
|
141
|
-
==
|
190
|
+
== TODO
|
142
191
|
|
143
192
|
* Parse 409 error response ("application/xcap-error+xml") as it contains the explanation of the conflict ({RFC 4825 section 11}[http://tools.ietf.org/html/rfc4825#section-11]).
|
144
193
|
|
@@ -9,39 +9,35 @@ module XCAPClient
|
|
9
9
|
@auid = auid
|
10
10
|
|
11
11
|
# Check application data.
|
12
|
-
raise ConfigError, "
|
12
|
+
raise ConfigError, "application `data' must be a hash ('#{@auid}')" unless (Hash === data)
|
13
13
|
|
14
14
|
@xmlns = data[:xmlns].freeze
|
15
15
|
@mime_type = data[:mime_type].freeze
|
16
|
-
@document_name = data[:document_name] || "index"
|
17
|
-
@scope = data[:scope] || :user
|
18
|
-
@scope.freeze
|
19
16
|
|
20
17
|
# Check auid.
|
21
|
-
raise ConfigError, "
|
18
|
+
raise ConfigError, "application `auid' must be a non empty string ('#{@auid}')" unless String === @auid && ! @auid.empty?
|
22
19
|
|
23
20
|
# Check xmlns.
|
24
|
-
raise ConfigError, "
|
21
|
+
raise ConfigError, "application `xmlns' must be a non empty string ('#{@auid}')" unless String === @xmlns && ! @xmlns.empty?
|
25
22
|
|
26
23
|
# Check mime-type.
|
27
|
-
raise ConfigError, "
|
24
|
+
raise ConfigError, "application `mime_type' must be a non empty string ('#{@auid}')" unless String === @mime_type && ! @mime_type.empty?
|
28
25
|
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
# Check scope.
|
33
|
-
raise ConfigError, "Application `scope' must be :user or :global ('#{@auid}')" unless [:user, :global].include?(@scope)
|
34
|
-
|
35
|
-
# Create first document.
|
36
|
-
@documents = {}
|
37
|
-
@documents[@document_name] = Document.new(@document_name)
|
26
|
+
# Create the _documents_ Array.
|
27
|
+
@documents = []
|
38
28
|
|
39
29
|
end
|
40
30
|
|
41
|
-
# Get the XCAPClient::Document with name
|
42
|
-
#
|
43
|
-
|
44
|
-
|
31
|
+
# Get the XCAPClient::Document with name _name_, scope _scope_ (:users or :global) belonging to user _xui_.
|
32
|
+
# If _name_ is nil then the first available document is fetched (careful).
|
33
|
+
# If _scope_ is not set then it's :users by default. If _xui_ is nil then it's a document owned by us.
|
34
|
+
def document(name=nil, scope=nil, xui=nil)
|
35
|
+
scope = :users unless scope
|
36
|
+
if name
|
37
|
+
@documents.find { |doc| doc.name == name and doc.scope == scope and doc.xui == xui }
|
38
|
+
else
|
39
|
+
@documents.first
|
40
|
+
end
|
45
41
|
end
|
46
42
|
|
47
43
|
# Get an Array containing all the documents created for this application.
|
@@ -49,12 +45,14 @@ module XCAPClient
|
|
49
45
|
@documents
|
50
46
|
end
|
51
47
|
|
52
|
-
# Creates a new XCAPClient::Document for this application with name _document_name_.
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
# Creates a new XCAPClient::Document for this application with name _document_name_, scope _scope_ and xui _xui_.
|
49
|
+
# _scope_ can be :users (default) or :global Symbol. If _xui_ is nil then the documents belongs to our user.
|
50
|
+
def add_document(name, scope=nil, xui=nil)
|
51
|
+
scope = :users unless scope
|
52
|
+
raise DocumentError, "document '#{name}' with scope '#{scope} and xui '#{xui}' already exists" if document(name, scope, xui)
|
53
|
+
@documents << document = Document.new(name, scope, xui)
|
56
54
|
|
57
|
-
return
|
55
|
+
return document
|
58
56
|
end
|
59
57
|
|
60
58
|
end
|
data/lib/xcapclient/client.rb
CHANGED
@@ -42,7 +42,6 @@ module XCAPClient
|
|
42
42
|
"User-Agent" => "#{USER_AGENT}/#{VERSION}",
|
43
43
|
"Connection" => "close"
|
44
44
|
}
|
45
|
-
GLOBAL_XUI = "global"
|
46
45
|
XCAP_CAPS_XMLNS = "urn:ietf:params:xml:ns:xcap-caps"
|
47
46
|
HTTP_TIMEOUT = 6
|
48
47
|
CONF_PARAMETERS = [:xcap_root, :user, :auth_user, :password, :identity_header, :identity_user, :ssl_verify_cert]
|
@@ -63,10 +62,6 @@ module XCAPClient
|
|
63
62
|
#
|
64
63
|
# * _applications_: A hash of hashes containing each XCAP application available for the client. Each application is an entry of the hash containing a key whose value is the "auid" of the application and whose value is a hast with the following fields:
|
65
64
|
# * _xmlns_: The XML namespace uri of the application.
|
66
|
-
# * _document_name_: The name of the default document for this application ("index" if not set).
|
67
|
-
# * _scope_: Can be :user or :global (:user if not set).
|
68
|
-
# * _:user_: Each user has his own document(s) for this application.
|
69
|
-
# * _:global_: The document(s) is shared for all the users.
|
70
65
|
#
|
71
66
|
# Example:
|
72
67
|
# xcap_conf = {
|
@@ -79,15 +74,11 @@ module XCAPClient
|
|
79
74
|
# xcap_apps = {
|
80
75
|
# "pres-rules" => {
|
81
76
|
# :xmlns => "urn:ietf:params:xml:ns:pres-rules",
|
82
|
-
# :mime_type => "application/auth-policy+xml"
|
83
|
-
# :document_name => "index",
|
84
|
-
# :scope => :user
|
77
|
+
# :mime_type => "application/auth-policy+xml"
|
85
78
|
# },
|
86
79
|
# "rls-services" => {
|
87
80
|
# :xmlns => "urn:ietf:params:xml:ns:rls-services",
|
88
|
-
# :mime_type => "application/rls-services+xml"
|
89
|
-
# :document_name => "index",
|
90
|
-
# :scope => :user
|
81
|
+
# :mime_type => "application/rls-services+xml"
|
91
82
|
# }
|
92
83
|
# }
|
93
84
|
#
|
@@ -103,7 +94,8 @@ module XCAPClient
|
|
103
94
|
# :ssl_verify_cert => true
|
104
95
|
# }
|
105
96
|
#
|
106
|
-
# A XCAP application called "xcap-caps" is automatically added to the list of applications of the new client. This
|
97
|
+
# A XCAP application called "xcap-caps" is automatically added to the list of applications of the new client. This
|
98
|
+
# application is defined in the {RFC 4825}[http://tools.ietf.org/html/rfc4825].
|
107
99
|
#
|
108
100
|
def initialize(conf={}, applications={})
|
109
101
|
|
@@ -150,13 +142,12 @@ module XCAPClient
|
|
150
142
|
# Generate applications.
|
151
143
|
@applications = {}
|
152
144
|
|
153
|
-
# Add the "xcap-caps" application.
|
145
|
+
# Add the "xcap-caps" application with a document "index".
|
154
146
|
@applications["xcap-caps"] = Application.new("xcap-caps", {
|
155
147
|
:xmlns => "urn:ietf:params:xml:ns:xcap-caps",
|
156
|
-
:mime_type => "application/xcap-caps+xml"
|
157
|
-
:scope => :global,
|
158
|
-
:document_name => "index"
|
148
|
+
:mime_type => "application/xcap-caps+xml"
|
159
149
|
})
|
150
|
+
@applications["xcap-caps"].add_document("index", :global)
|
160
151
|
|
161
152
|
# Add custom applications.
|
162
153
|
applications.each do |auid, data|
|
@@ -556,6 +547,9 @@ module XCAPClient
|
|
556
547
|
raise WrongAUID, "There is no application with auid '#{auid}'" unless application
|
557
548
|
|
558
549
|
# Get the document.
|
550
|
+
# NOTE: If _document_ is a String then it's supposed to be a document owned by our user with scope :users.
|
551
|
+
# NOTE: If _document_ is a Document then it can be whatever document.
|
552
|
+
# NOTE: If _document_ is nil then the first document is used (careful).
|
559
553
|
case document
|
560
554
|
when Document
|
561
555
|
when String
|
@@ -563,11 +557,13 @@ module XCAPClient
|
|
563
557
|
document = application.document(document_name)
|
564
558
|
raise DocumentError, "document '#{document_name}' doesn't exist in application '#{auid}'" unless document
|
565
559
|
when NilClass
|
566
|
-
document = application.
|
560
|
+
document = application.documents.first
|
567
561
|
else
|
568
562
|
raise ArgumentError, "`document' must be Document, String or nil"
|
569
563
|
end
|
570
564
|
|
565
|
+
raise ArgumentError, "no document provided" unless document
|
566
|
+
|
571
567
|
return [application, document]
|
572
568
|
|
573
569
|
end
|
@@ -609,15 +605,23 @@ module XCAPClient
|
|
609
605
|
extra_headers["Content-Type"] = content_type if content_type
|
610
606
|
|
611
607
|
# XUI.
|
612
|
-
xui =
|
613
|
-
|
614
|
-
|
608
|
+
xui = document.xui ? document.xui : @user
|
609
|
+
|
610
|
+
# scope/XUI.
|
611
|
+
scope_xui = case document.scope
|
612
|
+
when :users
|
613
|
+
"users/#{xui}"
|
615
614
|
when :global
|
616
|
-
|
615
|
+
"global"
|
617
616
|
end
|
618
617
|
|
619
618
|
# URI.
|
620
|
-
uri =
|
619
|
+
uri = case document.scope
|
620
|
+
when :users
|
621
|
+
"#{@xcap_root}/#{application.auid}/users/#{xui}/#{percent_encode(document.name)}"
|
622
|
+
when :global
|
623
|
+
"#{@xcap_root}/#{application.auid}/global/#{percent_encode(document.name)}"
|
624
|
+
end
|
621
625
|
uri += "/~~/#{percent_encode(selector)}" if selector
|
622
626
|
uri += get_xmlns_query(xml_namespaces) if xml_namespaces
|
623
627
|
|
data/lib/xcapclient/document.rb
CHANGED
@@ -5,6 +5,12 @@ module XCAPClient
|
|
5
5
|
# The name of the document as it exists in the server.
|
6
6
|
attr_reader :name
|
7
7
|
|
8
|
+
# The scope of this document (:users or :global).
|
9
|
+
attr_reader :scope
|
10
|
+
|
11
|
+
# The XUI this document belongs to. This allow fetching a document owner by other user (for example a icon).
|
12
|
+
attr_reader :xui
|
13
|
+
|
8
14
|
# Contains the plain document fetched from the server or manually set.
|
9
15
|
attr_accessor :plain
|
10
16
|
|
@@ -17,15 +23,31 @@ module XCAPClient
|
|
17
23
|
# The last response received from the server. It's a HTTP::Message[http://dev.ctor.org/doc/httpclient/] object.
|
18
24
|
attr_accessor :last_response
|
19
25
|
|
20
|
-
#
|
21
|
-
|
26
|
+
# Convenient field to indicate that the document has been modified locally but it hasn't been commited
|
27
|
+
# yet to the server (true then).
|
28
|
+
# This field must be set manually by the application if it wants to use it (for example after giving a new
|
29
|
+
# value to @plain or after modifyng @parsed).
|
30
|
+
attr_accessor :local_modified
|
31
|
+
|
32
|
+
# Convenient field to indicate that the document has been modified in the server but it hasn't been fetched
|
33
|
+
# so the local copy isn't up-to-date (true then).
|
34
|
+
# This field must be set manually by the application if it wants to use it (for example after the SIP UA receives
|
35
|
+
# a NOTIFY indicating that this document has been modified in the server).
|
36
|
+
attr_accessor :server_modified
|
37
|
+
|
38
|
+
# Create a new instance. _name_ and _xui_ are String. _scope_ can be :users (default) or :group Symbol. _xui_ is the user
|
39
|
+
# owning the document, if it's nil then is a document owned by our user.
|
40
|
+
def initialize(name, scope=nil, xui=nil)
|
41
|
+
scope = :users unless scope
|
22
42
|
@name = name
|
23
|
-
@
|
24
|
-
@
|
25
|
-
@etag = etag
|
43
|
+
@scope = scope
|
44
|
+
@xui = xui
|
26
45
|
|
27
46
|
# Check name.
|
28
|
-
raise ConfigError, "
|
47
|
+
raise ConfigError, "document `name' must be a non empty string" unless String === @name && ! @name.empty?
|
48
|
+
|
49
|
+
# Check scope.
|
50
|
+
raise ConfigError, "document `scope' must be :users or _global" unless @scope == :users or @scope == :global
|
29
51
|
end
|
30
52
|
|
31
53
|
# Delete the local plain and parsed document and the ETag.
|
@@ -39,7 +61,7 @@ module XCAPClient
|
|
39
61
|
# Parse the plain XML document using Nokogiri and store it into @parsed attribute.
|
40
62
|
# NOTE: This method is just available if Nokogiri is installed.
|
41
63
|
def parse
|
42
|
-
raise DocumentError, "
|
64
|
+
raise DocumentError, "cannot parse the document as the plain document doesn't exist" unless @plain
|
43
65
|
begin
|
44
66
|
@parsed = ::Nokogiri::XML::Document.parse(@plain, nil, "UTF-8", PARSE_OPTIONS)
|
45
67
|
rescue ::Nokogiri::SyntaxError => e
|
@@ -50,4 +72,4 @@ module XCAPClient
|
|
50
72
|
|
51
73
|
end
|
52
74
|
|
53
|
-
end
|
75
|
+
end
|
data/lib/xcapclient/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xcapclient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "I\xC3\xB1aki Baz Castillo"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-12 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
-
description:
|
25
|
+
description: XCAP (RFC 4825) is a protocol on top of HTTP allowing a client (usually built within a SIP user agent) to manipulate the content of XML documents stored in a server. These documents represent per user buddy list, presence authorization policy, media content (i.e. user avatar) and other kind of features.Ruby XCAPClient library implements the XCAP protocol in client side, allowing the application to get, store, modify and delete XML documents (totally or partially) in the server.
|
26
26
|
email: ibc@aliax.net
|
27
27
|
executables: []
|
28
28
|
|