clix/avatar.lua

Sat, 24 Jun 2023 09:59:07 +0200

author
Kim Alvefur <zash@zash.se>
date
Sat, 24 Jun 2023 09:59:07 +0200
changeset 170
0d561f921c13
parent 168
75e8ca131178
permissions
-rw-r--r--

clix.adhoc: Move stanza to dataform converter here

Removes the need for verse to have a custom util.dataforms fork only for
this

168
75e8ca131178 Update to handle Prosody module namespacing
Kim Alvefur <zash@zash.se>
parents: 157
diff changeset
1 local b64 = require"prosody.util.encodings".base64.encode;
75e8ca131178 Update to handle Prosody module namespacing
Kim Alvefur <zash@zash.se>
parents: 157
diff changeset
2 local unb64 = require"prosody.util.encodings".base64.decode;
75e8ca131178 Update to handle Prosody module namespacing
Kim Alvefur <zash@zash.se>
parents: 157
diff changeset
3 local st = require "prosody.util.stanza";
75e8ca131178 Update to handle Prosody module namespacing
Kim Alvefur <zash@zash.se>
parents: 157
diff changeset
4 local sha1 = require "prosody.util.hashes".sha1;
157
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
5
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
6 return function(opts, arg)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
7 if opts.short_help then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
8 print("Manage PEP avatars");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
9 return;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
10 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
11
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
12 local subcommands = {};
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
13
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
14 function subcommands.fetch(conn)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
15 local waiting = {[true] = true};
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
16 for _, userjid in ipairs(arg) do
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
17 waiting[userjid] = true;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
18 local userpep = conn.pubsub:service(userjid);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
19 userpep:node("urn:xmpp:avatar:metadata"):items(true, function(result)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
20 local metadata_tag = result:find("{http://jabber.org/protocol/pubsub}pubsub/items/item/{urn:xmpp:avatar:metadata}metadata");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
21 if not metadata_tag or not metadata_tag:get_child("info") then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
22 if result.attr.type == "error" then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
23 conn:error("Got error from %s: %s:%s", userjid, result:get_error());
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
24 else
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
25 conn:error("%s has no avatar", userjid)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
26 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
27 waiting[userjid] = nil;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
28 if next(waiting) == nil then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
29 conn:close();
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
30 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
31 return;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
32 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
33
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
34 for info_tag in metadata_tag:childtags("info") do
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
35 conn:info("Has avatar with type %s", info_tag.attr.type or "?")
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
36 local filename = (opts.output or (userjid .. "_" .. info_tag.attr.id)) .. "." .. (info_tag.attr.type or "/dat"):match("/([^./+]+)");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
37 local output = assert(io.open(filename, "w"));
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
38 waiting[info_tag.attr.id] = true;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
39 conn:debug("Writing to %s", filename);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
40 userpep:node("urn:xmpp:avatar:data"):item(info_tag.attr.id, function(dataresult)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
41 local data = unb64(dataresult:find("{http://jabber.org/protocol/pubsub}pubsub/items/item/{urn:xmpp:avatar:data}data#"));
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
42 if data then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
43 assert(output:write(data));
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
44 assert(output:close());
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
45 conn:info("Avatar of %s written to %s", userjid, filename);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
46 else
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
47 conn:error("Got no data for %s id %s", userjid, info_tag.attr.id);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
48 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
49 waiting[info_tag.attr.id] = nil;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
50 if next(waiting) == nil then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
51 conn:close();
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
52 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
53 end);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
54
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
55 if not opts.all then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
56 break
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
57 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
58 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
59
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
60 waiting[userjid] = nil;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
61 end)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
63 waiting[true] = nil;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
64 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 function subcommands.publish(conn)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
67 local waiting = {meta=true};
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
68 local userpep = conn.pubsub:service(nil);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
69 local metadata_tag = st.stanza("metadata", { xmlns = "urn:xmpp:avatar:metadata" });
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
70 local metadata_node = userpep:node("urn:xmpp:avatar:metadata");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
71 local data_node = userpep:node("urn:xmpp:avatar:data");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
72 local first_h = nil;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
73 local sha1pat = string.rep("%x", #sha1("",true));
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
74
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
75 for _, file in ipairs(arg) do
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
76 local h, width, height, typ = file:match("_("..sha1pat..")_(%d+)x(%d+)%.(%w+)$");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
77 if not h then h, typ = file:match("_("..sha1pat..")%.(%w+)$"); end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
78 if not h then typ = file:match("%.(%w+)$"); end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
79
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
80 local f = assert(io.open(file));
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
81 local data = f:read("*a");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
82 f:close();
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
83 local bytes = string.format("%d", #data);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
84
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
85 if not h then h = sha1(data, true); end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
86 if not first_h then first_h = h; end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
87 if typ == "jpg" then typ = "jpeg"; end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
88
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
89 local data_tag = st.stanza("data", { xmlns = "urn:xmpp:avatar:data" }):text(b64(data));
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
90 waiting[h] = true;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
91 data_node:publish(h, nil, data_tag, function(ok)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
92 waiting[h] = nil;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
93 if next(waiting) == nil then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
94 conn:close();
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
95 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
96
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
97 end);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
98
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
99 metadata_tag:tag("info", {id = h; type = "image/" .. typ; bytes = bytes; width = width; height = height}):up();
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
100 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
101
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
102 metadata_node:publish(first_h, nil, metadata_tag, function(ok)
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
103 waiting.meta = nil;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
104 if next(waiting) == nil then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
105 conn:close();
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
106 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
107 end);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
108
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
109 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
110
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
111 if ((#arg == 0) or opts.help) then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
112 print("Subcommands:");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
113 print(" publish file_HASH_WxH.png");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
114 print(" fetch user@example.com");
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
115 return 0;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
116 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
117 if opts.output and opts.all then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
118 print("Can't download multiple avatars to a single file")
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
119 return 1;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
120 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
121
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
122 local subcommand = table.remove(arg, 1);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
123 local on_connect = subcommands[subcommand];
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
124
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
125 if not on_connect then
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
126 print("No such command: " .. subcommand);
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
127 return 1;
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
128 end
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
129
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
130 return clix_connect(opts, on_connect, {"pubsub"})
aa0f11fb166c clix.avatar: Publish and fetch XEP-0084 Avatars
Kim Alvefur <zash@zash.se>
parents:
diff changeset
131 end

mercurial