Mercurial > pidgin.yaz
annotate src/protocols/jabber/presence.c @ 9456:0577bb34622d
[gaim-migrate @ 10280]
This fixes bug #964043
We were truncating the port to 4 ascii digits, because our buffer was too
small. Oops. Let this be an example to you, not all users are on crack.
This bug was somewhat confusing by the fact that the spin button to choose
the port is only big enough to show 4 digits at a time. That's completely
unrelated though, you can hit HOME and END and stuff to see all the digits
and it saves file and all.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Tue, 06 Jul 2004 06:22:14 +0000 |
parents | 7a9261d979df |
children | 8b2451878e26 |
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 | |
23 #include "debug.h" | |
24 #include "notify.h" | |
25 #include "request.h" | |
26 #include "server.h" | |
7095
c8bf2da398e3
[gaim-migrate @ 7660]
Christian Hammond <chipx86@chipx86.com>
parents:
7015
diff
changeset
|
27 #include "util.h" |
7014 | 28 |
29 #include "buddy.h" | |
30 #include "chat.h" | |
31 #include "presence.h" | |
32 #include "iq.h" | |
33 #include "jutil.h" | |
34 #include "xmlnode.h" | |
35 | |
36 | |
37 static void chats_send_presence_foreach(gpointer key, gpointer val, | |
38 gpointer user_data) | |
39 { | |
40 JabberChat *chat = val; | |
41 xmlnode *presence = user_data; | |
8577 | 42 char *chat_full_jid; |
43 | |
44 if(!chat->conv) | |
45 return; | |
46 | |
47 chat_full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, | |
8401 | 48 chat->handle); |
7014 | 49 |
8401 | 50 xmlnode_set_attrib(presence, "to", chat_full_jid); |
7014 | 51 jabber_send(chat->js, presence); |
8401 | 52 g_free(chat_full_jid); |
7014 | 53 } |
54 | |
8193 | 55 void jabber_presence_fake_to_self(JabberStream *js, const char *away_state, const char *msg) { |
8185 | 56 char *my_base_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); |
57 if(gaim_find_buddy(js->gc->account, my_base_jid)) { | |
58 JabberBuddy *jb; | |
59 JabberBuddyResource *jbr; | |
60 if((jb = jabber_buddy_find(js, my_base_jid, TRUE))) { | |
8193 | 61 int state = 0; |
62 if(away_state) { | |
63 if(!strcmp(away_state, _("Away")) || | |
64 (msg && *msg && !strcmp(away_state, GAIM_AWAY_CUSTOM))) | |
65 state = JABBER_STATE_AWAY; | |
66 else if(!strcmp(away_state, _("Chatty"))) | |
67 state = JABBER_STATE_CHAT; | |
68 else if(!strcmp(away_state, _("Extended Away"))) | |
69 state = JABBER_STATE_XA; | |
70 else if(!strcmp(away_state, _("Do Not Disturb"))) | |
71 state = JABBER_STATE_DND; | |
72 } | |
73 jabber_buddy_track_resource(jb, js->user->resource, 0, state, (msg && *msg) ? msg : NULL); | |
8185 | 74 if((jbr = jabber_buddy_find_resource(jb, NULL))) |
75 serv_got_update(js->gc, my_base_jid, 1, 0, 0, 0, jbr->state); | |
76 } | |
77 } | |
78 g_free(my_base_jid); | |
79 } | |
80 | |
7014 | 81 |
82 void jabber_presence_send(GaimConnection *gc, const char *state, | |
83 const char *msg) | |
84 { | |
85 JabberStream *js = gc->proto_data; | |
86 xmlnode *presence; | |
87 char *stripped = NULL; | |
88 | |
89 if(msg) { | |
7095
c8bf2da398e3
[gaim-migrate @ 7660]
Christian Hammond <chipx86@chipx86.com>
parents:
7015
diff
changeset
|
90 gaim_markup_html_to_xhtml(msg, NULL, &stripped); |
7249 | 91 } else if(!state || strcmp(state, GAIM_AWAY_CUSTOM)) { |
7247 | 92 /* i can't wait until someone re-writes the status/away stuff */ |
7014 | 93 stripped = g_strdup(""); |
94 } | |
95 | |
7248 | 96 if(gc->away) |
97 g_free(gc->away); | |
7014 | 98 gc->away = stripped; |
99 | |
8185 | 100 presence = jabber_presence_create(state, stripped); |
7014 | 101 jabber_send(js, presence); |
102 g_hash_table_foreach(js->chats, chats_send_presence_foreach, presence); | |
103 xmlnode_free(presence); | |
8185 | 104 |
105 jabber_presence_fake_to_self(js, state, stripped); | |
7014 | 106 } |
107 | |
108 xmlnode *jabber_presence_create(const char *state, const char *msg) | |
109 { | |
110 xmlnode *show, *status, *presence; | |
111 | |
112 | |
113 presence = xmlnode_new("presence"); | |
114 | |
115 if(state) { | |
116 const char *show_string = NULL; | |
117 if(!strcmp(state, _("Chatty"))) | |
118 show_string = "chat"; | |
119 else if(!strcmp(state, _("Away")) || | |
120 (msg && !strcmp(state, GAIM_AWAY_CUSTOM))) | |
121 show_string = "away"; | |
122 else if(!strcmp(state, _("Extended Away"))) | |
123 show_string = "xa"; | |
124 else if(!strcmp(state, _("Do Not Disturb"))) | |
125 show_string = "dnd"; | |
9320 | 126 else if(!strcmp(state, _("Invisible"))) |
7014 | 127 xmlnode_set_attrib(presence, "type", "invisible"); |
9320 | 128 else if(!strcmp(state, "unavailable")) |
129 xmlnode_set_attrib(presence, "type", "unavailable"); | |
7014 | 130 |
131 if(show_string) { | |
132 show = xmlnode_new_child(presence, "show"); | |
133 xmlnode_insert_data(show, show_string, -1); | |
134 } | |
135 } | |
136 | |
137 if(msg && *msg) { | |
138 status = xmlnode_new_child(presence, "status"); | |
139 xmlnode_insert_data(status, msg, -1); | |
140 } | |
141 | |
142 return presence; | |
143 } | |
144 | |
145 struct _jabber_add_permit { | |
146 GaimConnection *gc; | |
147 char *who; | |
148 }; | |
149 | |
150 static void authorize_add_cb(struct _jabber_add_permit *jap) | |
151 { | |
152 if(g_list_find(gaim_connections_get_all(), jap->gc)) { | |
153 jabber_presence_subscription_set(jap->gc->proto_data, jap->who, | |
154 "subscribed"); | |
155 | |
156 if(!gaim_find_buddy(jap->gc->account, jap->who)) | |
7015
dece74f05509
[gaim-migrate @ 7578]
Christian Hammond <chipx86@chipx86.com>
parents:
7014
diff
changeset
|
157 gaim_account_notify_added(jap->gc->account, NULL, jap->who, NULL, NULL); |
7014 | 158 } |
159 | |
160 g_free(jap->who); | |
161 g_free(jap); | |
162 } | |
163 | |
164 static void deny_add_cb(struct _jabber_add_permit *jap) | |
165 { | |
166 if(g_list_find(gaim_connections_get_all(), jap->gc)) { | |
167 jabber_presence_subscription_set(jap->gc->proto_data, jap->who, | |
168 "unsubscribed"); | |
169 } | |
170 | |
171 g_free(jap->who); | |
172 g_free(jap); | |
173 } | |
174 | |
8193 | 175 static int show_to_state(const char *show) { |
176 if(!show) | |
177 return 0; | |
178 else if(!strcmp(show, "away")) | |
179 return JABBER_STATE_AWAY; | |
180 else if(!strcmp(show, "chat")) | |
181 return JABBER_STATE_CHAT; | |
182 else if(!strcmp(show, "xa")) | |
183 return JABBER_STATE_XA; | |
184 else if(!strcmp(show, "dnd")) | |
185 return JABBER_STATE_DND; | |
186 return 0; | |
187 } | |
188 | |
7014 | 189 void jabber_presence_parse(JabberStream *js, xmlnode *packet) |
190 { | |
191 const char *from = xmlnode_get_attrib(packet, "from"); | |
192 const char *type = xmlnode_get_attrib(packet, "type"); | |
7944 | 193 const char *real_jid = NULL; |
9152 | 194 const char *affiliation = NULL; |
195 const char *role = NULL; | |
7014 | 196 char *status = NULL; |
197 int priority = 0; | |
198 JabberID *jid; | |
199 JabberChat *chat; | |
200 JabberBuddy *jb; | |
7835 | 201 JabberBuddyResource *jbr = NULL; |
7014 | 202 GaimBuddy *b; |
203 char *buddy_name; | |
204 int state = 0; | |
205 xmlnode *y; | |
206 gboolean muc = FALSE; | |
207 | |
208 | |
8043 | 209 if(!(jb = jabber_buddy_find(js, from, TRUE))) |
210 return; | |
211 | |
212 if(!(jid = jabber_id_new(from))) | |
7280 | 213 return; |
214 | |
7014 | 215 if(jb->error_msg) { |
216 g_free(jb->error_msg); | |
217 jb->error_msg = NULL; | |
218 } | |
219 | |
7813 | 220 if(type && !strcmp(type, "error")) { |
8401 | 221 char *msg = jabber_parse_error(js, packet); |
7644 | 222 |
7014 | 223 state = JABBER_STATE_ERROR; |
8401 | 224 jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence")); |
7813 | 225 } else if(type && !strcmp(type, "subscribe")) { |
7014 | 226 struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1); |
227 char *msg = g_strdup_printf(_("The user %s wants to add you to their buddy list."), from); | |
228 jap->gc = js->gc; | |
229 jap->who = g_strdup(from); | |
230 | |
231 gaim_request_action(js->gc, NULL, msg, NULL, 0, jap, 2, | |
232 _("Authorize"), G_CALLBACK(authorize_add_cb), | |
233 _("Deny"), G_CALLBACK(deny_add_cb)); | |
234 g_free(msg); | |
8043 | 235 jabber_id_free(jid); |
7145 | 236 return; |
7813 | 237 } else if(type && !strcmp(type, "subscribed")) { |
7014 | 238 /* we've been allowed to see their presence, but we don't care */ |
8043 | 239 jabber_id_free(jid); |
7014 | 240 return; |
241 } else { | |
242 if((y = xmlnode_get_child(packet, "show"))) { | |
243 char *show = xmlnode_get_data(y); | |
8185 | 244 state = show_to_state(show); |
7014 | 245 g_free(show); |
246 } else { | |
247 state = 0; | |
248 } | |
249 } | |
250 | |
7310 | 251 |
7014 | 252 for(y = packet->child; y; y = y->next) { |
8135 | 253 if(y->type != XMLNODE_TYPE_TAG) |
7014 | 254 continue; |
255 | |
256 if(!strcmp(y->name, "status")) { | |
7615 | 257 g_free(status); |
7014 | 258 status = xmlnode_get_data(y); |
259 } else if(!strcmp(y->name, "priority")) { | |
260 char *p = xmlnode_get_data(y); | |
261 if(p) { | |
262 priority = atoi(p); | |
263 g_free(p); | |
264 } | |
265 } else if(!strcmp(y->name, "x")) { | |
266 const char *xmlns = xmlnode_get_attrib(y, "xmlns"); | |
267 if(xmlns && !strcmp(xmlns, "http://jabber.org/protocol/muc#user")) { | |
268 /* this is where we'd normally get the "op" status of the | |
269 * user, but since we don't have a good way to show that yet | |
270 * we'll ignore it */ | |
7629 | 271 xmlnode *z; |
272 | |
7014 | 273 muc = TRUE; |
7629 | 274 if((z = xmlnode_get_child(y, "status"))) { |
275 const char *code = xmlnode_get_attrib(z, "code"); | |
276 if(code && !strcmp(code, "201")) { | |
7895 | 277 chat = jabber_chat_find(js, jid->node, jid->domain); |
8396 | 278 chat->config_dialog_type = GAIM_REQUEST_ACTION; |
279 chat->config_dialog_handle = | |
280 gaim_request_action(js->gc, _("Create New Room"), | |
7895 | 281 _("Create New Room"), |
282 _("You are creating a new room. Would you like to " | |
283 "configure it, or accept the default settings?"), | |
284 1, chat, 2, _("Configure Room"), | |
7923 | 285 G_CALLBACK(jabber_chat_request_room_configure), |
7895 | 286 _("Accept Defaults"), |
287 G_CALLBACK(jabber_chat_create_instant_room)); | |
7629 | 288 } |
289 } | |
7944 | 290 if((z = xmlnode_get_child(y, "item"))) { |
291 real_jid = xmlnode_get_attrib(z, "jid"); | |
9152 | 292 affiliation = xmlnode_get_attrib(z, "affiliation"); |
293 role = xmlnode_get_attrib(z, "role"); | |
7944 | 294 } |
7014 | 295 } |
296 } | |
297 } | |
298 | |
299 | |
7322 | 300 if(jid->node && (chat = jabber_chat_find(js, jid->node, jid->domain))) { |
8462 | 301 static int i = 1; |
7014 | 302 char *room_jid = g_strdup_printf("%s@%s", jid->node, jid->domain); |
303 | |
304 if(state == JABBER_STATE_ERROR) { | |
8401 | 305 char *title, *msg = jabber_parse_error(js, packet); |
7014 | 306 |
7321 | 307 if(chat->conv) { |
8401 | 308 title = g_strdup_printf(_("Error in chat %s"), from); |
7321 | 309 serv_got_chat_left(js->gc, chat->id); |
310 } else { | |
8401 | 311 title = g_strdup_printf(_("Error joining chat %s"), from); |
7321 | 312 } |
8401 | 313 gaim_notify_error(js->gc, title, title, msg); |
314 g_free(title); | |
315 g_free(msg); | |
7014 | 316 |
317 jabber_chat_destroy(chat); | |
7310 | 318 jabber_id_free(jid); |
7615 | 319 g_free(status); |
8182 | 320 g_free(room_jid); |
7014 | 321 return; |
322 } | |
323 | |
324 | |
7813 | 325 if(type && !strcmp(type, "unavailable")) { |
7972 | 326 gboolean nick_change = FALSE; |
7973 | 327 |
9152 | 328 /* If we haven't joined the chat yet, we don't care that someone |
329 * left, or it was us leaving after we closed the chat */ | |
8182 | 330 if(!chat->conv) { |
9152 | 331 if(!strcmp(jid->resource, chat->handle)) |
332 jabber_chat_destroy(chat); | |
8182 | 333 jabber_id_free(jid); |
334 g_free(status); | |
335 g_free(room_jid); | |
336 return; | |
337 } | |
338 | |
7973 | 339 jabber_buddy_remove_resource(jb, jid->resource); |
7972 | 340 if(chat->muc) { |
341 xmlnode *x; | |
8135 | 342 for(x = xmlnode_get_child(packet, "x"); x; x = xmlnode_get_next_twin(x)) { |
7972 | 343 const char *xmlns, *nick, *code; |
344 xmlnode *stat, *item; | |
345 if(!(xmlns = xmlnode_get_attrib(x, "xmlns")) || | |
346 strcmp(xmlns, "http://jabber.org/protocol/muc#user")) | |
347 continue; | |
348 if(!(stat = xmlnode_get_child(x, "status"))) | |
349 continue; | |
9152 | 350 if(!(code = xmlnode_get_attrib(stat, "code"))) |
7972 | 351 continue; |
9152 | 352 if(!strcmp(code, "301")) { |
353 /* XXX: we got banned */ | |
354 } else if(!strcmp(code, "303")) { | |
355 if(!(item = xmlnode_get_child(x, "item"))) | |
356 continue; | |
357 if(!(nick = xmlnode_get_attrib(item, "nick"))) | |
358 continue; | |
359 nick_change = TRUE; | |
360 if(!strcmp(jid->resource, chat->handle)) { | |
361 g_free(chat->handle); | |
362 chat->handle = g_strdup(nick); | |
363 } | |
364 gaim_conv_chat_rename_user(GAIM_CONV_CHAT(chat->conv), jid->resource, nick); | |
365 jabber_chat_remove_handle(chat, jid->resource); | |
366 break; | |
367 } else if(!strcmp(code, "307")) { | |
368 /* XXX: we got kicked */ | |
369 } else if(!strcmp(code, "321")) { | |
370 /* XXX: removed due to an affiliation change */ | |
371 } else if(!strcmp(code, "322")) { | |
372 /* XXX: removed because room is now members-only */ | |
373 } else if(!strcmp(code, "332")) { | |
374 /* XXX: removed due to system shutdown */ | |
8401 | 375 } |
7972 | 376 } |
377 } | |
378 if(!nick_change) { | |
9152 | 379 if(!g_utf8_collate(jid->resource, chat->handle)) { |
7972 | 380 serv_got_chat_left(js->gc, chat->id); |
381 jabber_chat_destroy(chat); | |
382 } else { | |
383 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(chat->conv), jid->resource, | |
7974 | 384 status); |
9152 | 385 jabber_chat_remove_handle(chat, jid->resource); |
7972 | 386 } |
7014 | 387 } |
388 } else { | |
8182 | 389 if(!chat->conv) { |
390 chat->id = i++; | |
391 chat->muc = muc; | |
392 chat->conv = serv_got_joined_chat(js->gc, chat->id, room_jid); | |
8401 | 393 g_free(chat->handle); |
394 chat->handle = g_strdup(jid->resource); | |
8182 | 395 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(chat->conv), jid->resource); |
396 } | |
397 | |
7973 | 398 jabber_buddy_track_resource(jb, jid->resource, priority, state, |
399 status); | |
400 | |
9152 | 401 jabber_chat_track_handle(chat, jid->resource, real_jid, affiliation, role); |
402 | |
7014 | 403 if(!jabber_chat_find_buddy(chat->conv, jid->resource)) |
7118
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
7095
diff
changeset
|
404 gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat->conv), jid->resource, |
7944 | 405 real_jid); |
7014 | 406 } |
407 g_free(room_jid); | |
408 } else { | |
7124 | 409 if(state != JABBER_STATE_ERROR && !(jb->subscription & JABBER_SUB_TO)) { |
7014 | 410 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
411 "got unexpected presence from %s, ignoring\n", from); | |
412 jabber_id_free(jid); | |
7615 | 413 g_free(status); |
7014 | 414 return; |
415 } | |
416 | |
7322 | 417 buddy_name = g_strdup_printf("%s%s%s", jid->node ? jid->node : "", |
418 jid->node ? "@" : "", jid->domain); | |
7014 | 419 if((b = gaim_find_buddy(js->gc->account, buddy_name)) == NULL) { |
420 jabber_id_free(jid); | |
421 g_free(buddy_name); | |
7615 | 422 g_free(status); |
7014 | 423 return; |
424 } | |
425 | |
426 if(state == JABBER_STATE_ERROR || | |
7813 | 427 (type && (!strcmp(type, "unavailable") || |
428 !strcmp(type, "unsubscribed")))) { | |
8043 | 429 GaimConversation *conv; |
430 | |
7014 | 431 jabber_buddy_remove_resource(jb, jid->resource); |
8043 | 432 if((conv = jabber_find_unnormalized_conv(from, js->gc->account))) |
433 gaim_conversation_set_name(conv, buddy_name); | |
434 | |
7395 | 435 } else { |
7014 | 436 jabber_buddy_track_resource(jb, jid->resource, priority, state, |
437 status); | |
7395 | 438 } |
7014 | 439 |
7835 | 440 if((jbr = jabber_buddy_find_resource(jb, NULL))) |
7014 | 441 serv_got_update(js->gc, buddy_name, 1, 0, b->signon, b->idle, |
442 jbr->state); | |
443 else | |
444 serv_got_update(js->gc, buddy_name, 0, 0, 0, 0, 0); | |
445 | |
446 g_free(buddy_name); | |
447 } | |
448 g_free(status); | |
449 jabber_id_free(jid); | |
450 } | |
451 | |
452 void jabber_presence_subscription_set(JabberStream *js, const char *who, const char *type) | |
453 { | |
454 xmlnode *presence = xmlnode_new("presence"); | |
455 | |
456 xmlnode_set_attrib(presence, "to", who); | |
457 xmlnode_set_attrib(presence, "type", type); | |
458 | |
459 jabber_send(js, presence); | |
460 xmlnode_free(presence); | |
461 } |