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