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))) {