Mercurial > pidgin.yaz
comparison libpurple/protocols/jabber/presence.c @ 26528:882748e27f9d
propagate from branch 'im.pidgin.pidgin' (head 58b2ba106e563fcd0984b9438aa427f1d61e25e9)
to branch 'im.pidgin.cpw.darkrain42.xmpp.bosh' (head 66b3abfbbc6c37e976677819dd23987db9d3b083)
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Sat, 04 Apr 2009 03:15:59 +0000 |
parents | ff4212a5268f 592b88eae0d5 |
children | 20743d9bd62d |
comparison
equal
deleted
inserted
replaced
26515:c08719989149 | 26528:882748e27f9d |
---|---|
91 } | 91 } |
92 } | 92 } |
93 g_free(my_base_jid); | 93 g_free(my_base_jid); |
94 } | 94 } |
95 | 95 |
96 | 96 void jabber_set_status(PurpleAccount *account, PurpleStatus *status) |
97 void jabber_presence_send(PurpleAccount *account, PurpleStatus *status) | 97 { |
98 { | 98 PurpleConnection *gc; |
99 PurpleConnection *gc = NULL; | 99 JabberStream *js; |
100 JabberStream *js = NULL; | 100 |
101 if (!purple_account_is_connected(account)) | |
102 return; | |
103 | |
104 if (!purple_status_is_active(status)) | |
105 return; | |
106 | |
107 if (purple_status_is_exclusive(status) && !purple_status_is_active(status)) { | |
108 /* An exclusive status can't be deactivated. You should just | |
109 * activate some other exclusive status. */ | |
110 return; | |
111 } | |
112 | |
113 gc = purple_account_get_connection(account); | |
114 js = purple_connection_get_protocol_data(gc); | |
115 jabber_presence_send(js, FALSE); | |
116 } | |
117 | |
118 void jabber_presence_send(JabberStream *js, gboolean force) | |
119 { | |
120 PurpleAccount *account; | |
101 xmlnode *presence, *x, *photo; | 121 xmlnode *presence, *x, *photo; |
102 char *stripped = NULL; | 122 char *stripped = NULL; |
103 JabberBuddyState state; | 123 JabberBuddyState state; |
104 int priority; | 124 int priority; |
105 const char *artist = NULL, *title = NULL, *source = NULL, *uri = NULL, *track = NULL; | 125 const char *artist = NULL, *title = NULL, *source = NULL, *uri = NULL, *track = NULL; |
106 int length = -1; | 126 int length = -1; |
107 gboolean allowBuzz; | 127 gboolean allowBuzz; |
108 PurplePresence *p; | 128 PurplePresence *p; |
109 PurpleStatus *tune; | 129 PurpleStatus *status, *tune; |
110 | 130 |
111 if (purple_account_is_disconnected(account)) | 131 account = purple_connection_get_account(js->gc); |
112 return; | |
113 | |
114 p = purple_account_get_presence(account); | 132 p = purple_account_get_presence(account); |
115 if (NULL == status) { | 133 status = purple_presence_get_active_status(p); |
116 status = purple_presence_get_active_status(p); | |
117 } | |
118 | |
119 if (purple_status_is_exclusive(status)) { | |
120 /* An exclusive status can't be deactivated. You should just | |
121 * activate some other exclusive status. */ | |
122 if (!purple_status_is_active(status)) | |
123 return; | |
124 } else { | |
125 /* Work with the exclusive status. */ | |
126 status = purple_presence_get_active_status(p); | |
127 } | |
128 | |
129 gc = purple_account_get_connection(account); | |
130 js = gc->proto_data; | |
131 | 134 |
132 /* we don't want to send presence before we've gotten our roster */ | 135 /* we don't want to send presence before we've gotten our roster */ |
133 if(!js->roster_parsed) { | 136 if(!js->roster_parsed) { |
134 purple_debug_info("jabber", "attempt to send presence before roster retrieved\n"); | 137 purple_debug_info("jabber", "attempt to send presence before roster retrieved\n"); |
135 return; | 138 return; |
139 | 142 |
140 /* check for buzz support */ | 143 /* check for buzz support */ |
141 allowBuzz = purple_status_get_attr_boolean(status,"buzz"); | 144 allowBuzz = purple_status_get_attr_boolean(status,"buzz"); |
142 /* changing the buzz state has to trigger a re-broadcasting of the presence for caps */ | 145 /* changing the buzz state has to trigger a re-broadcasting of the presence for caps */ |
143 | 146 |
144 if (js->googletalk && stripped == NULL && purple_presence_is_status_primitive_active(p, PURPLE_STATUS_TUNE)) { | 147 tune = purple_presence_get_status(p, "tune"); |
145 tune = purple_presence_get_status(p, "tune"); | 148 if (js->googletalk && !stripped && purple_status_is_active(tune)) { |
146 stripped = jabber_google_presence_outgoing(tune); | 149 stripped = jabber_google_presence_outgoing(tune); |
147 } | 150 } |
148 | 151 |
149 #define CHANGED(a,b) ((!a && b) || (a && a[0] == '\0' && b && b[0] != '\0') || \ | 152 #define CHANGED(a,b) ((!a && b) || (a && a[0] == '\0' && b && b[0] != '\0') || \ |
150 (a && !b) || (a && a[0] != '\0' && b && b[0] == '\0') || (a && b && strcmp(a,b))) | 153 (a && !b) || (a && a[0] != '\0' && b && b[0] == '\0') || (a && b && strcmp(a,b))) |
151 /* check if there are any differences to the <presence> and send them in that case */ | 154 /* check if there are any differences to the <presence> and send them in that case */ |
152 if (allowBuzz != js->allowBuzz || js->old_state != state || CHANGED(js->old_msg, stripped) || | 155 if (force || allowBuzz != js->allowBuzz || js->old_state != state || |
153 js->old_priority != priority || CHANGED(js->old_avatarhash, js->avatar_hash)) { | 156 CHANGED(js->old_msg, stripped) || js->old_priority != priority || |
157 CHANGED(js->old_avatarhash, js->avatar_hash)) { | |
158 /* Need to update allowBuzz before creating the presence (with caps) */ | |
154 js->allowBuzz = allowBuzz; | 159 js->allowBuzz = allowBuzz; |
155 | 160 |
156 presence = jabber_presence_create_js(js, state, stripped, priority); | 161 presence = jabber_presence_create_js(js, state, stripped, priority); |
157 | 162 |
158 if(js->avatar_hash) { | 163 if(js->avatar_hash) { |
179 js->old_priority = priority; | 184 js->old_priority = priority; |
180 } | 185 } |
181 g_free(stripped); | 186 g_free(stripped); |
182 | 187 |
183 /* next, check if there are any changes to the tune values */ | 188 /* next, check if there are any changes to the tune values */ |
184 tune = purple_presence_get_status(p, "tune"); | 189 if (purple_status_is_active(tune)) { |
185 if (tune && purple_status_is_active(tune)) { | |
186 artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST); | 190 artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST); |
187 title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); | 191 title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); |
188 source = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM); | 192 source = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM); |
189 uri = purple_status_get_attr_string(tune, PURPLE_TUNE_URL); | 193 uri = purple_status_get_attr_string(tune, PURPLE_TUNE_URL); |
190 track = purple_status_get_attr_string(tune, PURPLE_TUNE_TRACK); | 194 track = purple_status_get_attr_string(tune, PURPLE_TUNE_TRACK); |
258 xmlnode_insert_data(pri, pstr, -1); | 262 xmlnode_insert_data(pri, pstr, -1); |
259 g_free(pstr); | 263 g_free(pstr); |
260 } | 264 } |
261 | 265 |
262 /* JEP-0115 */ | 266 /* JEP-0115 */ |
267 /* calculate hash */ | |
268 jabber_caps_calculate_own_hash(js); | |
269 /* create xml */ | |
263 c = xmlnode_new_child(presence, "c"); | 270 c = xmlnode_new_child(presence, "c"); |
264 xmlnode_set_namespace(c, "http://jabber.org/protocol/caps"); | 271 xmlnode_set_namespace(c, "http://jabber.org/protocol/caps"); |
265 xmlnode_set_attrib(c, "node", CAPS0115_NODE); | 272 xmlnode_set_attrib(c, "node", CAPS0115_NODE); |
266 xmlnode_set_attrib(c, "ver", VERSION); | 273 xmlnode_set_attrib(c, "hash", "sha-1"); |
267 #ifdef USE_VV | 274 xmlnode_set_attrib(c, "ver", jabber_caps_get_own_hash(js)); |
268 /* Make sure this is 'voice-v1', or you won't be able to talk to Google Talk */ | |
269 xmlnode_set_attrib(c, "ext", "voice-v1"); | |
270 #endif | |
271 | |
272 if(js != NULL) { | |
273 /* add the extensions */ | |
274 char extlist[1024]; | |
275 unsigned remaining = 1023; /* one less for the \0 */ | |
276 GList *feature; | |
277 | |
278 extlist[0] = '\0'; | |
279 for(feature = jabber_features; feature && remaining > 0; feature = feature->next) { | |
280 JabberFeature *feat = (JabberFeature*)feature->data; | |
281 unsigned featlen; | |
282 | |
283 if(feat->is_enabled != NULL && feat->is_enabled(js, feat->shortname, feat->namespace) == FALSE) | |
284 continue; /* skip this feature */ | |
285 | |
286 featlen = strlen(feat->shortname); | |
287 | |
288 /* cut off when we don't have any more space left in our buffer (too bad) */ | |
289 if(featlen > remaining) | |
290 break; | |
291 | |
292 strncat(extlist,feat->shortname,remaining); | |
293 remaining -= featlen; | |
294 if(feature->next) { /* no space at the end */ | |
295 strncat(extlist," ",remaining); | |
296 --remaining; | |
297 } | |
298 } | |
299 /* did we add anything? */ | |
300 if(remaining < 1023) | |
301 xmlnode_set_attrib(c, "ext", extlist); | |
302 } | |
303 | 275 |
304 return presence; | 276 return presence; |
305 } | 277 } |
306 | 278 |
307 struct _jabber_add_permit { | 279 struct _jabber_add_permit { |
367 JabberStream *js; | 339 JabberStream *js; |
368 JabberBuddy *jb; | 340 JabberBuddy *jb; |
369 char *from; | 341 char *from; |
370 } JabberPresenceCapabilities; | 342 } JabberPresenceCapabilities; |
371 | 343 |
372 static void jabber_presence_set_capabilities(JabberCapsClientInfo *info, gpointer user_data) { | 344 static void |
373 JabberPresenceCapabilities *userdata = user_data; | 345 jabber_presence_set_capabilities(JabberCapsClientInfo *info, GList *exts, |
374 JabberID *jid; | 346 JabberPresenceCapabilities *userdata) |
347 { | |
375 JabberBuddyResource *jbr; | 348 JabberBuddyResource *jbr; |
376 GList *iter; | 349 char *resource = g_utf8_strrchr(userdata->from, -1, '/'); |
377 | 350 resource += 1; |
378 jid = jabber_id_new(userdata->from); | 351 |
379 jbr = jabber_buddy_find_resource(userdata->jb, jid->resource); | 352 jbr = jabber_buddy_find_resource(userdata->jb, resource); |
380 jabber_id_free(jid); | 353 if (!jbr) { |
381 | |
382 if(!jbr) { | |
383 g_free(userdata->from); | 354 g_free(userdata->from); |
384 g_free(userdata); | 355 g_free(userdata); |
385 return; | 356 if (exts) { |
386 } | 357 g_list_foreach(exts, (GFunc)g_free, NULL); |
387 | 358 g_list_free(exts); |
388 if(jbr->caps) | 359 } |
389 jabber_caps_free_clientinfo(jbr->caps); | 360 return; |
390 jbr->caps = info; | 361 } |
391 | 362 |
392 if (info) { | 363 /* Any old jbr->caps.info is owned by the caps code */ |
393 for(iter = info->features; iter; iter = g_list_next(iter)) { | 364 if (jbr->caps.exts) { |
394 if(!strcmp((const char*)iter->data, "http://jabber.org/protocol/commands")) { | 365 g_list_foreach(jbr->caps.exts, (GFunc)g_free, NULL); |
395 JabberIq *iq = jabber_iq_new_query(userdata->js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#items"); | 366 g_list_free(jbr->caps.exts); |
396 xmlnode *query = xmlnode_get_child_with_namespace(iq->node,"query","http://jabber.org/protocol/disco#items"); | 367 } |
397 xmlnode_set_attrib(iq->node, "to", userdata->from); | 368 |
398 xmlnode_set_attrib(query, "node", "http://jabber.org/protocol/commands"); | 369 jbr->caps.info = info; |
399 | 370 jbr->caps.exts = exts; |
400 jabber_iq_set_callback(iq, jabber_adhoc_disco_result_cb, NULL); | 371 |
401 jabber_iq_send(iq); | 372 if (jabber_resource_has_capability(jbr, "http://jabber.org/protocol/commands")) { |
402 break; | 373 JabberIq *iq = jabber_iq_new_query(userdata->js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#items"); |
403 } | 374 xmlnode *query = xmlnode_get_child_with_namespace(iq->node, "query", "http://jabber.org/protocol/disco#items"); |
404 } | 375 xmlnode_set_attrib(iq->node, "to", userdata->from); |
376 xmlnode_set_attrib(query, "node", "http://jabber.org/protocol/commands"); | |
377 jabber_iq_set_callback(iq, jabber_adhoc_disco_result_cb, NULL); | |
378 jabber_iq_send(iq); | |
405 } | 379 } |
406 | 380 |
407 g_free(userdata->from); | 381 g_free(userdata->from); |
408 g_free(userdata); | 382 g_free(userdata); |
409 } | 383 } |
744 | 718 |
745 } else { | 719 } else { |
746 jbr = jabber_buddy_track_resource(jb, jid->resource, priority, | 720 jbr = jabber_buddy_track_resource(jb, jid->resource, priority, |
747 state, status); | 721 state, status); |
748 if(caps) { | 722 if(caps) { |
723 /* handle XEP-0115 */ | |
749 const char *node = xmlnode_get_attrib(caps,"node"); | 724 const char *node = xmlnode_get_attrib(caps,"node"); |
750 const char *ver = xmlnode_get_attrib(caps,"ver"); | 725 const char *ver = xmlnode_get_attrib(caps,"ver"); |
726 const char *hash = xmlnode_get_attrib(caps,"hash"); | |
751 const char *ext = xmlnode_get_attrib(caps,"ext"); | 727 const char *ext = xmlnode_get_attrib(caps,"ext"); |
752 | 728 |
753 if(node && ver) { | 729 /* v1.3 uses: node, ver, and optionally ext. |
730 * v1.5 uses: node, ver, and hash. */ | |
731 if (node && ver) { | |
754 JabberPresenceCapabilities *userdata = g_new0(JabberPresenceCapabilities, 1); | 732 JabberPresenceCapabilities *userdata = g_new0(JabberPresenceCapabilities, 1); |
755 userdata->js = js; | 733 userdata->js = js; |
756 userdata->jb = jb; | 734 userdata->jb = jb; |
757 userdata->from = g_strdup(from); | 735 userdata->from = g_strdup(from); |
758 jabber_caps_get_info(js, from, node, ver, ext, jabber_presence_set_capabilities, userdata); | 736 jabber_caps_get_info(js, from, node, ver, hash, ext, |
737 (jabber_caps_get_info_cb)jabber_presence_set_capabilities, | |
738 userdata); | |
759 } | 739 } |
760 } | 740 } |
761 } | 741 } |
762 | 742 |
763 if((found_jbr = jabber_buddy_find_resource(jb, NULL))) { | 743 if((found_jbr = jabber_buddy_find_resource(jb, NULL))) { |