Mercurial > pidgin
annotate src/protocols/jabber/presence.c @ 12645:fc28451f5d96
[gaim-migrate @ 14983]
SF Patch #1314512 from Sadrul (who has a patch for everything)
"This patch introduces a flag for protocol plugins that
support offline messages (like Y!M and ICQ). This was
encouraged by the following conversation:
<sadrul> should offline buddies be listed/enabled in
the send-to menu?
<rekkanoryo> i would think only for protocols that
support offline messaging, if it's indicated that the
buddy is offline
-- <snip> --
<Bleeter> sadrul: personally, I'd like to see a
'supports offline' flag of some description
<Bleeter> one could then redirect (via plugins) through
email or alternative methods
<Bleeter> just a thought
<Paco-Paco> yeah, that sounds like a reasonble thing to have
This patch uses this flag to disable the buddies in the
send-to menu who are offline and the protocol doesn't
support offline messages."
I made this make the label insensitive instead of the whole menuitem. This
should address SimGuy's concerns about inconsistency (i.e. you could create a
conversation with someone via the buddy list that you couldn't create via the
Send To menu). I also hacked up some voodoo to show the label as sensitive when
moused-over, as that looks better (given the label-insensitive thing is itself a
hack). I think this works quite well.
BUG NOTE:
This makes more obvious an existing bug. The Send To menu isn't updated when
buddies sign on or off or change status (at least under some circumstances).
We need to fix that anyway, so I'm not going to let it hold up this commit.
Switching tabs will clear it up. I'm thinking we just might want to build the
contents of that menu when it is selected. That would save us a mess of
inefficient signal callbacks that update the Send To menus in open windows all
the time.
AIM NOTE:
This assumes that AIM can't offline message. That's not strictly true. You can
message invisible users on AIM. However, by design, we can't tell when a user
is invisible without resorting to dirty hackery. In practice, this isn't a
problem, as you can still select the AIM user from the menu. And really, how
often will you be choosing the Invisible contact, rather than the user going
Invisible in the middle of a conversation or IMing you while they're Invisible?
JABBER NOTE:
This assumes that Jabber can always offline message. This isn't strictly true.
Sadrul said:
I have updated Jabber according to this link which seems to
talk about how to determine the existence offline-message
support in a server:
http://www.jabber.org/jeps/jep-0013.html#discover
However, jabber.org doesn't seem to send the required
info. So I am not sure about it.
He later said:
I talked to Nathan and he said offline message support is
mostly assumed for most jabber servers. GTalk doesn't yet
support it, but they are working on it. So I have made
jabber to always return TRUE.
If there is truly no way to detect offline messaging capability, then this is
an acceptable solution. We could special case Google Talk because of its
popularity, and remove that later. It's probably not worth it though.
MSN NOTE:
This assumes that MSN can never offline message. That's effectively true, but
to be technically correct, MSN can offline message if there's already a
switchboard conversation open with a user. We could write an offline_message
function in the MSN prpl to detect that, but it'd be of limited usefulness,
especially given that under most circumstances (where this might matter), the
switchboard connection will be closed almost immediately.
CVS NOTE:
I'm writing to share a tragic little story.
I have a PC that I use for Gaim development. One day, I was writing a commit
message on it, when all of a suddent it went berserk. The screen started
flashing, and the whole commit message just disappeared. All of it. And it was
a good commit message! I had to cram and rewrite it really quickly. Needless to
say, my rushed commit message wasn't nearly as good, and I blame the PC for that.
Seriously, though, what kind of version control system loses your commit
message on a broken connection to the server? Stupid!
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Fri, 23 Dec 2005 19:26:04 +0000 |
parents | e4e47871c373 |
children | 41cf9be29754 |
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"); | |
124 xmlnode_set_attrib(x, "xmlns", "vcard-temp:x:update"); | |
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 { |
11568 | 139 xmlnode *show, *status, *presence, *pri; |
9954 | 140 const char *show_string = NULL; |
7014 | 141 |
142 | |
143 presence = xmlnode_new("presence"); | |
144 | |
145 | |
9954 | 146 if(state == JABBER_BUDDY_STATE_UNAVAILABLE) |
147 xmlnode_set_attrib(presence, "type", "unavailable"); | |
148 else if(state != JABBER_BUDDY_STATE_ONLINE && | |
149 state != JABBER_BUDDY_STATE_UNKNOWN && | |
150 state != JABBER_BUDDY_STATE_ERROR) | |
151 show_string = jabber_buddy_state_get_status_id(state); | |
152 | |
153 if(show_string) { | |
154 show = xmlnode_new_child(presence, "show"); | |
155 xmlnode_insert_data(show, show_string, -1); | |
7014 | 156 } |
157 | |
9954 | 158 if(msg) { |
7014 | 159 status = xmlnode_new_child(presence, "status"); |
160 xmlnode_insert_data(status, msg, -1); | |
161 } | |
162 | |
11568 | 163 if(priority) { |
164 char *pstr = g_strdup_printf("%d", priority); | |
165 pri = xmlnode_new_child(presence, "priority"); | |
166 xmlnode_insert_data(pri, pstr, -1); | |
167 g_free(pstr); | |
168 } | |
169 | |
7014 | 170 return presence; |
171 } | |
172 | |
173 struct _jabber_add_permit { | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
174 JabberStream *js; |
7014 | 175 GaimConnection *gc; |
176 char *who; | |
177 }; | |
178 | |
179 static void authorize_add_cb(struct _jabber_add_permit *jap) | |
180 { | |
181 if(g_list_find(gaim_connections_get_all(), jap->gc)) { | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
182 GaimBuddy *buddy = NULL; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
183 |
7014 | 184 jabber_presence_subscription_set(jap->gc->proto_data, jap->who, |
185 "subscribed"); | |
186 | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
187 buddy = gaim_find_buddy(jap->gc->account, jap->who); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
188 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
189 if (buddy) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
190 JabberBuddy *jb = NULL; |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
191 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
192 jb = jabber_buddy_find(jap->js, jap->who, TRUE); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
193 |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
194 if ((jb->subscription & JABBER_SUB_TO) == 0) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
195 gaim_account_request_add(jap->gc->account, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
196 jap->who, NULL, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
197 NULL, NULL); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
198 } else { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
199 gaim_account_notify_added(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 } |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
203 } else { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
204 gaim_account_request_add(jap->gc->account, jap->who, |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
205 NULL, NULL, NULL); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
206 } |
7014 | 207 } |
208 | |
209 g_free(jap->who); | |
210 g_free(jap); | |
211 } | |
212 | |
213 static void deny_add_cb(struct _jabber_add_permit *jap) | |
214 { | |
215 if(g_list_find(gaim_connections_get_all(), jap->gc)) { | |
216 jabber_presence_subscription_set(jap->gc->proto_data, jap->who, | |
217 "unsubscribed"); | |
218 } | |
219 | |
220 g_free(jap->who); | |
221 g_free(jap); | |
222 } | |
223 | |
10189 | 224 static void jabber_vcard_parse_avatar(JabberStream *js, xmlnode *packet, gpointer blah) |
225 { | |
10941 | 226 JabberBuddy *jb = NULL; |
10189 | 227 GaimBuddy *b = NULL; |
10941 | 228 xmlnode *vcard, *photo, *binval; |
11127 | 229 char *text; |
11137 | 230 guchar *data; |
11127 | 231 gsize size; |
10189 | 232 const char *from = xmlnode_get_attrib(packet, "from"); |
233 | |
234 if(!from) | |
235 return; | |
236 | |
10941 | 237 jb = jabber_buddy_find(js, from, TRUE); |
238 | |
239 js->pending_avatar_requests = g_slist_remove(js->pending_avatar_requests, jb); | |
240 | |
10189 | 241 if((vcard = xmlnode_get_child(packet, "vCard")) || |
242 (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) { | |
10941 | 243 if((photo = xmlnode_get_child(vcard, "PHOTO")) && |
11361 | 244 (( (binval = xmlnode_get_child(photo, "BINVAL")) && |
245 (text = xmlnode_get_data(binval))) || | |
246 (text = xmlnode_get_data(photo)))) { | |
11127 | 247 data = gaim_base64_decode(text, &size); |
10189 | 248 |
10941 | 249 gaim_buddy_icons_set_for_user(js->gc->account, from, data, size); |
250 if((b = gaim_find_buddy(js->gc->account, from))) { | |
251 unsigned char hashval[20]; | |
252 char hash[41], *p; | |
253 int i; | |
10189 | 254 |
11183 | 255 gaim_cipher_digest_region("sha1", (guchar *)data, size, |
10941 | 256 sizeof(hashval), hashval, NULL); |
257 p = hash; | |
258 for(i=0; i<20; i++, p+=2) | |
259 snprintf(p, 3, "%02x", hashval[i]); | |
260 gaim_blist_node_set_string((GaimBlistNode*)b, "avatar_hash", hash); | |
10189 | 261 } |
10941 | 262 g_free(text); |
10189 | 263 } |
264 } | |
265 } | |
266 | |
7014 | 267 void jabber_presence_parse(JabberStream *js, xmlnode *packet) |
268 { | |
269 const char *from = xmlnode_get_attrib(packet, "from"); | |
270 const char *type = xmlnode_get_attrib(packet, "type"); | |
7944 | 271 const char *real_jid = NULL; |
9152 | 272 const char *affiliation = NULL; |
273 const char *role = NULL; | |
7014 | 274 char *status = NULL; |
275 int priority = 0; | |
276 JabberID *jid; | |
277 JabberChat *chat; | |
278 JabberBuddy *jb; | |
9954 | 279 JabberBuddyResource *jbr = NULL, *found_jbr = NULL; |
9554 | 280 GaimConvChatBuddyFlags flags = GAIM_CBFLAGS_NONE; |
9846 | 281 gboolean delayed = FALSE; |
10189 | 282 GaimBuddy *b = NULL; |
7014 | 283 char *buddy_name; |
9954 | 284 JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN; |
7014 | 285 xmlnode *y; |
286 gboolean muc = FALSE; | |
10189 | 287 char *avatar_hash = NULL; |
7014 | 288 |
289 | |
8043 | 290 if(!(jb = jabber_buddy_find(js, from, TRUE))) |
291 return; | |
292 | |
293 if(!(jid = jabber_id_new(from))) | |
7280 | 294 return; |
295 | |
7014 | 296 if(jb->error_msg) { |
297 g_free(jb->error_msg); | |
298 jb->error_msg = NULL; | |
299 } | |
300 | |
7813 | 301 if(type && !strcmp(type, "error")) { |
8401 | 302 char *msg = jabber_parse_error(js, packet); |
7644 | 303 |
9954 | 304 state = JABBER_BUDDY_STATE_ERROR; |
8401 | 305 jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence")); |
7813 | 306 } else if(type && !strcmp(type, "subscribe")) { |
7014 | 307 struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1); |
10949 | 308 char *msg; |
309 | |
310 msg = g_strdup_printf(_("The user %s wants to add %s to his or " | |
311 "her buddy list."), | |
312 from, gaim_account_get_username(js->gc->account)); | |
7014 | 313 jap->gc = js->gc; |
314 jap->who = g_strdup(from); | |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
315 jap->js = js; |
7014 | 316 |
10189 | 317 gaim_request_action(js->gc, NULL, msg, NULL, GAIM_DEFAULT_ACTION_NONE, |
10116 | 318 jap, 2, |
12603
e4e47871c373
[gaim-migrate @ 14938]
Richard Laager <rlaager@wiktel.com>
parents:
12285
diff
changeset
|
319 _("_Authorize"), G_CALLBACK(authorize_add_cb), |
e4e47871c373
[gaim-migrate @ 14938]
Richard Laager <rlaager@wiktel.com>
parents:
12285
diff
changeset
|
320 _("_Deny"), G_CALLBACK(deny_add_cb)); |
7014 | 321 g_free(msg); |
8043 | 322 jabber_id_free(jid); |
7145 | 323 return; |
7813 | 324 } else if(type && !strcmp(type, "subscribed")) { |
7014 | 325 /* we've been allowed to see their presence, but we don't care */ |
8043 | 326 jabber_id_free(jid); |
7014 | 327 return; |
12285
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
328 } else if(type && !strcmp(type, "unsubscribe")) { |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
329 /* 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
|
330 * might be better to add "unsubscribe" to the presence status |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
331 * if lower down, but I'm not sure. */ |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
332 /* they are unsubscribing from our presence, we don't care */ |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
333 /* Well, maybe just a little, we might want/need to start |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
334 * acknowledging this (and the others) at some point. */ |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
335 jabber_id_free(jid); |
af257d8679fe
[gaim-migrate @ 14589]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12265
diff
changeset
|
336 return; |
7014 | 337 } else { |
338 if((y = xmlnode_get_child(packet, "show"))) { | |
339 char *show = xmlnode_get_data(y); | |
9954 | 340 state = jabber_buddy_status_id_get_state(show); |
7014 | 341 g_free(show); |
342 } else { | |
9954 | 343 state = JABBER_BUDDY_STATE_ONLINE; |
7014 | 344 } |
345 } | |
346 | |
7310 | 347 |
7014 | 348 for(y = packet->child; y; y = y->next) { |
8135 | 349 if(y->type != XMLNODE_TYPE_TAG) |
7014 | 350 continue; |
351 | |
352 if(!strcmp(y->name, "status")) { | |
7615 | 353 g_free(status); |
7014 | 354 status = xmlnode_get_data(y); |
355 } else if(!strcmp(y->name, "priority")) { | |
356 char *p = xmlnode_get_data(y); | |
357 if(p) { | |
358 priority = atoi(p); | |
359 g_free(p); | |
360 } | |
361 } else if(!strcmp(y->name, "x")) { | |
362 const char *xmlns = xmlnode_get_attrib(y, "xmlns"); | |
9846 | 363 if(xmlns && !strcmp(xmlns, "jabber:x:delay")) { |
9847 | 364 /* XXX: compare the time. jabber:x:delay can happen on presence packets that aren't really and truly delayed */ |
9846 | 365 delayed = TRUE; |
366 } else if(xmlns && !strcmp(xmlns, "http://jabber.org/protocol/muc#user")) { | |
7629 | 367 xmlnode *z; |
368 | |
7014 | 369 muc = TRUE; |
7629 | 370 if((z = xmlnode_get_child(y, "status"))) { |
371 const char *code = xmlnode_get_attrib(z, "code"); | |
372 if(code && !strcmp(code, "201")) { | |
7895 | 373 chat = jabber_chat_find(js, jid->node, jid->domain); |
8396 | 374 chat->config_dialog_type = GAIM_REQUEST_ACTION; |
375 chat->config_dialog_handle = | |
376 gaim_request_action(js->gc, _("Create New Room"), | |
7895 | 377 _("Create New Room"), |
378 _("You are creating a new room. Would you like to " | |
379 "configure it, or accept the default settings?"), | |
12603
e4e47871c373
[gaim-migrate @ 14938]
Richard Laager <rlaager@wiktel.com>
parents:
12285
diff
changeset
|
380 1, chat, 2, _("_Configure Room"), |
7923 | 381 G_CALLBACK(jabber_chat_request_room_configure), |
12603
e4e47871c373
[gaim-migrate @ 14938]
Richard Laager <rlaager@wiktel.com>
parents:
12285
diff
changeset
|
382 _("_Accept Defaults"), |
7895 | 383 G_CALLBACK(jabber_chat_create_instant_room)); |
7629 | 384 } |
385 } | |
7944 | 386 if((z = xmlnode_get_child(y, "item"))) { |
387 real_jid = xmlnode_get_attrib(z, "jid"); | |
9152 | 388 affiliation = xmlnode_get_attrib(z, "affiliation"); |
389 role = xmlnode_get_attrib(z, "role"); | |
9931 | 390 if(affiliation != NULL && !strcmp(affiliation, "owner")) |
391 flags |= GAIM_CBFLAGS_FOUNDER; | |
9743 | 392 if (role != NULL) { |
393 if (!strcmp(role, "moderator")) | |
9931 | 394 flags |= GAIM_CBFLAGS_OP; |
9743 | 395 else if (!strcmp(role, "participant")) |
9931 | 396 flags |= GAIM_CBFLAGS_VOICE; |
9743 | 397 } |
7944 | 398 } |
10189 | 399 } else if(xmlns && !strcmp(xmlns, "vcard-temp:x:update")) { |
400 xmlnode *photo = xmlnode_get_child(y, "photo"); | |
401 if(photo) { | |
402 if(avatar_hash) | |
403 g_free(avatar_hash); | |
404 avatar_hash = xmlnode_get_data(photo); | |
405 } | |
7014 | 406 } |
407 } | |
408 } | |
409 | |
410 | |
7322 | 411 if(jid->node && (chat = jabber_chat_find(js, jid->node, jid->domain))) { |
8462 | 412 static int i = 1; |
7014 | 413 char *room_jid = g_strdup_printf("%s@%s", jid->node, jid->domain); |
414 | |
9954 | 415 if(state == JABBER_BUDDY_STATE_ERROR) { |
8401 | 416 char *title, *msg = jabber_parse_error(js, packet); |
7014 | 417 |
7321 | 418 if(chat->conv) { |
8401 | 419 title = g_strdup_printf(_("Error in chat %s"), from); |
7321 | 420 serv_got_chat_left(js->gc, chat->id); |
421 } else { | |
8401 | 422 title = g_strdup_printf(_("Error joining chat %s"), from); |
7321 | 423 } |
8401 | 424 gaim_notify_error(js->gc, title, title, msg); |
425 g_free(title); | |
426 g_free(msg); | |
7014 | 427 |
428 jabber_chat_destroy(chat); | |
7310 | 429 jabber_id_free(jid); |
7615 | 430 g_free(status); |
8182 | 431 g_free(room_jid); |
10189 | 432 if(avatar_hash) |
433 g_free(avatar_hash); | |
7014 | 434 return; |
435 } | |
436 | |
437 | |
7813 | 438 if(type && !strcmp(type, "unavailable")) { |
7972 | 439 gboolean nick_change = FALSE; |
7973 | 440 |
9152 | 441 /* If we haven't joined the chat yet, we don't care that someone |
442 * left, or it was us leaving after we closed the chat */ | |
8182 | 443 if(!chat->conv) { |
10558 | 444 if(jid->resource && chat->handle && !strcmp(jid->resource, chat->handle)) |
9152 | 445 jabber_chat_destroy(chat); |
8182 | 446 jabber_id_free(jid); |
447 g_free(status); | |
448 g_free(room_jid); | |
10189 | 449 if(avatar_hash) |
450 g_free(avatar_hash); | |
8182 | 451 return; |
452 } | |
453 | |
7973 | 454 jabber_buddy_remove_resource(jb, jid->resource); |
7972 | 455 if(chat->muc) { |
456 xmlnode *x; | |
8135 | 457 for(x = xmlnode_get_child(packet, "x"); x; x = xmlnode_get_next_twin(x)) { |
7972 | 458 const char *xmlns, *nick, *code; |
459 xmlnode *stat, *item; | |
460 if(!(xmlns = xmlnode_get_attrib(x, "xmlns")) || | |
461 strcmp(xmlns, "http://jabber.org/protocol/muc#user")) | |
462 continue; | |
463 if(!(stat = xmlnode_get_child(x, "status"))) | |
464 continue; | |
9152 | 465 if(!(code = xmlnode_get_attrib(stat, "code"))) |
7972 | 466 continue; |
9152 | 467 if(!strcmp(code, "301")) { |
468 /* XXX: we got banned */ | |
469 } else if(!strcmp(code, "303")) { | |
470 if(!(item = xmlnode_get_child(x, "item"))) | |
471 continue; | |
472 if(!(nick = xmlnode_get_attrib(item, "nick"))) | |
473 continue; | |
474 nick_change = TRUE; | |
475 if(!strcmp(jid->resource, chat->handle)) { | |
476 g_free(chat->handle); | |
477 chat->handle = g_strdup(nick); | |
478 } | |
479 gaim_conv_chat_rename_user(GAIM_CONV_CHAT(chat->conv), jid->resource, nick); | |
480 jabber_chat_remove_handle(chat, jid->resource); | |
481 break; | |
482 } else if(!strcmp(code, "307")) { | |
483 /* XXX: we got kicked */ | |
484 } else if(!strcmp(code, "321")) { | |
485 /* XXX: removed due to an affiliation change */ | |
486 } else if(!strcmp(code, "322")) { | |
487 /* XXX: removed because room is now members-only */ | |
488 } else if(!strcmp(code, "332")) { | |
489 /* XXX: removed due to system shutdown */ | |
8401 | 490 } |
7972 | 491 } |
492 } | |
493 if(!nick_change) { | |
9152 | 494 if(!g_utf8_collate(jid->resource, chat->handle)) { |
7972 | 495 serv_got_chat_left(js->gc, chat->id); |
496 jabber_chat_destroy(chat); | |
497 } else { | |
498 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(chat->conv), jid->resource, | |
7974 | 499 status); |
9152 | 500 jabber_chat_remove_handle(chat, jid->resource); |
7972 | 501 } |
7014 | 502 } |
503 } else { | |
8182 | 504 if(!chat->conv) { |
505 chat->id = i++; | |
506 chat->muc = muc; | |
507 chat->conv = serv_got_joined_chat(js->gc, chat->id, room_jid); | |
10722 | 508 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(chat->conv), chat->handle); |
10486 | 509 |
10941 | 510 jabber_chat_disco_traffic(chat); |
8182 | 511 } |
512 | |
7973 | 513 jabber_buddy_track_resource(jb, jid->resource, priority, state, |
514 status); | |
515 | |
9152 | 516 jabber_chat_track_handle(chat, jid->resource, real_jid, affiliation, role); |
517 | |
7014 | 518 if(!jabber_chat_find_buddy(chat->conv, jid->resource)) |
7118
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
7095
diff
changeset
|
519 gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat->conv), jid->resource, |
9846 | 520 real_jid, flags, !delayed); |
9554 | 521 else |
522 gaim_conv_chat_user_set_flags(GAIM_CONV_CHAT(chat->conv), jid->resource, | |
523 flags); | |
7014 | 524 } |
525 g_free(room_jid); | |
526 } else { | |
7322 | 527 buddy_name = g_strdup_printf("%s%s%s", jid->node ? jid->node : "", |
528 jid->node ? "@" : "", jid->domain); | |
7014 | 529 if((b = gaim_find_buddy(js->gc->account, buddy_name)) == NULL) { |
530 jabber_id_free(jid); | |
10189 | 531 if(avatar_hash) |
532 g_free(avatar_hash); | |
7014 | 533 g_free(buddy_name); |
7615 | 534 g_free(status); |
7014 | 535 return; |
536 } | |
537 | |
10189 | 538 if(avatar_hash) { |
539 const char *avatar_hash2 = gaim_blist_node_get_string((GaimBlistNode*)b, "avatar_hash"); | |
540 if(!avatar_hash2 || strcmp(avatar_hash, avatar_hash2)) { | |
541 JabberIq *iq; | |
542 xmlnode *vcard; | |
543 | |
10941 | 544 /* XXX this is a crappy way of trying to prevent |
545 * someone from spamming us with presence packets | |
546 * and causing us to DoS ourselves...what we really | |
547 * need is a queue system that can throttle itself, | |
548 * but i'm too tired to write that right now */ | |
549 if(!g_slist_find(js->pending_avatar_requests, jb)) { | |
550 | |
551 js->pending_avatar_requests = g_slist_prepend(js->pending_avatar_requests, jb); | |
10189 | 552 |
10941 | 553 iq = jabber_iq_new(js, JABBER_IQ_GET); |
554 xmlnode_set_attrib(iq->node, "to", buddy_name); | |
555 vcard = xmlnode_new_child(iq->node, "vCard"); | |
556 xmlnode_set_attrib(vcard, "xmlns", "vcard-temp"); | |
557 | |
558 jabber_iq_set_callback(iq, jabber_vcard_parse_avatar, NULL); | |
559 jabber_iq_send(iq); | |
560 } | |
10189 | 561 } |
562 } | |
563 | |
9954 | 564 if(state == JABBER_BUDDY_STATE_ERROR || |
7813 | 565 (type && (!strcmp(type, "unavailable") || |
566 !strcmp(type, "unsubscribed")))) { | |
8043 | 567 GaimConversation *conv; |
568 | |
7014 | 569 jabber_buddy_remove_resource(jb, jid->resource); |
8043 | 570 if((conv = jabber_find_unnormalized_conv(from, js->gc->account))) |
571 gaim_conversation_set_name(conv, buddy_name); | |
572 | |
7395 | 573 } else { |
9954 | 574 jbr = jabber_buddy_track_resource(jb, jid->resource, priority, |
575 state, status); | |
7395 | 576 } |
7014 | 577 |
9954 | 578 if((found_jbr = jabber_buddy_find_resource(jb, NULL))) { |
579 if(!jbr || jbr == found_jbr) { | |
9990 | 580 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 | 581 } |
582 } else { | |
9990 | 583 gaim_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL); |
9954 | 584 } |
7014 | 585 g_free(buddy_name); |
586 } | |
587 g_free(status); | |
588 jabber_id_free(jid); | |
10189 | 589 if(avatar_hash) |
590 g_free(avatar_hash); | |
7014 | 591 } |
592 | |
593 void jabber_presence_subscription_set(JabberStream *js, const char *who, const char *type) | |
594 { | |
595 xmlnode *presence = xmlnode_new("presence"); | |
596 | |
597 xmlnode_set_attrib(presence, "to", who); | |
598 xmlnode_set_attrib(presence, "type", type); | |
599 | |
600 jabber_send(js, presence); | |
601 xmlnode_free(presence); | |
602 } | |
9954 | 603 |
604 void gaim_status_to_jabber(const GaimStatus *status, JabberBuddyState *state, const char **msg, int *priority) | |
605 { | |
10216 | 606 const char *status_id = NULL; |
607 | |
608 *state = JABBER_BUDDY_STATE_UNKNOWN; | |
609 *msg = NULL; | |
610 *priority = 0; | |
9954 | 611 |
612 if(!status) { | |
10216 | 613 *state = JABBER_BUDDY_STATE_UNAVAILABLE; |
614 } else { | |
615 if(state) { | |
616 status_id = gaim_status_get_id(status); | |
617 *state = jabber_buddy_status_id_get_state(status_id); | |
618 } | |
619 | |
620 if(msg) | |
621 *msg = gaim_status_get_attr_string(status, "message"); | |
622 | |
11872 | 623 /* if the message is blank, then there really isn't a message */ |
624 if(*msg && !**msg) | |
625 *msg = NULL; | |
626 | |
10216 | 627 if(priority) |
628 *priority = gaim_status_get_attr_int(status, "priority"); | |
9954 | 629 } |
630 | |
631 } |