Mercurial > pidgin
annotate src/protocols/jabber/presence.c @ 13967:99b9b58b19dd
[gaim-migrate @ 16523]
Fix a crazy MSN crash. Basically it's possible to have more than one
slplink associated with a given switchboard, but our code did not
allow for that. I think it happens when you're in a multi-user
chat and you do stuff with multiple users that involves slplinks.
Like maybe file transfer and buddy icon related stuff.
Tracking this down took an ungodly amount of time, but thanks to
Meebo for letting me do it :-)
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 20 Jul 2006 07:31:15 +0000 |
parents | 2bac009eaa0c |
children | 6fc412e59214 |
rev | line source |
---|---|
7014 | 1 /* |
2 * gaim - Jabber Protocol Plugin | |
3 * | |
4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 */ | |
21 #include "internal.h" | |
22 | |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10646
diff
changeset
|
23 #include "cipher.h" |
7014 | 24 #include "debug.h" |
25 #include "notify.h" | |
26 #include "request.h" | |
27 #include "server.h" | |
9954 | 28 #include "status.h" |
7095
c8bf2da398e3
[gaim-migrate @ 7660]
Christian Hammond <chipx86@chipx86.com>
parents:
7015
diff
changeset
|
29 #include "util.h" |
7014 | 30 |
31 #include "buddy.h" | |
32 #include "chat.h" | |
33 #include "presence.h" | |
34 #include "iq.h" | |
35 #include "jutil.h" | |
36 #include "xmlnode.h" | |
37 | |
38 | |
39 static void chats_send_presence_foreach(gpointer key, gpointer val, | |
40 gpointer user_data) | |
41 { | |
42 JabberChat *chat = val; | |
43 xmlnode *presence = user_data; | |
8577 | 44 char *chat_full_jid; |
45 | |
46 if(!chat->conv) | |
47 return; | |
48 | |
49 chat_full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, | |
8401 | 50 chat->handle); |
7014 | 51 |
8401 | 52 xmlnode_set_attrib(presence, "to", chat_full_jid); |
7014 | 53 jabber_send(chat->js, presence); |
8401 | 54 g_free(chat_full_jid); |
7014 | 55 } |
56 | |
9954 | 57 void jabber_presence_fake_to_self(JabberStream *js, const GaimStatus *gstatus) { |
10286 | 58 char *my_base_jid; |
59 | |
60 if(!js->user) | |
61 return; | |
62 | |
63 my_base_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); | |
8185 | 64 if(gaim_find_buddy(js->gc->account, my_base_jid)) { |
65 JabberBuddy *jb; | |
66 JabberBuddyResource *jbr; | |
67 if((jb = jabber_buddy_find(js, my_base_jid, TRUE))) { | |
9954 | 68 JabberBuddyState state; |
69 const char *msg; | |
70 int priority; | |
71 | |
72 gaim_status_to_jabber(gstatus, &state, &msg, &priority); | |
73 | |
10490 | 74 if (state == JABBER_BUDDY_STATE_UNAVAILABLE || state == JABBER_BUDDY_STATE_UNKNOWN) { |
9744 | 75 jabber_buddy_remove_resource(jb, js->user->resource); |
76 } else { | |
9954 | 77 jabber_buddy_track_resource(jb, js->user->resource, priority, state, msg); |
9744 | 78 } |
9954 | 79 if((jbr = jabber_buddy_find_resource(jb, NULL))) { |
9990 | 80 gaim_prpl_got_user_status(js->gc->account, my_base_jid, jabber_buddy_state_get_status_id(jbr->state), "priority", jbr->priority, jbr->status ? "message" : NULL, jbr->status, NULL); |
9954 | 81 } else { |
9990 | 82 gaim_prpl_got_user_status(js->gc->account, my_base_jid, "offline", msg ? "message" : NULL, msg, NULL); |
9954 | 83 } |
8185 | 84 } |
85 } | |
86 g_free(my_base_jid); | |
87 } | |
88 | |
7014 | 89 |
10216 | 90 void jabber_presence_send(GaimAccount *account, GaimStatus *status) |
7014 | 91 { |
10382
9f28196ed769
[gaim-migrate @ 11608]
Luke Schierer <lschiere@pidgin.im>
parents:
10286
diff
changeset
|
92 GaimConnection *gc = NULL; |
9f28196ed769
[gaim-migrate @ 11608]
Luke Schierer <lschiere@pidgin.im>
parents:
10286
diff
changeset
|
93 JabberStream *js = NULL; |
11251 | 94 gboolean disconnected; |
10755 | 95 int primitive; |
10189 | 96 xmlnode *presence, *x, *photo; |
7014 | 97 char *stripped = NULL; |
9954 | 98 const char *msg; |
99 JabberBuddyState state; | |
100 int priority; | |
7014 | 101 |
10486 | 102 if(!gaim_status_is_active(status)) |
103 return; | |
104 | |
11251 | 105 disconnected = gaim_account_is_disconnected(account); |
10755 | 106 primitive = gaim_status_type_get_primitive(gaim_status_get_type(status)); |
107 | |
11251 | 108 if(disconnected) |
10755 | 109 return; |
110 | |
111 gc = gaim_account_get_connection(account); | |
112 js = gc->proto_data; | |
113 | |
9954 | 114 gaim_status_to_jabber(status, &state, &msg, &priority); |
115 | |
116 if(msg) | |
7095
c8bf2da398e3
[gaim-migrate @ 7660]
Christian Hammond <chipx86@chipx86.com>
parents:
7015
diff
changeset
|
117 gaim_markup_html_to_xhtml(msg, NULL, &stripped); |
7014 | 118 |
9954 | 119 presence = jabber_presence_create(state, stripped, priority); |
120 g_free(stripped); | |
7014 | 121 |
10189 | 122 if(js->avatar_hash) { |
123 x = xmlnode_new_child(presence, "x"); | |
13806 | 124 xmlnode_set_namespace(x, "vcard-temp:x:update"); |
10189 | 125 photo = xmlnode_new_child(x, "photo"); |
126 xmlnode_insert_data(photo, js->avatar_hash, -1); | |
127 } | |
128 | |
12265 | 129 jabber_send(js, presence); |
130 | |
7014 | 131 g_hash_table_foreach(js->chats, chats_send_presence_foreach, presence); |
132 xmlnode_free(presence); | |
8185 | 133 |
9954 | 134 jabber_presence_fake_to_self(js, status); |
7014 | 135 } |
136 | |
9954 | 137 xmlnode *jabber_presence_create(JabberBuddyState state, const char *msg, int priority) |
7014 | 138 { |
13384 | 139 xmlnode *show, *status, *presence, *pri, *c; |
9954 | 140 const char *show_string = NULL; |
7014 | 141 |
142 presence = xmlnode_new("presence"); | |
143 | |
9954 | 144 if(state == JABBER_BUDDY_STATE_UNAVAILABLE) |
145 xmlnode_set_attrib(presence, "type", "unavailable"); | |
146 else if(state != JABBER_BUDDY_STATE_ONLINE && | |
147 state != JABBER_BUDDY_STATE_UNKNOWN && | |
148 state != JABBER_BUDDY_STATE_ERROR) | |
12683 | 149 show_string = jabber_buddy_state_get_show(state); |
9954 | 150 |
151 if(show_string) { | |
152 show = xmlnode_new_child(presence, "show"); | |
153 xmlnode_insert_data(show, show_string, -1); | |
7014 | 154 } |
155 | |
9954 | 156 if(msg) { |
7014 | 157 status = xmlnode_new_child(presence, "status"); |
158 xmlnode_insert_data(status, msg, -1); | |
159 } | |
160 | |
11568 | 161 if(priority) { |
162 char *pstr = g_strdup_printf("%d", priority); | |
163 pri = xmlnode_new_child(presence, "priority"); | |
164 xmlnode_insert_data(pri, pstr, -1); | |
165 g_free(pstr); | |
166 } | |
167 | |
13384 | 168 /* JEP-0115 */ |
169 c = xmlnode_new_child(presence, "c"); | |
13806 | 170 xmlnode_set_namespace(c, "http://jabber.org/protocol/caps"); |
13384 | 171 xmlnode_set_attrib(c, "node", CAPS0115_NODE); |
172 xmlnode_set_attrib(c, "ver", VERSION); | |
173 | |
7014 | 174 return presence; |
175 } | |
176 | |
177 struct _jabber_add_permit { | |
13213
371f353f7d99
[gaim-migrate @ 15577]
Evan Schoenberg <evan.s@dreskin.net>
parents:
12683
diff
changeset
|
178 GaimConnection *gc; |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
179 JabberStream *js; |
7014 | 180 char *who; |
181 }; | |
182 | |
183 static void authorize_add_cb(struct _jabber_add_permit *jap) | |
184 { | |
185 if(g_list_find(gaim_connections_get_all(), jap->gc)) { | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
186 GaimBuddy *buddy = NULL; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
187 |
7014 | 188 jabber_presence_subscription_set(jap->gc->proto_data, jap->who, |
189 "subscribed"); | |
190 | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
191 buddy = gaim_find_buddy(jap->gc->account, jap->who); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
192 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
193 if (buddy) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
194 JabberBuddy *jb = NULL; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
195 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
196 jb = jabber_buddy_find(jap->js, jap->who, TRUE); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
197 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
198 if ((jb->subscription & JABBER_SUB_TO) == 0) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
199 gaim_account_request_add(jap->gc->account, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
200 jap->who, NULL, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
201 NULL, NULL); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
202 } else { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
203 gaim_account_notify_added(jap->gc->account, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
204 jap->who, NULL, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
205 NULL, NULL); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
206 } |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
207 } else { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
208 gaim_account_request_add(jap->gc->account, jap->who, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
209 NULL, NULL, NULL); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
210 } |
7014 | 211 } |
212 | |
213 g_free(jap->who); | |
214 g_free(jap); | |
215 } | |
216 | |
217 static void deny_add_cb(struct _jabber_add_permit *jap) | |
218 { | |
219 if(g_list_find(gaim_connections_get_all(), jap->gc)) { | |
220 jabber_presence_subscription_set(jap->gc->proto_data, jap->who, | |
221 "unsubscribed"); | |
222 } | |
223 | |
224 g_free(jap->who); | |
225 g_free(jap); | |
226 } | |
227 | |
10189 | 228 static void jabber_vcard_parse_avatar(JabberStream *js, xmlnode *packet, gpointer blah) |
229 { | |
10941 | 230 JabberBuddy *jb = NULL; |
10189 | 231 GaimBuddy *b = NULL; |
10941 | 232 xmlnode *vcard, *photo, *binval; |
11127 | 233 char *text; |
11137 | 234 guchar *data; |
11127 | 235 gsize size; |
10189 | 236 const char *from = xmlnode_get_attrib(packet, "from"); |
237 | |
238 if(!from) | |
239 return; | |
240 | |
10941 | 241 jb = jabber_buddy_find(js, from, TRUE); |
242 | |
243 js->pending_avatar_requests = g_slist_remove(js->pending_avatar_requests, jb); | |
244 | |
10189 | 245 if((vcard = xmlnode_get_child(packet, "vCard")) || |
246 (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) { | |
10941 | 247 if((photo = xmlnode_get_child(vcard, "PHOTO")) && |
11361 | 248 (( (binval = xmlnode_get_child(photo, "BINVAL")) && |
249 (text = xmlnode_get_data(binval))) || | |
250 (text = xmlnode_get_data(photo)))) { | |
11127 | 251 data = gaim_base64_decode(text, &size); |
10189 | 252 |
10941 | 253 gaim_buddy_icons_set_for_user(js->gc->account, from, data, size); |
254 if((b = gaim_find_buddy(js->gc->account, from))) { | |
255 unsigned char hashval[20]; | |
256 char hash[41], *p; | |
257 int i; | |
10189 | 258 |
13890 | 259 gaim_cipher_digest_region("sha1", data, size, |
10941 | 260 sizeof(hashval), hashval, NULL); |
261 p = hash; | |
262 for(i=0; i<20; i++, p+=2) | |
263 snprintf(p, 3, "%02x", hashval[i]); | |
264 gaim_blist_node_set_string((GaimBlistNode*)b, "avatar_hash", hash); | |
10189 | 265 } |
13890 | 266 g_free(data); |
10941 | 267 g_free(text); |
10189 | 268 } |
269 } | |
270 } | |
271 | |
7014 | 272 void jabber_presence_parse(JabberStream *js, xmlnode *packet) |
273 { | |
274 const char *from = xmlnode_get_attrib(packet, "from"); | |
275 const char *type = xmlnode_get_attrib(packet, "type"); | |
7944 | 276 const char *real_jid = NULL; |
9152 | 277 const char *affiliation = NULL; |
278 const char *role = NULL; | |
7014 | 279 char *status = NULL; |
280 int priority = 0; | |
281 JabberID *jid; | |
282 JabberChat *chat; | |
283 JabberBuddy *jb; | |
9954 | 284 JabberBuddyResource *jbr = NULL, *found_jbr = NULL; |
9554 | 285 GaimConvChatBuddyFlags flags = GAIM_CBFLAGS_NONE; |
9846 | 286 gboolean delayed = FALSE; |
10189 | 287 GaimBuddy *b = NULL; |
7014 | 288 char *buddy_name; |
9954 | 289 JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN; |
7014 | 290 xmlnode *y; |
291 gboolean muc = FALSE; | |
10189 | 292 char *avatar_hash = NULL; |
7014 | 293 |
8043 | 294 if(!(jb = jabber_buddy_find(js, from, TRUE))) |
295 return; | |
296 | |
297 if(!(jid = jabber_id_new(from))) | |
7280 | 298 return; |
299 | |
7014 | 300 if(jb->error_msg) { |
301 g_free(jb->error_msg); | |
302 jb->error_msg = NULL; | |
303 } | |
304 | |
7813 | 305 if(type && !strcmp(type, "error")) { |
8401 | 306 char *msg = jabber_parse_error(js, packet); |
7644 | 307 |
9954 | 308 state = JABBER_BUDDY_STATE_ERROR; |
8401 | 309 jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence")); |
7813 | 310 } else if(type && !strcmp(type, "subscribe")) { |
7014 | 311 struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1); |
10949 | 312 char *msg; |
313 | |
314 msg = g_strdup_printf(_("The user %s wants to add %s to his or " | |
315 "her buddy list."), | |
316 from, gaim_account_get_username(js->gc->account)); | |
7014 | 317 jap->gc = js->gc; |
318 jap->who = g_strdup(from); | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
319 jap->js = js; |
7014 | 320 |
10189 | 321 gaim_request_action(js->gc, NULL, msg, NULL, GAIM_DEFAULT_ACTION_NONE, |
10116 | 322 jap, 2, |
12603
e4e47871c373
[gaim-migrate @ 14938]
Richard Laager <rlaager@wiktel.com>
parents:
12285
diff
changeset
|
323 _("_Authorize"), G_CALLBACK(authorize_add_cb), |
e4e47871c373
[gaim-migrate @ 14938]
Richard Laager <rlaager@wiktel.com>
parents:
12285
diff
changeset
|
324 _("_Deny"), G_CALLBACK(deny_add_cb)); |
7014 | 325 g_free(msg); |
8043 | 326 jabber_id_free(jid); |
7145 | 327 return; |
7813 | 328 } else if(type && !strcmp(type, "subscribed")) { |
7014 | 329 /* we've been allowed to see their presence, but we don't care */ |
8043 | 330 jabber_id_free(jid); |
7014 | 331 return; |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
332 } else if(type && !strcmp(type, "unsubscribe")) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
333 /* XXX I'm not sure this is the right way to handle this, it |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
334 * might be better to add "unsubscribe" to the presence status |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
335 * if lower down, but I'm not sure. */ |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
336 /* they are unsubscribing from our presence, we don't care */ |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
337 /* Well, maybe just a little, we might want/need to start |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
338 * acknowledging this (and the others) at some point. */ |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
339 jabber_id_free(jid); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
340 return; |
7014 | 341 } else { |
342 if((y = xmlnode_get_child(packet, "show"))) { | |
343 char *show = xmlnode_get_data(y); | |
12683 | 344 state = jabber_buddy_show_get_state(show); |
7014 | 345 g_free(show); |
346 } else { | |
9954 | 347 state = JABBER_BUDDY_STATE_ONLINE; |
7014 | 348 } |
349 } | |
350 | |
7310 | 351 |
7014 | 352 for(y = packet->child; y; y = y->next) { |
8135 | 353 if(y->type != XMLNODE_TYPE_TAG) |
7014 | 354 continue; |
355 | |
356 if(!strcmp(y->name, "status")) { | |
7615 | 357 g_free(status); |
7014 | 358 status = xmlnode_get_data(y); |
359 } else if(!strcmp(y->name, "priority")) { | |
360 char *p = xmlnode_get_data(y); | |
361 if(p) { | |
362 priority = atoi(p); | |
363 g_free(p); | |
364 } | |
365 } else if(!strcmp(y->name, "x")) { | |
13806 | 366 const char *xmlns = xmlnode_get_namespace(y); |
9846 | 367 if(xmlns && !strcmp(xmlns, "jabber:x:delay")) { |
9847 | 368 /* XXX: compare the time. jabber:x:delay can happen on presence packets that aren't really and truly delayed */ |
9846 | 369 delayed = TRUE; |
370 } else if(xmlns && !strcmp(xmlns, "http://jabber.org/protocol/muc#user")) { | |
7629 | 371 xmlnode *z; |
372 | |
7014 | 373 muc = TRUE; |
7629 | 374 if((z = xmlnode_get_child(y, "status"))) { |
375 const char *code = xmlnode_get_attrib(z, "code"); | |
376 if(code && !strcmp(code, "201")) { | |
13444 | 377 if((chat = jabber_chat_find(js, jid->node, jid->domain))) { |
378 chat->config_dialog_type = GAIM_REQUEST_ACTION; | |
379 chat->config_dialog_handle = | |
380 gaim_request_action(js->gc, | |
381 _("Create New Room"), | |
382 _("Create New Room"), | |
383 _("You are creating a new room. Would" | |
384 " you like to configure it, or" | |
385 " accept the default settings?"), | |
386 1, chat, 2, _("_Configure Room"), | |
387 G_CALLBACK(jabber_chat_request_room_configure), | |
388 _("_Accept Defaults"), | |
389 G_CALLBACK(jabber_chat_create_instant_room)); | |
390 } | |
7629 | 391 } |
392 } | |
7944 | 393 if((z = xmlnode_get_child(y, "item"))) { |
394 real_jid = xmlnode_get_attrib(z, "jid"); | |
9152 | 395 affiliation = xmlnode_get_attrib(z, "affiliation"); |
396 role = xmlnode_get_attrib(z, "role"); | |
9931 | 397 if(affiliation != NULL && !strcmp(affiliation, "owner")) |
398 flags |= GAIM_CBFLAGS_FOUNDER; | |
9743 | 399 if (role != NULL) { |
400 if (!strcmp(role, "moderator")) | |
9931 | 401 flags |= GAIM_CBFLAGS_OP; |
9743 | 402 else if (!strcmp(role, "participant")) |
9931 | 403 flags |= GAIM_CBFLAGS_VOICE; |
9743 | 404 } |
7944 | 405 } |
10189 | 406 } else if(xmlns && !strcmp(xmlns, "vcard-temp:x:update")) { |
407 xmlnode *photo = xmlnode_get_child(y, "photo"); | |
408 if(photo) { | |
409 if(avatar_hash) | |
410 g_free(avatar_hash); | |
411 avatar_hash = xmlnode_get_data(photo); | |
412 } | |
7014 | 413 } |
414 } | |
415 } | |
416 | |
417 | |
7322 | 418 if(jid->node && (chat = jabber_chat_find(js, jid->node, jid->domain))) { |
8462 | 419 static int i = 1; |
7014 | 420 char *room_jid = g_strdup_printf("%s@%s", jid->node, jid->domain); |
421 | |
9954 | 422 if(state == JABBER_BUDDY_STATE_ERROR) { |
8401 | 423 char *title, *msg = jabber_parse_error(js, packet); |
7014 | 424 |
7321 | 425 if(chat->conv) { |
8401 | 426 title = g_strdup_printf(_("Error in chat %s"), from); |
7321 | 427 serv_got_chat_left(js->gc, chat->id); |
428 } else { | |
8401 | 429 title = g_strdup_printf(_("Error joining chat %s"), from); |
7321 | 430 } |
8401 | 431 gaim_notify_error(js->gc, title, title, msg); |
432 g_free(title); | |
433 g_free(msg); | |
7014 | 434 |
435 jabber_chat_destroy(chat); | |
7310 | 436 jabber_id_free(jid); |
7615 | 437 g_free(status); |
8182 | 438 g_free(room_jid); |
10189 | 439 if(avatar_hash) |
440 g_free(avatar_hash); | |
7014 | 441 return; |
442 } | |
443 | |
444 | |
7813 | 445 if(type && !strcmp(type, "unavailable")) { |
7972 | 446 gboolean nick_change = FALSE; |
7973 | 447 |
9152 | 448 /* If we haven't joined the chat yet, we don't care that someone |
449 * left, or it was us leaving after we closed the chat */ | |
8182 | 450 if(!chat->conv) { |
10558 | 451 if(jid->resource && chat->handle && !strcmp(jid->resource, chat->handle)) |
9152 | 452 jabber_chat_destroy(chat); |
8182 | 453 jabber_id_free(jid); |
454 g_free(status); | |
455 g_free(room_jid); | |
10189 | 456 if(avatar_hash) |
457 g_free(avatar_hash); | |
8182 | 458 return; |
459 } | |
460 | |
7973 | 461 jabber_buddy_remove_resource(jb, jid->resource); |
7972 | 462 if(chat->muc) { |
463 xmlnode *x; | |
8135 | 464 for(x = xmlnode_get_child(packet, "x"); x; x = xmlnode_get_next_twin(x)) { |
7972 | 465 const char *xmlns, *nick, *code; |
466 xmlnode *stat, *item; | |
13806 | 467 if(!(xmlns = xmlnode_get_namespace(x)) || |
7972 | 468 strcmp(xmlns, "http://jabber.org/protocol/muc#user")) |
469 continue; | |
470 if(!(stat = xmlnode_get_child(x, "status"))) | |
471 continue; | |
9152 | 472 if(!(code = xmlnode_get_attrib(stat, "code"))) |
7972 | 473 continue; |
9152 | 474 if(!strcmp(code, "301")) { |
475 /* XXX: we got banned */ | |
476 } else if(!strcmp(code, "303")) { | |
477 if(!(item = xmlnode_get_child(x, "item"))) | |
478 continue; | |
479 if(!(nick = xmlnode_get_attrib(item, "nick"))) | |
480 continue; | |
481 nick_change = TRUE; | |
482 if(!strcmp(jid->resource, chat->handle)) { | |
483 g_free(chat->handle); | |
484 chat->handle = g_strdup(nick); | |
485 } | |
486 gaim_conv_chat_rename_user(GAIM_CONV_CHAT(chat->conv), jid->resource, nick); | |
487 jabber_chat_remove_handle(chat, jid->resource); | |
488 break; | |
489 } else if(!strcmp(code, "307")) { | |
490 /* XXX: we got kicked */ | |
491 } else if(!strcmp(code, "321")) { | |
492 /* XXX: removed due to an affiliation change */ | |
493 } else if(!strcmp(code, "322")) { | |
494 /* XXX: removed because room is now members-only */ | |
495 } else if(!strcmp(code, "332")) { | |
496 /* XXX: removed due to system shutdown */ | |
8401 | 497 } |
7972 | 498 } |
499 } | |
500 if(!nick_change) { | |
9152 | 501 if(!g_utf8_collate(jid->resource, chat->handle)) { |
7972 | 502 serv_got_chat_left(js->gc, chat->id); |
503 jabber_chat_destroy(chat); | |
504 } else { | |
505 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(chat->conv), jid->resource, | |
7974 | 506 status); |
9152 | 507 jabber_chat_remove_handle(chat, jid->resource); |
7972 | 508 } |
7014 | 509 } |
510 } else { | |
8182 | 511 if(!chat->conv) { |
512 chat->id = i++; | |
513 chat->muc = muc; | |
514 chat->conv = serv_got_joined_chat(js->gc, chat->id, room_jid); | |
10722 | 515 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(chat->conv), chat->handle); |
10486 | 516 |
10941 | 517 jabber_chat_disco_traffic(chat); |
8182 | 518 } |
519 | |
7973 | 520 jabber_buddy_track_resource(jb, jid->resource, priority, state, |
521 status); | |
522 | |
9152 | 523 jabber_chat_track_handle(chat, jid->resource, real_jid, affiliation, role); |
524 | |
7014 | 525 if(!jabber_chat_find_buddy(chat->conv, jid->resource)) |
7118
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
7095
diff
changeset
|
526 gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat->conv), jid->resource, |
9846 | 527 real_jid, flags, !delayed); |
9554 | 528 else |
529 gaim_conv_chat_user_set_flags(GAIM_CONV_CHAT(chat->conv), jid->resource, | |
530 flags); | |
7014 | 531 } |
532 g_free(room_jid); | |
533 } else { | |
7322 | 534 buddy_name = g_strdup_printf("%s%s%s", jid->node ? jid->node : "", |
535 jid->node ? "@" : "", jid->domain); | |
7014 | 536 if((b = gaim_find_buddy(js->gc->account, buddy_name)) == NULL) { |
537 jabber_id_free(jid); | |
10189 | 538 if(avatar_hash) |
539 g_free(avatar_hash); | |
7014 | 540 g_free(buddy_name); |
7615 | 541 g_free(status); |
7014 | 542 return; |
543 } | |
544 | |
10189 | 545 if(avatar_hash) { |
546 const char *avatar_hash2 = gaim_blist_node_get_string((GaimBlistNode*)b, "avatar_hash"); | |
547 if(!avatar_hash2 || strcmp(avatar_hash, avatar_hash2)) { | |
548 JabberIq *iq; | |
549 xmlnode *vcard; | |
550 | |
10941 | 551 /* XXX this is a crappy way of trying to prevent |
552 * someone from spamming us with presence packets | |
553 * and causing us to DoS ourselves...what we really | |
554 * need is a queue system that can throttle itself, | |
555 * but i'm too tired to write that right now */ | |
556 if(!g_slist_find(js->pending_avatar_requests, jb)) { | |
557 | |
558 js->pending_avatar_requests = g_slist_prepend(js->pending_avatar_requests, jb); | |
10189 | 559 |
10941 | 560 iq = jabber_iq_new(js, JABBER_IQ_GET); |
561 xmlnode_set_attrib(iq->node, "to", buddy_name); | |
562 vcard = xmlnode_new_child(iq->node, "vCard"); | |
13806 | 563 xmlnode_set_namespace(vcard, "vcard-temp"); |
10941 | 564 |
565 jabber_iq_set_callback(iq, jabber_vcard_parse_avatar, NULL); | |
566 jabber_iq_send(iq); | |
567 } | |
10189 | 568 } |
569 } | |
570 | |
9954 | 571 if(state == JABBER_BUDDY_STATE_ERROR || |
7813 | 572 (type && (!strcmp(type, "unavailable") || |
573 !strcmp(type, "unsubscribed")))) { | |
8043 | 574 GaimConversation *conv; |
575 | |
7014 | 576 jabber_buddy_remove_resource(jb, jid->resource); |
8043 | 577 if((conv = jabber_find_unnormalized_conv(from, js->gc->account))) |
578 gaim_conversation_set_name(conv, buddy_name); | |
579 | |
7395 | 580 } else { |
9954 | 581 jbr = jabber_buddy_track_resource(jb, jid->resource, priority, |
582 state, status); | |
7395 | 583 } |
7014 | 584 |
9954 | 585 if((found_jbr = jabber_buddy_find_resource(jb, NULL))) { |
586 if(!jbr || jbr == found_jbr) { | |
9990 | 587 gaim_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(state), "priority", found_jbr->priority, found_jbr->status ? "message" : NULL, found_jbr->status, NULL); |
9954 | 588 } |
589 } else { | |
9990 | 590 gaim_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL); |
9954 | 591 } |
7014 | 592 g_free(buddy_name); |
593 } | |
594 g_free(status); | |
595 jabber_id_free(jid); | |
10189 | 596 if(avatar_hash) |
597 g_free(avatar_hash); | |
7014 | 598 } |
599 | |
600 void jabber_presence_subscription_set(JabberStream *js, const char *who, const char *type) | |
601 { | |
602 xmlnode *presence = xmlnode_new("presence"); | |
603 | |
604 xmlnode_set_attrib(presence, "to", who); | |
605 xmlnode_set_attrib(presence, "type", type); | |
606 | |
607 jabber_send(js, presence); | |
608 xmlnode_free(presence); | |
609 } | |
9954 | 610 |
611 void gaim_status_to_jabber(const GaimStatus *status, JabberBuddyState *state, const char **msg, int *priority) | |
612 { | |
10216 | 613 const char *status_id = NULL; |
614 | |
13442 | 615 if(state) *state = JABBER_BUDDY_STATE_UNKNOWN; |
616 if(msg) *msg = NULL; | |
617 if(priority) *priority = 0; | |
9954 | 618 |
619 if(!status) { | |
13442 | 620 if(state) *state = JABBER_BUDDY_STATE_UNAVAILABLE; |
10216 | 621 } else { |
622 if(state) { | |
623 status_id = gaim_status_get_id(status); | |
624 *state = jabber_buddy_status_id_get_state(status_id); | |
625 } | |
626 | |
13496
d2aadcdbec6c
[gaim-migrate @ 15872]
Richard Laager <rlaager@wiktel.com>
parents:
13444
diff
changeset
|
627 if(msg) { |
10216 | 628 *msg = gaim_status_get_attr_string(status, "message"); |
629 | |
13496
d2aadcdbec6c
[gaim-migrate @ 15872]
Richard Laager <rlaager@wiktel.com>
parents:
13444
diff
changeset
|
630 /* if the message is blank, then there really isn't a message */ |
d2aadcdbec6c
[gaim-migrate @ 15872]
Richard Laager <rlaager@wiktel.com>
parents:
13444
diff
changeset
|
631 if(*msg && !**msg) |
d2aadcdbec6c
[gaim-migrate @ 15872]
Richard Laager <rlaager@wiktel.com>
parents:
13444
diff
changeset
|
632 *msg = NULL; |
d2aadcdbec6c
[gaim-migrate @ 15872]
Richard Laager <rlaager@wiktel.com>
parents:
13444
diff
changeset
|
633 } |
11872 | 634 |
10216 | 635 if(priority) |
636 *priority = gaim_status_get_attr_int(status, "priority"); | |
9954 | 637 } |
638 } |