Mercurial > pidgin
annotate libgaim/protocols/jabber/jabber.c @ 15119:acf1b5803346
[gaim-migrate @ 17905]
I think gdk pixbuf recognizes "jpeg" and not "jpg"
Also, is there any reason that Gaim didn't think that
gif and jpeg were valid for msn and yahoo? It seems
like that would cause us to convert people's icons
to pngs, with possible negative consequences
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 07 Dec 2006 03:37:13 +0000 |
parents | a259abeeee27 |
children | c8957b9c6202 |
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; | |
14961
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) { | |
15007 | 929 if (connect_server[0]) { |
930 jabber_login_connect(js, server, | |
931 gaim_account_get_int(account, | |
932 "port", 5222)); | |
933 } else { | |
934 js->srv_query_data = gaim_srv_resolve("xmpp-client", | |
935 "tcp", | |
936 js->user->domain, | |
937 srv_resolved_cb, | |
938 js); | |
939 } | |
14192 | 940 } |
941 } | |
942 | |
943 static void jabber_close(GaimConnection *gc) | |
944 { | |
945 JabberStream *js = gc->proto_data; | |
946 | |
947 /* Don't perform any actions on the ssl connection | |
948 * if we were forcibly disconnected because it will crash | |
949 * on some SSL backends. | |
950 */ | |
951 if (!gc->disconnect_timeout) | |
952 jabber_send_raw(js, "</stream:stream>", -1); | |
953 | |
14308 | 954 if (js->srv_query_data) |
955 gaim_srv_cancel(js->srv_query_data); | |
956 | |
14192 | 957 if(js->gsc) { |
958 #ifdef HAVE_OPENSSL | |
959 if (!gc->disconnect_timeout) | |
960 #endif | |
961 gaim_ssl_close(js->gsc); | |
962 } else if (js->fd > 0) { | |
963 if(js->gc->inpa) | |
964 gaim_input_remove(js->gc->inpa); | |
965 close(js->fd); | |
966 } | |
967 if(js->iq_callbacks) | |
968 g_hash_table_destroy(js->iq_callbacks); | |
969 if(js->disco_callbacks) | |
970 g_hash_table_destroy(js->disco_callbacks); | |
971 if(js->buddies) | |
972 g_hash_table_destroy(js->buddies); | |
973 if(js->chats) | |
974 g_hash_table_destroy(js->chats); | |
975 while(js->chat_servers) { | |
976 g_free(js->chat_servers->data); | |
977 js->chat_servers = g_list_delete_link(js->chat_servers, js->chat_servers); | |
978 } | |
979 while(js->user_directories) { | |
980 g_free(js->user_directories->data); | |
981 js->user_directories = g_list_delete_link(js->user_directories, js->user_directories); | |
982 } | |
983 if(js->stream_id) | |
984 g_free(js->stream_id); | |
985 if(js->user) | |
986 jabber_id_free(js->user); | |
987 if(js->avatar_hash) | |
988 g_free(js->avatar_hash); | |
989 gaim_circ_buffer_destroy(js->write_buffer); | |
990 if(js->writeh) | |
991 gaim_input_remove(js->writeh); | |
992 #ifdef HAVE_CYRUS_SASL | |
993 if(js->sasl) | |
994 sasl_dispose(&js->sasl); | |
995 if(js->sasl_mechs) | |
996 g_string_free(js->sasl_mechs, TRUE); | |
997 if(js->sasl_cb) | |
998 g_free(js->sasl_cb); | |
999 #endif | |
1000 g_free(js); | |
1001 | |
1002 gc->proto_data = NULL; | |
1003 } | |
1004 | |
1005 void jabber_stream_set_state(JabberStream *js, JabberStreamState state) | |
1006 { | |
1007 GaimPresence *gpresence; | |
1008 GaimStatus *status; | |
1009 | |
1010 js->state = state; | |
1011 switch(state) { | |
1012 case JABBER_STREAM_OFFLINE: | |
1013 break; | |
1014 case JABBER_STREAM_CONNECTING: | |
1015 gaim_connection_update_progress(js->gc, _("Connecting"), 1, | |
1016 JABBER_CONNECT_STEPS); | |
1017 break; | |
1018 case JABBER_STREAM_INITIALIZING: | |
1019 gaim_connection_update_progress(js->gc, _("Initializing Stream"), | |
1020 js->gsc ? 5 : 2, JABBER_CONNECT_STEPS); | |
1021 jabber_stream_init(js); | |
1022 break; | |
1023 case JABBER_STREAM_AUTHENTICATING: | |
1024 gaim_connection_update_progress(js->gc, _("Authenticating"), | |
1025 js->gsc ? 6 : 3, JABBER_CONNECT_STEPS); | |
1026 if(js->protocol_version == JABBER_PROTO_0_9 && js->registration) { | |
1027 jabber_register_start(js); | |
1028 } else if(js->auth_type == JABBER_AUTH_IQ_AUTH) { | |
1029 jabber_auth_start_old(js); | |
1030 } | |
1031 break; | |
1032 case JABBER_STREAM_REINITIALIZING: | |
1033 gaim_connection_update_progress(js->gc, _("Re-initializing Stream"), | |
1034 (js->gsc ? 7 : 4), JABBER_CONNECT_STEPS); | |
14638 | 1035 |
1036 /* The stream will be reinitialized later, in jabber_recv_cb_ssl() */ | |
1037 js->reinit = TRUE; | |
1038 | |
14192 | 1039 break; |
1040 case JABBER_STREAM_CONNECTED: | |
1041 jabber_roster_request(js); | |
1042 gpresence = gaim_account_get_presence(js->gc->account); | |
1043 status = gaim_presence_get_active_status(gpresence); | |
1044 jabber_presence_send(js->gc->account, status); | |
1045 gaim_connection_set_state(js->gc, GAIM_CONNECTED); | |
1046 jabber_disco_items_server(js); | |
1047 break; | |
1048 } | |
1049 } | |
1050 | |
1051 char *jabber_get_next_id(JabberStream *js) | |
1052 { | |
1053 return g_strdup_printf("gaim%x", js->next_id++); | |
1054 } | |
1055 | |
14391 | 1056 |
14192 | 1057 static void jabber_idle_set(GaimConnection *gc, int idle) |
1058 { | |
1059 JabberStream *js = gc->proto_data; | |
1060 | |
1061 js->idle = idle ? time(NULL) - idle : idle; | |
1062 } | |
1063 | |
1064 static const char *jabber_list_icon(GaimAccount *a, GaimBuddy *b) | |
1065 { | |
1066 return "jabber"; | |
1067 } | |
1068 | |
1069 static void jabber_list_emblems(GaimBuddy *b, const char **se, const char **sw, | |
1070 const char **nw, const char **ne) | |
1071 { | |
1072 JabberStream *js; | |
1073 JabberBuddy *jb = NULL; | |
1074 | |
1075 if(!b->account->gc) | |
1076 return; | |
1077 js = b->account->gc->proto_data; | |
1078 if(js) | |
1079 jb = jabber_buddy_find(js, b->name, FALSE); | |
1080 | |
1081 if(!GAIM_BUDDY_IS_ONLINE(b)) { | |
1082 if(jb && jb->error_msg) | |
1083 *nw = "error"; | |
1084 | |
1085 if(jb && (jb->subscription & JABBER_SUB_PENDING || | |
1086 !(jb->subscription & JABBER_SUB_TO))) | |
1087 *se = "notauthorized"; | |
1088 else | |
1089 *se = "offline"; | |
1090 } else { | |
1091 GaimStatusType *status_type = gaim_status_get_type(gaim_presence_get_active_status(gaim_buddy_get_presence(b))); | |
1092 GaimStatusPrimitive primitive = gaim_status_type_get_primitive(status_type); | |
1093 | |
1094 if(primitive > GAIM_STATUS_AVAILABLE) { | |
1095 *se = gaim_status_type_get_id(status_type); | |
1096 } | |
1097 } | |
1098 } | |
1099 | |
1100 static char *jabber_status_text(GaimBuddy *b) | |
1101 { | |
1102 JabberBuddy *jb = jabber_buddy_find(b->account->gc->proto_data, b->name, | |
1103 FALSE); | |
1104 char *ret = NULL; | |
1105 | |
1106 if(jb && !GAIM_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) { | |
1107 ret = g_strdup(_("Not Authorized")); | |
1108 } else if(jb && !GAIM_BUDDY_IS_ONLINE(b) && jb->error_msg) { | |
1109 ret = g_strdup(jb->error_msg); | |
1110 } else { | |
1111 char *stripped; | |
1112 | |
1113 if(!(stripped = gaim_markup_strip_html(jabber_buddy_get_status_msg(jb)))) { | |
1114 GaimStatus *status = gaim_presence_get_active_status(gaim_buddy_get_presence(b)); | |
1115 | |
1116 if(!gaim_status_is_available(status)) | |
1117 stripped = g_strdup(gaim_status_get_name(status)); | |
1118 } | |
1119 | |
1120 if(stripped) { | |
1121 ret = g_markup_escape_text(stripped, -1); | |
1122 g_free(stripped); | |
1123 } | |
1124 } | |
1125 | |
1126 return ret; | |
1127 } | |
1128 | |
1129 static void jabber_tooltip_text(GaimBuddy *b, GString *str, gboolean full) | |
1130 { | |
1131 JabberBuddy *jb; | |
1132 | |
1133 g_return_if_fail(b != NULL); | |
1134 g_return_if_fail(b->account != NULL); | |
1135 g_return_if_fail(b->account->gc != NULL); | |
1136 g_return_if_fail(b->account->gc->proto_data != NULL); | |
1137 | |
1138 jb = jabber_buddy_find(b->account->gc->proto_data, b->name, | |
1139 FALSE); | |
1140 | |
1141 if(jb) { | |
1142 JabberBuddyResource *jbr = NULL; | |
1143 const char *sub; | |
1144 GList *l; | |
1145 | |
1146 if (full) { | |
1147 if(jb->subscription & JABBER_SUB_FROM) { | |
1148 if(jb->subscription & JABBER_SUB_TO) | |
1149 sub = _("Both"); | |
1150 else if(jb->subscription & JABBER_SUB_PENDING) | |
1151 sub = _("From (To pending)"); | |
1152 else | |
1153 sub = _("From"); | |
1154 } else { | |
1155 if(jb->subscription & JABBER_SUB_TO) | |
1156 sub = _("To"); | |
1157 else if(jb->subscription & JABBER_SUB_PENDING) | |
1158 sub = _("None (To pending)"); | |
1159 else | |
1160 sub = _("None"); | |
1161 } | |
1162 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Subscription"), sub); | |
1163 } | |
1164 | |
1165 for(l=jb->resources; l; l = l->next) { | |
1166 char *text = NULL; | |
1167 char *res = NULL; | |
1168 const char *state; | |
1169 | |
1170 jbr = l->data; | |
1171 | |
1172 if(jbr->status) { | |
1173 char *tmp; | |
1174 text = gaim_strreplace(jbr->status, "\n", "<br />\n"); | |
1175 tmp = gaim_markup_strip_html(text); | |
1176 g_free(text); | |
1177 text = g_markup_escape_text(tmp, -1); | |
1178 g_free(tmp); | |
1179 } | |
1180 | |
1181 if(jbr->name) | |
1182 res = g_strdup_printf(" (%s)", jbr->name); | |
1183 | |
1184 state = jabber_buddy_state_get_name(jbr->state); | |
1185 if (text != NULL && !gaim_utf8_strcasecmp(state, text)) { | |
1186 g_free(text); | |
1187 text = NULL; | |
1188 } | |
1189 | |
1190 g_string_append_printf(str, "\n<b>%s%s:</b> %s%s%s", | |
1191 _("Status"), | |
1192 res ? res : "", | |
1193 state, | |
1194 text ? ": " : "", | |
1195 text ? text : ""); | |
1196 | |
1197 g_free(text); | |
1198 g_free(res); | |
1199 } | |
1200 | |
1201 if(!GAIM_BUDDY_IS_ONLINE(b) && jb->error_msg) { | |
1202 g_string_append_printf(str, "\n<b>%s:</b> %s", | |
1203 _("Error"), jb->error_msg); | |
1204 } | |
1205 } | |
1206 } | |
1207 | |
1208 static GList *jabber_status_types(GaimAccount *account) | |
1209 { | |
1210 GaimStatusType *type; | |
1211 GList *types = NULL; | |
1212 GaimValue *priority_value; | |
1213 | |
1214 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1215 gaim_value_set_int(priority_value, 1); | |
1216 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AVAILABLE, | |
1217 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_ONLINE), | |
1218 NULL, TRUE, TRUE, FALSE, | |
1219 "priority", _("Priority"), priority_value, | |
1220 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1221 NULL); | |
1222 types = g_list_append(types, type); | |
1223 | |
1224 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1225 gaim_value_set_int(priority_value, 1); | |
1226 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AVAILABLE, | |
1227 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_CHAT), | |
1228 _("Chatty"), TRUE, TRUE, FALSE, | |
1229 "priority", _("Priority"), priority_value, | |
1230 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1231 NULL); | |
1232 types = g_list_append(types, type); | |
1233 | |
1234 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1235 gaim_value_set_int(priority_value, 0); | |
1236 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AWAY, | |
1237 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_AWAY), | |
1238 NULL, TRUE, TRUE, FALSE, | |
1239 "priority", _("Priority"), priority_value, | |
1240 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1241 NULL); | |
1242 types = g_list_append(types, type); | |
1243 | |
1244 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1245 gaim_value_set_int(priority_value, 0); | |
1246 type = gaim_status_type_new_with_attrs(GAIM_STATUS_EXTENDED_AWAY, | |
1247 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_XA), | |
1248 NULL, TRUE, TRUE, FALSE, | |
1249 "priority", _("Priority"), priority_value, | |
1250 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1251 NULL); | |
1252 types = g_list_append(types, type); | |
1253 | |
1254 priority_value = gaim_value_new(GAIM_TYPE_INT); | |
1255 gaim_value_set_int(priority_value, 0); | |
1256 type = gaim_status_type_new_with_attrs(GAIM_STATUS_UNAVAILABLE, | |
1257 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_DND), | |
1258 _("Do Not Disturb"), TRUE, TRUE, FALSE, | |
1259 "priority", _("Priority"), priority_value, | |
1260 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1261 NULL); | |
1262 types = g_list_append(types, type); | |
1263 | |
1264 /* | |
1265 if(js->protocol_version == JABBER_PROTO_0_9) | |
1266 m = g_list_append(m, _("Invisible")); | |
1267 */ | |
1268 | |
1269 type = gaim_status_type_new_with_attrs(GAIM_STATUS_OFFLINE, | |
1270 jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_UNAVAILABLE), | |
1271 NULL, FALSE, TRUE, FALSE, | |
1272 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), | |
1273 NULL); | |
1274 types = g_list_append(types, type); | |
1275 | |
1276 return types; | |
1277 } | |
1278 | |
1279 static void | |
1280 jabber_password_change_result_cb(JabberStream *js, xmlnode *packet, | |
1281 gpointer data) | |
1282 { | |
1283 const char *type; | |
1284 | |
1285 type = xmlnode_get_attrib(packet, "type"); | |
1286 | |
1287 if(type && !strcmp(type, "result")) { | |
1288 gaim_notify_info(js->gc, _("Password Changed"), _("Password Changed"), | |
1289 _("Your password has been changed.")); | |
1290 } else { | |
1291 char *msg = jabber_parse_error(js, packet); | |
1292 | |
1293 gaim_notify_error(js->gc, _("Error changing password"), | |
1294 _("Error changing password"), msg); | |
1295 g_free(msg); | |
1296 } | |
1297 } | |
1298 | |
1299 static void jabber_password_change_cb(JabberStream *js, | |
1300 GaimRequestFields *fields) | |
1301 { | |
1302 const char *p1, *p2; | |
1303 JabberIq *iq; | |
1304 xmlnode *query, *y; | |
1305 | |
1306 p1 = gaim_request_fields_get_string(fields, "password1"); | |
1307 p2 = gaim_request_fields_get_string(fields, "password2"); | |
1308 | |
1309 if(strcmp(p1, p2)) { | |
1310 gaim_notify_error(js->gc, NULL, _("New passwords do not match."), NULL); | |
1311 return; | |
1312 } | |
1313 | |
1314 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); | |
1315 | |
1316 xmlnode_set_attrib(iq->node, "to", js->user->domain); | |
1317 | |
1318 query = xmlnode_get_child(iq->node, "query"); | |
1319 | |
1320 y = xmlnode_new_child(query, "username"); | |
1321 xmlnode_insert_data(y, js->user->node, -1); | |
1322 y = xmlnode_new_child(query, "password"); | |
1323 xmlnode_insert_data(y, p1, -1); | |
1324 | |
1325 jabber_iq_set_callback(iq, jabber_password_change_result_cb, NULL); | |
1326 | |
1327 jabber_iq_send(iq); | |
1328 | |
1329 gaim_account_set_password(js->gc->account, p1); | |
1330 } | |
1331 | |
1332 static void jabber_password_change(GaimPluginAction *action) | |
1333 { | |
1334 | |
1335 GaimConnection *gc = (GaimConnection *) action->context; | |
1336 JabberStream *js = gc->proto_data; | |
1337 GaimRequestFields *fields; | |
1338 GaimRequestFieldGroup *group; | |
1339 GaimRequestField *field; | |
1340 | |
1341 fields = gaim_request_fields_new(); | |
1342 group = gaim_request_field_group_new(NULL); | |
1343 gaim_request_fields_add_group(fields, group); | |
1344 | |
1345 field = gaim_request_field_string_new("password1", _("Password"), | |
1346 "", FALSE); | |
1347 gaim_request_field_string_set_masked(field, TRUE); | |
1348 gaim_request_field_group_add_field(group, field); | |
1349 | |
1350 field = gaim_request_field_string_new("password2", _("Password (again)"), | |
1351 "", FALSE); | |
1352 gaim_request_field_string_set_masked(field, TRUE); | |
1353 gaim_request_field_group_add_field(group, field); | |
1354 | |
1355 gaim_request_fields(js->gc, _("Change Jabber Password"), | |
1356 _("Change Jabber Password"), _("Please enter your new password"), | |
1357 fields, _("OK"), G_CALLBACK(jabber_password_change_cb), | |
1358 _("Cancel"), NULL, js); | |
1359 } | |
1360 | |
1361 static GList *jabber_actions(GaimPlugin *plugin, gpointer context) | |
1362 { | |
1363 GList *m = NULL; | |
1364 GaimPluginAction *act; | |
1365 | |
1366 act = gaim_plugin_action_new(_("Set User Info..."), | |
1367 jabber_setup_set_info); | |
1368 m = g_list_append(m, act); | |
1369 | |
1370 /* if (js->protocol_options & CHANGE_PASSWORD) { */ | |
1371 act = gaim_plugin_action_new(_("Change Password..."), | |
1372 jabber_password_change); | |
1373 m = g_list_append(m, act); | |
1374 /* } */ | |
1375 | |
1376 act = gaim_plugin_action_new(_("Search for Users..."), | |
1377 jabber_user_search_begin); | |
1378 m = g_list_append(m, act); | |
1379 | |
1380 return m; | |
1381 } | |
1382 | |
1383 static GaimChat *jabber_find_blist_chat(GaimAccount *account, const char *name) | |
1384 { | |
1385 GaimBlistNode *gnode, *cnode; | |
1386 JabberID *jid; | |
1387 | |
1388 if(!(jid = jabber_id_new(name))) | |
1389 return NULL; | |
1390 | |
1391 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { | |
1392 for(cnode = gnode->child; cnode; cnode = cnode->next) { | |
1393 GaimChat *chat = (GaimChat*)cnode; | |
1394 const char *room, *server; | |
1395 if(!GAIM_BLIST_NODE_IS_CHAT(cnode)) | |
1396 continue; | |
1397 | |
1398 if(chat->account != account) | |
1399 continue; | |
1400 | |
1401 if(!(room = g_hash_table_lookup(chat->components, "room"))) | |
1402 continue; | |
1403 if(!(server = g_hash_table_lookup(chat->components, "server"))) | |
1404 continue; | |
1405 | |
1406 if(jid->node && jid->domain && | |
1407 !g_utf8_collate(room, jid->node) && !g_utf8_collate(server, jid->domain)) { | |
1408 jabber_id_free(jid); | |
1409 return chat; | |
1410 } | |
1411 } | |
1412 } | |
1413 jabber_id_free(jid); | |
1414 return NULL; | |
1415 } | |
1416 | |
1417 static void jabber_convo_closed(GaimConnection *gc, const char *who) | |
1418 { | |
1419 JabberStream *js = gc->proto_data; | |
1420 JabberID *jid; | |
1421 JabberBuddy *jb; | |
1422 JabberBuddyResource *jbr; | |
1423 | |
1424 if(!(jid = jabber_id_new(who))) | |
1425 return; | |
1426 | |
1427 if((jb = jabber_buddy_find(js, who, TRUE)) && | |
1428 (jbr = jabber_buddy_find_resource(jb, jid->resource))) { | |
1429 if(jbr->thread_id) { | |
1430 g_free(jbr->thread_id); | |
1431 jbr->thread_id = NULL; | |
1432 } | |
1433 } | |
1434 | |
1435 jabber_id_free(jid); | |
1436 } | |
1437 | |
1438 | |
1439 char *jabber_parse_error(JabberStream *js, xmlnode *packet) | |
1440 { | |
1441 xmlnode *error; | |
1442 const char *code = NULL, *text = NULL; | |
1443 const char *xmlns = xmlnode_get_namespace(packet); | |
1444 char *cdata = NULL; | |
1445 | |
1446 if((error = xmlnode_get_child(packet, "error"))) { | |
1447 cdata = xmlnode_get_data(error); | |
1448 code = xmlnode_get_attrib(error, "code"); | |
1449 | |
1450 /* Stanza errors */ | |
1451 if(xmlnode_get_child(error, "bad-request")) { | |
1452 text = _("Bad Request"); | |
1453 } else if(xmlnode_get_child(error, "conflict")) { | |
1454 text = _("Conflict"); | |
1455 } else if(xmlnode_get_child(error, "feature-not-implemented")) { | |
1456 text = _("Feature Not Implemented"); | |
1457 } else if(xmlnode_get_child(error, "forbidden")) { | |
1458 text = _("Forbidden"); | |
1459 } else if(xmlnode_get_child(error, "gone")) { | |
1460 text = _("Gone"); | |
1461 } else if(xmlnode_get_child(error, "internal-server-error")) { | |
1462 text = _("Internal Server Error"); | |
1463 } else if(xmlnode_get_child(error, "item-not-found")) { | |
1464 text = _("Item Not Found"); | |
1465 } else if(xmlnode_get_child(error, "jid-malformed")) { | |
1466 text = _("Malformed Jabber ID"); | |
1467 } else if(xmlnode_get_child(error, "not-acceptable")) { | |
1468 text = _("Not Acceptable"); | |
1469 } else if(xmlnode_get_child(error, "not-allowed")) { | |
1470 text = _("Not Allowed"); | |
1471 } else if(xmlnode_get_child(error, "not-authorized")) { | |
1472 text = _("Not Authorized"); | |
1473 } else if(xmlnode_get_child(error, "payment-required")) { | |
1474 text = _("Payment Required"); | |
1475 } else if(xmlnode_get_child(error, "recipient-unavailable")) { | |
1476 text = _("Recipient Unavailable"); | |
1477 } else if(xmlnode_get_child(error, "redirect")) { | |
1478 /* XXX */ | |
1479 } else if(xmlnode_get_child(error, "registration-required")) { | |
1480 text = _("Registration Required"); | |
1481 } else if(xmlnode_get_child(error, "remote-server-not-found")) { | |
1482 text = _("Remote Server Not Found"); | |
1483 } else if(xmlnode_get_child(error, "remote-server-timeout")) { | |
1484 text = _("Remote Server Timeout"); | |
1485 } else if(xmlnode_get_child(error, "resource-constraint")) { | |
1486 text = _("Server Overloaded"); | |
1487 } else if(xmlnode_get_child(error, "service-unavailable")) { | |
1488 text = _("Service Unavailable"); | |
1489 } else if(xmlnode_get_child(error, "subscription-required")) { | |
1490 text = _("Subscription Required"); | |
1491 } else if(xmlnode_get_child(error, "unexpected-request")) { | |
1492 text = _("Unexpected Request"); | |
1493 } else if(xmlnode_get_child(error, "undefined-condition")) { | |
1494 text = _("Unknown Error"); | |
1495 } | |
1496 } else if(xmlns && !strcmp(xmlns, "urn:ietf:params:xml:ns:xmpp-sasl")) { | |
1497 if(xmlnode_get_child(packet, "aborted")) { | |
1498 js->gc->wants_to_die = TRUE; | |
1499 text = _("Authorization Aborted"); | |
1500 } else if(xmlnode_get_child(packet, "incorrect-encoding")) { | |
1501 text = _("Incorrect encoding in authorization"); | |
1502 } else if(xmlnode_get_child(packet, "invalid-authzid")) { | |
1503 js->gc->wants_to_die = TRUE; | |
1504 text = _("Invalid authzid"); | |
1505 } else if(xmlnode_get_child(packet, "invalid-mechanism")) { | |
1506 js->gc->wants_to_die = TRUE; | |
1507 text = _("Invalid Authorization Mechanism"); | |
1508 } else if(xmlnode_get_child(packet, "mechanism-too-weak")) { | |
1509 js->gc->wants_to_die = TRUE; | |
1510 text = _("Authorization mechanism too weak"); | |
1511 } else if(xmlnode_get_child(packet, "not-authorized")) { | |
1512 js->gc->wants_to_die = TRUE; | |
1513 text = _("Not Authorized"); | |
1514 } else if(xmlnode_get_child(packet, "temporary-auth-failure")) { | |
1515 text = _("Temporary Authentication Failure"); | |
1516 } else { | |
1517 js->gc->wants_to_die = TRUE; | |
1518 text = _("Authentication Failure"); | |
1519 } | |
1520 } else if(!strcmp(packet->name, "stream:error")) { | |
1521 if(xmlnode_get_child(packet, "bad-format")) { | |
1522 text = _("Bad Format"); | |
1523 } else if(xmlnode_get_child(packet, "bad-namespace-prefix")) { | |
1524 text = _("Bad Namespace Prefix"); | |
1525 } else if(xmlnode_get_child(packet, "conflict")) { | |
1526 js->gc->wants_to_die = TRUE; | |
1527 text = _("Resource Conflict"); | |
1528 } else if(xmlnode_get_child(packet, "connection-timeout")) { | |
1529 text = _("Connection Timeout"); | |
1530 } else if(xmlnode_get_child(packet, "host-gone")) { | |
1531 text = _("Host Gone"); | |
1532 } else if(xmlnode_get_child(packet, "host-unknown")) { | |
1533 text = _("Host Unknown"); | |
1534 } else if(xmlnode_get_child(packet, "improper-addressing")) { | |
1535 text = _("Improper Addressing"); | |
1536 } else if(xmlnode_get_child(packet, "internal-server-error")) { | |
1537 text = _("Internal Server Error"); | |
1538 } else if(xmlnode_get_child(packet, "invalid-id")) { | |
1539 text = _("Invalid ID"); | |
1540 } else if(xmlnode_get_child(packet, "invalid-namespace")) { | |
1541 text = _("Invalid Namespace"); | |
1542 } else if(xmlnode_get_child(packet, "invalid-xml")) { | |
1543 text = _("Invalid XML"); | |
1544 } else if(xmlnode_get_child(packet, "nonmatching-hosts")) { | |
1545 text = _("Non-matching Hosts"); | |
1546 } else if(xmlnode_get_child(packet, "not-authorized")) { | |
1547 text = _("Not Authorized"); | |
1548 } else if(xmlnode_get_child(packet, "policy-violation")) { | |
1549 text = _("Policy Violation"); | |
1550 } else if(xmlnode_get_child(packet, "remote-connection-failed")) { | |
1551 text = _("Remote Connection Failed"); | |
1552 } else if(xmlnode_get_child(packet, "resource-constraint")) { | |
1553 text = _("Resource Constraint"); | |
1554 } else if(xmlnode_get_child(packet, "restricted-xml")) { | |
1555 text = _("Restricted XML"); | |
1556 } else if(xmlnode_get_child(packet, "see-other-host")) { | |
1557 text = _("See Other Host"); | |
1558 } else if(xmlnode_get_child(packet, "system-shutdown")) { | |
1559 text = _("System Shutdown"); | |
1560 } else if(xmlnode_get_child(packet, "undefined-condition")) { | |
1561 text = _("Undefined Condition"); | |
1562 } else if(xmlnode_get_child(packet, "unsupported-encoding")) { | |
1563 text = _("Unsupported Encoding"); | |
1564 } else if(xmlnode_get_child(packet, "unsupported-stanza-type")) { | |
1565 text = _("Unsupported Stanza Type"); | |
1566 } else if(xmlnode_get_child(packet, "unsupported-version")) { | |
1567 text = _("Unsupported Version"); | |
1568 } else if(xmlnode_get_child(packet, "xml-not-well-formed")) { | |
1569 text = _("XML Not Well Formed"); | |
1570 } else { | |
1571 text = _("Stream Error"); | |
1572 } | |
1573 } | |
1574 | |
1575 if(text || cdata) { | |
1576 char *ret = g_strdup_printf("%s%s%s", code ? code : "", | |
1577 code ? ": " : "", text ? text : cdata); | |
1578 g_free(cdata); | |
1579 return ret; | |
1580 } else { | |
1581 return NULL; | |
1582 } | |
1583 } | |
1584 | |
1585 static GaimCmdRet jabber_cmd_chat_config(GaimConversation *conv, | |
1586 const char *cmd, char **args, char **error, void *data) | |
1587 { | |
1588 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1589 jabber_chat_request_room_configure(chat); | |
1590 return GAIM_CMD_RET_OK; | |
1591 } | |
1592 | |
1593 static GaimCmdRet jabber_cmd_chat_register(GaimConversation *conv, | |
1594 const char *cmd, char **args, char **error, void *data) | |
1595 { | |
1596 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1597 jabber_chat_register(chat); | |
1598 return GAIM_CMD_RET_OK; | |
1599 } | |
1600 | |
1601 static GaimCmdRet jabber_cmd_chat_topic(GaimConversation *conv, | |
1602 const char *cmd, char **args, char **error, void *data) | |
1603 { | |
1604 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1605 jabber_chat_change_topic(chat, args ? args[0] : NULL); | |
1606 return GAIM_CMD_RET_OK; | |
1607 } | |
1608 | |
1609 static GaimCmdRet jabber_cmd_chat_nick(GaimConversation *conv, | |
1610 const char *cmd, char **args, char **error, void *data) | |
1611 { | |
1612 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1613 | |
1614 if(!args || !args[0]) | |
1615 return GAIM_CMD_RET_FAILED; | |
1616 | |
1617 jabber_chat_change_nick(chat, args[0]); | |
1618 return GAIM_CMD_RET_OK; | |
1619 } | |
1620 | |
1621 static GaimCmdRet jabber_cmd_chat_part(GaimConversation *conv, | |
1622 const char *cmd, char **args, char **error, void *data) | |
1623 { | |
1624 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1625 jabber_chat_part(chat, args ? args[0] : NULL); | |
1626 return GAIM_CMD_RET_OK; | |
1627 } | |
1628 | |
1629 static GaimCmdRet jabber_cmd_chat_ban(GaimConversation *conv, | |
1630 const char *cmd, char **args, char **error, void *data) | |
1631 { | |
1632 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1633 | |
1634 if(!args || !args[0]) | |
1635 return GAIM_CMD_RET_FAILED; | |
1636 | |
1637 if(!jabber_chat_ban_user(chat, args[0], args[1])) { | |
1638 *error = g_strdup_printf(_("Unable to ban user %s"), args[0]); | |
1639 return GAIM_CMD_RET_FAILED; | |
1640 } | |
1641 | |
1642 return GAIM_CMD_RET_OK; | |
1643 } | |
1644 | |
1645 static GaimCmdRet jabber_cmd_chat_affiliate(GaimConversation *conv, | |
1646 const char *cmd, char **args, char **error, void *data) | |
1647 { | |
1648 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1649 | |
1650 if (!args || !args[0] || !args[1]) | |
1651 return GAIM_CMD_RET_FAILED; | |
1652 | |
1653 if (strcmp(args[1], "owner") != 0 && | |
1654 strcmp(args[1], "admin") != 0 && | |
1655 strcmp(args[1], "member") != 0 && | |
1656 strcmp(args[1], "outcast") != 0 && | |
1657 strcmp(args[1], "none") != 0) { | |
1658 *error = g_strdup_printf(_("Unknown affiliation: \"%s\""), args[1]); | |
1659 return GAIM_CMD_RET_FAILED; | |
1660 } | |
1661 | |
1662 if (!jabber_chat_affiliate_user(chat, args[0], args[1])) { | |
1663 *error = g_strdup_printf(_("Unable to affiliate user %s as \"%s\""), args[0], args[1]); | |
1664 return GAIM_CMD_RET_FAILED; | |
1665 } | |
1666 | |
1667 return GAIM_CMD_RET_OK; | |
1668 } | |
1669 | |
1670 static GaimCmdRet jabber_cmd_chat_role(GaimConversation *conv, | |
1671 const char *cmd, char **args, char **error, void *data) | |
1672 { | |
1673 JabberChat *chat; | |
1674 | |
1675 if (!args || !args[0] || !args[1]) | |
1676 return GAIM_CMD_RET_FAILED; | |
1677 | |
1678 if (strcmp(args[1], "moderator") != 0 && | |
1679 strcmp(args[1], "participant") != 0 && | |
1680 strcmp(args[1], "visitor") != 0 && | |
1681 strcmp(args[1], "none") != 0) { | |
1682 *error = g_strdup_printf(_("Unknown role: \"%s\""), args[1]); | |
1683 return GAIM_CMD_RET_FAILED; | |
1684 } | |
1685 | |
1686 chat = jabber_chat_find_by_conv(conv); | |
1687 | |
1688 if (!jabber_chat_role_user(chat, args[0], args[1])) { | |
1689 *error = g_strdup_printf(_("Unable to set role \"%s\" for user: %s"), | |
1690 args[1], args[0]); | |
1691 return GAIM_CMD_RET_FAILED; | |
1692 } | |
1693 | |
1694 return GAIM_CMD_RET_OK; | |
1695 } | |
1696 | |
1697 static GaimCmdRet jabber_cmd_chat_invite(GaimConversation *conv, | |
1698 const char *cmd, char **args, char **error, void *data) | |
1699 { | |
1700 if(!args || !args[0]) | |
1701 return GAIM_CMD_RET_FAILED; | |
1702 | |
1703 jabber_chat_invite(gaim_conversation_get_gc(conv), | |
1704 gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)), args[1] ? args[1] : "", | |
1705 args[0]); | |
1706 | |
1707 return GAIM_CMD_RET_OK; | |
1708 } | |
1709 | |
1710 static GaimCmdRet jabber_cmd_chat_join(GaimConversation *conv, | |
1711 const char *cmd, char **args, char **error, void *data) | |
1712 { | |
1713 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1714 GHashTable *components; | |
1715 | |
1716 if(!args || !args[0]) | |
1717 return GAIM_CMD_RET_FAILED; | |
1718 | |
1719 components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); | |
1720 | |
1721 g_hash_table_replace(components, "room", args[0]); | |
1722 g_hash_table_replace(components, "server", chat->server); | |
1723 g_hash_table_replace(components, "handle", chat->handle); | |
1724 if(args[1]) | |
1725 g_hash_table_replace(components, "password", args[1]); | |
1726 | |
1727 jabber_chat_join(gaim_conversation_get_gc(conv), components); | |
1728 | |
1729 g_hash_table_destroy(components); | |
1730 return GAIM_CMD_RET_OK; | |
1731 } | |
1732 | |
1733 static GaimCmdRet jabber_cmd_chat_kick(GaimConversation *conv, | |
1734 const char *cmd, char **args, char **error, void *data) | |
1735 { | |
1736 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1737 | |
1738 if(!args || !args[0]) | |
1739 return GAIM_CMD_RET_FAILED; | |
1740 | |
1741 if(!jabber_chat_kick_user(chat, args[0], args[1])) { | |
1742 *error = g_strdup_printf(_("Unable to kick user %s"), args[0]); | |
1743 return GAIM_CMD_RET_FAILED; | |
1744 } | |
1745 | |
1746 return GAIM_CMD_RET_OK; | |
1747 } | |
1748 | |
1749 static GaimCmdRet jabber_cmd_chat_msg(GaimConversation *conv, | |
1750 const char *cmd, char **args, char **error, void *data) | |
1751 { | |
1752 JabberChat *chat = jabber_chat_find_by_conv(conv); | |
1753 char *who; | |
1754 | |
1755 who = g_strdup_printf("%s@%s/%s", chat->room, chat->server, args[0]); | |
1756 | |
1757 jabber_message_send_im(gaim_conversation_get_gc(conv), who, args[1], 0); | |
1758 | |
1759 g_free(who); | |
1760 return GAIM_CMD_RET_OK; | |
1761 } | |
1762 | |
1763 static gboolean jabber_offline_message(const GaimBuddy *buddy) | |
1764 { | |
1765 return TRUE; | |
1766 } | |
1767 | |
1768 static void jabber_register_commands(void) | |
1769 { | |
1770 gaim_cmd_register("config", "", GAIM_CMD_P_PRPL, | |
1771 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1772 "prpl-jabber", jabber_cmd_chat_config, | |
1773 _("config: Configure a chat room."), NULL); | |
1774 gaim_cmd_register("configure", "", GAIM_CMD_P_PRPL, | |
1775 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1776 "prpl-jabber", jabber_cmd_chat_config, | |
1777 _("configure: Configure a chat room."), NULL); | |
1778 gaim_cmd_register("nick", "s", GAIM_CMD_P_PRPL, | |
1779 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1780 "prpl-jabber", jabber_cmd_chat_nick, | |
1781 _("nick <new nickname>: Change your nickname."), | |
1782 NULL); | |
1783 gaim_cmd_register("part", "s", GAIM_CMD_P_PRPL, | |
1784 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1785 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1786 jabber_cmd_chat_part, _("part [room]: Leave the room."), | |
1787 NULL); | |
1788 gaim_cmd_register("register", "", GAIM_CMD_P_PRPL, | |
1789 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1790 "prpl-jabber", jabber_cmd_chat_register, | |
1791 _("register: Register with a chat room."), NULL); | |
1792 /* XXX: there needs to be a core /topic cmd, methinks */ | |
1793 gaim_cmd_register("topic", "s", GAIM_CMD_P_PRPL, | |
1794 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1795 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1796 jabber_cmd_chat_topic, | |
1797 _("topic [new topic]: View or change the topic."), | |
1798 NULL); | |
1799 gaim_cmd_register("ban", "ws", GAIM_CMD_P_PRPL, | |
1800 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1801 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1802 jabber_cmd_chat_ban, | |
1803 _("ban <user> [room]: Ban a user from the room."), | |
1804 NULL); | |
1805 gaim_cmd_register("affiliate", "ws", GAIM_CMD_P_PRPL, | |
1806 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1807 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1808 jabber_cmd_chat_affiliate, | |
1809 _("affiliate <user> <owner|admin|member|outcast|none>: Set a user's affiliation with the room."), | |
1810 NULL); | |
1811 gaim_cmd_register("role", "ws", GAIM_CMD_P_PRPL, | |
1812 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1813 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1814 jabber_cmd_chat_role, | |
1815 _("role <user> <moderator|participant|visitor|none>: Set a user's role in the room."), | |
1816 NULL); | |
1817 gaim_cmd_register("invite", "ws", GAIM_CMD_P_PRPL, | |
1818 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1819 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1820 jabber_cmd_chat_invite, | |
1821 _("invite <user> [message]: Invite a user to the room."), | |
1822 NULL); | |
1823 gaim_cmd_register("join", "ws", GAIM_CMD_P_PRPL, | |
1824 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1825 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1826 jabber_cmd_chat_join, | |
1827 _("join: <room> [server]: Join a chat on this server."), | |
1828 NULL); | |
1829 gaim_cmd_register("kick", "ws", GAIM_CMD_P_PRPL, | |
1830 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY | | |
1831 GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", | |
1832 jabber_cmd_chat_kick, | |
1833 _("kick <user> [room]: Kick a user from the room."), | |
1834 NULL); | |
1835 gaim_cmd_register("msg", "ws", GAIM_CMD_P_PRPL, | |
1836 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, | |
1837 "prpl-jabber", jabber_cmd_chat_msg, | |
1838 _("msg <user> <message>: Send a private message to another user."), | |
1839 NULL); | |
1840 } | |
1841 | |
1842 static GaimPluginProtocolInfo prpl_info = | |
1843 { | |
1844 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME, | |
1845 NULL, /* user_splits */ | |
1846 NULL, /* protocol_options */ | |
15119 | 1847 {"png,gif,jpeg", 0, 0, 96, 96, GAIM_ICON_SCALE_SEND | GAIM_ICON_SCALE_DISPLAY}, /* icon_spec */ |
14192 | 1848 jabber_list_icon, /* list_icon */ |
1849 jabber_list_emblems, /* list_emblems */ | |
1850 jabber_status_text, /* status_text */ | |
1851 jabber_tooltip_text, /* tooltip_text */ | |
1852 jabber_status_types, /* status_types */ | |
1853 jabber_blist_node_menu, /* blist_node_menu */ | |
1854 jabber_chat_info, /* chat_info */ | |
1855 jabber_chat_info_defaults, /* chat_info_defaults */ | |
1856 jabber_login, /* login */ | |
1857 jabber_close, /* close */ | |
1858 jabber_message_send_im, /* send_im */ | |
1859 jabber_set_info, /* set_info */ | |
1860 jabber_send_typing, /* send_typing */ | |
1861 jabber_buddy_get_info, /* get_info */ | |
1862 jabber_presence_send, /* set_away */ | |
14391 | 1863 jabber_idle_set, /* set_idle */ |
14192 | 1864 NULL, /* change_passwd */ |
1865 jabber_roster_add_buddy, /* add_buddy */ | |
1866 NULL, /* add_buddies */ | |
1867 jabber_roster_remove_buddy, /* remove_buddy */ | |
1868 NULL, /* remove_buddies */ | |
1869 NULL, /* add_permit */ | |
1870 NULL, /* add_deny */ | |
1871 NULL, /* rem_permit */ | |
1872 NULL, /* rem_deny */ | |
1873 NULL, /* set_permit_deny */ | |
1874 jabber_chat_join, /* join_chat */ | |
1875 NULL, /* reject_chat */ | |
1876 jabber_get_chat_name, /* get_chat_name */ | |
1877 jabber_chat_invite, /* chat_invite */ | |
1878 jabber_chat_leave, /* chat_leave */ | |
1879 NULL, /* chat_whisper */ | |
1880 jabber_message_send_chat, /* chat_send */ | |
1881 jabber_keepalive, /* keepalive */ | |
1882 jabber_register_account, /* register_user */ | |
1883 jabber_buddy_get_info_chat, /* get_cb_info */ | |
1884 NULL, /* get_cb_away */ | |
1885 jabber_roster_alias_change, /* alias_buddy */ | |
1886 jabber_roster_group_change, /* group_buddy */ | |
1887 jabber_roster_group_rename, /* rename_group */ | |
1888 NULL, /* buddy_free */ | |
1889 jabber_convo_closed, /* convo_closed */ | |
1890 jabber_normalize, /* normalize */ | |
1891 jabber_set_buddy_icon, /* set_buddy_icon */ | |
1892 NULL, /* remove_group */ | |
1893 jabber_chat_buddy_real_name, /* get_cb_real_name */ | |
1894 jabber_chat_set_topic, /* set_chat_topic */ | |
1895 jabber_find_blist_chat, /* find_blist_chat */ | |
1896 jabber_roomlist_get_list, /* roomlist_get_list */ | |
1897 jabber_roomlist_cancel, /* roomlist_cancel */ | |
1898 NULL, /* roomlist_expand_category */ | |
1899 NULL, /* can_receive_file */ | |
1900 jabber_si_xfer_send, /* send_file */ | |
1901 jabber_si_new_xfer, /* new_xfer */ | |
1902 jabber_offline_message, /* offline_message */ | |
1903 NULL, /* whiteboard_prpl_ops */ | |
14573
9cbf4d3ef444
[gaim-migrate @ 17297]
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
14542
diff
changeset
|
1904 jabber_prpl_send_raw, /* send_raw */ |
14192 | 1905 }; |
1906 | |
14296 | 1907 static gboolean load_plugin(GaimPlugin *plugin) |
1908 { | |
1909 gaim_signal_register(plugin, "jabber-receiving-xmlnode", | |
1910 gaim_marshal_VOID__POINTER_POINTER, NULL, 2, | |
1911 gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_CONNECTION), | |
1912 gaim_value_new_outgoing(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_XMLNODE)); | |
1913 | |
1914 gaim_signal_register(plugin, "jabber-sending-xmlnode", | |
1915 gaim_marshal_VOID__POINTER_POINTER, NULL, 2, | |
1916 gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_CONNECTION), | |
1917 gaim_value_new_outgoing(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_XMLNODE)); | |
1918 | |
14606 | 1919 gaim_signal_register(plugin, "jabber-sending-text", |
1920 gaim_marshal_VOID__POINTER_POINTER, NULL, 2, | |
1921 gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_CONNECTION), | |
1922 gaim_value_new(GAIM_TYPE_STRING)); | |
1923 | |
1924 | |
14296 | 1925 return TRUE; |
1926 } | |
1927 | |
1928 static gboolean unload_plugin(GaimPlugin *plugin) | |
1929 { | |
1930 gaim_signal_unregister(plugin, "jabber-receiving-xmlnode"); | |
1931 | |
1932 gaim_signal_unregister(plugin, "jabber-sending-xmlnode"); | |
14606 | 1933 |
1934 gaim_signal_unregister(plugin, "jabber-sending-text"); | |
1935 | |
14296 | 1936 return TRUE; |
1937 } | |
1938 | |
14192 | 1939 static GaimPluginInfo info = |
1940 { | |
1941 GAIM_PLUGIN_MAGIC, | |
1942 GAIM_MAJOR_VERSION, | |
1943 GAIM_MINOR_VERSION, | |
1944 GAIM_PLUGIN_PROTOCOL, /**< type */ | |
1945 NULL, /**< ui_requirement */ | |
1946 0, /**< flags */ | |
1947 NULL, /**< dependencies */ | |
1948 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
1949 | |
1950 "prpl-jabber", /**< id */ | |
1951 "Jabber", /**< name */ | |
1952 VERSION, /**< version */ | |
1953 /** summary */ | |
1954 N_("Jabber Protocol Plugin"), | |
1955 /** description */ | |
1956 N_("Jabber Protocol Plugin"), | |
1957 NULL, /**< author */ | |
1958 GAIM_WEBSITE, /**< homepage */ | |
1959 | |
14296 | 1960 load_plugin, /**< load */ |
1961 unload_plugin, /**< unload */ | |
14192 | 1962 NULL, /**< destroy */ |
1963 | |
1964 NULL, /**< ui_info */ | |
1965 &prpl_info, /**< extra_info */ | |
1966 NULL, /**< prefs_info */ | |
1967 jabber_actions | |
1968 }; | |
1969 | |
1970 static void | |
1971 init_plugin(GaimPlugin *plugin) | |
1972 { | |
1973 GaimAccountUserSplit *split; | |
1974 GaimAccountOption *option; | |
1975 | |
1976 split = gaim_account_user_split_new(_("Server"), "jabber.org", '@'); | |
1977 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); | |
1978 | |
1979 split = gaim_account_user_split_new(_("Resource"), "Home", '/'); | |
1980 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); | |
1981 | |
1982 option = gaim_account_option_bool_new(_("Force old (port 5223) SSL"), "old_ssl", FALSE); | |
1983 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
1984 option); | |
1985 | |
1986 option = gaim_account_option_bool_new( | |
1987 _("Allow plaintext auth over unencrypted streams"), | |
1988 "auth_plain_in_clear", FALSE); | |
1989 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
1990 option); | |
1991 | |
1992 option = gaim_account_option_int_new(_("Connect port"), "port", 5222); | |
1993 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
1994 option); | |
1995 | |
1996 option = gaim_account_option_string_new(_("Connect server"), | |
1997 "connect_server", NULL); | |
1998 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, | |
1999 option); | |
2000 | |
2001 my_protocol = plugin; | |
2002 | |
2003 gaim_prefs_remove("/plugins/prpl/jabber"); | |
2004 | |
2005 /* XXX - If any other plugin wants SASL this won't be good ... */ | |
2006 #ifdef HAVE_CYRUS_SASL | |
2007 sasl_client_init(NULL); | |
2008 #endif | |
2009 jabber_register_commands(); | |
14294 | 2010 |
2011 jabber_iq_init(); | |
14192 | 2012 } |
2013 | |
2014 GAIM_INIT_PLUGIN(jabber, init_plugin, info); |