2
* Copyright (C) 2007 Colin DIDIER
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 2 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
#include <sys/types.h>
19
#include <sys/socket.h>
30
#include "xmpp-servers.h"
32
#include "rosters-tools.h"
36
channels_join(SERVER_REC *server, const char *data, int automatic)
41
isnickflag_func(SERVER_REC *server, char flag)
47
ischannel_func(SERVER_REC *server, const char *data)
53
get_nick_flags(SERVER_REC *server)
59
send_message(SERVER_REC *server, const char *target, const char *msg,
65
if (!IS_XMPP_SERVER(server))
67
g_return_if_fail(target != NULL);
68
g_return_if_fail(msg != NULL);
69
if (target_type == SEND_TARGET_CHANNEL) {
70
recoded = xmpp_recode_out(target);
71
lmsg = lm_message_new_with_sub_type(recoded,
72
LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_GROUPCHAT);
74
str = rosters_resolve_name(XMPP_SERVER(server), target);
75
recoded = xmpp_recode_out(str != NULL ? str : target);
77
lmsg = lm_message_new_with_sub_type(recoded,
78
LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_CHAT);
81
/* ugly from irssi: recode the sent message back */
82
str = recode_in(server, msg, target);
83
recoded = xmpp_recode_out(str);
85
lm_message_node_add_child(lmsg->node, "body", recoded);
87
signal_emit("xmpp send message", 2, server, lmsg);
88
lm_message_unref(lmsg);
92
server_cleanup(XMPP_SERVER_REC *server)
94
if (!IS_XMPP_SERVER(server))
96
if (server->timeout_tag)
97
g_source_remove(server->timeout_tag);
98
if (lm_connection_get_state(server->lmconn) !=
99
LM_CONNECTION_STATE_CLOSED)
100
lm_connection_close(server->lmconn, NULL);
101
lm_connection_unref(server->lmconn);
103
g_free(server->user);
104
g_free(server->domain);
105
g_free(server->resource);
106
g_free(server->ping_id);
110
xmpp_server_init_connect(SERVER_CONNECT_REC *connrec)
112
XMPP_SERVER_REC *server;
113
XMPP_SERVER_CONNECT_REC *conn = (XMPP_SERVER_CONNECT_REC *)connrec;
116
if (conn->address == NULL || conn->address[0] == '\0')
118
if (conn->nick == NULL || conn->nick[0] == '\0')
120
g_return_val_if_fail(IS_XMPP_SERVER_CONNECT(conn), NULL);
122
server = g_new0(XMPP_SERVER_REC, 1);
123
server->chat_type = XMPP_PROTOCOL;
124
server->user = xmpp_extract_user(conn->nick);
125
server->domain = xmpp_have_domain(conn->nick) ?
126
xmpp_extract_domain(conn->nick) : g_strdup(conn->address);
127
server->jid = xmpp_have_domain(conn->nick) ?
128
xmpp_strip_resource(conn->nick)
129
: g_strconcat(server->user, "@", server->domain, (void *)NULL);
130
server->resource = xmpp_extract_resource(conn->nick);
131
if (server->resource == NULL)
132
server->resource = g_strdup("irssi-xmpp");
133
server->priority = settings_get_int("xmpp_priority");
134
if (xmpp_priority_out_of_bound(server->priority))
135
server->priority = 0;
136
server->ping_id = NULL;
137
server->server_features = NULL;
138
server->my_resources = NULL;
139
server->roster = NULL;
140
server->msg_handlers = NULL;
141
server->channels_join = channels_join;
142
server->isnickflag = isnickflag_func;
143
server->ischannel = ischannel_func;
144
server->get_nick_flags = get_nick_flags;
145
server->send_message = send_message;
146
server->connrec = (XMPP_SERVER_CONNECT_REC *)conn;
147
server_connect_ref(connrec);
149
/* don't use irssi's sockets */
150
server->connrec->no_connect = TRUE;
151
server->connect_pid = -1;
153
if (server->connrec->port <= 0)
154
server->connrec->port = (server->connrec->use_ssl) ?
155
LM_CONNECTION_DEFAULT_PORT_SSL : LM_CONNECTION_DEFAULT_PORT;
157
if (conn->real_jid == NULL)
158
conn->real_jid = conn->nick;
161
conn->nick = g_strdup(settings_get_bool("xmpp_set_nick_as_username") ?
162
server->user : server->jid);
164
/* init loudmouth connection structure */
165
server->lmconn = lm_connection_new(NULL);
166
lm_connection_set_server(server->lmconn, server->connrec->address);
167
lm_connection_set_port(server->lmconn, server->connrec->port);
168
recoded = xmpp_recode_out(server->jid);
169
lm_connection_set_jid(server->lmconn, recoded);
171
lm_connection_set_keep_alive_rate(server->lmconn, 30);
173
server->timeout_tag = 0;
174
server_connect_init((SERVER_REC *)server);
175
server->connect_tag = 1;
176
return (SERVER_REC *)server;
180
lm_ssl_cb(LmSSL *ssl, LmSSLStatus status, gpointer user_data)
182
XMPP_SERVER_REC *server;
184
if ((server = XMPP_SERVER(user_data)) == NULL)
185
return LM_SSL_RESPONSE_CONTINUE;
187
case LM_SSL_STATUS_NO_CERT_FOUND:
188
g_warning("SSL (%s): no certificate found",
189
server->connrec->address);
191
case LM_SSL_STATUS_UNTRUSTED_CERT:
192
g_warning("SSL (%s): certificate is not trusted",
193
server->connrec->address);
195
case LM_SSL_STATUS_CERT_EXPIRED:
196
g_warning("SSL (%s): certificate has expired",
197
server->connrec->address);
199
case LM_SSL_STATUS_CERT_NOT_ACTIVATED:
200
g_warning("SSL (%s): certificate has not been activated",
201
server->connrec->address);
203
case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH:
204
g_warning("SSL (%s): certificate hostname does not match "
205
"expected hostname", server->connrec->address);
207
case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH:
208
g_warning("SSL (%s): certificate fingerprint does not match "
209
"expected fingerprint", server->connrec->address);
211
case LM_SSL_STATUS_GENERIC_ERROR:
212
g_warning("SSL (%s): generic error", server->connrec->address);
215
return LM_SSL_RESPONSE_CONTINUE;
219
lm_close_cb(LmConnection *connection, LmDisconnectReason reason,
222
XMPP_SERVER_REC *server;
224
if ((server = XMPP_SERVER(user_data)) == NULL || !server->connected
225
|| reason == LM_DISCONNECT_REASON_OK)
227
server->connection_lost = TRUE;
228
server_disconnect(SERVER(server));
232
lm_auth_cb(LmConnection *connection, gboolean success,
235
XMPP_SERVER_REC *server;
237
if ((server = XMPP_SERVER(user_data)) == NULL)
240
server_connect_failed(SERVER(server), "Authentication failed");
243
signal_emit("xmpp server status", 2, server,
244
"Authenticated successfully.");
246
/* finnish connection process */
247
lookup_servers = g_slist_remove(lookup_servers, server);
248
g_source_remove(server->connect_tag);
249
server->connect_tag = -1;
250
server->show = XMPP_PRESENCE_AVAILABLE;
251
server->connected = TRUE;
252
if (server->timeout_tag) {
253
g_source_remove(server->timeout_tag);
254
server->timeout_tag = 0;
256
server_connect_finished(SERVER(server));
257
server->real_connect_time = server->connect_time;
261
* Displays input prompt on command line and takes input data from user
262
* From irssi-silc (silc-client/lib/silcutil/silcutil.c)
267
char input[2048], *ret = NULL;
270
#ifndef DISABLE_TERMIOS
272
struct termios to_old;
274
if ((fd = open("/dev/tty", O_RDONLY)) < 0) {
275
g_warning("Cannot open /dev/tty: %s\n",
279
signal(SIGINT, SIG_IGN);
281
/* Get terminal info */
284
/* Echo OFF, and assure we can prompt and get input */
285
to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
286
to.c_lflag |= ICANON;
288
tcsetattr(fd, TCSANOW, &to);
290
printf("\tXMPP Password: ");
293
memset(input, 0, sizeof(input));
294
if ((read(fd, input, sizeof(input))) < 0) {
295
g_warning("Cannot read from /dev/tty: %s\n",
297
tcsetattr(fd, TCSANOW, &to_old);
300
if (strlen(input) <= 1) {
301
tcsetattr(fd, TCSANOW, &to_old);
304
if ((ret = strchr(input, '\n')) != NULL)
307
/* Restore old terminfo */
308
tcsetattr(fd, TCSANOW, &to_old);
309
signal(SIGINT, SIG_DFL);
311
ret = g_strdup(input);
312
memset(input, 0, sizeof(input));
313
#endif /* DISABLE_TERMIOS */
318
lm_open_cb(LmConnection *connection, gboolean success,
321
XMPP_SERVER_REC *server;
324
char *recoded_user, *recoded_password, *recoded_resource;
326
if ((server = XMPP_SERVER(user_data)) == NULL || !success)
328
/* get the server address */
329
host = lm_connection_get_local_host(server->lmconn);
331
net_host2ip(host, &ip);
332
signal_emit("server connecting", 2, server, &ip);
335
signal_emit("server connecting", 1, server);
336
if (server->connrec->use_ssl)
337
signal_emit("xmpp server status", 2, server,
338
"Using SSL encryption.");
339
else if (lm_ssl_get_use_starttls(lm_connection_get_ssl(server->lmconn)))
340
signal_emit("xmpp server status", 2, server,
341
"Using STARTTLS encryption.");
342
recoded_user = xmpp_recode_out(server->user);
344
/* prompt for password or re-use typed password */
345
if (server->connrec->prompted_password != NULL) {
346
g_free_not_null(server->connrec->password);
347
server->connrec->password =
348
g_strdup(server->connrec->prompted_password);
349
} else if (server->connrec->password == NULL
350
|| *(server->connrec->password) == '\0'
351
|| *(server->connrec->password) == '\r') {
352
g_free_not_null(server->connrec->password);
353
server->connrec->prompted_password = get_password();
354
signal_emit("send command", 1, "redraw");
355
if (server->connrec->prompted_password != NULL)
356
server->connrec->password =
357
g_strdup(server->connrec->prompted_password);
359
server->connrec->password = g_strdup("");
362
recoded_password = xmpp_recode_out(server->connrec->password);
363
recoded_resource = xmpp_recode_out(server->resource);
364
lm_connection_authenticate(connection, recoded_user,
365
recoded_password, recoded_resource, lm_auth_cb, server,
367
g_free(recoded_user);
368
g_free(recoded_password);
369
g_free(recoded_resource);
373
set_ssl(LmConnection *lmconn, GError **error, gpointer user_data,
374
gboolean use_starttls)
378
if (!lm_ssl_is_supported() && error != NULL) {
379
*error = g_new(GError, 1);
381
g_strdup("SSL is not supported in this build");
384
ssl = lm_ssl_new(NULL, lm_ssl_cb, user_data, NULL);
385
lm_connection_set_ssl(lmconn, ssl);
387
lm_ssl_use_starttls(ssl, TRUE, FALSE);
393
set_proxy(LmConnection *lmconn, GError **error)
400
str = settings_get_str("xmpp_proxy_type");
401
if (str != NULL && g_ascii_strcasecmp(str, XMPP_PROXY_HTTP) == 0)
402
type = LM_PROXY_TYPE_HTTP;
405
*error = g_new(GError, 1);
406
(*error)->message = g_strdup("Invalid proxy type");
410
str = settings_get_str("xmpp_proxy_address");
411
if (str == NULL || *str == '\0') {
413
*error = g_new(GError, 1);
415
g_strdup("Proxy address not specified");
419
int port = settings_get_int("xmpp_proxy_port");
422
*error = g_new(GError, 1);
424
g_strdup("Invalid proxy port range");
428
proxy = lm_proxy_new_with_server(type, str, port);
429
str = settings_get_str("xmpp_proxy_user");
430
if (str != NULL && *str != '\0') {
431
recoded = xmpp_recode_out(str);
432
lm_proxy_set_username(proxy, recoded);
435
str = settings_get_str("xmpp_proxy_password");
436
if (str != NULL && *str != '\0') {
437
recoded = xmpp_recode_out(str);
438
lm_proxy_set_password(proxy, recoded);
441
lm_connection_set_proxy(lmconn, proxy);
442
lm_proxy_unref(proxy);
447
check_connection_timeout(XMPP_SERVER_REC *server)
449
if (g_slist_find(lookup_servers, server) == NULL)
451
if (!server->connected) {
452
g_warning("%s: no response from server",
453
server->connrec->address);
454
server->connection_lost = TRUE;
455
server_disconnect(SERVER(server));
457
server->timeout_tag = 0;
462
xmpp_server_connect(XMPP_SERVER_REC *server)
467
if (!IS_XMPP_SERVER(server))
471
if (server->connrec->use_ssl) {
472
if (!set_ssl(server->lmconn, &error, server, FALSE)) {
473
err_msg = "Cannot init ssl";
477
set_ssl(server->lmconn, &error, server, TRUE);
478
if (settings_get_bool("xmpp_use_proxy")
479
&& !set_proxy(server->lmconn, &error)) {
480
err_msg = "Cannot set proxy";
483
lm_connection_set_disconnect_function(server->lmconn,
484
lm_close_cb, server, NULL);
485
lookup_servers = g_slist_append(lookup_servers, server);
486
signal_emit("server looking", 1, server);
487
server->timeout_tag = g_timeout_add(
488
settings_get_time("server_connect_timeout"),
489
(GSourceFunc)check_connection_timeout, server);
490
if (!lm_connection_open(server->lmconn, lm_open_cb, server,
492
err_msg = "Connection failed";
498
server->connection_lost = TRUE;
500
server_connect_failed(SERVER(server), error->message);
503
server_connect_failed(SERVER(server), err_msg);
507
sig_connected(XMPP_SERVER_REC *server)
512
if (!IS_XMPP_SERVER(server) || (server->connrec->reconnection
513
&& xmpp_presence_changed(server->connrec->show, server->show,
514
server->connrec->away_reason, server->away_reason,
515
server->connrec->priority, server->priority)))
517
/* set presence available */
518
lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE,
519
LM_MESSAGE_SUB_TYPE_AVAILABLE);
520
str = g_strdup_printf("%d", server->priority);
521
lm_message_node_add_child(lmsg->node, "priority", str);
523
signal_emit("xmpp send presence", 2, server, lmsg);
524
lm_message_unref(lmsg);
528
sig_server_quit(XMPP_SERVER_REC *server, char *reason)
533
if (!IS_XMPP_SERVER(server))
535
lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE,
536
LM_MESSAGE_SUB_TYPE_UNAVAILABLE);
537
str = xmpp_recode_out((reason != NULL) ?
538
reason : settings_get_str("quit_message"));
539
lm_message_node_add_child(lmsg->node, "status", str);
541
signal_emit("xmpp send presence", 2, server, lmsg);
542
lm_message_unref(lmsg);
550
for (tmp = lookup_servers; tmp != NULL; tmp = next) {
552
if (IS_XMPP_SERVER(tmp->data))
553
server_connect_failed(SERVER(tmp->data), NULL);
555
for (tmp = servers; tmp != NULL; tmp = next) {
557
if (IS_XMPP_SERVER(tmp->data))
558
server_disconnect(SERVER(tmp->data));
563
sig_session_save(void)
565
/* We don't support /UPGRADE, so disconnect all servers
566
* before performing it. */
571
xmpp_servers_init(void)
573
signal_add_last("server connected", sig_connected);
574
signal_add_last("server disconnected", server_cleanup);
575
signal_add_last("server connect failed", server_cleanup);
576
signal_add("server quit", sig_server_quit);
577
signal_add_first("session save", sig_session_save);
579
settings_add_int("xmpp", "xmpp_priority", 0);
580
settings_add_int("xmpp", "xmpp_priority_away", -1);
581
settings_add_bool("xmpp_lookandfeel", "xmpp_set_nick_as_username",
583
settings_add_bool("xmpp_proxy", "xmpp_use_proxy", FALSE);
584
settings_add_str("xmpp_proxy", "xmpp_proxy_type", "http");
585
settings_add_str("xmpp_proxy", "xmpp_proxy_address", NULL);
586
settings_add_int("xmpp_proxy", "xmpp_proxy_port", 8080);
587
settings_add_str("xmpp_proxy", "xmpp_proxy_user", NULL);
588
settings_add_str("xmpp_proxy", "xmpp_proxy_password", NULL);
592
xmpp_servers_deinit(void)
594
/* disconnect all servers before unloading the module */
597
signal_remove("server connected", sig_connected);
598
signal_remove("server disconnected", server_cleanup);
599
signal_remove("server connect failed", server_cleanup);
600
signal_remove("server quit", sig_server_quit);
601
signal_remove("session save", sig_session_save);