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