Mercurial > pidgin
annotate libgaim/protocols/jabber/jabber.c @ 15203:f814b2df9cce
[gaim-migrate @ 17993]
Blocking on Google Talk. Our Privacy API sucks so bad that even with no prior support for blocking in Jabber, this has no interface changes. If someone wanted to implement the deprecated Jabber privacy lists API, though, that would be ok by me.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Thu, 14 Dec 2006 04:56:54 +0000 |
parents | bbeb1dfcb25b |
children | 4bf7801a2539 |
rev | line source |
---|---|
14192 | 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 "account.h" | |
24 #include "accountopt.h" | |
25 #include "blist.h" | |
26 #include "cmds.h" | |
27 #include "connection.h" | |
28 #include "debug.h" | |
29 #include "dnssrv.h" | |
30 #include "message.h" | |
31 #include "notify.h" | |
32 #include "pluginpref.h" | |
33 #include "proxy.h" | |
34 #include "prpl.h" | |
35 #include "request.h" | |
36 #include "server.h" | |
37 #include "util.h" | |
38 #include "version.h" | |
39 | |
40 #include "auth.h" | |
41 #include "buddy.h" | |
42 #include "chat.h" | |
43 #include "disco.h" | |
15203 | 44 #include "google.h" |
14192 | 45 #include "iq.h" |
46 #include "jutil.h" | |
47 #include "message.h" | |
48 #include "parser.h" | |
49 #include "presence.h" | |
50 #include "jabber.h" | |
51 #include "roster.h" | |
52 #include "si.h" | |
53 #include "xdata.h" | |
54 | |
55 #define JABBER_CONNECT_STEPS (js->gsc ? 8 : 5) | |
56 | |
57 static GaimPlugin *my_protocol = NULL; | |
58 | |
59 static void jabber_stream_init(JabberStream *js) | |
60 { | |
61 char *open_stream; | |
62 | |
63 open_stream = g_strdup_printf("<stream:stream to='%s' " | |
64 "xmlns='jabber:client' " | |
65 "xmlns:stream='http://etherx.jabber.org/streams' " | |
66 "version='1.0'>", | |
67 js->user->domain); | |
68 /* setup the parser fresh for each stream */ | |
69 jabber_parser_setup(js); | |
70 jabber_send_raw(js, open_stream, -1); | |
71 js->reinit = FALSE; | |
72 g_free(open_stream); | |
73 } | |
74 | |
75 static void | |
76 jabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
77 { | |
78 const char *type = xmlnode_get_attrib(packet, "type"); | |
79 if(type && !strcmp(type, "result")) { | |
80 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); | |
81 } else { | |
82 gaim_connection_error(js->gc, _("Error initializing session")); | |
83 } | |
84 } | |
85 | |
86 static void jabber_session_init(JabberStream *js) | |
87 { | |
88 JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET); | |
89 xmlnode *session; | |
90 | |
91 jabber_iq_set_callback(iq, jabber_session_initialized_cb, NULL); | |
92 | |
93 session = xmlnode_new_child(iq->node, "session"); | |
94 xmlnode_set_namespace(session, "urn:ietf:params:xml:ns:xmpp-session"); | |
95 | |
96 jabber_iq_send(iq); | |
97 } | |
98 | |
99 static void jabber_bind_result_cb(JabberStream *js, xmlnode *packet, | |
100 gpointer data) | |
101 { | |
102 const char *type = xmlnode_get_attrib(packet, "type"); | |
103 xmlnode *bind; | |
104 | |
105 if(type && !strcmp(type, "result") && | |
106 (bind = xmlnode_get_child_with_namespace(packet, "bind", "urn:ietf:params:xml:ns:xmpp-bind"))) { | |
107 xmlnode *jid; | |
108 char *full_jid; | |
109 if((jid = xmlnode_get_child(bind, "jid")) && (full_jid = xmlnode_get_data(jid))) { | |
110 JabberBuddy *my_jb = NULL; | |
111 jabber_id_free(js->user); | |
112 if(!(js->user = jabber_id_new(full_jid))) { | |
113 gaim_connection_error(js->gc, _("Invalid response from server.")); | |
114 } | |
115 if((my_jb = jabber_buddy_find(js, full_jid, TRUE))) | |
116 my_jb->subscription |= JABBER_SUB_BOTH; | |
117 g_free(full_jid); | |
118 } | |
119 } else { | |
120 char *msg = jabber_parse_error(js, packet); | |
121 gaim_connection_error(js->gc, msg); | |
122 g_free(msg); | |
123 } | |
124 | |
125 jabber_session_init(js); | |
126 } | |
127 | |
128 static void jabber_stream_features_parse(JabberStream *js, xmlnode *packet) | |
129 { | |
130 if(xmlnode_get_child(packet, "starttls")) { | |
131 if(jabber_process_starttls(js, packet)) | |
132 return; | |
133 } | |
134 | |
135 if(js->registration) { | |
136 jabber_register_start(js); | |
137 } else if(xmlnode_get_child(packet, "mechanisms")) { | |
138 jabber_auth_start(js, packet); | |
139 } else if(xmlnode_get_child(packet, "bind")) { | |
140 xmlnode *bind, *resource; | |
141 JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET); | |
142 bind = xmlnode_new_child(iq->node, "bind"); | |
143 xmlnode_set_namespace(bind, "urn:ietf:params:xml:ns:xmpp-bind"); | |
144 resource = xmlnode_new_child(bind, "resource"); | |
145 xmlnode_insert_data(resource, js->user->resource, -1); | |
146 | |
147 jabber_iq_set_callback(iq, jabber_bind_result_cb, NULL); | |
148 | |
149 jabber_iq_send(iq); | |
150 } else /* if(xmlnode_get_child_with_namespace(packet, "auth")) */ { | |
151 /* If we get an empty stream:features packet, or we explicitly get | |
152 * an auth feature with namespace http://jabber.org/features/iq-auth | |
153 * we should revert back to iq:auth authentication, even though we're | |
154 * connecting to an XMPP server. */ | |
155 js->auth_type = JABBER_AUTH_IQ_AUTH; | |
156 jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING); | |
157 } | |
158 } | |
159 | |
160 static void jabber_stream_handle_error(JabberStream *js, xmlnode *packet) | |
161 { | |
162 char *msg = jabber_parse_error(js, packet); | |
163 | |
164 gaim_connection_error(js->gc, msg); | |
165 g_free(msg); | |
166 } | |
167 | |
168 static void tls_init(JabberStream *js); | |
169 | |
170 void jabber_process_packet(JabberStream *js, xmlnode *packet) | |
171 { | |
14296 | 172 gaim_signal_emit(my_protocol, "jabber-receiving-xmlnode", js->gc, &packet); |
173 | |
174 /* if the signal leaves us with a null packet, we're done */ | |
175 if(NULL == packet) | |
176 return; | |
177 | |
14192 | 178 if(!strcmp(packet->name, "iq")) { |
179 jabber_iq_parse(js, packet); | |
180 } else if(!strcmp(packet->name, "presence")) { | |
181 jabber_presence_parse(js, packet); | |
182 } else if(!strcmp(packet->name, "message")) { | |
183 jabber_message_parse(js, packet); | |
184 } else if(!strcmp(packet->name, "stream:features")) { | |
185 jabber_stream_features_parse(js, packet); | |
186 } else if (!strcmp(packet->name, "features") && | |
187 !strcmp(xmlnode_get_namespace(packet), "http://etherx.jabber.org/streams")) { | |
188 jabber_stream_features_parse(js, packet); | |
189 } else if(!strcmp(packet->name, "stream:error")) { | |
190 jabber_stream_handle_error(js, packet); | |
191 } else if (!strcmp(packet->name, "error") && | |
192 !strcmp(xmlnode_get_namespace(packet), "http://etherx.jabber.org/streams")) { | |
193 jabber_stream_handle_error(js, packet); | |
194 } else if(!strcmp(packet->name, "challenge")) { | |
195 if(js->state == JABBER_STREAM_AUTHENTICATING) | |
196 jabber_auth_handle_challenge(js, packet); | |
197 } else if(!strcmp(packet->name, "success")) { | |
198 if(js->state == JABBER_STREAM_AUTHENTICATING) | |
199 jabber_auth_handle_success(js, packet); | |
200 } else if(!strcmp(packet->name, "failure")) { | |
201 if(js->state == JABBER_STREAM_AUTHENTICATING) | |
202 jabber_auth_handle_failure(js, packet); | |
203 } else if(!strcmp(packet->name, "proceed")) { | |
204 if(js->state == JABBER_STREAM_AUTHENTICATING && !js->gsc) | |
205 tls_init(js); | |
206 } else { | |
207 gaim_debug(GAIM_DEBUG_WARNING, "jabber", "Unknown packet: %s\n", | |
208 packet->name); | |
209 } | |
210 } | |
211 | |
212 static int jabber_do_send(JabberStream *js, const char *data, int len) | |
213 { | |
214 int ret; | |
215 | |
216 if (js->gsc) | |
217 ret = gaim_ssl_write(js->gsc, data, len); | |
218 else | |
219 ret = write(js->fd, data, len); | |
220 | |
221 return ret; | |
222 } | |
223 | |
224 static void jabber_send_cb(gpointer data, gint source, GaimInputCondition cond) | |
225 { | |
226 JabberStream *js = data; | |
227 int ret, writelen; | |
228 writelen = gaim_circ_buffer_get_max_read(js->write_buffer); | |
229 | |
230 if (writelen == 0) { | |
231 gaim_input_remove(js->writeh); | |
232 js->writeh = 0; | |
233 return; | |
234 } | |
235 | |
236 ret = jabber_do_send(js, js->write_buffer->outptr, writelen); | |
237 | |
238 if (ret < 0 && errno == EAGAIN) | |
239 return; | |
240 else if (ret <= 0) { | |
241 gaim_connection_error(js->gc, _("Write error")); | |
242 return; | |
243 } | |
244 | |
245 gaim_circ_buffer_mark_read(js->write_buffer, ret); | |
246 } | |
247 | |
248 void jabber_send_raw(JabberStream *js, const char *data, int len) | |
249 { | |
250 int ret; | |
251 | |
252 /* because printing a tab to debug every minute gets old */ | |
253 if(strcmp(data, "\t")) | |
254 gaim_debug(GAIM_DEBUG_MISC, "jabber", "Sending%s: %s\n", | |
255 js->gsc ? " (ssl)" : "", data); | |
256 | |
257 /* If we've got a security layer, we need to encode the data, | |
258 * splitting it on the maximum buffer length negotiated */ | |
14606 | 259 |
260 gaim_signal_emit(my_protocol, "jabber-sending-text", js->gc, data); | |
261 | |
14192 | 262 #ifdef HAVE_CYRUS_SASL |
263 if (js->sasl_maxbuf>0) { | |
264 int pos; | |
265 | |
266 if (!js->gsc && js->fd<0) | |
267 return; | |
268 pos = 0; | |
269 if (len == -1) | |
270 len = strlen(data); | |
271 while (pos < len) { | |
272 int towrite; | |
273 const char *out; | |
274 unsigned olen; | |
275 | |
276 if ((len - pos) < js->sasl_maxbuf) | |
277 towrite = len - pos; | |
278 else | |
279 towrite = js->sasl_maxbuf; | |
280 | |
281 sasl_encode(js->sasl, &data[pos], towrite, &out, &olen); | |
282 pos += towrite; | |
283 | |
284 if (js->writeh > 0) | |
285 ret = jabber_do_send(js, out, olen); | |
286 else { | |
287 ret = -1; | |
288 errno = EAGAIN; | |
289 } | |
290 | |
291 if (ret < 0 && errno != EAGAIN) | |
292 gaim_connection_error(js->gc, _("Write error")); | |
293 else if (ret < olen) { | |
294 if (ret < 0) | |
295 ret = 0; | |
296 if (js->writeh == 0) | |
297 js->writeh = gaim_input_add( | |
298 js->gsc ? js->gsc->fd : js->fd, | |
299 GAIM_INPUT_WRITE, | |
300 jabber_send_cb, js); | |
301 gaim_circ_buffer_append(js->write_buffer, | |
302 out + ret, olen - ret); | |
303 } | |
304 } | |
305 return; | |
306 } | |
307 #endif | |
308 | |
309 if (len == -1) | |
310 len = strlen(data); | |
311 | |
312 if (js->writeh == 0) | |
313 ret = jabber_do_send(js, data, len); | |
314 else { | |
315 ret = -1; | |
316 errno = EAGAIN; | |
317 } | |
318 | |
319 if (ret < 0 && errno != EAGAIN) | |
320 gaim_connection_error(js->gc, _("Write error")); | |
321 else if (ret < len) { | |
322 if (ret < 0) | |
323 ret = 0; | |
324 if (js->writeh == 0) | |
325 js->writeh = gaim_input_add( | |
326 js->gsc ? js->gsc->fd : js->fd, | |
327 GAIM_INPUT_WRITE, jabber_send_cb, js); | |
328 gaim_circ_buffer_append(js->write_buffer, | |
329 data + ret, len - ret); | |
330 } | |
14542 | 331 return; |
332 } | |
14192 | 333 |
14573
9cbf4d3ef444
[gaim-migrate @ 17297]
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
14542
diff
changeset
|
334 static int jabber_prpl_send_raw(GaimConnection *gc, const char *buf, int len) |
14542 | 335 { |
336 JabberStream *js = (JabberStream*)gc->proto_data; | |
337 jabber_send_raw(js, buf, len); | |
338 return len; | |
14192 | 339 } |
340 | |
341 void jabber_send(JabberStream *js, xmlnode *packet) | |
342 { | |
343 char *txt; | |
344 int len; | |
345 | |
14296 | 346 gaim_signal_emit(my_protocol, "jabber-sending-xmlnode", js->gc, &packet); |
347 | |
348 /* if we get NULL back, we're done processing */ | |
349 if(NULL == packet) | |
350 return; | |
351 | |
14192 | 352 txt = xmlnode_to_str(packet, &len); |
353 jabber_send_raw(js, txt, len); | |
354 g_free(txt); | |
355 } | |
356 | |
357 static void jabber_keepalive(GaimConnection *gc) | |
358 { | |
359 jabber_send_raw(gc->proto_data, "\t", -1); | |
360 } | |
361 | |
362 static void | |
363 jabber_recv_cb_ssl(gpointer data, GaimSslConnection *gsc, | |
364 GaimInputCondition cond) | |
365 { | |
366 GaimConnection *gc = data; | |
367 JabberStream *js = gc->proto_data; | |
368 int len; | |
369 static char buf[4096]; | |
370 | |
371 /* TODO: It should be possible to make this check unnecessary */ | |
372 if(!GAIM_CONNECTION_IS_VALID(gc)) { | |
373 gaim_ssl_close(gsc); | |
374 return; | |
375 } | |
376 | |
377 while((len = gaim_ssl_read(gsc, buf, sizeof(buf) - 1)) > 0) { | |
378 buf[len] = '\0'; | |
379 gaim_debug(GAIM_DEBUG_INFO, "jabber", "Recv (ssl)(%d): %s\n", len, buf); | |
380 jabber_parser_process(js, buf, len); | |
381 if(js->reinit) | |
382 jabber_stream_init(js); | |
383 } | |
384 | |
385 if(errno == EAGAIN) | |
386 return; | |
387 else | |
388 gaim_connection_error(gc, _("Read Error")); | |
389 } | |
390 | |
391 static void | |
392 jabber_recv_cb(gpointer data, gint source, GaimInputCondition condition) | |
393 { | |
394 GaimConnection *gc = data; | |
395 JabberStream *js = gc->proto_data; | |
396 int len; | |
397 static char buf[4096]; | |
398 | |
399 if(!GAIM_CONNECTION_IS_VALID(gc)) | |
400 return; | |
401 | |
402 if((len = read(js->fd, buf, sizeof(buf) - 1)) > 0) { | |
403 #ifdef HAVE_CYRUS_SASL | |
404 if (js->sasl_maxbuf>0) { | |
405 const char *out; | |
14635
ba12c5e9d7e7
[gaim-migrate @ 17381]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14606
diff
changeset
|
406 unsigned int olen; |
14192 | 407 sasl_decode(js->sasl, buf, len, &out, &olen); |
408 if (olen>0) { | |
14635
ba12c5e9d7e7
[gaim-migrate @ 17381]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14606
diff
changeset
|
409 gaim_debug(GAIM_DEBUG_INFO, "jabber", "RecvSASL (%u): %s\n", olen, out); |
14192 | 410 jabber_parser_process(js,out,olen); |
14638 | 411 if(js->reinit) |
412 jabber_stream_init(js); | |
14192 | 413 } |
414 return; | |
415 } | |
416 #endif | |
417 buf[len] = '\0'; | |
418 gaim_debug(GAIM_DEBUG_INFO, "jabber", "Recv (%d): %s\n", len, buf); | |
419 jabber_parser_process(js, buf, len); | |
14638 | 420 if(js->reinit) |
421 jabber_stream_init(js); | |
14192 | 422 } else if(errno == EAGAIN) { |
423 return; | |
424 } else { | |
425 gaim_connection_error(gc, _("Read Error")); | |
426 } | |
427 } | |
428 | |
429 static void | |
430 jabber_login_callback_ssl(gpointer data, GaimSslConnection *gsc, | |
431 GaimInputCondition cond) | |
432 { | |
433 GaimConnection *gc = data; | |
14961
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
434 JabberStream *js; |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
435 |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
436 /* TODO: It should be possible to make this check unnecessary */ |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
437 if(!GAIM_CONNECTION_IS_VALID(gc)) { |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
438 gaim_ssl_close(gsc); |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
439 return; |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
440 } |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
441 |
8a564904e9b5
[gaim-migrate @ 17740]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14837
diff
changeset
|
442 js = gc->proto_data; |
14192 | 443 |
444 if(js->state == JABBER_STREAM_CONNECTING) | |
445 jabber_send_raw(js, "<?xml version='1.0' ?>", -1); | |
446 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING); | |
447 gaim_ssl_input_add(gsc, jabber_recv_cb_ssl, gc); | |
448 } | |
449 | |
450 | |
451 static void | |
452 jabber_login_callback(gpointer data, gint source, const gchar *error) | |
453 { | |
454 GaimConnection *gc = data; | |
455 JabberStream *js = gc->proto_data; | |
456 | |
457 if (source < 0) { | |
458 gaim_connection_error(gc, _("Couldn't connect to host")); | |
459 return; | |
460 } | |
461 | |
462 js->fd = source; | |
463 | |
464 if(js->state == JABBER_STREAM_CONNECTING) | |
465 jabber_send_raw(js, "<?xml version='1.0' ?>", -1); | |
466 | |
467 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING); | |
468 gc->inpa = gaim_input_add(js->fd, GAIM_INPUT_READ, jabber_recv_cb, gc); | |
469 } | |
470 | |
471 static void | |
472 jabber_ssl_connect_failure(GaimSslConnection *gsc, GaimSslErrorType error, | |
473 gpointer data) | |
474 { | |
475 GaimConnection *gc = data; | |
476 JabberStream *js = gc->proto_data; | |
477 | |
14250 | 478 js->gsc = NULL; |
479 | |
14192 | 480 switch(error) { |
481 case GAIM_SSL_CONNECT_FAILED: | |
482 gaim_connection_error(gc, _("Connection Failed")); | |
483 break; | |
484 case GAIM_SSL_HANDSHAKE_FAILED: | |
485 gaim_connection_error(gc, _("SSL Handshake Failed")); | |
486 break; | |
487 } | |
488 } | |
489 | |
490 static void tls_init(JabberStream *js) | |
491 { | |
492 gaim_input_remove(js->gc->inpa); | |
493 js->gc->inpa = 0; | |
494 js->gsc = gaim_ssl_connect_fd(js->gc->account, js->fd, | |
495 jabber_login_callback_ssl, jabber_ssl_connect_failure, js->gc); | |
496 } | |
497 | |
498 static void jabber_login_connect(JabberStream *js, const char *server, int port) | |
499 { | |
14837 | 500 if (gaim_proxy_connect(js->gc, js->gc->account, server, |
501 port, jabber_login_callback, js->gc) == NULL) | |
14192 | 502 gaim_connection_error(js->gc, _("Unable to create socket")); |
503 } | |
504 | |
505 static void srv_resolved_cb(GaimSrvResponse *resp, int results, gpointer data) | |
506 { | |
507 JabberStream *js; | |
508 | |
14308 | 509 js = data; |
510 js->srv_query_data = NULL; | |
14192 | 511 |
512 if(results) { | |
513 jabber_login_connect(js, resp->hostname, resp->port); | |
514 g_free(resp); | |
515 } else { | |
516 jabber_login_connect(js, js->user->domain, | |
517 gaim_account_get_int(js->gc->account, "port", 5222)); | |
518 } | |
519 } | |
520 | |
521 | |
522 | |
523 static void | |
524 jabber_login(GaimAccount *account) | |
525 { | |
526 GaimConnection *gc = gaim_account_get_connection(account); | |
527 const char *connect_server = gaim_account_get_string(account, | |
528 "connect_server", ""); | |
529 JabberStream *js; | |
530 JabberBuddy *my_jb = NULL; | |
531 | |
532 gc->flags |= GAIM_CONNECTION_HTML; | |
533 js = gc->proto_data = g_new0(JabberStream, 1); | |
534 js->gc = gc; | |
535 js->fd = -1; | |
536 js->iq_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, | |
537 g_free, g_free); | |
538 js->disco_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, | |
539 g_free, g_free); | |
540 js->buddies = g_hash_table_new_full(g_str_hash, g_str_equal, | |
541 g_free, (GDestroyNotify)jabber_buddy_free); | |
542 js->chats = g_hash_table_new_full(g_str_hash, g_str_equal, | |
543 g_free, (GDestroyNotify)jabber_chat_free); | |
544 js->chat_servers = g_list_append(NULL, g_strdup("conference.jabber.org")); | |
545 js->user = jabber_id_new(gaim_account_get_username(account)); | |
546 js->next_id = g_random_int(); | |
547 js->write_buffer = gaim_circ_buffer_new(512); | |
548 | |
549 if(!js->user) { | |
550 gaim_connection_error(gc, _("Invalid Jabber ID")); | |
551 return; | |
552 } | |
553 | |
554 if(!js->user->resource) { | |
555 char *me; | |
556 js->user->resource = g_strdup("Home"); | |
557 if(!js->user->node) { | |
558 js->user->node = js->user->domain; | |
559 js->user->domain = g_strdup("jabber.org"); | |
560 } | |
561 me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, | |
562 js->user->resource); | |
563 gaim_account_set_username(account, me); | |
564 g_free(me); | |
565 } | |
566 | |
567 if((my_jb = jabber_buddy_find(js, gaim_account_get_username(account), TRUE))) | |
568 my_jb->subscription |= JABBER_SUB_BOTH; | |
569 | |
570 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING); | |
571 | |
572 /* if they've got old-ssl mode going, we probably want to ignore SRV lookups */ | |
573 if(gaim_account_get_bool(js->gc->account, "old_ssl", FALSE)) { | |
574 if(gaim_ssl_is_supported()) { | |
575 js->gsc = gaim_ssl_connect(js->gc->account, | |
576 connect_server[0] ? connect_server : js->user->domain, | |
577 gaim_account_get_int(account, "port", 5223), jabber_login_callback_ssl, | |
578 jabber_ssl_connect_failure, js->gc); | |
579 } else { | |
580 gaim_connection_error(js->gc, _("SSL support unavailable")); | |
581 } | |
582 } | |
583 | |
584 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll | |
585 * invoke the magic of SRV lookups, to figure out host and port */ | |
586 if(!js->gsc) { | |
587 if(connect_server[0]) { | |
588 jabber_login_connect(js, connect_server, gaim_account_get_int(account, "port", 5222)); | |
589 } else { | |
14308 | 590 js->srv_query_data = gaim_srv_resolve("xmpp-client", |
591 "tcp", js->user->domain, srv_resolved_cb, js); | |
14192 | 592 } |
593 } | |
594 } | |
595 | |
596 | |
597 static gboolean | |
598 conn_close_cb(gpointer data) | |
599 { | |
600 JabberStream *js = data; | |
601 GaimAccount *account = gaim_connection_get_account(js->gc); | |
602 | |
603 gaim_account_disconnect(account); | |
604 | |
605 return FALSE; | |
606 } | |
607 | |
608 static void | |
609 jabber_connection_schedule_close(JabberStream *js) | |
610 { | |
611 gaim_timeout_add(0, conn_close_cb, js); | |
612 } | |
613 | |
614 static void | |
615 jabber_registration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
616 { | |
617 const char *type = xmlnode_get_attrib(packet, "type"); | |
618 char *buf; | |
619 | |
620 if(!strcmp(type, "result")) { | |
621 buf = g_strdup_printf(_("Registration of %s@%s successful"), | |
622 js->user->node, js->user->domain); | |
623 gaim_notify_info(NULL, _("Registration Successful"), | |
624 _("Registration Successful"), buf); | |
625 g_free(buf); | |
626 } else { | |
627 char *msg = jabber_parse_error(js, packet); | |
628 | |
629 if(!msg) | |
630 msg = g_strdup(_("Unknown Error")); | |
631 | |
632 gaim_notify_error(NULL, _("Registration Failed"), | |
633 _("Registration Failed"), msg); | |
634 g_free(msg); | |
635 } | |
636 jabber_connection_schedule_close(js); | |
637 } | |
638 | |
639 static void | |
640 jabber_register_cb(JabberStream *js, GaimRequestFields *fields) | |
641 { | |
642 GList *groups, *flds; | |
643 xmlnode *query, *y; | |
644 JabberIq *iq; | |
645 char *username; | |
646 | |
647 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); | |
648 query = xmlnode_get_child(iq->node, "query"); | |
649 | |
650 for(groups = gaim_request_fields_get_groups(fields); groups; | |
651 groups = groups->next) { | |
652 for(flds = gaim_request_field_group_get_fields(groups->data); | |
653 flds; flds = flds->next) { | |
654 GaimRequestField *field = flds->data; | |
655 const char *id = gaim_request_field_get_id(field); | |
656 const char *value = gaim_request_field_string_get_value(field); | |
657 | |
658 if(!strcmp(id, "username")) { | |
659 y = xmlnode_new_child(query, "username"); | |
660 } else if(!strcmp(id, "password")) { | |
661 y = xmlnode_new_child(query, "password"); | |
662 } else if(!strcmp(id, "name")) { | |
663 y = xmlnode_new_child(query, "name"); | |
664 } else if(!strcmp(id, "email")) { | |
665 y = xmlnode_new_child(query, "email"); | |
666 } else if(!strcmp(id, "nick")) { | |
667 y = xmlnode_new_child(query, "nick"); | |
668 } else if(!strcmp(id, "first")) { | |
669 y = xmlnode_new_child(query, "first"); | |
670 } else if(!strcmp(id, "last")) { | |
671 y = xmlnode_new_child(query, "last"); | |
672 } else if(!strcmp(id, "address")) { | |
673 y = xmlnode_new_child(query, "address"); | |
674 } else if(!strcmp(id, "city")) { | |
675 y = xmlnode_new_child(query, "city"); | |
676 } else if(!strcmp(id, "state")) { | |
677 y = xmlnode_new_child(query, "state"); | |
678 } else if(!strcmp(id, "zip")) { | |
679 y = xmlnode_new_child(query, "zip"); | |
680 } else if(!strcmp(id, "phone")) { | |
681 y = xmlnode_new_child(query, "phone"); | |
682 } else if(!strcmp(id, "url")) { | |
683 y = xmlnode_new_child(query, "url"); | |
684 } else if(!strcmp(id, "date")) { | |
685 y = xmlnode_new_child(query, "date"); | |
686 } else { | |
687 continue; | |
688 } | |
689 xmlnode_insert_data(y, value, -1); | |
690 if(!strcmp(id, "username")) { | |
691 if(js->user->node) | |
692 g_free(js->user->node); | |
693 js->user->node = g_strdup(value); | |
694 } | |
695 } | |
696 } | |
697 | |
698 username = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, | |
699 js->user->resource); | |
700 gaim_account_set_username(js->gc->account, username); | |
701 g_free(username); | |
702 | |
703 jabber_iq_set_callback(iq, jabber_registration_result_cb, NULL); | |
704 | |
705 jabber_iq_send(iq); | |
706 | |
707 } | |
708 | |
709 static void | |
710 jabber_register_cancel_cb(JabberStream *js, GaimRequestFields *fields) | |
711 { | |
712 jabber_connection_schedule_close(js); | |
713 } | |
714 | |
715 static void jabber_register_x_data_cb(JabberStream *js, xmlnode *result, gpointer data) | |
716 { | |
717 xmlnode *query; | |
718 JabberIq *iq; | |
719 | |
720 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); | |
721 query = xmlnode_get_child(iq->node, "query"); | |
722 | |
723 xmlnode_insert_child(query, result); | |
724 | |
725 jabber_iq_set_callback(iq, jabber_registration_result_cb, NULL); | |
726 jabber_iq_send(iq); | |
727 } | |
728 | |
729 void jabber_register_parse(JabberStream *js, xmlnode *packet) | |
730 { | |
14294 | 731 const char *type; |
732 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) | |
733 return; | |
734 | |
14192 | 735 if(js->registration) { |
736 GaimRequestFields *fields; | |
737 GaimRequestFieldGroup *group; | |
738 GaimRequestField *field; | |
739 xmlnode *query, *x, *y; | |
740 char *instructions; | |
741 | |
742 /* get rid of the login thingy */ | |
743 gaim_connection_set_state(js->gc, GAIM_CONNECTED); | |
744 | |
745 query = xmlnode_get_child(packet, "query"); | |
746 | |
747 if(xmlnode_get_child(query, "registered")) { | |
748 gaim_notify_error(NULL, _("Already Registered"), | |
749 _("Already Registered"), NULL); | |
750 jabber_connection_schedule_close(js); | |
751 return; | |
752 } | |
753 | |
754 if((x = xmlnode_get_child_with_namespace(packet, "x", | |
755 "jabber:x:data"))) { | |
756 jabber_x_data_request(js, x, jabber_register_x_data_cb, NULL); | |
757 return; | |
758 } else if((x = xmlnode_get_child_with_namespace(packet, "x", | |
759 "jabber:x:oob"))) { | |
760 xmlnode *url; | |
761 | |
762 if((url = xmlnode_get_child(x, "url"))) { | |
763 char *href; | |
764 if((href = xmlnode_get_data(url))) { | |
765 gaim_notify_uri(NULL, href); | |
766 g_free(href); | |
767 js->gc->wants_to_die = TRUE; | |
768 jabber_connection_schedule_close(js); | |
769 return; | |
770 } | |
771 } | |
772 } | |
773 | |
774 /* as a last resort, use the old jabber:iq:register syntax */ | |
775 | |
776 fields = gaim_request_fields_new(); | |
777 group = gaim_request_field_group_new(NULL); | |
778 gaim_request_fields_add_group(fields, group); | |
779 | |
780 field = gaim_request_field_string_new("username", _("Username"), | |
781 js->user->node, FALSE); | |
782 gaim_request_field_group_add_field(group, field); | |
783 | |
784 field = gaim_request_field_string_new("password", _("Password"), | |
785 gaim_connection_get_password(js->gc), FALSE); | |
786 gaim_request_field_string_set_masked(field, TRUE); | |
787 gaim_request_field_group_add_field(group, field); | |
788 | |
789 if(xmlnode_get_child(query, "name")) { | |
790 field = gaim_request_field_string_new("name", _("Name"), | |
791 gaim_account_get_alias(js->gc->account), FALSE); | |
792 gaim_request_field_group_add_field(group, field); | |
793 } | |
794 if(xmlnode_get_child(query, "email")) { | |
795 field = gaim_request_field_string_new("email", _("E-mail"), | |
796 NULL, FALSE); | |
797 gaim_request_field_group_add_field(group, field); | |
798 } | |
799 if(xmlnode_get_child(query, "nick")) { | |
800 field = gaim_request_field_string_new("nick", _("Nickname"), | |
801 NULL, FALSE); | |
802 gaim_request_field_group_add_field(group, field); | |
803 } | |
804 if(xmlnode_get_child(query, "first")) { | |
805 field = gaim_request_field_string_new("first", _("First name"), | |
806 NULL, FALSE); | |
807 gaim_request_field_group_add_field(group, field); | |
808 } | |
809 if(xmlnode_get_child(query, "last")) { | |
810 field = gaim_request_field_string_new("last", _("Last name"), | |
811 NULL, FALSE); | |
812 gaim_request_field_group_add_field(group, field); | |
813 } | |
814 if(xmlnode_get_child(query, "address")) { | |
815 field = gaim_request_field_string_new("address", _("Address"), | |
816 NULL, FALSE); | |
817 gaim_request_field_group_add_field(group, field); | |
818 } | |
819 if(xmlnode_get_child(query, "city")) { | |
820 field = gaim_request_field_string_new("city", _("City"), | |
821 NULL, FALSE); | |
822 gaim_request_field_group_add_field(group, field); | |
823 } | |
824 if(xmlnode_get_child(query, "state")) { | |
825 field = gaim_request_field_string_new("state", _("State"), | |
826 NULL, FALSE); | |
827 gaim_request_field_group_add_field(group, field); | |
828 } | |
829 if(xmlnode_get_child(query, "zip")) { | |
830 field = gaim_request_field_string_new("zip", _("Postal code"), | |
831 NULL, FALSE); | |
832 gaim_request_field_group_add_field(group, field); | |
833 } | |
834 if(xmlnode_get_child(query, "phone")) { | |
835 field = gaim_request_field_string_new("phone", _("Phone"), | |
836 NULL, FALSE); | |
837 gaim_request_field_group_add_field(group, field); | |
838 } | |
839 if(xmlnode_get_child(query, "url")) { | |
840 field = gaim_request_field_string_new("url", _("URL"), | |
841 NULL, FALSE); | |
842 gaim_request_field_group_add_field(group, field); | |
843 } | |
844 if(xmlnode_get_child(query, "date")) { | |
845 field = gaim_request_field_string_new("date", _("Date"), | |
846 NULL, FALSE); | |
847 gaim_request_field_group_add_field(group, field); | |
848 } | |
849 | |
850 if((y = xmlnode_get_child(query, "instructions"))) | |
851 instructions = xmlnode_get_data(y); | |
852 else | |
853 instructions = g_strdup(_("Please fill out the information below " | |
854 "to register your new account.")); | |
855 | |
856 gaim_request_fields(js->gc, _("Register New Jabber Account"), | |
857 _("Register New Jabber Account"), instructions, fields, | |
858 _("Register"), G_CALLBACK(jabber_register_cb), | |
859 _("Cancel"), G_CALLBACK(jabber_register_cancel_cb), js); | |
860 | |
861 g_free(instructions); | |
862 } | |
863 } | |
864 | |
865 void jabber_register_start(JabberStream *js) | |
866 { | |
867 JabberIq *iq; | |
868 | |
869 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:register"); | |
870 jabber_iq_send(iq); | |
871 } | |
872 | |
873 static void jabber_register_account(GaimAccount *account) | |
874 { | |
875 GaimConnection *gc = gaim_account_get_connection(account); | |
876 JabberStream *js; | |
877 JabberBuddy *my_jb = NULL; | |
878 const char *connect_server = gaim_account_get_string(account, | |
879 "connect_server", ""); | |
880 const char *server; | |
881 | |
882 js = gc->proto_data = g_new0(JabberStream, 1); | |
883 js->gc = gc; | |
884 js->registration = TRUE; | |
885 js->iq_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, | |
886 g_free, g_free); | |
887 js->disco_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, | |
888 g_free, g_free); | |
889 js->user = jabber_id_new(gaim_account_get_username(account)); | |
890 js->next_id = g_random_int(); | |
891 | |
892 if(!js->user) { | |
893 gaim_connection_error(gc, _("Invalid Jabber ID")); | |
894 return; | |
895 } | |
896 | |
897 js->write_buffer = gaim_circ_buffer_new(512); | |
898 | |
899 if(!js->user->resource) { | |
900 char *me; | |
901 js->user->resource = g_strdup("Home"); | |
902 if(!js->user->node) { | |
903 js->user->node = js->user->domain; | |
904 js->user->domain = g_strdup("jabber.org"); | |
905 } | |
906 me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, | |
907 js->user->resource); | |
908 gaim_account_set_username(account, me); | |
909 g_free(me); | |
910 } | |
911 | |
912 if((my_jb = jabber_buddy_find(js, gaim_account_get_username(account), TRUE))) | |
913 my_jb->subscription |= JABBER_SUB_BOTH; | |
914 | |
915 server = connect_server[0] ? connect_server : js->user->domain; | |
916 | |
917 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING); | |
918 | |
919 if(gaim_account_get_bool(account, "old_ssl", FALSE)) { | |
920 if(gaim_ssl_is_supported()) { | |
921 js->gsc = gaim_ssl_connect(account, server, | |
922 gaim_account_get_int(account, "port", 5222), | |
923 jabber_login_callback_ssl, jabber_ssl_connect_failure, gc); | |
924 } else { | |
925 gaim_connection_error(gc, _("SSL support unavailable")); | |
926 } | |
927 } | |
928 | |
929 if(!js->gsc) { | |
15007 | 930 if (connect_server[0]) { |
931 jabber_login_connect(js, server, | |
932 gaim_account_get_int(account, | |
933 "port", 5222)); | |
934 } else { | |
935 js->srv_query_data = gaim_srv_resolve("xmpp-client", | |
936 "tcp", | |
937 js->user->domain, | |
938 srv_resolved_cb, | |
939 js); | |
940 } | |
14192 | 941 } |
942 } | |
943 | |
944 static void jabber_close(GaimConnection *gc) | |
945 { | |
946 JabberStream *js = gc->proto_data; | |
947 | |
948 /* Don't perform any actions on the ssl connection | |
949 * if we were forcibly disconnected because it will crash | |
950 * on some SSL backends. | |
951 */ | |
952 if (!gc->disconnect_timeout) | |
953 jabber_send_raw(js, "</stream:stream>", -1); | |
954 | |
14308 | 955 if (js->srv_query_data) |
956 gaim_srv_cancel(js->srv_query_data); | |
957 | |
14192 | 958 if(js->gsc) { |
959 #ifdef HAVE_OPENSSL | |
960 if (!gc->disconnect_timeout) | |
961 #endif | |
962 gaim_ssl_close(js->gsc); | |
963 } else if (js->fd > 0) { | |
964 if(js->gc->inpa) | |
965 gaim_input_remove(js->gc->inpa); | |
966 close(js->fd); | |
967 } | |
968 if(js->iq_callbacks) | |
969 g_hash_table_destroy(js->iq_callbacks); | |
970 if(js->disco_callbacks) | |
971 g_hash_table_destroy(js->disco_callbacks); | |
972 if(js->buddies) | |
973 g_hash_table_destroy(js->buddies); | |
974 if(js->chats) | |
975 g_hash_table_destroy(js->chats); | |
976 while(js->chat_servers) { | |
977 g_free(js->chat_servers->data); | |
978 js->chat_servers = g_list_delete_link(js->chat_servers, js->chat_servers); | |
979 } | |
980 while(js->user_directories) { | |
981 g_free(js->user_directories->data); | |
982 js->user_directories = g_list_delete_link(js->user_directories, js->user_directories); | |
983 } | |
984 if(js->stream_id) | |
985 g_free(js->stream_id); | |
986 if(js->user) | |
987 jabber_id_free(js->user); | |
988 if(js->avatar_hash) | |
989 g_free(js->avatar_hash); | |
990 gaim_circ_buffer_destroy(js->write_buffer); | |
991 if(js->writeh) | |
992 gaim_input_remove(js->writeh); | |
993 #ifdef HAVE_CYRUS_SASL | |
994 if(js->sasl) | |
995 sasl_dispose(&js->sasl); | |
996 if(js->sasl_mechs) | |
997 g_string_free(js->sasl_mechs, TRUE); | |
998 if(js->sasl_cb) | |
999 g_free(js->sasl_cb); | |
1000 #endif | |
15136 | 1001 g_free(js->server_name); |
15163 | 1002 g_free(js->gmail_last_time); |
1003 g_free(js->gmail_last_tid); | |
14192 | 1004 g_free(js); |
1005 | |
1006 gc->proto_data = NULL; | |
1007 } | |
1008 | |
1009 void jabber_stream_set_state(JabberStream *js, JabberStreamState state) | |
1010 { | |
1011 GaimPresence *gpresence; | |
1012 GaimStatus *status; | |
1013 | |
1014 js->state = state; | |
1015 switch(state) { | |
1016 case JABBER_STREAM_OFFLINE: | |
1017 break; | |
1018 case JABBER_STREAM_CONNECTING: | |
1019 gaim_connection_update_progress(js->gc, _("Connecting"), 1, | |
1020 JABBER_CONNECT_STEPS); | |
1021 break; | |
1022 case JABBER_STREAM_INITIALIZING: | |
1023 gaim_connection_update_progress(js->gc, _("Initializing Stream"), | |
1024 js->gsc ? 5 : 2, JABBER_CONNECT_STEPS); | |
1025 jabber_stream_init(js); | |
1026 break; | |
1027 case JABBER_STREAM_AUTHENTICATING: | |
1028 gaim_connection_update_progress(js->gc, _("Authenticating"), | |
1029 js->gsc ? 6 : 3, JABBER_CONNECT_STEPS); | |
1030 if(js->protocol_version == JABBER_PROTO_0_9 && js->registration) { | |
1031 jabber_register_start(js); | |
1032 } else if(js->auth_type == JABBER_AUTH_IQ_AUTH) { | |
1033 jabber_auth_start_old(js); | |
1034 } | |
1035 break; | |
1036 case JABBER_STREAM_REINITIALIZING: | |
1037 gaim_connection_update_progress(js->gc, _("Re-initializing Stream"), | |
1038 (js->gsc ? 7 : 4), JABBER_CONNECT_STEPS); | |
14638 | 1039 |
1040 /* The stream will be reinitialized later, in jabber_recv_cb_ssl() */ | |
1041 js->reinit = TRUE; | |
1042 | |
14192 | 1043 break; |
1044 case JABBER_STREAM_CONNECTED: | |
1045 gpresence = gaim_account_get_presence(js->gc->account); | |
1046 status = gaim_presence_get_active_status(gpresence); | |
1047 jabber_presence_send(js->gc->account, status); | |
1048 gaim_connection_set_state(js->gc, GAIM_CONNECTED); | |
1049 jabber_disco_items_server(js); | |
1050 break; | |
1051 } | |
1052 } | |
1053 | |
1054 char *jabber_get_next_id(JabberStream *js) | |
1055 { | |
1056 return g_strdup_printf("gaim%x", js->next_id++); | |
1057 } | |
1058 | |
14391 | 1059 |
14192 | 1060 static void jabber_idle_set(GaimConnection *gc, int idle) |
1061 { | |
1062 JabberStream *js = gc->proto_data; | |
1063 | |
1064 js->idle = idle ? time(NULL) - idle : idle; | |
1065 } | |
1066 | |
1067 static const char *jabber_list_icon(GaimAccount *a, GaimBuddy *b) | |
1068 { | |
1069 return "jabber"; | |
1070 } | |
1071 | |
1072 static void jabber_list_emblems(GaimBuddy *b, const char **se, const char **sw, | |
1073 const char **nw, const char **ne) | |
1074 { | |
1075 JabberStream *js; | |
1076 JabberBuddy *jb = NULL; | |
1077 | |
1078 if(!b->account->gc) | |
1079 return; | |
1080 js = b->account->gc->proto_data; | |
1081 if(js) | |
1082 jb = jabber_buddy_find(js, b->name, FALSE); | |
1083 | |
1084 if(!GAIM_BUDDY_IS_ONLINE(b)) { | |
1085 if(jb && jb->error_msg) | |
1086 *nw = "error"; | |
1087 | |
1088 if(jb && (jb->subscription & JABBER_SUB_PENDING || | |
1089 !(jb->subscription & JABBER_SUB_TO))) | |
1090 *se = "notauthorized"; | |
1091 else | |
1092 *se = "offline"; | |
1093 } else { | |
1094 GaimStatusType *status_type = gaim_status_get_type(gaim_presence_get_active_status(gaim_buddy_get_presence(b))); | |
1095 GaimStatusPrimitive primitive = gaim_status_type_get_primitive(status_type); | |
1096 | |
1097 if(primitive > GAIM_STATUS_AVAILABLE) { | |
1098 *se = gaim_status_type_get_id(status_type); | |
1099 } | |
1100 } | |
1101 } | |
1102 | |
1103 static char *jabber_status_text(GaimBuddy *b) | |
1104 { | |
1105 JabberBuddy *jb = jabber_buddy_find(b->account->gc->proto_data, b->name, | |
1106 FALSE); | |
1107 char *ret = NULL; | |
1108 | |
1109 if(jb && !GAIM_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) { | |
1110 ret = g_strdup(_("Not Authorized")); | |
1111 } else if(jb && !GAIM_BUDDY_IS_ONLINE(b) && jb->error_msg) { | |
1112 ret = g_strdup(jb->error_msg); | |
1113 } else { | |
1114 char *stripped; | |
1115 | |
1116 if(!(stripped = gaim_markup_strip_html(jabber_buddy_get_status_msg(jb)))) { | |
1117 GaimStatus *status = gaim_presence_get_active_status(gaim_buddy_get_presence(b)); | |
1118 | |
1119 if(!gaim_status_is_available(status)) | |
1120 stripped = g_strdup(gaim_status_get_name(status)); | |
1121 } | |
1122 | |
1123 if(stripped) { | |
1124 ret = g_markup_escape_text(stripped, -1); | |
1125 g_free(stripped); | |
1126 } | |
1127 } | |
1128 | |
1129 return ret; | |
1130 } | |
1131 | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1132 static void jabber_tooltip_text(GaimBuddy *b, GaimNotifyUserInfo *user_info, gboolean full) |
14192 | 1133 { |
1134 JabberBuddy *jb; | |
1135 | |
1136 g_return_if_fail(b != NULL); | |
1137 g_return_if_fail(b->account != NULL); | |
1138 g_return_if_fail(b->account->gc != NULL); | |
1139 g_return_if_fail(b->account->gc->proto_data != NULL); | |
1140 | |
1141 jb = jabber_buddy_find(b->account->gc->proto_data, b->name, | |
1142 FALSE); | |
1143 | |
1144 if(jb) { | |
1145 JabberBuddyResource *jbr = NULL; | |
1146 const char *sub; | |
1147 GList *l; | |
1148 | |
1149 if (full) { | |
1150 if(jb->subscription & JABBER_SUB_FROM) { | |
1151 if(jb->subscription & JABBER_SUB_TO) | |
1152 sub = _("Both"); | |
1153 else if(jb->subscription & JABBER_SUB_PENDING) | |
1154 sub = _("From (To pending)"); | |
1155 else | |
1156 sub = _("From"); | |
1157 } else { | |
1158 if(jb->subscription & JABBER_SUB_TO) | |
1159 sub = _("To"); | |
1160 else if(jb->subscription & JABBER_SUB_PENDING) | |
1161 sub = _("None (To pending)"); | |
1162 else | |
1163 sub = _("None"); | |
1164 } | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1165 |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1166 gaim_notify_user_info_add_pair(user_info, _("Subscription"), sub); |
14192 | 1167 } |
1168 | |
1169 for(l=jb->resources; l; l = l->next) { | |
1170 char *text = NULL; | |
1171 char *res = NULL; | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1172 char *label, *value; |
14192 | 1173 const char *state; |
1174 | |
1175 jbr = l->data; | |
1176 | |
1177 if(jbr->status) { | |
1178 char *tmp; | |
1179 text = gaim_strreplace(jbr->status, "\n", "<br />\n"); | |
1180 tmp = gaim_markup_strip_html(text); | |
1181 g_free(text); | |
1182 text = g_markup_escape_text(tmp, -1); | |
1183 g_free(tmp); | |
1184 } | |
1185 | |
1186 if(jbr->name) | |
1187 res = g_strdup_printf(" (%s)", jbr->name); | |
1188 | |
1189 state = jabber_buddy_state_get_name(jbr->state); | |
1190 if (text != NULL && !gaim_utf8_strcasecmp(state, text)) { | |
1191 g_free(text); | |
1192 text = NULL; | |
1193 } | |
1194 | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1195 label = g_strdup_printf("%s%s", |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1196 _("Status"), (res ? res : "")); |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1197 value = g_strdup_printf("%s%s%s", |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1198 state, |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1199 (text ? ": " : ""), |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1200 (text ? text : "")); |
14192 | 1201 |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1202 gaim_notify_user_info_add_pair(user_info, label, value); |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1203 |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1204 g_free(label); |
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1205 g_free(value); |
14192 | 1206 g_free(text); |
1207 g_free(res); | |
1208 } | |
1209 | |
1210 if(!GAIM_BUDDY_IS_ONLINE(b) && jb->error_msg) { | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15136
diff
changeset
|
1211 gaim_notify_user_info_add_pair(user_info, _("Error"), jb->error_msg); |
14192 | 1212 } |
1213 } | |
1214 } | |
1215 | |
1216 static GList *jabber_status_types(GaimAccount *account) | |
1217 { | |
1218 GaimStatusType *type; | |
1219 GList *types = NULL; | |
1220 GaimValue *priority_value; | |
1221 | |
1222 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1223 gaim_value_set_int(priority_value, 1); | |
1224 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AVAILABLE, | |
1225 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_ONLINE), | |
1226 NULL, TRUE, TRUE, FALSE, | |
1227 "priority", _("Priority"), priority_value, | |
1228 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1229 NULL); | |
1230 types = g_list_append(types, type); | |
1231 | |
1232 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1233 gaim_value_set_int(priority_value, 1); | |
1234 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AVAILABLE, | |
1235 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_CHAT), | |
1236 _("Chatty"), TRUE, TRUE, FALSE, | |
1237 "priority", _("Priority"), priority_value, | |
1238 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1239 NULL); | |
1240 types = g_list_append(types, type); | |
1241 | |
1242 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1243 gaim_value_set_int(priority_value, 0); | |
1244 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AWAY, | |
1245 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_AWAY), | |
1246 NULL, TRUE, TRUE, FALSE, | |
1247 "priority", _("Priority"), priority_value, | |
1248 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1249 NULL); | |
1250 types = g_list_append(types, type); | |
1251 | |
1252 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1253 gaim_value_set_int(priority_value, 0); | |
1254 type = gaim_status_type_new_with_attrs(GAIM_STATUS_EXTENDED_AWAY, | |
1255 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_XA), | |
1256 NULL, TRUE, TRUE, FALSE, | |
1257 "priority", _("Priority"), priority_value, | |
1258 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1259 NULL); | |
1260 types = g_list_append(types, type); | |
1261 | |
1262 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1263 gaim_value_set_int(priority_value, 0); | |
1264 type = gaim_status_type_new_with_attrs(GAIM_STATUS_UNAVAILABLE, | |
1265 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_DND), | |
1266 _("Do Not Disturb"), TRUE, TRUE, FALSE, | |
1267 "priority", _("Priority"), priority_value, | |
1268 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1269 NULL); | |
1270 types = g_list_append(types, type); | |
1271 | |
1272 /* | |
1273 if(js->protocol_version == JABBER_PROTO_0_9) | |
1274 m = g_list_append(m, _("Invisible")); | |
1275 */ | |
1276 | |
1277 type = gaim_status_type_new_with_attrs(GAIM_STATUS_OFFLINE, | |
1278 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_UNAVAILABLE), | |
1279 NULL, FALSE, TRUE, FALSE, | |
1280 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1281 NULL); | |
1282 types = g_list_append(types, type); | |
1283 | |
1284 return types; | |
1285 } | |
1286 | |
1287 static void | |
1288 jabber_password_change_result_cb(JabberStream *js, xmlnode *packet, | |
1289 gpointer data) | |
1290 { | |
1291 const char *type; | |
1292 | |
1293 type = xmlnode_get_attrib(packet, "type"); | |
1294 | |
1295 if(type && !strcmp(type, "result")) { | |
1296 gaim_notify_info(js->gc, _("Password Changed"), _("Password Changed"), | |
1297 _("Your password has been changed.")); | |
1298 } else { | |
1299 char *msg = jabber_parse_error(js, packet); | |
1300 | |
1301 gaim_notify_error(js->gc, _("Error changing password"), | |
1302 _("Error changing password"), msg); | |
1303 g_free(msg); | |
1304 } | |
1305 } | |
1306 | |
1307 static void jabber_password_change_cb(JabberStream *js, | |
1308 GaimRequestFields *fields) | |
1309 { | |
1310 const char *p1, *p2; | |
1311 JabberIq *iq; | |
1312 xmlnode *query, *y; | |
1313 | |
1314 p1 = gaim_request_fields_get_string(fields, "password1"); | |
1315 p2 = gaim_request_fields_get_string(fields, "password2"); | |
1316 | |
1317 if(strcmp(p1, p2)) { | |
1318 gaim_notify_error(js->gc, NULL, _("New passwords do not match."), NULL); | |
1319 return; | |
1320 } | |
1321 | |
1322 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); | |
1323 | |
1324 xmlnode_set_attrib(iq->node, "to", js->user->domain); | |
1325 | |
1326 query = xmlnode_get_child(iq->node, "query"); | |
1327 | |
1328 y = xmlnode_new_child(query, "username"); | |
1329 xmlnode_insert_data(y, js->user->node, -1); | |
1330 y = xmlnode_new_child(query, "password"); | |
1331 xmlnode_insert_data(y, p1, -1); | |
1332 | |
1333 jabber_iq_set_callback(iq, jabber_password_change_result_cb, NULL); | |
1334 | |
1335 jabber_iq_send(iq); | |
1336 | |
1337 gaim_account_set_password(js->gc->account, p1); | |
1338 } | |
1339 | |
1340 static void jabber_password_change(GaimPluginAction *action) | |
1341 { | |
1342 | |
1343 GaimConnection *gc = (GaimConnection *) action->context; | |
1344 JabberStream *js = gc->proto_data; | |
1345 GaimRequestFields *fields; | |
1346 GaimRequestFieldGroup *group; | |
1347 GaimRequestField *field; | |
1348 | |
1349 fields = gaim_request_fields_new(); | |
1350 group = gaim_request_field_group_new(NULL); | |
1351 gaim_request_fields_add_group(fields, group); | |
1352 | |
1353 field = gaim_request_field_string_new("password1", _("Password"), | |
1354 "", FALSE); | |
1355 gaim_request_field_string_set_masked(field, TRUE); | |
1356 gaim_request_field_group_add_field(group, field); | |
1357 | |
1358 field = gaim_request_field_string_new("password2", _("Password (again)"), | |
1359 "", FALSE); | |
1360 gaim_request_field_string_set_masked(field, TRUE); | |
1361 gaim_request_field_group_add_field(group, field); | |
1362 | |
1363 gaim_request_fields(js->gc, _("Change Jabber Password"), | |
1364 _("Change Jabber Password"), _("Please enter your new password"), | |
1365 fields, _("OK"), G_CALLBACK(jabber_password_change_cb), | |
1366 _("Cancel"), NULL, js); | |
1367 } | |
1368 | |
1369 static GList *jabber_actions(GaimPlugin *plugin, gpointer context) | |
1370 { | |
1371 GList *m = NULL; | |
1372 GaimPluginAction *act; | |
1373 | |
1374 act = gaim_plugin_action_new(_("Set User Info..."), | |
1375 jabber_setup_set_info); | |
1376 m = g_list_append(m, act); | |
1377 | |
1378 /* if (js->protocol_options & CHANGE_PASSWORD) { */ | |
1379 act = gaim_plugin_action_new(_("Change Password..."), | |
1380 jabber_password_change); | |
1381 m = g_list_append(m, act); | |
1382 /* } */ | |
1383 | |
1384 act = gaim_plugin_action_new(_("Search for Users..."), | |
1385 jabber_user_search_begin); | |
1386 m = g_list_append(m, act); | |
1387 | |
1388 return m; | |
1389 } | |
1390 | |
1391 static GaimChat *jabber_find_blist_chat(GaimAccount *account, const char *name) | |
1392 { | |
1393 GaimBlistNode *gnode, *cnode; | |
1394 JabberID *jid; | |
1395 | |
1396 if(!(jid = jabber_id_new(name))) | |
1397 return NULL; | |
1398 | |
1399 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { | |
1400 for(cnode = gnode->child; cnode; cnode = cnode->next) { | |
1401 GaimChat *chat = (GaimChat*)cnode; | |
1402 const char *room, *server; | |
1403 if(!GAIM_BLIST_NODE_IS_CHAT(cnode)) | |
1404 continue; | |
1405 | |
1406 if(chat->account != account) | |
1407 continue; | |
1408 | |
1409 if(!(room = g_hash_table_lookup(chat->components, "room"))) | |
1410 continue; | |
1411 if(!(server = g_hash_table_lookup(chat->components, "server"))) | |
1412 continue; | |
1413 | |
1414 if(jid->node && jid->domain && | |
1415 !g_utf8_collate(room, jid->node) && !g_utf8_collate(server, jid->domain)) { | |
1416 jabber_id_free(jid); | |
1417 return chat; | |
1418 } | |
1419 } | |
1420 } | |
1421 jabber_id_free(jid); | |
1422 return NULL; | |
1423 } | |
1424 | |
1425 static void jabber_convo_closed(GaimConnection *gc, const char *who) | |
1426 { | |
1427 JabberStream *js = gc->proto_data; | |
1428 JabberID *jid; | |
1429 JabberBuddy *jb; | |
1430 JabberBuddyResource *jbr; | |
1431 | |
1432 if(!(jid = jabber_id_new(who))) | |
1433 return; | |
1434 | |
1435 if((jb = jabber_buddy_find(js, who, TRUE)) && | |
1436 (jbr = jabber_buddy_find_resource(jb, jid->resource))) { | |
1437 if(jbr->thread_id) { | |
1438 g_free(jbr->thread_id); | |
1439 jbr->thread_id = NULL; | |
1440 } | |
1441 } | |
1442 | |
1443 jabber_id_free(jid); | |
1444 } | |
1445 | |
1446 | |
1447 char *jabber_parse_error(JabberStream *js, xmlnode *packet) | |
1448 { | |
1449 xmlnode *error; | |
1450 const char *code = NULL, *text = NULL; | |
1451 const char *xmlns = xmlnode_get_namespace(packet); | |
1452 char *cdata = NULL; | |
1453 | |
1454 if((error = xmlnode_get_child(packet, "error"))) { | |
1455 cdata = xmlnode_get_data(error); | |
1456 code = xmlnode_get_attrib(error, "code"); | |
1457 | |
1458 /* Stanza errors */ | |
1459 if(xmlnode_get_child(error, "bad-request")) { | |
1460 text = _("Bad Request"); | |
1461 } else if(xmlnode_get_child(error, "conflict")) { | |
1462 text = _("Conflict"); | |
1463 } else if(xmlnode_get_child(error, "feature-not-implemented")) { | |
1464 text = _("Feature Not Implemented"); | |
1465 } else if(xmlnode_get_child(error, "forbidden")) { | |
1466 text = _("Forbidden"); | |
1467 } else if(xmlnode_get_child(error, "gone")) { | |
1468 text = _("Gone"); | |
1469 } else if(xmlnode_get_child(error, "internal-server-error")) { | |
1470 text = _("Internal Server Error"); | |
1471 } else if(xmlnode_get_child(error, "item-not-found")) { | |
1472 text = _("Item Not Found"); | |
1473 } else if(xmlnode_get_child(error, "jid-malformed")) { | |
1474 text = _("Malformed Jabber ID"); | |
1475 } else if(xmlnode_get_child(error, "not-acceptable")) { | |
1476 text = _("Not Acceptable"); | |
1477 } else if(xmlnode_get_child(error, "not-allowed")) { | |
1478 text = _("Not Allowed"); | |
1479 } else if(xmlnode_get_child(error, "not-authorized")) { | |
1480 text = _("Not Authorized"); | |
1481 } else if(xmlnode_get_child(error, "payment-required")) { | |
1482 text = _("Payment Required"); | |
1483 } else if(xmlnode_get_child(error, "recipient-unavailable")) { | |
1484 text = _("Recipient Unavailable"); | |
1485 } else if(xmlnode_get_child(error, "redirect")) { | |
1486 /* XXX */ | |
1487 } else if(xmlnode_get_child(error, "registration-required")) { | |
1488 text = _("Registration Required"); | |
1489 } else if(xmlnode_get_child(error, "remote-server-not-found")) { | |
1490 text = _("Remote Server Not Found"); | |
1491 } else if(xmlnode_get_child(error, "remote-server-timeout")) { | |
1492 text = _("Remote Server Timeout"); | |
1493 } else if(xmlnode_get_child(error, "resource-constraint")) { | |
1494 text = _("Server Overloaded"); | |
1495 } else if(xmlnode_get_child(error, "service-unavailable")) { | |
1496 text = _("Service Unavailable"); | |
1497 } else if(xmlnode_get_child(error, "subscription-required")) { | |
1498 text = _("Subscription Required"); | |
1499 } else if(xmlnode_get_child(error, "unexpected-request")) { | |
1500 text = _("Unexpected Request"); | |
1501 } else if(xmlnode_get_child(error, "undefined-condition")) { | |
1502 text = _("Unknown Error"); | |
1503 } | |
1504 } else if(xmlns && !strcmp(xmlns, "urn:ietf:params:xml:ns:xmpp-sasl")) { | |
1505 if(xmlnode_get_child(packet, "aborted")) { | |
1506 js->gc->wants_to_die = TRUE; | |
1507 text = _("Authorization Aborted"); | |
1508 } else if(xmlnode_get_child(packet, "incorrect-encoding")) { | |
1509 text = _("Incorrect encoding in authorization"); | |
1510 } else if(xmlnode_get_child(packet, "invalid-authzid")) { | |
1511 js->gc->wants_to_die = TRUE; | |
1512 text = _("Invalid authzid"); | |
1513 } else if(xmlnode_get_child(packet, "invalid-mechanism")) { | |
1514 js->gc->wants_to_die = TRUE; | |
1515 text = _("Invalid Authorization Mechanism"); | |
1516 } else if(xmlnode_get_child(packet, "mechanism-too-weak")) { | |
1517 js->gc->wants_to_die = TRUE; | |
1518 text = _("Authorization mechanism too weak"); | |
1519 } else if(xmlnode_get_child(packet, "not-authorized")) { | |
1520 js->gc->wants_to_die = TRUE; | |
1521 text = _("Not Authorized"); | |
1522 } else if(xmlnode_get_child(packet, "temporary-auth-failure")) { | |
1523 text = _("Temporary Authentication Failure"); | |
1524 } else { | |
1525 js->gc->wants_to_die = TRUE; | |
1526 text = _("Authentication Failure"); | |
1527 } | |
1528 } else if(!strcmp(packet->name, "stream:error")) { | |
1529 if(xmlnode_get_child(packet, "bad-format")) { | |
1530 text = _("Bad Format"); | |
1531 } else if(xmlnode_get_child(packet, "bad-namespace-prefix")) { | |
1532 text = _("Bad Namespace Prefix"); | |
1533 } else if(xmlnode_get_child(packet, "conflict")) { | |
1534 js->gc->wants_to_die = TRUE; | |
1535 text = _("Resource Conflict"); | |
1536 } else if(xmlnode_get_child(packet, "connection-timeout")) { | |
1537 text = _("Connection Timeout"); | |
1538 } else if(xmlnode_get_child(packet, "host-gone")) { | |
1539 text = _("Host Gone"); | |
1540 } else if(xmlnode_get_child(packet, "host-unknown")) { | |
1541 text = _("Host Unknown"); | |
1542 } else if(xmlnode_get_child(packet, "improper-addressing")) { | |
1543 text = _("Improper Addressing"); | |
1544 } else if(xmlnode_get_child(packet, "internal-server-error")) { | |
1545 text = _("Internal Server Error"); | |
1546 } else if(xmlnode_get_child(packet, "invalid-id")) { | |
1547 text = _("Invalid ID"); | |
1548 } else if(xmlnode_get_child(packet, "invalid-namespace")) { | |
1549 text = _("Invalid Namespace"); | |
1550 } else if(xmlnode_get_child(packet, "invalid-xml")) { | |
1551 text = _("Invalid XML"); | |
1552 } else if(xmlnode_get_child(packet, "nonmatching-hosts")) { | |
1553 text = _("Non-matching Hosts"); | |
1554 } else if(xmlnode_get_child(packet, "not-authorized")) { | |
1555 text = _("Not Authorized"); | |
1556 } else if(xmlnode_get_child(packet, "policy-violation")) { | |
1557 text = _("Policy Violation"); | |
1558 } else if(xmlnode_get_child(packet, "remote-connection-failed")) { | |
1559 text = _("Remote Connection Failed"); | |
1560 } else if(xmlnode_get_child(packet, "resource-constraint")) { | |
1561 text = _("Resource Constraint"); | |
1562 } else if(xmlnode_get_child(packet, "restricted-xml")) { | |
1563 text = _("Restricted XML"); | |
1564 } else if(xmlnode_get_child(packet, "see-other-host")) { | |
1565 text = _("See Other Host"); | |
1566 } else if(xmlnode_get_child(packet, "system-shutdown")) { | |
1567 text = _("System Shutdown"); | |
1568 } else if(xmlnode_get_child(packet, "undefined-condition")) { | |
1569 text = _("Undefined Condition"); | |
1570 } else if(xmlnode_get_child(packet, "unsupported-encoding")) { | |
1571 text = _("Unsupported Encoding"); | |
1572 } else if(xmlnode_get_child(packet, "unsupported-stanza-type")) { | |
1573 text = _("Unsupported Stanza Type"); | |
1574 } else if(xmlnode_get_child(packet, "unsupported-version")) { | |
1575 text = _("Unsupported Version"); | |
1576 } else if(xmlnode_get_child(packet, "xml-not-well-formed")) { | |
1577 text = _("XML Not Well Formed"); | |
1578 } else { | |
1579 text = _("Stream Error"); | |
1580 } | |
1581 } | |
1582 | |
1583 if(text || cdata) { | |
1584 char *ret = g_strdup_printf("%s%s%s", code ? code : "", | |
1585 code ? ": " : "", text ? text : cdata); | |
1586 g_free(cdata); | |
1587 return ret; | |
1588 } else { | |
1589 return NULL; | |
1590 } | |
1591 } | |
1592 | |
1593 static GaimCmdRet jabber_cmd_chat_config(GaimConversation *conv, | |
1594 const char *cmd, char **args, char **error, void *data) | |
1595 { | |
1596 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1597 jabber_chat_request_room_configure(chat); | |
1598 return GAIM_CMD_RET_OK; | |
1599 } | |
1600 | |
1601 static GaimCmdRet jabber_cmd_chat_register(GaimConversation *conv, | |
1602 const char *cmd, char **args, char **error, void *data) | |
1603 { | |
1604 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1605 jabber_chat_register(chat); | |
1606 return GAIM_CMD_RET_OK; | |
1607 } | |
1608 | |
1609 static GaimCmdRet jabber_cmd_chat_topic(GaimConversation *conv, | |
1610 const char *cmd, char **args, char **error, void *data) | |
1611 { | |
1612 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1613 jabber_chat_change_topic(chat, args ? args[0] : NULL); | |
1614 return GAIM_CMD_RET_OK; | |
1615 } | |
1616 | |
1617 static GaimCmdRet jabber_cmd_chat_nick(GaimConversation *conv, | |
1618 const char *cmd, char **args, char **error, void *data) | |
1619 { | |
1620 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1621 | |
1622 if(!args || !args[0]) | |
1623 return GAIM_CMD_RET_FAILED; | |
1624 | |
1625 jabber_chat_change_nick(chat, args[0]); | |
1626 return GAIM_CMD_RET_OK; | |
1627 } | |
1628 | |
1629 static GaimCmdRet jabber_cmd_chat_part(GaimConversation *conv, | |
1630 const char *cmd, char **args, char **error, void *data) | |
1631 { | |
1632 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1633 jabber_chat_part(chat, args ? args[0] : NULL); | |
1634 return GAIM_CMD_RET_OK; | |
1635 } | |
1636 | |
1637 static GaimCmdRet jabber_cmd_chat_ban(GaimConversation *conv, | |
1638 const char *cmd, char **args, char **error, void *data) | |
1639 { | |
1640 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1641 | |
1642 if(!args || !args[0]) | |
1643 return GAIM_CMD_RET_FAILED; | |
1644 | |
1645 if(!jabber_chat_ban_user(chat, args[0], args[1])) { | |
1646 *error = g_strdup_printf(_("Unable to ban user %s"), args[0]); | |
1647 return GAIM_CMD_RET_FAILED; | |
1648 } | |
1649 | |
1650 return GAIM_CMD_RET_OK; | |
1651 } | |
1652 | |
1653 static GaimCmdRet jabber_cmd_chat_affiliate(GaimConversation *conv, | |
1654 const char *cmd, char **args, char **error, void *data) | |
1655 { | |
1656 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1657 | |
1658 if (!args || !args[0] || !args[1]) | |
1659 return GAIM_CMD_RET_FAILED; | |
1660 | |
1661 if (strcmp(args[1], "owner") != 0 && | |
1662 strcmp(args[1], "admin") != 0 && | |
1663 strcmp(args[1], "member") != 0 && | |
1664 strcmp(args[1], "outcast") != 0 && | |
1665 strcmp(args[1], "none") != 0) { | |
1666 *error = g_strdup_printf(_("Unknown affiliation: \"%s\""), args[1]); | |
1667 return GAIM_CMD_RET_FAILED; | |
1668 } | |
1669 | |
1670 if (!jabber_chat_affiliate_user(chat, args[0], args[1])) { | |
1671 *error = g_strdup_printf(_("Unable to affiliate user %s as \"%s\""), args[0], args[1]); | |
1672 return GAIM_CMD_RET_FAILED; | |
1673 } | |
1674 | |
1675 return GAIM_CMD_RET_OK; | |
1676 } | |
1677 | |
1678 static GaimCmdRet jabber_cmd_chat_role(GaimConversation *conv, | |
1679 const char *cmd, char **args, char **error, void *data) | |
1680 { | |
1681 JabberChat *chat; | |
1682 | |
1683 if (!args || !args[0] || !args[1]) | |
1684 return GAIM_CMD_RET_FAILED; | |
1685 | |
1686 if (strcmp(args[1], "moderator") != 0 && | |
1687 strcmp(args[1], "participant") != 0 && | |
1688 strcmp(args[1], "visitor") != 0 && | |
1689 strcmp(args[1], "none") != 0) { | |
1690 *error = g_strdup_printf(_("Unknown role: \"%s\""), args[1]); | |
1691 return GAIM_CMD_RET_FAILED; | |
1692 } | |
1693 | |
1694 chat = jabber_chat_find_by_conv(conv); | |
1695 | |
1696 if (!jabber_chat_role_user(chat, args[0], args[1])) { | |
1697 *error = g_strdup_printf(_("Unable to set role \"%s\" for user: %s"), | |
1698 args[1], args[0]); | |
1699 return GAIM_CMD_RET_FAILED; | |
1700 } | |
1701 | |
1702 return GAIM_CMD_RET_OK; | |
1703 } | |
1704 | |
1705 static GaimCmdRet jabber_cmd_chat_invite(GaimConversation *conv, | |
1706 const char *cmd, char **args, char **error, void *data) | |
1707 { | |
1708 if(!args || !args[0]) | |
1709 return GAIM_CMD_RET_FAILED; | |
1710 | |
1711 jabber_chat_invite(gaim_conversation_get_gc(conv), | |
1712 gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)), args[1] ? args[1] : "", | |
1713 args[0]); | |
1714 | |
1715 return GAIM_CMD_RET_OK; | |
1716 } | |
1717 | |
1718 static GaimCmdRet jabber_cmd_chat_join(GaimConversation *conv, | |
1719 const char *cmd, char **args, char **error, void *data) | |
1720 { | |
1721 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1722 GHashTable *components; | |
1723 | |
1724 if(!args || !args[0]) | |
1725 return GAIM_CMD_RET_FAILED; | |
1726 | |
1727 components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); | |
1728 | |
1729 g_hash_table_replace(components, "room", args[0]); | |
1730 g_hash_table_replace(components, "server", chat->server); | |
1731 g_hash_table_replace(components, "handle", chat->handle); | |
1732 if(args[1]) | |
1733 g_hash_table_replace(components, "password", args[1]); | |
1734 | |
1735 jabber_chat_join(gaim_conversation_get_gc(conv), components); | |
1736 | |
1737 g_hash_table_destroy(components); | |
1738 return GAIM_CMD_RET_OK; | |
1739 } | |
1740 | |
1741 static GaimCmdRet jabber_cmd_chat_kick(GaimConversation *conv, | |
1742 const char *cmd, char **args, char **error, void *data) | |
1743 { | |
1744 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1745 | |
1746 if(!args || !args[0]) | |
1747 return GAIM_CMD_RET_FAILED; | |
1748 | |
1749 if(!jabber_chat_kick_user(chat, args[0], args[1])) { | |
1750 *error = g_strdup_printf(_("Unable to kick user %s"), args[0]); | |
1751 return GAIM_CMD_RET_FAILED; | |
1752 } | |
1753 | |
1754 return GAIM_CMD_RET_OK; | |
1755 } | |
1756 | |
1757 static GaimCmdRet jabber_cmd_chat_msg(GaimConversation *conv, | |
1758 const char *cmd, char **args, char **error, void *data) | |
1759 { | |
1760 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1761 char *who; | |
1762 | |
1763 who = g_strdup_printf("%s@%s/%s", chat->room, chat->server, args[0]); | |
1764 | |
1765 jabber_message_send_im(gaim_conversation_get_gc(conv), who, args[1], 0); | |
1766 | |
1767 g_free(who); | |
1768 return GAIM_CMD_RET_OK; | |
1769 } | |
1770 | |
1771 static gboolean jabber_offline_message(const GaimBuddy *buddy) | |
1772 { | |
1773 return TRUE; | |
1774 } | |
1775 | |
1776 static void jabber_register_commands(void) | |
1777 { | |
1778 gaim_cmd_register("config", "", GAIM_CMD_P_PRPL, | |
1779 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1780 "prpl-jabber", jabber_cmd_chat_config, | |
1781 _("config: Configure a chat room."), NULL); | |
1782 gaim_cmd_register("configure", "", GAIM_CMD_P_PRPL, | |
1783 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1784 "prpl-jabber", jabber_cmd_chat_config, | |
1785 _("configure: Configure a chat room."), NULL); | |
1786 gaim_cmd_register("nick", "s", GAIM_CMD_P_PRPL, | |
1787 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1788 "prpl-jabber", jabber_cmd_chat_nick, | |
1789 _("nick <new nickname>: Change your nickname."), | |
1790 NULL); | |
1791 gaim_cmd_register("part", "s", GAIM_CMD_P_PRPL, | |
1792 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1793 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1794 jabber_cmd_chat_part, _("part [room]: Leave the room."), | |
1795 NULL); | |
1796 gaim_cmd_register("register", "", GAIM_CMD_P_PRPL, | |
1797 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1798 "prpl-jabber", jabber_cmd_chat_register, | |
1799 _("register: Register with a chat room."), NULL); | |
1800 /* XXX: there needs to be a core /topic cmd, methinks */ | |
1801 gaim_cmd_register("topic", "s", GAIM_CMD_P_PRPL, | |
1802 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1803 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1804 jabber_cmd_chat_topic, | |
1805 _("topic [new topic]: View or change the topic."), | |
1806 NULL); | |
1807 gaim_cmd_register("ban", "ws", GAIM_CMD_P_PRPL, | |
1808 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1809 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1810 jabber_cmd_chat_ban, | |
1811 _("ban <user> [room]: Ban a user from the room."), | |
1812 NULL); | |
1813 gaim_cmd_register("affiliate", "ws", GAIM_CMD_P_PRPL, | |
1814 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1815 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1816 jabber_cmd_chat_affiliate, | |
1817 _("affiliate <user> <owner|admin|member|outcast|none>: Set a user's affiliation with the room."), | |
1818 NULL); | |
1819 gaim_cmd_register("role", "ws", GAIM_CMD_P_PRPL, | |
1820 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1821 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1822 jabber_cmd_chat_role, | |
1823 _("role <user> <moderator|participant|visitor|none>: Set a user's role in the room."), | |
1824 NULL); | |
1825 gaim_cmd_register("invite", "ws", GAIM_CMD_P_PRPL, | |
1826 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1827 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1828 jabber_cmd_chat_invite, | |
1829 _("invite <user> [message]: Invite a user to the room."), | |
1830 NULL); | |
1831 gaim_cmd_register("join", "ws", GAIM_CMD_P_PRPL, | |
1832 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1833 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1834 jabber_cmd_chat_join, | |
1835 _("join: <room> [server]: Join a chat on this server."), | |
1836 NULL); | |
1837 gaim_cmd_register("kick", "ws", GAIM_CMD_P_PRPL, | |
1838 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1839 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1840 jabber_cmd_chat_kick, | |
1841 _("kick <user> [room]: Kick a user from the room."), | |
1842 NULL); | |
1843 gaim_cmd_register("msg", "ws", GAIM_CMD_P_PRPL, | |
1844 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1845 "prpl-jabber", jabber_cmd_chat_msg, | |
1846 _("msg <user> <message>: Send a private message to another user."), | |
1847 NULL); | |
1848 } | |
1849 | |
1850 static GaimPluginProtocolInfo prpl_info = | |
1851 { | |
15163 | 1852 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK, |
14192 | 1853 NULL, /* user_splits */ |
1854 NULL, /* protocol_options */ | |
15175 | 1855 {"png,gif,jpeg", 32, 32, 96, 96, GAIM_ICON_SCALE_SEND | GAIM_ICON_SCALE_DISPLAY}, /* icon_spec */ |
14192 | 1856 jabber_list_icon, /* list_icon */ |
1857 jabber_list_emblems, /* list_emblems */ | |
1858 jabber_status_text, /* status_text */ | |
1859 jabber_tooltip_text, /* tooltip_text */ | |
1860 jabber_status_types, /* status_types */ | |
1861 jabber_blist_node_menu, /* blist_node_menu */ | |
1862 jabber_chat_info, /* chat_info */ | |
1863 jabber_chat_info_defaults, /* chat_info_defaults */ | |
1864 jabber_login, /* login */ | |
1865 jabber_close, /* close */ | |
1866 jabber_message_send_im, /* send_im */ | |
1867 jabber_set_info, /* set_info */ | |
1868 jabber_send_typing, /* send_typing */ | |
1869 jabber_buddy_get_info, /* get_info */ | |
1870 jabber_presence_send, /* set_away */ | |
14391 | 1871 jabber_idle_set, /* set_idle */ |
14192 | 1872 NULL, /* change_passwd */ |
1873 jabber_roster_add_buddy, /* add_buddy */ | |
1874 NULL, /* add_buddies */ | |
1875 jabber_roster_remove_buddy, /* remove_buddy */ | |
1876 NULL, /* remove_buddies */ | |
1877 NULL, /* add_permit */ | |
15203 | 1878 jabber_google_roster_add_deny, /* add_deny */ |
14192 | 1879 NULL, /* rem_permit */ |
15203 | 1880 jabber_google_roster_rem_deny, /* rem_deny */ |
14192 | 1881 NULL, /* set_permit_deny */ |
1882 jabber_chat_join, /* join_chat */ | |
1883 NULL, /* reject_chat */ | |
1884 jabber_get_chat_name, /* get_chat_name */ | |
1885 jabber_chat_invite, /* chat_invite */ | |
1886 jabber_chat_leave, /* chat_leave */ | |
1887 NULL, /* chat_whisper */ | |
1888 jabber_message_send_chat, /* chat_send */ | |
1889 jabber_keepalive, /* keepalive */ | |
1890 jabber_register_account, /* register_user */ | |
1891 jabber_buddy_get_info_chat, /* get_cb_info */ | |
1892 NULL, /* get_cb_away */ | |
1893 jabber_roster_alias_change, /* alias_buddy */ | |
1894 jabber_roster_group_change, /* group_buddy */ | |
1895 jabber_roster_group_rename, /* rename_group */ | |
1896 NULL, /* buddy_free */ | |
1897 jabber_convo_closed, /* convo_closed */ | |
1898 jabber_normalize, /* normalize */ | |
1899 jabber_set_buddy_icon, /* set_buddy_icon */ | |
1900 NULL, /* remove_group */ | |
1901 jabber_chat_buddy_real_name, /* get_cb_real_name */ | |
1902 jabber_chat_set_topic, /* set_chat_topic */ | |
1903 jabber_find_blist_chat, /* find_blist_chat */ | |
1904 jabber_roomlist_get_list, /* roomlist_get_list */ | |
1905 jabber_roomlist_cancel, /* roomlist_cancel */ | |
1906 NULL, /* roomlist_expand_category */ | |
1907 NULL, /* can_receive_file */ | |
1908 jabber_si_xfer_send, /* send_file */ | |
1909 jabber_si_new_xfer, /* new_xfer */ | |
1910 jabber_offline_message, /* offline_message */ | |
1911 NULL, /* whiteboard_prpl_ops */ | |
14573
9cbf4d3ef444
[gaim-migrate @ 17297]
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
14542
diff
changeset
|
1912 jabber_prpl_send_raw, /* send_raw */ |
15123 | 1913 jabber_roomlist_room_serialize, /* roomlist_room_serialize */ |
14192 | 1914 }; |
1915 | |
14296 | 1916 static gboolean load_plugin(GaimPlugin *plugin) |
1917 { | |
1918 gaim_signal_register(plugin, "jabber-receiving-xmlnode", | |
1919 gaim_marshal_VOID__POINTER_POINTER, NULL, 2, | |
1920 gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_CONNECTION), | |
1921 gaim_value_new_outgoing(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_XMLNODE)); | |
1922 | |
1923 gaim_signal_register(plugin, "jabber-sending-xmlnode", | |
1924 gaim_marshal_VOID__POINTER_POINTER, NULL, 2, | |
1925 gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_CONNECTION), | |
1926 gaim_value_new_outgoing(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_XMLNODE)); | |
1927 | |
14606 | 1928 gaim_signal_register(plugin, "jabber-sending-text", |
1929 gaim_marshal_VOID__POINTER_POINTER, NULL, 2, | |
1930 gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_CONNECTION), | |
1931 gaim_value_new(GAIM_TYPE_STRING)); | |
1932 | |
1933 | |
14296 | 1934 return TRUE; |
1935 } | |
1936 | |
1937 static gboolean unload_plugin(GaimPlugin *plugin) | |
1938 { | |
1939 gaim_signal_unregister(plugin, "jabber-receiving-xmlnode"); | |
1940 | |
1941 gaim_signal_unregister(plugin, "jabber-sending-xmlnode"); | |
14606 | 1942 |
1943 gaim_signal_unregister(plugin, "jabber-sending-text"); | |
1944 | |
14296 | 1945 return TRUE; |
1946 } | |
1947 | |
14192 | 1948 static GaimPluginInfo info = |
1949 { | |
1950 GAIM_PLUGIN_MAGIC, | |
1951 GAIM_MAJOR_VERSION, | |
1952 GAIM_MINOR_VERSION, | |
1953 GAIM_PLUGIN_PROTOCOL, /**< type */ | |
1954 NULL, /**< ui_requirement */ | |
1955 0, /**< flags */ | |
1956 NULL, /**< dependencies */ | |
1957 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
1958 | |
1959 "prpl-jabber", /**< id */ | |
1960 "Jabber", /**< name */ | |
1961 VERSION, /**< version */ | |
1962 /** summary */ | |
1963 N_("Jabber Protocol Plugin"), | |
1964 /** description */ | |
1965 N_("Jabber Protocol Plugin"), | |
1966 NULL, /**< author */ | |
1967 GAIM_WEBSITE, /**< homepage */ | |
1968 | |
14296 | 1969 load_plugin, /**< load */ |
1970 unload_plugin, /**< unload */ | |
14192 | 1971 NULL, /**< destroy */ |
1972 | |
1973 NULL, /**< ui_info */ | |
1974 &prpl_info, /**< extra_info */ | |
1975 NULL, /**< prefs_info */ | |
1976 jabber_actions | |
1977 }; | |
1978 | |
1979 static void | |
1980 init_plugin(GaimPlugin *plugin) | |
1981 { | |
1982 GaimAccountUserSplit *split; | |
1983 GaimAccountOption *option; | |
1984 | |
1985 split = gaim_account_user_split_new(_("Server"), "jabber.org", '@'); | |
1986 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); | |
1987 | |
1988 split = gaim_account_user_split_new(_("Resource"), "Home", '/'); | |
1989 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); | |
1990 | |
1991 option = gaim_account_option_bool_new(_("Force old (port 5223) SSL"), "old_ssl", FALSE); | |
1992 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
1993 option); | |
1994 | |
1995 option = gaim_account_option_bool_new( | |
1996 _("Allow plaintext auth over unencrypted streams"), | |
1997 "auth_plain_in_clear", FALSE); | |
1998 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
1999 option); | |
2000 | |
2001 option = gaim_account_option_int_new(_("Connect port"), "port", 5222); | |
2002 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
2003 option); | |
2004 | |
2005 option = gaim_account_option_string_new(_("Connect server"), | |
2006 "connect_server", NULL); | |
2007 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
2008 option); | |
2009 | |
2010 my_protocol = plugin; | |
2011 | |
2012 gaim_prefs_remove("/plugins/prpl/jabber"); | |
2013 | |
2014 /* XXX - If any other plugin wants SASL this won't be good ... */ | |
2015 #ifdef HAVE_CYRUS_SASL | |
2016 sasl_client_init(NULL); | |
2017 #endif | |
2018 jabber_register_commands(); | |
14294 | 2019 |
2020 jabber_iq_init(); | |
14192 | 2021 } |
2022 | |
2023 GAIM_INIT_PLUGIN(jabber, init_plugin, info); |