|
|
|
@ -23,14 +23,12 @@
|
|
|
|
|
* \extref Iksemel http://iksemel.jabberstudio.org/
|
|
|
|
|
*
|
|
|
|
|
* \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
|
|
|
|
|
* \todo If you have TLS, you can't unload this module. See bug #9738. This needs to be fixed,
|
|
|
|
|
* but the bug is in the unmantained Iksemel library
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*** MODULEINFO
|
|
|
|
|
<depend>iksemel</depend>
|
|
|
|
|
<use>gnutls</use>
|
|
|
|
|
<use>openssl</use>
|
|
|
|
|
***/
|
|
|
|
|
|
|
|
|
|
#include "asterisk.h"
|
|
|
|
@ -71,13 +69,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*-- Forward declarations */
|
|
|
|
|
static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username, char *pass);
|
|
|
|
|
static int aji_highest_bit(int number);
|
|
|
|
|
static void aji_buddy_destroy(struct aji_buddy *obj);
|
|
|
|
|
static void aji_client_destroy(struct aji_client *obj);
|
|
|
|
|
static int aji_send_exec(struct ast_channel *chan, void *data);
|
|
|
|
|
static int aji_status_exec(struct ast_channel *chan, void *data);
|
|
|
|
|
static int aji_is_secure(struct aji_client *client);
|
|
|
|
|
static int aji_start_tls(struct aji_client *client);
|
|
|
|
|
static int aji_tls_handshake(struct aji_client *client);
|
|
|
|
|
static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout);
|
|
|
|
|
static int aji_recv(struct aji_client *client, int timeout);
|
|
|
|
|
static int aji_send_header(struct aji_client *client, const char *to);
|
|
|
|
|
static int aji_send(struct aji_client *client, iks *x);
|
|
|
|
|
static int aji_send_raw(struct aji_client *client, const char *xmlstr);
|
|
|
|
|
static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
|
|
|
|
|
static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass);
|
|
|
|
|
static int aji_act_hook(void *data, int type, iks *node);
|
|
|
|
|
static void aji_handle_iq(struct aji_client *client, iks *node);
|
|
|
|
|
static void aji_handle_message(struct aji_client *client, ikspak *pak);
|
|
|
|
@ -150,7 +156,6 @@ struct aji_capabilities *capabilities = NULL;
|
|
|
|
|
|
|
|
|
|
/*! \brief Global flags, initialized to default values */
|
|
|
|
|
static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
|
|
|
|
|
static int tls_initialized = FALSE;
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Deletes the aji_client data structure.
|
|
|
|
@ -501,6 +506,252 @@ static int aji_send_exec(struct ast_channel *chan, void *data)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Tests whether the connection is secured or not
|
|
|
|
|
* \return 0 if the connection is not secured
|
|
|
|
|
*/
|
|
|
|
|
static int aji_is_secure(struct aji_client *client)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
return client->stream_flags & SECURE;
|
|
|
|
|
#else
|
|
|
|
|
return 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Starts the TLS procedure
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return IKS_OK on success, an error code if sending failed, IKS_NET_TLSFAIL
|
|
|
|
|
* if OpenSSL is not installed
|
|
|
|
|
*/
|
|
|
|
|
static int aji_start_tls(struct aji_client *client)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
#ifndef HAVE_OPENSSL
|
|
|
|
|
return IKS_NET_TLSFAIL;
|
|
|
|
|
#endif
|
|
|
|
|
/* This is sent not encrypted */
|
|
|
|
|
ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
client->stream_flags |= TRY_SECURE;
|
|
|
|
|
|
|
|
|
|
return IKS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief TLS handshake, OpenSSL initialization
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return IKS_OK on success, IKS_NET_TLSFAIL on failure
|
|
|
|
|
*/
|
|
|
|
|
static int aji_tls_handshake(struct aji_client *client)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
int sock;
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_OPENSSL
|
|
|
|
|
return IKS_NET_TLSFAIL;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
ast_debug(1, "Starting TLS handshake\n");
|
|
|
|
|
|
|
|
|
|
/* Load encryption, hashing algorithms and error strings */
|
|
|
|
|
SSL_library_init();
|
|
|
|
|
SSL_load_error_strings();
|
|
|
|
|
|
|
|
|
|
/* Choose an SSL/TLS protocol version, create SSL_CTX */
|
|
|
|
|
client->ssl_method = SSLv3_method();
|
|
|
|
|
client->ssl_context = SSL_CTX_new(client->ssl_method);
|
|
|
|
|
if (!client->ssl_context)
|
|
|
|
|
return IKS_NET_TLSFAIL;
|
|
|
|
|
|
|
|
|
|
/* Create new SSL session */
|
|
|
|
|
client->ssl_session = SSL_new(client->ssl_context);
|
|
|
|
|
if (!client->ssl_session)
|
|
|
|
|
return IKS_NET_TLSFAIL;
|
|
|
|
|
|
|
|
|
|
/* Enforce TLS on our XMPP connection */
|
|
|
|
|
sock = iks_fd(client->p);
|
|
|
|
|
ret = SSL_set_fd(client->ssl_session, sock);
|
|
|
|
|
if (!ret)
|
|
|
|
|
return IKS_NET_TLSFAIL;
|
|
|
|
|
|
|
|
|
|
/* Perform SSL handshake */
|
|
|
|
|
ret = SSL_connect(client->ssl_session);
|
|
|
|
|
if (!ret)
|
|
|
|
|
return IKS_NET_TLSFAIL;
|
|
|
|
|
|
|
|
|
|
client->stream_flags &= (~TRY_SECURE);
|
|
|
|
|
client->stream_flags |= SECURE;
|
|
|
|
|
|
|
|
|
|
/* Sent over the established TLS connection */
|
|
|
|
|
ret = aji_send_header(client, client->jid->server);
|
|
|
|
|
if (ret != IKS_OK)
|
|
|
|
|
return IKS_NET_TLSFAIL;
|
|
|
|
|
|
|
|
|
|
ast_debug(1, "TLS started with server\n");
|
|
|
|
|
|
|
|
|
|
return IKS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Secured or unsecured IO socket receiving function
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param buffer the reception buffer
|
|
|
|
|
* \param buf_len the size of the buffer
|
|
|
|
|
* \param timeout the select timer
|
|
|
|
|
* \return the number of read bytes on success, 0 on timeout expiration,
|
|
|
|
|
* -1 on error
|
|
|
|
|
*/
|
|
|
|
|
static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
|
|
|
|
|
{
|
|
|
|
|
int sock;
|
|
|
|
|
fd_set fds;
|
|
|
|
|
struct timeval tv, *tvptr = NULL;
|
|
|
|
|
int len, res;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
if (aji_is_secure(client)) {
|
|
|
|
|
sock = SSL_get_fd(client->ssl_session);
|
|
|
|
|
if (sock < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
} else
|
|
|
|
|
#endif /* HAVE_OPENSSL */
|
|
|
|
|
sock = iks_fd(client->p);
|
|
|
|
|
|
|
|
|
|
memset(&tv, 0, sizeof(struct timeval));
|
|
|
|
|
FD_ZERO(&fds);
|
|
|
|
|
FD_SET(sock, &fds);
|
|
|
|
|
tv.tv_sec = timeout;
|
|
|
|
|
|
|
|
|
|
/* NULL value for tvptr makes ast_select wait indefinitely */
|
|
|
|
|
tvptr = (timeout != -1) ? &tv : NULL;
|
|
|
|
|
|
|
|
|
|
/* ast_select emulates linux behaviour in terms of timeout handling */
|
|
|
|
|
res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
|
|
|
|
|
if (res > 0) {
|
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
if (aji_is_secure(client)) {
|
|
|
|
|
len = SSL_read(client->ssl_session, buffer, buf_len);
|
|
|
|
|
} else
|
|
|
|
|
#endif /* HAVE_OPENSSL */
|
|
|
|
|
len = recv(sock, buffer, buf_len, 0);
|
|
|
|
|
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
return len;
|
|
|
|
|
} else if (len <= 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Tries to receive data from the Jabber server
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param timeout the timeout value
|
|
|
|
|
* This function receives (encrypted or unencrypted) data from the XMPP server,
|
|
|
|
|
* and passes it to the parser.
|
|
|
|
|
* \return IKS_OK on success, IKS_NET_RWERR on IO error, IKS_NET_NOCONN, if no
|
|
|
|
|
* connection available, IKS_NET_EXPIRED on timeout expiration
|
|
|
|
|
*/
|
|
|
|
|
static int aji_recv (struct aji_client *client, int timeout)
|
|
|
|
|
{
|
|
|
|
|
int len, ret;
|
|
|
|
|
char buf[NET_IO_BUF_SIZE -1];
|
|
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 1, timeout);
|
|
|
|
|
if (len < 0) return IKS_NET_RWERR;
|
|
|
|
|
if (len == 0) return IKS_NET_EXPIRED;
|
|
|
|
|
buf[len] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Log the message here, because iksemel's logHook is
|
|
|
|
|
unaccessible */
|
|
|
|
|
aji_log_hook(client, buf, len, 1);
|
|
|
|
|
|
|
|
|
|
ret = iks_parse(client->p, buf, len, 0);
|
|
|
|
|
if (ret != IKS_OK) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return IKS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Sends XMPP header to the server
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param to the target XMPP server
|
|
|
|
|
* \return IKS_OK on success, any other value on failure
|
|
|
|
|
*/
|
|
|
|
|
static int aji_send_header(struct aji_client *client, const char *to)
|
|
|
|
|
{
|
|
|
|
|
char *msg;
|
|
|
|
|
int len, err;
|
|
|
|
|
|
|
|
|
|
len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
|
|
|
|
|
msg = iks_malloc(len);
|
|
|
|
|
if (!msg)
|
|
|
|
|
return IKS_NOMEM;
|
|
|
|
|
sprintf(msg, "<?xml version='1.0'?>"
|
|
|
|
|
"<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
|
|
|
|
|
"%s' to='%s' version='1.0'>", client->name_space, to);
|
|
|
|
|
err = aji_send_raw(client, msg);
|
|
|
|
|
iks_free(msg);
|
|
|
|
|
if (err != IKS_OK)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
return IKS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Wraps raw sending
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param x the XMPP packet to send
|
|
|
|
|
* \return IKS_OK on success, any other value on failure
|
|
|
|
|
*/
|
|
|
|
|
static int aji_send(struct aji_client *client, iks *x)
|
|
|
|
|
{
|
|
|
|
|
return aji_send_raw(client, iks_string(iks_stack(x), x));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Sends an XML string over an XMPP connection
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param xmlstr the XML string to send
|
|
|
|
|
* The XML data is sent whether the connection is secured or not. In the
|
|
|
|
|
* latter case, we just call iks_send_raw().
|
|
|
|
|
* \return IKS_OK on success, any other value on failure
|
|
|
|
|
*/
|
|
|
|
|
static int aji_send_raw(struct aji_client *client, const char *xmlstr)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
int len = strlen(xmlstr);
|
|
|
|
|
|
|
|
|
|
if (aji_is_secure(client)) {
|
|
|
|
|
ret = SSL_write(client->ssl_session, xmlstr, len);
|
|
|
|
|
if (ret) {
|
|
|
|
|
/* Log the message here, because iksemel's logHook is
|
|
|
|
|
unaccessible */
|
|
|
|
|
aji_log_hook(client, xmlstr, len, 0);
|
|
|
|
|
return IKS_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/* If needed, data will be sent unencrypted, and logHook will
|
|
|
|
|
be called inside iks_send_raw */
|
|
|
|
|
ret = iks_send_raw(client->p, xmlstr);
|
|
|
|
|
if (ret != IKS_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
return IKS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief the debug loop.
|
|
|
|
|
* \param data void
|
|
|
|
@ -532,7 +783,7 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief A wrapper function for iks_start_sasl
|
|
|
|
|
* \param prs the XML parser
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param type the SASL authentication type. Supported types are PLAIN and MD5
|
|
|
|
|
* \param username
|
|
|
|
|
* \param pass password.
|
|
|
|
@ -543,7 +794,7 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom
|
|
|
|
|
* computed with iks_start_sasl().
|
|
|
|
|
* \return IKS_OK on success, IKSNET_NOTSUPP on failure.
|
|
|
|
|
*/
|
|
|
|
|
static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username, char *pass)
|
|
|
|
|
static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
|
|
|
|
|
{
|
|
|
|
|
iks *x = NULL;
|
|
|
|
|
int len;
|
|
|
|
@ -551,7 +802,7 @@ static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username,
|
|
|
|
|
char *base64;
|
|
|
|
|
|
|
|
|
|
if (type == IKS_STREAM_SASL_MD5)
|
|
|
|
|
return iks_start_sasl(prs, IKS_SASL_DIGEST_MD5, username, pass);
|
|
|
|
|
return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass);
|
|
|
|
|
|
|
|
|
|
x = iks_new("auth");
|
|
|
|
|
if (!x) {
|
|
|
|
@ -567,7 +818,7 @@ static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username,
|
|
|
|
|
snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
|
|
|
|
|
ast_base64encode(base64, (const unsigned char *) s, len, (len + 2) * 4 / 3);
|
|
|
|
|
iks_insert_cdata(x, base64, 0);
|
|
|
|
|
iks_send(prs, x);
|
|
|
|
|
aji_send(client, x);
|
|
|
|
|
iks_delete(x);
|
|
|
|
|
|
|
|
|
|
return IKS_OK;
|
|
|
|
@ -603,12 +854,13 @@ static int aji_act_hook(void *data, int type, iks *node)
|
|
|
|
|
if (!client->component) { /*client */
|
|
|
|
|
switch (type) {
|
|
|
|
|
case IKS_NODE_START:
|
|
|
|
|
if (client->usetls && !iks_is_secure(client->p)) {
|
|
|
|
|
if (iks_has_tls()) {
|
|
|
|
|
iks_start_tls(client->p);
|
|
|
|
|
tls_initialized = TRUE;
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
|
|
|
|
|
if (client->usetls && !aji_is_secure(client)) {
|
|
|
|
|
if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
|
|
|
|
|
ast_log(LOG_ERROR, "OpenSSL not installed. You need to install OpenSSL on this system\n");
|
|
|
|
|
ASTOBJ_UNREF(client, aji_client_destroy);
|
|
|
|
|
return IKS_HOOK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!client->usesasl) {
|
|
|
|
@ -618,7 +870,7 @@ static int aji_act_hook(void *data, int type, iks *node)
|
|
|
|
|
iks_insert_attrib(auth, "id", client->mid);
|
|
|
|
|
iks_insert_attrib(auth, "to", client->jid->server);
|
|
|
|
|
ast_aji_increment_mid(client->mid);
|
|
|
|
|
iks_send(client->p, auth);
|
|
|
|
|
aji_send(client, auth);
|
|
|
|
|
iks_delete(auth);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
@ -626,19 +878,25 @@ static int aji_act_hook(void *data, int type, iks *node)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IKS_NODE_NORMAL:
|
|
|
|
|
if (client->stream_flags & TRY_SECURE) {
|
|
|
|
|
if (!strcmp("proceed", iks_name(node))) {
|
|
|
|
|
return aji_tls_handshake(client);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!strcmp("stream:features", iks_name(node))) {
|
|
|
|
|
features = iks_stream_features(node);
|
|
|
|
|
if (client->usesasl) {
|
|
|
|
|
if (client->usetls && !iks_is_secure(client->p))
|
|
|
|
|
if (client->usetls && !aji_is_secure(client))
|
|
|
|
|
break;
|
|
|
|
|
if (client->authorized) {
|
|
|
|
|
if (features & IKS_STREAM_BIND) {
|
|
|
|
|
iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
|
|
|
|
|
iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
|
|
|
|
|
auth = iks_make_resource_bind(client->jid);
|
|
|
|
|
if (auth) {
|
|
|
|
|
iks_insert_attrib(auth, "id", client->mid);
|
|
|
|
|
ast_aji_increment_mid(client->mid);
|
|
|
|
|
iks_send(client->p, auth);
|
|
|
|
|
aji_send(client, auth);
|
|
|
|
|
iks_delete(auth);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
@ -651,7 +909,7 @@ static int aji_act_hook(void *data, int type, iks *node)
|
|
|
|
|
if (auth) {
|
|
|
|
|
iks_insert_attrib(auth, "id", "auth");
|
|
|
|
|
ast_aji_increment_mid(client->mid);
|
|
|
|
|
iks_send(client->p, auth);
|
|
|
|
|
aji_send(client, auth);
|
|
|
|
|
iks_delete(auth);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
@ -664,7 +922,7 @@ static int aji_act_hook(void *data, int type, iks *node)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
features = aji_highest_bit(features);
|
|
|
|
|
ret = aji_start_sasl(client->p, features, client->jid->user, client->password);
|
|
|
|
|
ret = aji_start_sasl(client, features, client->jid->user, client->password);
|
|
|
|
|
if (ret != IKS_OK) {
|
|
|
|
|
ASTOBJ_UNREF(client, aji_client_destroy);
|
|
|
|
|
return IKS_HOOK;
|
|
|
|
@ -676,7 +934,7 @@ static int aji_act_hook(void *data, int type, iks *node)
|
|
|
|
|
ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
|
|
|
|
|
} else if (!strcmp("success", iks_name(node))) {
|
|
|
|
|
client->authorized = 1;
|
|
|
|
|
iks_send_header(client->p, client->jid->server);
|
|
|
|
|
aji_send_header(client, client->jid->server);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case IKS_NODE_ERROR:
|
|
|
|
@ -701,12 +959,12 @@ static int aji_act_hook(void *data, int type, iks *node)
|
|
|
|
|
handshake = NULL;
|
|
|
|
|
asprintf(&handshake, "<handshake>%s</handshake>", shasum);
|
|
|
|
|
if (handshake) {
|
|
|
|
|
iks_send_raw(client->p, handshake);
|
|
|
|
|
aji_send_raw(client, handshake);
|
|
|
|
|
ast_free(handshake);
|
|
|
|
|
handshake = NULL;
|
|
|
|
|
}
|
|
|
|
|
client->state = AJI_CONNECTING;
|
|
|
|
|
if (iks_recv(client->p, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
|
|
|
|
|
if(aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
|
|
|
|
|
client->state = AJI_CONNECTED;
|
|
|
|
|
else
|
|
|
|
|
ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
|
|
|
|
@ -782,7 +1040,7 @@ static int aji_register_approve_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_attrib(iq, "to", pak->from->full);
|
|
|
|
|
iks_insert_attrib(iq, "id", pak->id);
|
|
|
|
|
iks_insert_attrib(iq, "type", "result");
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
|
|
|
|
|
iks_insert_attrib(presence, "from", client->jid->full);
|
|
|
|
|
iks_insert_attrib(presence, "to", pak->from->partial);
|
|
|
|
@ -791,7 +1049,7 @@ static int aji_register_approve_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_attrib(presence, "type", "subscribe");
|
|
|
|
|
iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
|
|
|
|
|
iks_insert_node(presence, x);
|
|
|
|
|
iks_send(client->p, presence);
|
|
|
|
|
aji_send(client, presence);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
@ -841,7 +1099,7 @@ static int aji_register_query_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_insert_node(iq, error);
|
|
|
|
|
iks_insert_node(error, notacceptable);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -868,7 +1126,7 @@ static int aji_register_query_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_cdata(instructions, explain, 0);
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_insert_node(query, instructions);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -912,7 +1170,7 @@ static int aji_ditems_handler(void *data, ikspak *pak)
|
|
|
|
|
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_insert_node(query, item);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -941,7 +1199,7 @@ static int aji_ditems_handler(void *data, ikspak *pak)
|
|
|
|
|
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_insert_node(query, confirm);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -968,7 +1226,7 @@ static int aji_ditems_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_insert_node(query, feature);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -1029,7 +1287,7 @@ static int aji_client_info_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_node(query, ident);
|
|
|
|
|
iks_insert_node(query, google);
|
|
|
|
|
iks_insert_node(query, disco);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of Memory.\n");
|
|
|
|
|
if (iq)
|
|
|
|
@ -1116,7 +1374,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_node(query, version);
|
|
|
|
|
iks_insert_node(query, vcard);
|
|
|
|
|
iks_insert_node(query, search);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -1160,7 +1418,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_attrib(confirm, "jid", client->user);
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_insert_node(query, confirm);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -1187,7 +1445,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_insert_node(query, feature);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -1205,7 +1463,7 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Handles \verbatim <iq> \endverbatim tags.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param node iks
|
|
|
|
|
* \return void.
|
|
|
|
|
*/
|
|
|
|
@ -1216,7 +1474,7 @@ static void aji_handle_iq(struct aji_client *client, iks *node)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Handles presence packets.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param pak ikspak the node
|
|
|
|
|
*/
|
|
|
|
|
static void aji_handle_message(struct aji_client *client, ikspak *pak)
|
|
|
|
@ -1256,7 +1514,7 @@ static void aji_handle_message(struct aji_client *client, ikspak *pak)
|
|
|
|
|
}
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Check the presence info
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param pak ikspak
|
|
|
|
|
*/
|
|
|
|
|
static void aji_handle_presence(struct aji_client *client, ikspak *pak)
|
|
|
|
@ -1428,7 +1686,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
|
|
|
|
|
ast_aji_increment_mid(client->mid);
|
|
|
|
|
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
|
|
|
|
|
iks_insert_node(iq, query);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
@ -1474,7 +1732,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief handles subscription requests.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param pak ikspak iksemel packet.
|
|
|
|
|
* \return void.
|
|
|
|
|
*/
|
|
|
|
@ -1492,7 +1750,7 @@ static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
|
|
|
|
|
iks_insert_attrib(presence, "id", pak->id);
|
|
|
|
|
iks_insert_cdata(status, "Asterisk has approved subscription", 0);
|
|
|
|
|
iks_insert_node(presence, status);
|
|
|
|
|
iks_send(client->p, presence);
|
|
|
|
|
aji_send(client, presence);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to allocate nodes\n");
|
|
|
|
|
if (presence)
|
|
|
|
@ -1524,7 +1782,7 @@ static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief sends messages.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param address
|
|
|
|
|
* \param message
|
|
|
|
|
* \return 1.
|
|
|
|
@ -1537,7 +1795,7 @@ int ast_aji_send(struct aji_client *client, const char *address, const char *mes
|
|
|
|
|
message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
|
|
|
|
|
if (message_packet) {
|
|
|
|
|
iks_insert_attrib(message_packet, "from", client->jid->full);
|
|
|
|
|
res = iks_send(client->p, message_packet);
|
|
|
|
|
res = aji_send(client, message_packet);
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
}
|
|
|
|
@ -1550,7 +1808,7 @@ int ast_aji_send(struct aji_client *client, const char *address, const char *mes
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief create a chatroom.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param room name of room
|
|
|
|
|
* \param server name of server
|
|
|
|
|
* \param topic topic for the room.
|
|
|
|
@ -1566,7 +1824,7 @@ int ast_aji_create_chat(struct aji_client *client, char *room, char *server, cha
|
|
|
|
|
iks_insert_attrib(iq, "to", server);
|
|
|
|
|
iks_insert_attrib(iq, "id", client->mid);
|
|
|
|
|
ast_aji_increment_mid(client->mid);
|
|
|
|
|
iks_send(client->p, iq);
|
|
|
|
|
aji_send(client, iq);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
return res;
|
|
|
|
@ -1574,7 +1832,7 @@ int ast_aji_create_chat(struct aji_client *client, char *room, char *server, cha
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief join a chatroom.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param room room to join
|
|
|
|
|
* \return res.
|
|
|
|
|
*/
|
|
|
|
@ -1588,10 +1846,10 @@ int ast_aji_join_chat(struct aji_client *client, char *room)
|
|
|
|
|
iks_insert_cdata(priority, "0", 1);
|
|
|
|
|
iks_insert_attrib(presence, "to", room);
|
|
|
|
|
iks_insert_node(presence, priority);
|
|
|
|
|
res = iks_send(client->p, presence);
|
|
|
|
|
res = aji_send(client, presence);
|
|
|
|
|
iks_insert_cdata(priority, "5", 1);
|
|
|
|
|
iks_insert_attrib(presence, "to", room);
|
|
|
|
|
res = iks_send(client->p, presence);
|
|
|
|
|
res = aji_send(client, presence);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
if (presence)
|
|
|
|
@ -1603,7 +1861,7 @@ int ast_aji_join_chat(struct aji_client *client, char *room)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief invite to a chatroom.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param user
|
|
|
|
|
* \param room
|
|
|
|
|
* \param message
|
|
|
|
@ -1626,7 +1884,7 @@ int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char
|
|
|
|
|
iks_insert_attrib(namespace, "jid", room);
|
|
|
|
|
iks_insert_node(invite, body);
|
|
|
|
|
iks_insert_node(invite, namespace);
|
|
|
|
|
res = iks_send(client->p, invite);
|
|
|
|
|
res = aji_send(client, invite);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
if (body)
|
|
|
|
@ -1648,8 +1906,16 @@ static void *aji_recv_loop(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
|
|
|
|
|
int res = IKS_HOOK;
|
|
|
|
|
|
|
|
|
|
while(res != IKS_OK) {
|
|
|
|
|
if(option_verbose > 3)
|
|
|
|
|
ast_verbose("JABBER: Connecting.\n");
|
|
|
|
|
res = aji_reconnect(client);
|
|
|
|
|
sleep(4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
if (res != IKS_OK) {
|
|
|
|
|
if (res == IKS_NET_RWERR || client->timeout == 0) {
|
|
|
|
|
while(res != IKS_OK) {
|
|
|
|
|
ast_verb(4, "JABBER: reconnecting.\n");
|
|
|
|
|
res = aji_reconnect(client);
|
|
|
|
@ -1657,19 +1923,23 @@ static void *aji_recv_loop(void *data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = iks_recv(client->p, 1);
|
|
|
|
|
|
|
|
|
|
res = aji_recv(client, 1);
|
|
|
|
|
|
|
|
|
|
if (client->state == AJI_DISCONNECTING) {
|
|
|
|
|
ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
|
|
|
|
|
pthread_exit(NULL);
|
|
|
|
|
}
|
|
|
|
|
client->timeout--;
|
|
|
|
|
|
|
|
|
|
/* Decrease timeout if no data received */
|
|
|
|
|
if (res == IKS_NET_EXPIRED)
|
|
|
|
|
client->timeout--;
|
|
|
|
|
|
|
|
|
|
if (res == IKS_HOOK)
|
|
|
|
|
ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
|
|
|
|
|
else if (res == IKS_NET_TLSFAIL)
|
|
|
|
|
ast_log(LOG_WARNING, "JABBER: Failure in TLS.\n");
|
|
|
|
|
else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
|
|
|
|
|
res = iks_send_raw(client->p, " ");
|
|
|
|
|
res = aji_send_raw(client, " ");
|
|
|
|
|
if(res == IKS_OK)
|
|
|
|
|
client->timeout = 50;
|
|
|
|
|
else
|
|
|
|
@ -1727,7 +1997,7 @@ static int aji_register_transport(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_attrib(send, "id", client->mid);
|
|
|
|
|
ast_aji_increment_mid(client->mid);
|
|
|
|
|
iks_insert_attrib(send, "from", client->user);
|
|
|
|
|
res = iks_send(client->p, send);
|
|
|
|
|
res = aji_send(client, send);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
|
|
|
|
@ -1772,7 +2042,7 @@ static int aji_register_transport2(void *data, ikspak *pak)
|
|
|
|
|
iks_insert_node(regiq, regquery);
|
|
|
|
|
iks_insert_node(regquery, reguser);
|
|
|
|
|
iks_insert_node(regquery, regpass);
|
|
|
|
|
res = iks_send(client->p, regiq);
|
|
|
|
|
res = aji_send(client, regiq);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
if (regiq)
|
|
|
|
@ -1790,7 +2060,7 @@ static int aji_register_transport2(void *data, ikspak *pak)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief goes through roster and prunes users not needed in list, or adds them accordingly.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return void.
|
|
|
|
|
*/
|
|
|
|
|
static void aji_pruneregister(struct aji_client *client)
|
|
|
|
@ -1809,10 +2079,10 @@ static void aji_pruneregister(struct aji_client *client)
|
|
|
|
|
/* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
|
|
|
|
|
* be called at the same time */
|
|
|
|
|
if (ast_test_flag(iterator, AJI_AUTOPRUNE)) {
|
|
|
|
|
res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
|
|
|
|
|
res = aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
|
|
|
|
|
"GoodBye your status is no longer needed by Asterisk the Open Source PBX"
|
|
|
|
|
" so I am no longer subscribing to your presence.\n"));
|
|
|
|
|
res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
|
|
|
|
|
res = aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
|
|
|
|
|
"GoodBye you are no longer in the asterisk config file so I am removing"
|
|
|
|
|
" your access to my presence.\n"));
|
|
|
|
|
iks_insert_attrib(removeiq, "from", client->jid->full);
|
|
|
|
@ -1820,9 +2090,9 @@ static void aji_pruneregister(struct aji_client *client)
|
|
|
|
|
iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
|
|
|
|
|
iks_insert_attrib(removeitem, "jid", iterator->name);
|
|
|
|
|
iks_insert_attrib(removeitem, "subscription", "remove");
|
|
|
|
|
res = iks_send(client->p, removeiq);
|
|
|
|
|
res = aji_send(client, removeiq);
|
|
|
|
|
} else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
|
|
|
|
|
res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
|
|
|
|
|
res = aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
|
|
|
|
|
"Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
|
|
|
|
|
ast_clear_flag(iterator, AJI_AUTOREGISTER);
|
|
|
|
|
}
|
|
|
|
@ -1919,7 +2189,7 @@ static int aji_filter_roster(void *data, ikspak *pak)
|
|
|
|
|
}
|
|
|
|
|
/*!
|
|
|
|
|
* \brief reconnect to jabber server
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return res.
|
|
|
|
|
*/
|
|
|
|
|
static int aji_reconnect(struct aji_client *client)
|
|
|
|
@ -1940,7 +2210,7 @@ static int aji_reconnect(struct aji_client *client)
|
|
|
|
|
}
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Get the roster of jabber users
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return 1.
|
|
|
|
|
*/
|
|
|
|
|
static int aji_get_roster(struct aji_client *client)
|
|
|
|
@ -1950,7 +2220,7 @@ static int aji_get_roster(struct aji_client *client)
|
|
|
|
|
if(roster) {
|
|
|
|
|
iks_insert_attrib(roster, "id", "roster");
|
|
|
|
|
aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
|
|
|
|
|
iks_send(client->p, roster);
|
|
|
|
|
aji_send(client, roster);
|
|
|
|
|
}
|
|
|
|
|
if (roster)
|
|
|
|
|
iks_delete(roster);
|
|
|
|
@ -1986,7 +2256,7 @@ static int aji_client_connect(void *data, ikspak *pak)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief prepares client for connect.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return 1.
|
|
|
|
|
*/
|
|
|
|
|
static int aji_initialize(struct aji_client *client)
|
|
|
|
@ -2000,20 +2270,27 @@ static int aji_initialize(struct aji_client *client)
|
|
|
|
|
} else if (connected == IKS_NET_NODNS) {
|
|
|
|
|
ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, S_OR(client->serverhost, client->jid->server));
|
|
|
|
|
return IKS_HOOK;
|
|
|
|
|
} else /* if (!connected) phsultan: check if this is needed! */
|
|
|
|
|
iks_recv(client->p, 30);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IKS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief disconnect from jabber server.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return 1.
|
|
|
|
|
*/
|
|
|
|
|
int ast_aji_disconnect(struct aji_client *client)
|
|
|
|
|
{
|
|
|
|
|
if (client) {
|
|
|
|
|
ast_verb(4, "JABBER: Disconnecting\n");
|
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
|
if (client->stream_flags & SECURE) {
|
|
|
|
|
SSL_shutdown(client->ssl_session);
|
|
|
|
|
SSL_CTX_free(client->ssl_context);
|
|
|
|
|
SSL_free(client->ssl_session);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
iks_disconnect(client->p);
|
|
|
|
|
iks_parser_delete(client->p);
|
|
|
|
|
ASTOBJ_UNREF(client, aji_client_destroy);
|
|
|
|
@ -2024,7 +2301,7 @@ int ast_aji_disconnect(struct aji_client *client)
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief set presence of client.
|
|
|
|
|
* \param client aji_client
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \param to user send it to
|
|
|
|
|
* \param from user it came from
|
|
|
|
|
* \param level
|
|
|
|
@ -2052,7 +2329,7 @@ static void aji_set_presence(struct aji_client *client, char *to, char *from, in
|
|
|
|
|
iks_insert_attrib(cnode, "ext", "voice-v1");
|
|
|
|
|
iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
|
|
|
|
|
iks_insert_node(presence, cnode);
|
|
|
|
|
res = iks_send(client->p, presence);
|
|
|
|
|
res = aji_send(client, presence);
|
|
|
|
|
} else
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory.\n");
|
|
|
|
|
if (cnode)
|
|
|
|
@ -2422,7 +2699,9 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
|
|
|
|
|
ASTOBJ_UNREF(client, aji_client_destroy);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
|
|
|
|
|
|
|
|
|
|
ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
|
|
|
|
|
client->p = iks_stream_new(client->name_space, client, aji_act_hook);
|
|
|
|
|
if (!client->p) {
|
|
|
|
|
ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
|
|
|
|
|
return 0;
|
|
|
|
@ -2523,7 +2802,7 @@ static int aji_create_transport(char *label, struct aji_client *client)
|
|
|
|
|
/*!
|
|
|
|
|
* \brief creates buddy.
|
|
|
|
|
* \param label char.
|
|
|
|
|
* \param client aji_client buddy to dump it into.
|
|
|
|
|
* \param client the configured XMPP client we use to connect to a XMPP server
|
|
|
|
|
* \return 1 on success, 0 on failure.
|
|
|
|
|
*/
|
|
|
|
|
static int aji_create_buddy(char *label, struct aji_client *client)
|
|
|
|
@ -2695,16 +2974,6 @@ static int aji_reload(int reload)
|
|
|
|
|
static int unload_module(void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* Check if TLS is initialized. If that's the case, we can't unload this
|
|
|
|
|
module due to a bug in the iksemel library that will cause a crash or
|
|
|
|
|
a deadlock. We're trying to find a way to handle this, but in the meantime
|
|
|
|
|
we will simply refuse to die...
|
|
|
|
|
*/
|
|
|
|
|
if (tls_initialized) {
|
|
|
|
|
ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
|
|
|
|
|
return 1; /* You need a forced unload to get rid of this module */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
|
|
|
|
|
ast_unregister_application(app_ajisend);
|
|
|
|
|
ast_unregister_application(app_ajistatus);
|
|
|
|
@ -2713,7 +2982,7 @@ static int unload_module(void)
|
|
|
|
|
|
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
|
|
|
|
|
ASTOBJ_RDLOCK(iterator);
|
|
|
|
|
ast_debug(3, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
|
|
|
|
|
ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
|
|
|
|
|
iterator->state = AJI_DISCONNECTING;
|
|
|
|
|
ast_aji_disconnect(iterator);
|
|
|
|
|
pthread_join(iterator->thread, NULL);
|
|
|
|
|