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