comparison libpurple/protocols/jabber/useravatar.c @ 26874:76de9455154c

Drop support for XEP-0084 v0.12 and publish a <stop/> instead of deleting the node. It causes problems (see note about ejabberd 2.0.0) and backward-compatibility should be achievable in most cases via vcard-temp:x:update.
author Paul Aurich <paul@darkrain42.org>
date Sun, 03 May 2009 06:45:38 +0000
parents a0e48796defb
children afc3ec89e83b
comparison
equal deleted inserted replaced
26873:5872d1bc546f 26874:76de9455154c
31 31
32 static void update_buddy_metadata(JabberStream *js, const char *from, xmlnode *items); 32 static void update_buddy_metadata(JabberStream *js, const char *from, xmlnode *items);
33 33
34 void jabber_avatar_init(void) 34 void jabber_avatar_init(void)
35 { 35 {
36 jabber_pep_register_handler(NS_AVATAR_0_12_METADATA,
37 update_buddy_metadata);
38
39 jabber_add_feature(NS_AVATAR_1_1_METADATA, 36 jabber_add_feature(NS_AVATAR_1_1_METADATA,
40 jabber_pep_namespace_only_when_pep_enabled_cb); 37 jabber_pep_namespace_only_when_pep_enabled_cb);
41 jabber_add_feature(NS_AVATAR_1_1_DATA, 38 jabber_add_feature(NS_AVATAR_1_1_DATA,
42 jabber_pep_namespace_only_when_pep_enabled_cb); 39 jabber_pep_namespace_only_when_pep_enabled_cb);
43 40
46 } 43 }
47 44
48 static void 45 static void
49 remove_avatar_0_12_nodes(JabberStream *js) 46 remove_avatar_0_12_nodes(JabberStream *js)
50 { 47 {
48 /* Publish an empty avatar according to the XEP-0084 v0.12 semantics */
49 xmlnode *publish, *item, *metadata;
50 /* publish the metadata */
51 publish = xmlnode_new("publish");
52 xmlnode_set_attrib(publish, "node", NS_AVATAR_0_12_METADATA);
53
54 item = xmlnode_new_child(publish, "item");
55 xmlnode_set_attrib(item, "id", "stop");
56
57 metadata = xmlnode_new_child(item, "metadata");
58 xmlnode_set_namespace(metadata, NS_AVATAR_0_12_METADATA);
59
60 xmlnode_new_child(metadata, "stop");
61
62 /* publish */
63 jabber_pep_publish(js, publish);
64
65 /*
66 * This causes ejabberd 2.0.0 to RST our connection unceremoniously,
67 * so disable it for now (we publish a <stop/> to the metadata node
68 * instead.
69 */
70 #if 0
51 jabber_pep_delete_node(js, NS_AVATAR_0_12_METADATA); 71 jabber_pep_delete_node(js, NS_AVATAR_0_12_METADATA);
52 jabber_pep_delete_node(js, NS_AVATAR_0_12_DATA); 72 jabber_pep_delete_node(js, NS_AVATAR_0_12_DATA);
73 #endif
53 } 74 }
54 75
55 void jabber_avatar_set(JabberStream *js, PurpleStoredImage *img) 76 void jabber_avatar_set(JabberStream *js, PurpleStoredImage *img)
56 { 77 {
57 xmlnode *publish, *metadata, *item; 78 xmlnode *publish, *metadata, *item;
58 79
59 if (!js->pep) 80 if (!js->pep)
60 return; 81 return;
61 82
83 /* Hmmm, not sure if this is worth the traffic, but meh */
62 remove_avatar_0_12_nodes(js); 84 remove_avatar_0_12_nodes(js);
63 85
64 if (!img) { 86 if (!img) {
65 publish = xmlnode_new("publish"); 87 publish = xmlnode_new("publish");
66 xmlnode_set_attrib(publish, "node", NS_AVATAR_1_1_METADATA); 88 xmlnode_set_attrib(publish, "node", NS_AVATAR_1_1_METADATA);
167 } 189 }
168 } 190 }
169 } 191 }
170 192
171 static void 193 static void
194 do_got_own_avatar_0_12_cb(JabberStream *js, const char *from, xmlnode *items)
195 {
196 if (items)
197 /* It wasn't an error (i.e. 'item-not-found') */
198 remove_avatar_0_12_nodes(js);
199 }
200
201 static void
172 do_got_own_avatar_cb(JabberStream *js, const char *from, xmlnode *items) 202 do_got_own_avatar_cb(JabberStream *js, const char *from, xmlnode *items)
173 { 203 {
174 xmlnode *item = NULL, *metadata = NULL, *info = NULL; 204 xmlnode *item = NULL, *metadata = NULL, *info = NULL;
175 PurpleAccount *account = purple_connection_get_account(js->gc); 205 PurpleAccount *account = purple_connection_get_account(js->gc);
176 const char *server_hash = NULL; 206 const char *server_hash = NULL;
177 const char *ns; 207
178 208 if (items && (item = xmlnode_get_child(items, "item")) &&
179 if ((item = xmlnode_get_child(items, "item")) &&
180 (metadata = xmlnode_get_child(item, "metadata")) && 209 (metadata = xmlnode_get_child(item, "metadata")) &&
181 (info = xmlnode_get_child(metadata, "info"))) { 210 (info = xmlnode_get_child(metadata, "info"))) {
182 server_hash = xmlnode_get_attrib(info, "id"); 211 server_hash = xmlnode_get_attrib(info, "id");
183 } 212 }
184 213
185 if (!metadata) 214 if (items && !metadata)
186 return; 215 return;
187
188 ns = xmlnode_get_namespace(metadata);
189 if (!ns)
190 return;
191
192 /*
193 * We no longer publish avatars to the older namespace. If there is one
194 * there, delete it.
195 */
196 if (g_str_equal(ns, NS_AVATAR_0_12_METADATA) && server_hash) {
197 remove_avatar_0_12_nodes(js);
198 return;
199 }
200 216
201 /* Publish ours if it's different than the server's */ 217 /* Publish ours if it's different than the server's */
202 if (!purple_strequal(server_hash, js->initial_avatar_hash)) { 218 if (!purple_strequal(server_hash, js->initial_avatar_hash)) {
203 PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account); 219 PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
204 jabber_avatar_set(js, img); 220 jabber_avatar_set(js, img);
208 224
209 void jabber_avatar_fetch_mine(JabberStream *js) 225 void jabber_avatar_fetch_mine(JabberStream *js)
210 { 226 {
211 char *jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); 227 char *jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
212 jabber_pep_request_item(js, jid, NS_AVATAR_0_12_METADATA, NULL, 228 jabber_pep_request_item(js, jid, NS_AVATAR_0_12_METADATA, NULL,
213 do_got_own_avatar_cb); 229 do_got_own_avatar_0_12_cb);
214 jabber_pep_request_item(js, jid, NS_AVATAR_1_1_METADATA, NULL, 230 jabber_pep_request_item(js, jid, NS_AVATAR_1_1_METADATA, NULL,
215 do_got_own_avatar_cb); 231 do_got_own_avatar_cb);
216 g_free(jid); 232 g_free(jid);
217 } 233 }
218 234
245 261
246 static void 262 static void
247 do_buddy_avatar_update_data(JabberStream *js, const char *from, xmlnode *items) 263 do_buddy_avatar_update_data(JabberStream *js, const char *from, xmlnode *items)
248 { 264 {
249 xmlnode *item, *data; 265 xmlnode *item, *data;
250 const char *checksum, *ns; 266 const char *checksum;
251 char *b64data; 267 char *b64data;
252 void *img; 268 void *img;
253 size_t size; 269 size_t size;
254 if(!items) 270 if(!items)
255 return; 271 return;
260 276
261 data = xmlnode_get_child(item, "data"); 277 data = xmlnode_get_child(item, "data");
262 if(!data) 278 if(!data)
263 return; 279 return;
264 280
265 ns = xmlnode_get_namespace(data);
266 /* Make sure the namespace is one of the two valid possibilities */
267 if (!ns || (!g_str_equal(ns, NS_AVATAR_0_12_DATA) &&
268 !g_str_equal(ns, NS_AVATAR_1_1_DATA)))
269 return;
270
271 checksum = xmlnode_get_attrib(item,"id"); 281 checksum = xmlnode_get_attrib(item,"id");
272 if(!checksum) 282 if(!checksum)
273 return; 283 return;
274 284
275 b64data = xmlnode_get_data(data); 285 b64data = xmlnode_get_data(data);
288 298
289 static void 299 static void
290 update_buddy_metadata(JabberStream *js, const char *from, xmlnode *items) 300 update_buddy_metadata(JabberStream *js, const char *from, xmlnode *items)
291 { 301 {
292 PurpleBuddy *buddy = purple_find_buddy(purple_connection_get_account(js->gc), from); 302 PurpleBuddy *buddy = purple_find_buddy(purple_connection_get_account(js->gc), from);
293 const char *checksum, *ns; 303 const char *checksum;
294 xmlnode *item, *metadata; 304 xmlnode *item, *metadata;
295 if(!buddy) 305 if(!buddy)
296 return; 306 return;
297 307
298 if (!items) 308 if (!items)
304 314
305 metadata = xmlnode_get_child(item, "metadata"); 315 metadata = xmlnode_get_child(item, "metadata");
306 if(!metadata) 316 if(!metadata)
307 return; 317 return;
308 318
309 ns = xmlnode_get_namespace(metadata);
310 /* Make sure the namespace is one of the two valid possibilities */
311 if (!ns || (!g_str_equal(ns, NS_AVATAR_0_12_METADATA) &&
312 !g_str_equal(ns, NS_AVATAR_1_1_METADATA)))
313 return;
314
315 checksum = purple_buddy_icons_get_checksum_for_user(buddy); 319 checksum = purple_buddy_icons_get_checksum_for_user(buddy);
316 320
317 /* check if we have received a stop */ 321 /* <stop/> was the pre-v1.1 method of publishing an empty avatar */
318 if(xmlnode_get_child(metadata, "stop")) { 322 if(xmlnode_get_child(metadata, "stop")) {
319 purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL); 323 purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL);
320 } else { 324 } else {
321 xmlnode *info, *goodinfo = NULL; 325 xmlnode *info, *goodinfo = NULL;
322 gboolean has_children = FALSE; 326 gboolean has_children = FALSE;
345 const char *url = xmlnode_get_attrib(goodinfo, "url"); 349 const char *url = xmlnode_get_attrib(goodinfo, "url");
346 const char *id = xmlnode_get_attrib(goodinfo,"id"); 350 const char *id = xmlnode_get_attrib(goodinfo,"id");
347 351
348 /* the avatar might either be stored in a pep node, or on a HTTP(S) URL */ 352 /* the avatar might either be stored in a pep node, or on a HTTP(S) URL */
349 if(!url) { 353 if(!url) {
350 const char *data_ns; 354 jabber_pep_request_item(js, from, NS_AVATAR_1_1_DATA, id,
351 data_ns = (g_str_equal(ns, NS_AVATAR_0_12_METADATA) ?
352 NS_AVATAR_0_12_DATA : NS_AVATAR_1_1_DATA);
353 jabber_pep_request_item(js, from, data_ns, id,
354 do_buddy_avatar_update_data); 355 do_buddy_avatar_update_data);
355 } else { 356 } else {
356 PurpleUtilFetchUrlData *url_data; 357 PurpleUtilFetchUrlData *url_data;
357 JabberBuddyAvatarUpdateURLInfo *info = g_new0(JabberBuddyAvatarUpdateURLInfo, 1); 358 JabberBuddyAvatarUpdateURLInfo *info = g_new0(JabberBuddyAvatarUpdateURLInfo, 1);
358 info->js = js; 359 info->js = js;