A resource for interfacing Asterisk directly as a client or a component to a XMPP/Jabber compliant server. More...
#include "asterisk.h"#include <ctype.h>#include <iksemel.h>#include "asterisk/channel.h"#include "asterisk/jabber.h"#include "asterisk/file.h"#include "asterisk/config.h"#include "asterisk/callerid.h"#include "asterisk/lock.h"#include "asterisk/cli.h"#include "asterisk/app.h"#include "asterisk/pbx.h"#include "asterisk/md5.h"#include "asterisk/acl.h"#include "asterisk/utils.h"#include "asterisk/module.h"#include "asterisk/astobj.h"#include "asterisk/astdb.h"#include "asterisk/manager.h"#include "asterisk/event.h"#include "asterisk/devicestate.h"
Go to the source code of this file.
Defines | |
| #define | JABBER_CONFIG "jabber.conf" |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | acf_jabberreceive_read (struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) |
| static int | acf_jabberstatus_read (struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) |
| static int | aji_act_hook (void *data, int type, iks *node) |
| static iks * | aji_build_node_config (iks *pubsub, const char *node_type, const char *collection_name) |
| static iks * | aji_build_node_request (struct aji_client *client, const char *collection) |
| Build the a node request. | |
| static iks * | aji_build_publish_skeleton (struct aji_client *client, const char *node, const char *event_type) |
| Build the skeleton of a publish. | |
| static char * | aji_cli_create_collection (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| Method to expose PubSub collection node creation via CLI. | |
| static char * | aji_cli_create_leafnode (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| Method to expose PubSub leaf node creation via CLI. | |
| static char * | aji_cli_delete_pubsub_node (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| Method to expose PubSub node deletion via CLI. | |
| static char * | aji_cli_list_pubsub_nodes (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| Method to expose PubSub node list via CLI. | |
| static char * | aji_cli_purge_pubsub_nodes (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| Method to purge PubSub nodes via CLI. | |
| static int | aji_client_connect (void *data, ikspak *pak) |
| static int | aji_client_info_handler (void *data, ikspak *pak) |
| static void | aji_create_affiliations (struct aji_client *client, const char *node) |
| Add Owner affiliations for pubsub node. | |
| static int | aji_create_buddy (char *label, struct aji_client *client) |
| static int | aji_create_client (char *label, struct ast_variable *var, int debug) |
| static void | aji_create_pubsub_collection (struct aji_client *client, const char *collection_name) |
| Create a PubSub collection node. | |
| static void | aji_create_pubsub_leaf (struct aji_client *client, const char *collection_name, const char *leaf_name) |
| Create a PubSub leaf node. | |
| static iks * | aji_create_pubsub_node (struct aji_client *client, const char *node_type, const char *name, const char *collection_name) |
| Create a pubsub node. | |
| static int | aji_delete_node_list (void *data, ikspak *pak) |
| Delete pubsub item lists. | |
| static void | aji_delete_pubsub_node (struct aji_client *client, const char *node_name) |
| Delete a PubSub node. | |
| static void | aji_devstate_cb (const struct ast_event *ast_event, void *data) |
| Callback function for device state events. | |
| static int | aji_dinfo_handler (void *data, ikspak *pak) |
| static int | aji_ditems_handler (void *data, ikspak *pak) |
| static char * | aji_do_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | aji_do_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | aji_filter_roster (void *data, ikspak *pak) |
| static struct aji_resource * | aji_find_resource (struct aji_buddy *buddy, char *name) |
| static struct aji_version * | aji_find_version (char *node, char *version, ikspak *pak) |
| static int | aji_get_roster (struct aji_client *client) |
| static void | aji_handle_iq (struct aji_client *client, iks *node) |
| static void | aji_handle_message (struct aji_client *client, ikspak *pak) |
| static void | aji_handle_presence (struct aji_client *client, ikspak *pak) |
| static int | aji_handle_pubsub_error (void *data, ikspak *pak) |
| static int | aji_handle_pubsub_event (void *data, ikspak *pak) |
| Callback for handling PubSub events. | |
| static void | aji_handle_subscribe (struct aji_client *client, ikspak *pak) |
| static void | aji_init_event_distribution (struct aji_client *client) |
| Initialize collections for event distribution. | |
| static int | aji_initialize (struct aji_client *client) |
| static int | aji_io_recv (struct aji_client *client, char *buffer, size_t buf_len, int timeout) |
| static int | aji_is_secure (struct aji_client *client) |
| static int | aji_join_exec (struct ast_channel *chan, const char *data) |
| Application to join a chat room. | |
| static int | aji_leave_exec (struct ast_channel *chan, const char *data) |
| Application to leave a chat room. | |
| static int | aji_load_config (int reload) |
| static void | aji_log_hook (void *data, const char *xmpp, size_t size, int is_incoming) |
| static void | aji_message_destroy (struct aji_message *obj) |
| static void | aji_mwi_cb (const struct ast_event *ast_event, void *data) |
| Callback function for MWI events. | |
| static void | aji_pruneregister (struct aji_client *client) |
| static void | aji_publish_device_state (struct aji_client *client, const char *device, const char *device_state) |
| Publish device state to a PubSub node. | |
| static void | aji_publish_mwi (struct aji_client *client, const char *mailbox, const char *context, const char *oldmsgs, const char *newmsgs) |
| Publish MWI to a PubSub node. | |
| static iks * | aji_pubsub_iq_create (struct aji_client *client, const char *type) |
| Create an IQ packet. | |
| static void | aji_pubsub_purge_nodes (struct aji_client *client, const char *collection_name) |
| static void | aji_pubsub_subscribe (struct aji_client *client, const char *node) |
| Subscribe to a PubSub node. | |
| static int | aji_receive_node_list (void *data, ikspak *pak) |
| Receive pubsub item lists. | |
| static int | aji_reconnect (struct aji_client *client) |
| static int | aji_recv (struct aji_client *client, int timeout) |
| static void * | aji_recv_loop (void *data) |
| static int | aji_register_approve_handler (void *data, ikspak *pak) |
| static int | aji_register_query_handler (void *data, ikspak *pak) |
| static int | aji_reload (int reload) |
| static void | aji_request_pubsub_nodes (struct aji_client *client, const char *collection) |
| Request item list from pubsub. | |
| static int | aji_send_exec (struct ast_channel *chan, const char *data) |
| static int | aji_send_header (struct aji_client *client, const char *to) |
| static int | aji_send_raw (struct aji_client *client, const char *xmlstr) |
| static int | aji_send_raw_chat (struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message) |
| sends messages. | |
| static int | aji_sendgroup_exec (struct ast_channel *chan, const char *data) |
| Application to send a message to a groupchat. | |
| static int | aji_set_group_presence (struct aji_client *client, char *room, int level, char *nick, char *desc) |
| static void | aji_set_presence (struct aji_client *client, char *to, char *from, int level, char *desc) |
| static char * | aji_show_buddies (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | aji_show_clients (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | aji_start_sasl (struct aji_client *client, enum ikssasltype type, char *username, char *pass) |
| static int | aji_start_tls (struct aji_client *client) |
| static int | aji_status_exec (struct ast_channel *chan, const char *data) |
| static char * | aji_test (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | aji_tls_handshake (struct aji_client *client) |
| void | ast_aji_buddy_destroy (struct aji_buddy *obj) |
| void | ast_aji_client_destroy (struct aji_client *obj) |
| int | ast_aji_create_chat (struct aji_client *client, char *room, char *server, char *topic) |
| create a chatroom. | |
| int | ast_aji_disconnect (struct aji_client *client) |
| disconnect from jabber server. | |
| struct aji_client * | ast_aji_get_client (const char *name) |
| grab a aji_client structure by label name or JID. Bumps the refcount. (without the resource string) | |
| struct aji_client_container * | ast_aji_get_clients (void) |
| void | ast_aji_increment_mid (char *mid) |
| increments the mid field for messages and other events. | |
| int | ast_aji_invite_chat (struct aji_client *client, char *user, char *room, char *message) |
| invite to a chatroom. | |
| int | ast_aji_join_chat (struct aji_client *client, char *room, char *nick) |
| join a chatroom. | |
| int | ast_aji_leave_chat (struct aji_client *client, char *room, char *nick) |
| leave a chatroom. | |
| int | ast_aji_send (struct aji_client *client, iks *x) |
| Wraps raw sending. | |
| int | ast_aji_send_chat (struct aji_client *client, const char *address, const char *message) |
| sends messages. | |
| int | ast_aji_send_groupchat (struct aji_client *client, const char *nick, const char *address, const char *message) |
| sends message to a groupchat Prior to sending messages to a groupchat, one must be connected to it. | |
| static int | delete_old_messages (struct aji_client *client, char *from) |
| static int | delete_old_messages_all (struct aji_client *client) |
| static int | gtalk_yuck (iks *node) |
| static iks * | jabber_make_auth (iksid *id, const char *pass, const char *sid) |
| static int | load_module (void) |
| static int | manager_jabber_send (struct mansession *s, const struct message *m) |
| static int | reload (void) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "AJI - Asterisk Jabber Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } |
| static struct ast_cli_entry | aji_cli [] |
| static char * | app_ajijoin = "JabberJoin" |
| static char * | app_ajileave = "JabberLeave" |
| static char * | app_ajisend = "JabberSend" |
| static char * | app_ajisendgroup = "JabberSendGroup" |
| static char * | app_ajistatus = "JabberStatus" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct aji_capabilities * | capabilities = NULL |
| static struct aji_client_container | clients |
| static struct ast_event_sub * | device_state_sub = NULL |
| static struct ast_flags | globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT } |
| Global flags, initialized to default values. | |
| static struct ast_custom_function | jabberreceive_function |
| static struct ast_custom_function | jabberstatus_function |
| static ast_cond_t | message_received_condition |
| static ast_mutex_t | messagelock |
| static struct ast_event_sub * | mwi_sub = NULL |
| static struct ast_flags | pubsubflags = { 0 } |
| PubSub flags, initialized to default values. | |
A resource for interfacing Asterisk directly as a client or a component to a XMPP/Jabber compliant server.
References:
If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
Dialplan applications need RETURN variable, like JABBERSENDSTATUS
Definition in file res_jabber.c.
| #define JABBER_CONFIG "jabber.conf" |
Definition at line 285 of file res_jabber.c.
Referenced by aji_load_config().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 4784 of file res_jabber.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 4784 of file res_jabber.c.
| static int acf_jabberreceive_read | ( | struct ast_channel * | chan, |
| const char * | name, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | buflen | ||
| ) | [static] |
Definition at line 769 of file res_jabber.c.
References AJI_MAX_JIDLEN, aji_message_destroy(), args, aji_message::arrived, ast_aji_client_destroy(), ast_aji_get_client(), AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_cond_timedwait, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvdiff_sec(), ast_tvnow(), ASTOBJ_UNREF, aji_message::from, LOG_NOTICE, LOG_WARNING, aji_message::message, aji_client::message_timeout, aji_client::messages, ast_channel::name, and parse().
{
char *aux = NULL, *parse = NULL;
int timeout;
int jidlen, resourcelen;
struct timeval start;
long diff = 0;
struct aji_client *client = NULL;
int found = 0;
struct aji_message *tmp = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(account);
AST_APP_ARG(jid);
AST_APP_ARG(timeout);
);
AST_DECLARE_APP_ARGS(jid,
AST_APP_ARG(screenname);
AST_APP_ARG(resource);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.argc < 2 || args.argc > 3) {
ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
return -1;
}
parse = ast_strdupa(args.jid);
AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
return -1;
}
if (ast_strlen_zero(args.timeout)) {
timeout = 20;
} else {
sscanf(args.timeout, "%d", &timeout);
if (timeout <= 0) {
ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
return -1;
}
}
jidlen = strlen(jid.screenname);
resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
client = ast_aji_get_client(args.account);
if (!client) {
ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
return -1;
}
ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
start = ast_tvnow();
if (ast_autoservice_start(chan) < 0) {
ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", chan->name);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return -1;
}
/* search the messages list, grab the first message that matches with
* the from JID we're expecting, and remove it from the messages list */
while (diff < timeout) {
struct timespec ts = { 0, };
struct timeval wait;
int res;
wait = ast_tvadd(start, ast_tv(timeout, 0));
ts.tv_sec = wait.tv_sec;
ts.tv_nsec = wait.tv_usec * 1000;
/* wait up to timeout seconds for an incoming message */
ast_mutex_lock(&messagelock);
res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
ast_mutex_unlock(&messagelock);
if (res == ETIMEDOUT) {
ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
break;
}
AST_LIST_LOCK(&client->messages);
AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
if (jid.argc == 1) {
/* no resource provided, compare bare JIDs */
if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
continue;
}
} else {
/* resource appended, compare bare JIDs and resources */
char *resource = strchr(tmp->from, '/');
if (!resource || strlen(resource) == 0) {
ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from);
if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
continue;
}
} else {
resource ++;
if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
continue;
}
}
}
/* check if the message is not too old */
if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
ast_debug(3, "Found old message from %s, deleting it\n", tmp->from);
AST_LIST_REMOVE_CURRENT(list);
aji_message_destroy(tmp);
continue;
}
found = 1;
aux = ast_strdupa(tmp->message);
AST_LIST_REMOVE_CURRENT(list);
aji_message_destroy(tmp);
break;
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&client->messages);
if (found) {
break;
}
/* check timeout */
diff = ast_tvdiff_ms(ast_tvnow(), start);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
if (ast_autoservice_stop(chan) < 0) {
ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", chan->name);
}
/* return if we timed out */
if (!found) {
ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
return -1;
}
ast_copy_string(buf, aux, buflen);
return 0;
}
| static int acf_jabberstatus_read | ( | struct ast_channel * | chan, |
| const char * | name, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | buflen | ||
| ) | [static] |
Definition at line 698 of file res_jabber.c.
References aji_find_resource(), args, ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_get_client(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_resource::resource, aji_buddy::resources, and aji_resource::status.
{
struct aji_client *client = NULL;
struct aji_buddy *buddy = NULL;
struct aji_resource *r = NULL;
int stat = 7;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(jid);
);
AST_DECLARE_APP_ARGS(jid,
AST_APP_ARG(screenname);
AST_APP_ARG(resource);
);
if (!data) {
ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
return 0;
}
AST_STANDARD_APP_ARGS(args, data);
if (args.argc != 2) {
ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
return -1;
}
AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
if (jid.argc < 1 || jid.argc > 2) {
ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
return -1;
}
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
if (!buddy) {
ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return -1;
}
r = aji_find_resource(buddy, jid.resource);
if (!r && buddy->resources) {
r = buddy->resources;
}
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
if (!r) {
ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
} else {
stat = r->status;
}
snprintf(buf, buflen, "%d", stat);
return 0;
}
| static int aji_act_hook | ( | void * | data, |
| int | type, | ||
| iks * | node | ||
| ) | [static] |
Definition at line 1572 of file res_jabber.c.
References aji_client_connect(), AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, AJI_DISCONNECTING, aji_handle_iq(), aji_handle_message(), aji_handle_presence(), aji_handle_subscribe(), aji_is_secure(), AJI_MAX_ATTRLEN, aji_recv(), aji_send_header(), aji_send_raw(), aji_start_sasl(), aji_start_tls(), aji_tls_handshake(), asprintf(), ast_aji_client_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_debug, ast_free, ast_log(), ast_sha1_hash(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::authorized, aji_client::component, aji_client::f, jabber_make_auth(), aji_client::jid, LOG_ERROR, LOG_WARNING, aji_client::mid, aji_client::password, secret, aji_client::state, aji_client::stream_flags, TRY_SECURE, aji_client::usesasl, and aji_client::usetls.
Referenced by aji_create_client().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
ikspak *pak = NULL;
iks *auth = NULL;
int features = 0;
if (!node) {
ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
}
if (client->state == AJI_DISCONNECTING) {
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
}
pak = iks_packet(node);
/* work around iksemel's impossibility to recognize node names
* containing a semicolon. Set the namespace of the corresponding
* node accordingly. */
if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
char *node_ns = NULL;
char attr[AJI_MAX_ATTRLEN];
char *node_name = iks_name(iks_child(node));
char *aux = strchr(node_name, ':') + 1;
snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
node_ns = iks_find_attrib(iks_child(node), attr);
if (node_ns) {
pak->ns = node_ns;
pak->query = iks_child(node);
}
}
if (!client->component) { /*client */
switch (type) {
case IKS_NODE_START:
if (client->usetls && !aji_is_secure(client)) {
#ifndef HAVE_OPENSSL
ast_log(LOG_ERROR, "TLS connection cannot be established. Please install OpenSSL and its development libraries on this system, or disable the TLS option in your configuration file\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
#else
if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
ast_log(LOG_ERROR, "Could not start TLS\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
}
#endif
break;
}
if (!client->usesasl) {
iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
if (auth) {
iks_insert_attrib(auth, "id", client->mid);
iks_insert_attrib(auth, "to", client->jid->server);
ast_aji_increment_mid(client->mid);
ast_aji_send(client, auth);
iks_delete(auth);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
}
break;
case IKS_NODE_NORMAL:
#ifdef HAVE_OPENSSL
if (client->stream_flags & TRY_SECURE) {
if (!strcmp("proceed", iks_name(node))) {
return aji_tls_handshake(client);
}
}
#endif
if (!strcmp("stream:features", iks_name(node))) {
features = iks_stream_features(node);
if (client->usesasl) {
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);
auth = iks_make_resource_bind(client->jid);
if (auth) {
iks_insert_attrib(auth, "id", client->mid);
ast_aji_increment_mid(client->mid);
ast_aji_send(client, auth);
iks_delete(auth);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
break;
}
}
if (features & IKS_STREAM_SESSION) {
iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
auth = iks_make_session();
if (auth) {
iks_insert_attrib(auth, "id", "auth");
ast_aji_increment_mid(client->mid);
ast_aji_send(client, auth);
iks_delete(auth);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
}
} else {
int ret;
if (!client->jid->user) {
ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
break;
}
ret = aji_start_sasl(client, features, client->jid->user, client->password);
if (ret != IKS_OK) {
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
}
break;
}
}
} else if (!strcmp("failure", iks_name(node))) {
ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
} else if (!strcmp("success", iks_name(node))) {
client->authorized = 1;
aji_send_header(client, client->jid->server);
}
break;
case IKS_NODE_ERROR:
ast_log(LOG_ERROR, "JABBER: Node Error\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
break;
case IKS_NODE_STOP:
ast_log(LOG_WARNING, "JABBER: Disconnected\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
break;
}
} else if (client->state != AJI_CONNECTED && client->component) {
switch (type) {
case IKS_NODE_START:
if (client->state == AJI_DISCONNECTED) {
char secret[160], shasum[320], *handshake;
sprintf(secret, "%s%s", pak->id, client->password);
ast_sha1_hash(shasum, secret);
handshake = NULL;
if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
aji_send_raw(client, handshake);
ast_free(handshake);
handshake = NULL;
}
client->state = AJI_CONNECTING;
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");
break;
}
break;
case IKS_NODE_NORMAL:
break;
case IKS_NODE_ERROR:
ast_log(LOG_ERROR, "JABBER: Node Error\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
case IKS_NODE_STOP:
ast_log(LOG_WARNING, "JABBER: Disconnected\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_HOOK;
}
}
switch (pak->type) {
case IKS_PAK_NONE:
ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
break;
case IKS_PAK_MESSAGE:
aji_handle_message(client, pak);
ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
break;
case IKS_PAK_PRESENCE:
aji_handle_presence(client, pak);
ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
break;
case IKS_PAK_S10N:
aji_handle_subscribe(client, pak);
ast_debug(1, "JABBER: Handling paktype S10N\n");
break;
case IKS_PAK_IQ:
ast_debug(1, "JABBER: Handling paktype IQ\n");
aji_handle_iq(client, node);
break;
default:
ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
break;
}
iks_filter_packet(client->f, pak);
if (node)
iks_delete(node);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_OK;
}
| static iks * aji_build_node_config | ( | iks * | pubsub, |
| const char * | node_type, | ||
| const char * | collection_name | ||
| ) | [static] |
Definition at line 3812 of file res_jabber.c.
Referenced by aji_create_pubsub_node().
{
iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
*field_deliver_payload, *field_persist_items, *field_access_model,
*field_pubsub_collection;
configure = iks_insert(pubsub, "configure");
x = iks_insert(configure, "x");
iks_insert_attrib(x, "xmlns", "jabber:x:data");
iks_insert_attrib(x, "type", "submit");
field_owner = iks_insert(x, "field");
iks_insert_attrib(field_owner, "var", "FORM_TYPE");
iks_insert_attrib(field_owner, "type", "hidden");
iks_insert_cdata(iks_insert(field_owner, "value"),
"http://jabber.org/protocol/pubsub#owner", 39);
if (node_type) {
field_node_type = iks_insert(x, "field");
iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
}
field_node_config = iks_insert(x, "field");
iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
iks_insert_attrib(field_node_config, "type", "hidden");
iks_insert_cdata(iks_insert(field_node_config, "value"),
"http://jabber.org/protocol/pubsub#node_config", 45);
field_deliver_payload = iks_insert(x, "field");
iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
field_persist_items = iks_insert(x, "field");
iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
field_access_model = iks_insert(x, "field");
iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
if (node_type && !strcasecmp(node_type, "leaf")) {
field_pubsub_collection = iks_insert(x, "field");
iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
strlen(collection_name));
}
return configure;
}
| static iks * aji_build_node_request | ( | struct aji_client * | client, |
| const char * | collection | ||
| ) | [static] |
Build the a node request.
| client | the configured XMPP client we use to connect to a XMPP server |
| collection | name of the collection for request |
Definition at line 3542 of file res_jabber.c.
References aji_pubsub_iq_create().
Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().
{
iks *request = aji_pubsub_iq_create(client, "get");
iks *query;
query = iks_insert(request, "query");
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
if (collection) {
iks_insert_attrib(query, "node", collection);
}
return request;
}
| static iks * aji_build_publish_skeleton | ( | struct aji_client * | client, |
| const char * | node, | ||
| const char * | event_type | ||
| ) | [static] |
Build the skeleton of a publish.
| client | the configured XMPP client we use to connect to a XMPP server |
| node | Name of the node that will be published to |
| event_type |
Definition at line 3370 of file res_jabber.c.
References aji_pubsub_iq_create(), AJI_XEP0248, and ast_test_flag.
Referenced by aji_publish_device_state(), and aji_publish_mwi().
{
iks *request = aji_pubsub_iq_create(client, "set");
iks *pubsub, *publish, *item;
pubsub = iks_insert(request, "pubsub");
iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
publish = iks_insert(pubsub, "publish");
if (ast_test_flag(&globalflags, AJI_XEP0248)) {
iks_insert_attrib(publish, "node", node);
} else {
iks_insert_attrib(publish, "node", event_type);
}
item = iks_insert(publish, "item");
iks_insert_attrib(item, "id", node);
return item;
}
| static char * aji_cli_create_collection | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Method to expose PubSub collection node creation via CLI.
Definition at line 3860 of file res_jabber.c.
References aji_create_pubsub_collection(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.
{
struct aji_client *client;
const char *name;
const char *collection_name;
switch (cmd) {
case CLI_INIT:
e->command = "jabber create collection";
e->usage =
"Usage: jabber create collection <connection> <collection>\n"
" Creates a PubSub collection node using the account\n"
" as configured in jabber.conf.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 5) {
return CLI_SHOWUSAGE;
}
name = a->argv[3];
collection_name = a->argv[4];
if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
ast_cli(a->fd, "Unable to find client '%s'!\n", name);
return CLI_FAILURE;
}
ast_cli(a->fd, "Creating test PubSub node collection.\n");
aji_create_pubsub_collection(client, collection_name);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return CLI_SUCCESS;
}
| static char * aji_cli_create_leafnode | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Method to expose PubSub leaf node creation via CLI.
Definition at line 3899 of file res_jabber.c.
References aji_create_pubsub_leaf(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.
{
struct aji_client *client;
const char *name;
const char *collection_name;
const char *leaf_name;
switch (cmd) {
case CLI_INIT:
e->command = "jabber create leaf";
e->usage =
"Usage: jabber create leaf <connection> <collection> <leaf>\n"
" Creates a PubSub leaf node using the account\n"
" as configured in jabber.conf.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 6) {
return CLI_SHOWUSAGE;
}
name = a->argv[3];
collection_name = a->argv[4];
leaf_name = a->argv[5];
if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
ast_cli(a->fd, "Unable to find client '%s'!\n", name);
return CLI_FAILURE;
}
ast_cli(a->fd, "Creating test PubSub node collection.\n");
aji_create_pubsub_leaf(client, collection_name, leaf_name);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return CLI_SUCCESS;
}
| static char * aji_cli_delete_pubsub_node | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Method to expose PubSub node deletion via CLI.
| e | pointer to ast_cli_entry structure |
| cmd | |
| a | pointer to ast_cli_args structure |
Definition at line 3713 of file res_jabber.c.
References aji_delete_pubsub_node(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.
{
struct aji_client *client;
const char *name;
switch (cmd) {
case CLI_INIT:
e->command = "jabber delete node";
e->usage =
"Usage: jabber delete node <connection> <node>\n"
" Deletes a node on PubSub server\n"
" as configured in jabber.conf.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 5) {
return CLI_SHOWUSAGE;
}
name = a->argv[3];
if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
ast_cli(a->fd, "Unable to find client '%s'!\n", name);
return CLI_FAILURE;
}
aji_delete_pubsub_node(client, a->argv[4]);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return CLI_SUCCESS;
}
| static char * aji_cli_list_pubsub_nodes | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Method to expose PubSub node list via CLI.
| e | pointer to ast_cli_entry structure |
| cmd | |
| a | pointer to ast_cli_args structure |
Definition at line 3588 of file res_jabber.c.
References aji_request_pubsub_nodes(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.
{
struct aji_client *client;
const char *name = NULL;
const char *collection = NULL;
switch (cmd) {
case CLI_INIT:
e->command = "jabber list nodes";
e->usage =
"Usage: jabber list nodes <connection> [collection]\n"
" Lists the user's nodes on the respective connection\n"
" ([connection] as configured in jabber.conf.)\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc > 5 || a->argc < 4) {
return CLI_SHOWUSAGE;
} else if (a->argc == 4 || a->argc == 5) {
name = a->argv[3];
}
if (a->argc == 5) {
collection = a->argv[4];
}
if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
ast_cli(a->fd, "Unable to find client '%s'!\n", name);
return CLI_FAILURE;
}
ast_cli(a->fd, "Listing pubsub nodes.\n");
aji_request_pubsub_nodes(client, collection);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return CLI_SUCCESS;
}
| static char * aji_cli_purge_pubsub_nodes | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Method to purge PubSub nodes via CLI.
| e | pointer to ast_cli_entry structure |
| cmd | |
| a | pointer to ast_cli_args structure |
Definition at line 3633 of file res_jabber.c.
References aji_delete_pubsub_node(), aji_pubsub_purge_nodes(), AJI_XEP0248, ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ast_test_flag, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.
{
struct aji_client *client;
const char *name;
switch (cmd) {
case CLI_INIT:
e->command = "jabber purge nodes";
e->usage =
"Usage: jabber purge nodes <connection> <node>\n"
" Purges nodes on PubSub server\n"
" as configured in jabber.conf.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 5) {
return CLI_SHOWUSAGE;
}
name = a->argv[3];
if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
ast_cli(a->fd, "Unable to find client '%s'!\n", name);
return CLI_FAILURE;
}
if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
aji_pubsub_purge_nodes(client, a->argv[4]);
} else {
aji_delete_pubsub_node(client, a->argv[4]);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return CLI_SUCCESS;
}
| static int aji_client_connect | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 3079 of file res_jabber.c.
References AJI_CONNECTING, AJI_DISCONNECTED, aji_filter_roster(), aji_get_roster(), aji_init_event_distribution(), ast_aji_client_destroy(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::component, aji_client::distribute_events, aji_client::f, aji_client::jid, LOG_ERROR, aji_client::stack, and aji_client::state.
Referenced by aji_act_hook().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
int res = IKS_FILTER_PASS;
if (client) {
if (client->state == AJI_DISCONNECTED) {
iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
client->state = AJI_CONNECTING;
client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
if (!client->component) { /*client*/
aji_get_roster(client);
}
if (client->distribute_events) {
aji_init_event_distribution(client);
}
iks_filter_remove_hook(client->f, aji_client_connect);
/* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */
res = IKS_FILTER_EAT;
}
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return res;
}
| static int aji_client_info_handler | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 2005 of file res_jabber.c.
References aji_find_resource(), ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, aji_resource::cap, aji_client::jid, aji_version::jingle, LOG_ERROR, LOG_NOTICE, and aji_resource::resource.
Referenced by aji_create_client().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
struct aji_resource *resource = NULL;
struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
resource = aji_find_resource(buddy, pak->from->resource);
if (pak->subtype == IKS_TYPE_RESULT) {
if (!resource) {
ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
resource->cap->jingle = 1;
} else {
resource->cap->jingle = 0;
}
} else if (pak->subtype == IKS_TYPE_GET) {
iks *iq, *disco, *ident, *google, *query;
iq = iks_new("iq");
query = iks_new("query");
ident = iks_new("identity");
disco = iks_new("feature");
google = iks_new("feature");
if (iq && ident && disco && google) {
iks_insert_attrib(iq, "from", client->jid->full);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
iks_insert_attrib(ident, "category", "client");
iks_insert_attrib(ident, "type", "pc");
iks_insert_attrib(ident, "name", "asterisk");
iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
iks_insert_node(iq, query);
iks_insert_node(query, ident);
iks_insert_node(query, google);
iks_insert_node(query, disco);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of Memory.\n");
}
iks_delete(iq);
iks_delete(query);
iks_delete(ident);
iks_delete(google);
iks_delete(disco);
} else if (pak->subtype == IKS_TYPE_ERROR) {
ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
}
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static void aji_create_affiliations | ( | struct aji_client * | client, |
| const char * | node | ||
| ) | [static] |
Add Owner affiliations for pubsub node.
| client | the configured XMPP client we use to connect to a XMPP server |
| node | the name of the node to which to add affiliations |
Definition at line 3306 of file res_jabber.c.
References aji_pubsub_iq_create(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, and aji_client::buddies.
Referenced by aji_create_pubsub_node().
{
iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
iks *pubsub, *affiliations, *affiliate;
pubsub = iks_insert(modify_affiliates, "pubsub");
iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
affiliations = iks_insert(pubsub, "affiliations");
iks_insert_attrib(affiliations, "node", node);
ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
ASTOBJ_RDLOCK(iterator);
affiliate = iks_insert(affiliations, "affiliation");
iks_insert_attrib(affiliate, "jid", iterator->name);
iks_insert_attrib(affiliate, "affiliation", "owner");
ASTOBJ_UNLOCK(iterator);
});
ast_aji_send(client, modify_affiliates);
iks_delete(modify_affiliates);
}
| static int aji_create_buddy | ( | char * | label, |
| struct aji_client * | client | ||
| ) | [static] |
load config file.
Definition at line 4510 of file res_jabber.c.
References ast_aji_buddy_destroy(), ast_calloc, ast_copy_string(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_LINK, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::buddies, LOG_WARNING, and aji_buddy::name.
Referenced by aji_create_client(), aji_handle_presence(), and aji_handle_subscribe().
| static int aji_create_client | ( | char * | label, |
| struct ast_variable * | var, | ||
| int | debug | ||
| ) | [static] |
Definition at line 4255 of file res_jabber.c.
References aji_act_hook(), AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_client_info_handler(), aji_create_buddy(), aji_dinfo_handler(), AJI_DISCONNECTED, aji_ditems_handler(), aji_log_hook(), AJI_PUBSUB, aji_register_approve_handler(), aji_register_query_handler(), asprintf(), ast_aji_client_destroy(), ast_calloc, ast_clear_flag, ast_copy_flags, ast_copy_string(), ast_false(), AST_FLAGS_ALL, ast_free, AST_LIST_HEAD_INIT, ast_log(), ast_set2_flag, ast_set_flag, ast_test_flag, ast_true(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_INIT, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::authorized, aji_client::buddies, clients, aji_client::component, aji_client::debug, debug, aji_client::distribute_events, aji_client::f, aji_client::flags, aji_client::forcessl, aji_client::jid, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::message_timeout, aji_client::messages, aji_client::mid, ast_variable::name, aji_client::name, aji_client::name_space, ast_variable::next, aji_client::p, aji_client::password, aji_client::port, aji_client::priority, aji_client::pubsub_node, aji_client::serverhost, aji_client::stack, aji_client::state, aji_client::status, aji_client::statusmessage, aji_client::timeout, aji_client::user, aji_client::usesasl, aji_client::usetls, and ast_variable::value.
Referenced by aji_load_config().
{
char *resource;
struct aji_client *client = NULL;
int flag = 0;
client = ASTOBJ_CONTAINER_FIND(&clients, label);
if (!client) {
flag = 1;
client = ast_calloc(1, sizeof(*client));
if (!client) {
ast_log(LOG_ERROR, "Out of memory!\n");
return 0;
}
ASTOBJ_INIT(client);
ASTOBJ_WRLOCK(client);
ASTOBJ_CONTAINER_INIT(&client->buddies);
} else {
ASTOBJ_WRLOCK(client);
ASTOBJ_UNMARK(client);
}
ASTOBJ_CONTAINER_MARKALL(&client->buddies);
ast_copy_string(client->name, label, sizeof(client->name));
ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
/* Set default values for the client object */
client->debug = debug;
ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
client->port = 5222;
client->usetls = 1;
client->usesasl = 1;
client->forcessl = 0;
client->keepalive = 1;
client->timeout = 50;
client->message_timeout = 5;
client->distribute_events = 0;
AST_LIST_HEAD_INIT(&client->messages);
client->component = 0;
ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
client->priority = 0;
client->status = IKS_SHOW_AVAILABLE;
if (flag) {
client->authorized = 0;
client->state = AJI_DISCONNECTED;
}
while (var) {
if (!strcasecmp(var->name, "username")) {
ast_copy_string(client->user, var->value, sizeof(client->user));
} else if (!strcasecmp(var->name, "serverhost")) {
ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
} else if (!strcasecmp(var->name, "secret")) {
ast_copy_string(client->password, var->value, sizeof(client->password));
} else if (!strcasecmp(var->name, "statusmessage")) {
ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
} else if (!strcasecmp(var->name, "port")) {
client->port = atoi(var->value);
} else if (!strcasecmp(var->name, "timeout")) {
client->message_timeout = atoi(var->value);
} else if (!strcasecmp(var->name, "debug")) {
client->debug = (ast_false(var->value)) ? 0 : 1;
} else if (!strcasecmp(var->name, "type")) {
if (!strcasecmp(var->value, "component")) {
client->component = 1;
if (client->distribute_events) {
ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n");
client->distribute_events = 0;
}
}
} else if (!strcasecmp(var->name, "distribute_events")) {
if (ast_true(var->value)) {
if (client->component) {
ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n");
} else {
if (ast_test_flag(&pubsubflags, AJI_PUBSUB)) {
ast_log(LOG_ERROR, "Only one connection can be configured for distributed events.\n");
} else {
ast_set_flag(&pubsubflags, AJI_PUBSUB);
client->distribute_events = 1;
}
}
}
} else if (!strcasecmp(var->name, "pubsub_node")) {
ast_copy_string(client->pubsub_node, var->value, sizeof(client->pubsub_node));
} else if (!strcasecmp(var->name, "usetls")) {
client->usetls = (ast_false(var->value)) ? 0 : 1;
} else if (!strcasecmp(var->name, "usesasl")) {
client->usesasl = (ast_false(var->value)) ? 0 : 1;
} else if (!strcasecmp(var->name, "forceoldssl")) {
client->forcessl = (ast_false(var->value)) ? 0 : 1;
} else if (!strcasecmp(var->name, "keepalive")) {
client->keepalive = (ast_false(var->value)) ? 0 : 1;
} else if (!strcasecmp(var->name, "autoprune")) {
ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
} else if (!strcasecmp(var->name, "autoregister")) {
ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
} else if (!strcasecmp(var->name, "auth_policy")) {
if (!strcasecmp(var->value, "accept")) {
ast_set_flag(&client->flags, AJI_AUTOACCEPT);
} else {
ast_clear_flag(&client->flags, AJI_AUTOACCEPT);
}
} else if (!strcasecmp(var->name, "buddy")) {
aji_create_buddy((char *)var->value, client);
} else if (!strcasecmp(var->name, "priority")) {
client->priority = atoi(var->value);
} else if (!strcasecmp(var->name, "status")) {
if (!strcasecmp(var->value, "unavailable")) {
client->status = IKS_SHOW_UNAVAILABLE;
} else if (!strcasecmp(var->value, "available")
|| !strcasecmp(var->value, "online")) {
client->status = IKS_SHOW_AVAILABLE;
} else if (!strcasecmp(var->value, "chat")
|| !strcasecmp(var->value, "chatty")) {
client->status = IKS_SHOW_CHAT;
} else if (!strcasecmp(var->value, "away")) {
client->status = IKS_SHOW_AWAY;
} else if (!strcasecmp(var->value, "xa")
|| !strcasecmp(var->value, "xaway")) {
client->status = IKS_SHOW_XA;
} else if (!strcasecmp(var->value, "dnd")) {
client->status = IKS_SHOW_DND;
} else if (!strcasecmp(var->value, "invisible")) {
#ifdef IKS_SHOW_INVISIBLE
client->status = IKS_SHOW_INVISIBLE;
#else
ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
client->status = IKS_SHOW_DND;
#endif
} else {
ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
}
}
/* no transport support in this version */
/* else if (!strcasecmp(var->name, "transport"))
aji_create_transport(var->value, client);
*/
var = var->next;
}
if (!flag) {
ASTOBJ_UNLOCK(client);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return 1;
}
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;
}
client->stack = iks_stack_new(8192, 8192);
if (!client->stack) {
ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
return 0;
}
client->f = iks_filter_new();
if (!client->f) {
ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
return 0;
}
if (!strchr(client->user, '/') && !client->component) { /*client */
resource = NULL;
if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
client->jid = iks_id_new(client->stack, resource);
ast_free(resource);
}
} else {
client->jid = iks_id_new(client->stack, client->user);
}
if (client->component) {
iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
} else {
iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
}
iks_set_log_hook(client->p, aji_log_hook);
ASTOBJ_UNLOCK(client);
ASTOBJ_CONTAINER_LINK(&clients, client);
return 1;
}
| static void aji_create_pubsub_collection | ( | struct aji_client * | client, |
| const char * | collection_name | ||
| ) | [static] |
Create a PubSub collection node.
| client | the configured XMPP client we use to connect to a XMPP server |
| collection_name | The name to use for this collection |
Definition at line 3768 of file res_jabber.c.
References aji_create_pubsub_node().
Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().
{
aji_create_pubsub_node(client, "collection", collection_name, NULL);
}
| static void aji_create_pubsub_leaf | ( | struct aji_client * | client, |
| const char * | collection_name, | ||
| const char * | leaf_name | ||
| ) | [static] |
Create a PubSub leaf node.
| client | the configured XMPP client we use to connect to a XMPP server |
| leaf_name | The name to use for this collection |
Definition at line 3781 of file res_jabber.c.
References aji_create_pubsub_node().
Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().
{
aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
}
| static iks * aji_create_pubsub_node | ( | struct aji_client * | client, |
| const char * | node_type, | ||
| const char * | name, | ||
| const char * | collection_name | ||
| ) | [static] |
Create a pubsub node.
| client | the configured XMPP client we use to connect to a XMPP server |
| node_type | the type of node to create |
| name | the name of the node to create |
Definition at line 3794 of file res_jabber.c.
References aji_build_node_config(), aji_create_affiliations(), aji_pubsub_iq_create(), and ast_aji_send().
Referenced by aji_create_pubsub_collection(), aji_create_pubsub_leaf(), aji_handle_pubsub_error(), and aji_publish_device_state().
{
iks *node = aji_pubsub_iq_create(client, "set");
iks *pubsub, *create;
pubsub = iks_insert(node, "pubsub");
iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
create = iks_insert(pubsub, "create");
iks_insert_attrib(create, "node", name);
aji_build_node_config(pubsub, node_type, collection_name);
ast_aji_send(client, node);
aji_create_affiliations(client, name);
iks_delete(node);
return 0;
}
| static int aji_delete_node_list | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Delete pubsub item lists.
| data | pointer to aji_client structure |
| pak | response from pubsub diso::items query |
Definition at line 3686 of file res_jabber.c.
References aji_delete_pubsub_node(), ast_log(), ASTOBJ_REF, aji_client::jid, and LOG_WARNING.
Referenced by aji_pubsub_purge_nodes().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
iks *item = NULL;
if (iks_has_children(pak->query)) {
item = iks_first_tag(pak->query);
ast_log(LOG_WARNING, "Connection: %s Node name: %s\n", client->jid->partial,
iks_find_attrib(item, "node"));
while ((item = iks_next_tag(item))) {
aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
}
}
if (item) {
iks_delete(item);
}
return IKS_FILTER_EAT;
}
| static void aji_delete_pubsub_node | ( | struct aji_client * | client, |
| const char * | node_name | ||
| ) | [static] |
Delete a PubSub node.
| client | the configured XMPP client we use to connect to a XMPP server |
| node_name | the name of the node to delete return void |
Definition at line 3751 of file res_jabber.c.
References aji_pubsub_iq_create(), and ast_aji_send().
Referenced by aji_cli_delete_pubsub_node(), aji_cli_purge_pubsub_nodes(), and aji_delete_node_list().
{
iks *request = aji_pubsub_iq_create(client, "set");
iks *pubsub, *delete;
pubsub = iks_insert(request, "pubsub");
iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
delete = iks_insert(pubsub, "delete");
iks_insert_attrib(delete, "node", node_name);
ast_aji_send(client, request);
}
| static void aji_devstate_cb | ( | const struct ast_event * | ast_event, |
| void * | data | ||
| ) | [static] |
Callback function for device state events.
| ast_event | |
| data | void pointer to ast_client structure |
Definition at line 3198 of file res_jabber.c.
References aji_publish_device_state(), ast_aji_client_destroy(), ast_devstate_str(), ast_eid_cmp(), ast_eid_default, ast_event_get_ie_raw(), ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, AST_EVENT_IE_STATE, ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, and LOG_DEBUG.
Referenced by aji_init_event_distribution().
{
const char *device;
const char *device_state;
struct aji_client *client;
if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
{
/* If the event didn't originate from this server, don't send it back out. */
ast_log(LOG_DEBUG, "Returning here\n");
return;
}
client = ASTOBJ_REF((struct aji_client *) data);
device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
aji_publish_device_state(client, device, device_state);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
}
| static int aji_dinfo_handler | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 2071 of file res_jabber.c.
References aji_find_resource(), ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, aji_resource::cap, commands, aji_version::jingle, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_resource::resource, aji_client::user, and version.
Referenced by aji_create_client().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
char *node = NULL;
struct aji_resource *resource = NULL;
struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
if (pak->subtype == IKS_TYPE_ERROR) {
ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
resource = aji_find_resource(buddy, pak->from->resource);
if (pak->subtype == IKS_TYPE_RESULT) {
if (!resource) {
ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
resource->cap->jingle = 1;
} else {
resource->cap->jingle = 0;
}
} else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
iq = iks_new("iq");
query = iks_new("query");
identity = iks_new("identity");
disco = iks_new("feature");
reg = iks_new("feature");
commands = iks_new("feature");
gateway = iks_new("feature");
version = iks_new("feature");
vcard = iks_new("feature");
search = iks_new("feature");
if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
iks_insert_attrib(identity, "category", "gateway");
iks_insert_attrib(identity, "type", "pstn");
iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
iks_insert_attrib(reg, "var", "jabber:iq:register");
iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
iks_insert_attrib(version, "var", "jabber:iq:version");
iks_insert_attrib(vcard, "var", "vcard-temp");
iks_insert_attrib(search, "var", "jabber:iq:search");
iks_insert_node(iq, query);
iks_insert_node(query, identity);
iks_insert_node(query, disco);
iks_insert_node(query, reg);
iks_insert_node(query, commands);
iks_insert_node(query, gateway);
iks_insert_node(query, version);
iks_insert_node(query, vcard);
iks_insert_node(query, search);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
iks_delete(query);
iks_delete(identity);
iks_delete(disco);
iks_delete(reg);
iks_delete(commands);
iks_delete(gateway);
iks_delete(version);
iks_delete(vcard);
iks_delete(search);
} else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
iks *iq, *query, *confirm;
iq = iks_new("iq");
query = iks_new("query");
confirm = iks_new("item");
if (iq && query && confirm && client) {
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
iks_insert_attrib(confirm, "node", "confirmaccount");
iks_insert_attrib(confirm, "name", "Confirm AIM account");
iks_insert_attrib(confirm, "jid", client->user);
iks_insert_node(iq, query);
iks_insert_node(query, confirm);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
iks_delete(query);
iks_delete(confirm);
} else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
iks *iq, *query, *feature;
iq = iks_new("iq");
query = iks_new("query");
feature = iks_new("feature");
if (iq && query && feature && client) {
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
iks_insert_node(iq, query);
iks_insert_node(query, feature);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
iks_delete(query);
iks_delete(feature);
}
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static int aji_ditems_handler | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 1908 of file res_jabber.c.
References ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, LOG_ERROR, and aji_client::user.
Referenced by aji_create_client().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
char *node = NULL;
if (!(node = iks_find_attrib(pak->query, "node"))) {
iks *iq = NULL, *query = NULL, *item = NULL;
iq = iks_new("iq");
query = iks_new("query");
item = iks_new("item");
if (iq && query && item) {
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
iks_insert_attrib(item, "jid", client->user);
iks_insert_node(iq, query);
iks_insert_node(query, item);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
iks_delete(query);
iks_delete(item);
} else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
iks *iq, *query, *confirm;
iq = iks_new("iq");
query = iks_new("query");
confirm = iks_new("item");
if (iq && query && confirm && client) {
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
iks_insert_attrib(confirm, "node", "confirmaccount");
iks_insert_attrib(confirm, "name", "Confirm AIM account");
iks_insert_attrib(confirm, "jid", "blog.astjab.org");
iks_insert_node(iq, query);
iks_insert_node(query, confirm);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
iks_delete(query);
iks_delete(confirm);
} else if (!strcasecmp(node, "confirmaccount")) {
iks *iq = NULL, *query = NULL, *feature = NULL;
iq = iks_new("iq");
query = iks_new("query");
feature = iks_new("feature");
if (iq && query && feature && client) {
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
iks_insert_node(iq, query);
iks_insert_node(query, feature);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
iks_delete(query);
iks_delete(feature);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static char * aji_do_reload | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 4073 of file res_jabber.c.
References aji_reload(), ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
{
switch (cmd) {
case CLI_INIT:
e->command = "jabber reload";
e->usage =
"Usage: jabber reload\n"
" Reloads the Jabber module.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
aji_reload(1);
ast_cli(a->fd, "Jabber Reloaded.\n");
return CLI_SUCCESS;
}
| static char * aji_do_set_debug | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 4031 of file res_jabber.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
{
switch (cmd) {
case CLI_INIT:
e->command = "jabber set debug {on|off}";
e->usage =
"Usage: jabber set debug {on|off}\n"
" Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != e->args) {
return CLI_SHOWUSAGE;
}
if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
ASTOBJ_RDLOCK(iterator);
iterator->debug = 1;
ASTOBJ_UNLOCK(iterator);
});
ast_cli(a->fd, "Jabber Debugging Enabled.\n");
return CLI_SUCCESS;
} else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
ASTOBJ_RDLOCK(iterator);
iterator->debug = 0;
ASTOBJ_UNLOCK(iterator);
});
ast_cli(a->fd, "Jabber Debugging Disabled.\n");
return CLI_SUCCESS;
}
return CLI_SHOWUSAGE; /* defaults to invalid */
}
| static int aji_filter_roster | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 2942 of file res_jabber.c.
References AJI_AUTOPRUNE, AJI_AUTOREGISTER, AJI_CONNECTED, ast_clear_flag, ast_copy_flags, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_REF, ASTOBJ_UNLOCK, aji_client::buddies, aji_client::flags, and aji_client::state.
Referenced by aji_client_connect().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
int flag = 0;
iks *x = NULL;
struct aji_buddy *buddy;
client->state = AJI_CONNECTED;
ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
ASTOBJ_RDLOCK(iterator);
x = iks_child(pak->query);
flag = 0;
while (x) {
if (!iks_strcmp(iks_name(x), "item")) {
if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
flag = 1;
ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
}
}
x = iks_next(x);
}
if (!flag) {
ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
}
iks_delete(x);
ASTOBJ_UNLOCK(iterator);
});
x = iks_child(pak->query);
while (x) {
flag = 0;
if (iks_strcmp(iks_name(x), "item") == 0) {
ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
ASTOBJ_RDLOCK(iterator);
if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
flag = 1;
ASTOBJ_UNLOCK(iterator);
});
if (flag) {
/* found buddy, don't create a new one */
x = iks_next(x);
continue;
}
buddy = ast_calloc(1, sizeof(*buddy));
if (!buddy) {
ast_log(LOG_WARNING, "Out of memory\n");
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return 0;
}
ASTOBJ_INIT(buddy);
ASTOBJ_WRLOCK(buddy);
ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
ASTOBJ_MARK(buddy);
} else if (ast_test_flag(&client->flags, AJI_AUTOREGISTER)) {
if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
/* subscribe to buddy's presence only
if we really need to */
ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
}
}
ASTOBJ_UNLOCK(buddy);
if (buddy) {
ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
}
}
x = iks_next(x);
}
iks_delete(x);
aji_pruneregister(client);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static struct aji_resource* aji_find_resource | ( | struct aji_buddy * | buddy, |
| char * | name | ||
| ) | [static, read] |
Definition at line 546 of file res_jabber.c.
References aji_resource::next, aji_resource::resource, and aji_buddy::resources.
Referenced by acf_jabberstatus_read(), aji_client_info_handler(), aji_dinfo_handler(), and aji_status_exec().
| static struct aji_version* aji_find_version | ( | char * | node, |
| char * | version, | ||
| ikspak * | pak | ||
| ) | [static, read] |
Definition at line 474 of file res_jabber.c.
References ast_copy_string(), ast_free, ast_log(), ast_malloc, capabilities, aji_version::jingle, LOG_ERROR, aji_version::next, aji_capabilities::next, aji_capabilities::node, aji_version::parent, aji_version::version, and aji_capabilities::versions.
Referenced by aji_handle_presence().
{
struct aji_capabilities *list = NULL;
struct aji_version *res = NULL;
list = capabilities;
if (!node) {
node = pak->from->full;
}
if (!version) {
version = "none supplied.";
}
while (list) {
if (!strcasecmp(list->node, node)) {
res = list->versions;
while(res) {
if (!strcasecmp(res->version, version)) {
return res;
}
res = res->next;
}
/* Specified version not found. Let's add it to
this node in our capabilities list */
if (!res) {
res = ast_malloc(sizeof(*res));
if (!res) {
ast_log(LOG_ERROR, "Out of memory!\n");
return NULL;
}
res->jingle = 0;
res->parent = list;
ast_copy_string(res->version, version, sizeof(res->version));
res->next = list->versions;
list->versions = res;
return res;
}
}
list = list->next;
}
/* Specified node not found. Let's add it our capabilities list */
if (!list) {
list = ast_malloc(sizeof(*list));
if (!list) {
ast_log(LOG_ERROR, "Out of memory!\n");
return NULL;
}
res = ast_malloc(sizeof(*res));
if (!res) {
ast_log(LOG_ERROR, "Out of memory!\n");
ast_free(list);
return NULL;
}
ast_copy_string(list->node, node, sizeof(list->node));
ast_copy_string(res->version, version, sizeof(res->version));
res->jingle = 0;
res->parent = list;
res->next = NULL;
list->versions = res;
list->next = capabilities;
capabilities = list;
}
return res;
}
| static int aji_get_roster | ( | struct aji_client * | client | ) | [static] |
Definition at line 3056 of file res_jabber.c.
References aji_set_presence(), ast_aji_send(), aji_client::jid, aji_client::status, and aji_client::statusmessage.
Referenced by aji_client_connect(), and aji_reload().
{
iks *roster = NULL;
roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
if (roster) {
iks_insert_attrib(roster, "id", "roster");
aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
ast_aji_send(client, roster);
}
iks_delete(roster);
return 1;
}
| static void aji_handle_iq | ( | struct aji_client * | client, |
| iks * | node | ||
| ) | [static] |
Definition at line 2215 of file res_jabber.c.
Referenced by aji_act_hook().
{
/*Nothing to see here */
}
| static void aji_handle_message | ( | struct aji_client * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 2227 of file res_jabber.c.
References aji_message::arrived, ast_calloc, ast_cond_broadcast, ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_tvnow(), delete_old_messages(), aji_message::from, aji_message::id, aji_message::list, LOG_ERROR, aji_message::message, aji_client::messages, and aji_client::name.
Referenced by aji_act_hook().
{
struct aji_message *insert;
int deleted = 0;
ast_debug(3, "client %s received a message\n", client->name);
if (!(insert = ast_calloc(1, sizeof(*insert)))) {
return;
}
insert->arrived = ast_tvnow();
/* wake up threads waiting for messages */
ast_mutex_lock(&messagelock);
ast_cond_broadcast(&message_received_condition);
ast_mutex_unlock(&messagelock);
if (iks_find_cdata(pak->x, "body")) {
insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
}
if (pak->id) {
ast_copy_string(insert->id, pak->id, sizeof(insert->id));
}
if (pak->from){
/* insert will furtherly be added to message list */
insert->from = ast_strdup(pak->from->full);
if (!insert->from) {
ast_log(LOG_ERROR, "Memory allocation failure\n");
return;
}
ast_debug(3, "message comes from %s\n", insert->from);
}
/* remove old messages received from this JID
* and insert received message */
deleted = delete_old_messages(client, pak->from->partial);
ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
AST_LIST_LOCK(&client->messages);
AST_LIST_INSERT_HEAD(&client->messages, insert, list);
AST_LIST_UNLOCK(&client->messages);
}
| static void aji_handle_presence | ( | struct aji_client * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 2276 of file res_jabber.c.
References AJI_CONNECTED, aji_create_buddy(), aji_find_version(), aji_set_presence(), ast_aji_buddy_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_strdup, ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::buddies, aji_client::component, descrip, aji_resource::description, EVENT_FLAG_USER, gtalk_yuck(), aji_client::jid, last, LOG_ERROR, LOG_NOTICE, manager_event, aji_client::mid, aji_client::name, aji_resource::next, aji_resource::priority, aji_resource::resource, aji_buddy::resources, S_OR, aji_client::state, aji_resource::status, status, aji_client::status, aji_client::statusmessage, and type.
Referenced by aji_act_hook().
{
int status, priority;
struct aji_buddy *buddy;
struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
char *ver, *node, *descrip, *type;
if (client->state != AJI_CONNECTED)
aji_create_buddy(pak->from->partial, client);
buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
if (!buddy && pak->from->partial) {
/* allow our jid to be used to log in with another resource */
if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
aji_create_buddy(pak->from->partial, client);
else
ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
return;
}
type = iks_find_attrib(pak->x, "type");
if (client->component && type &&!strcasecmp("probe", type)) {
aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
ast_verbose("what i was looking for \n");
}
ASTOBJ_WRLOCK(buddy);
status = (pak->show) ? pak->show : 6;
priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
tmp = buddy->resources;
descrip = ast_strdup(iks_find_cdata(pak->x, "status"));
while (tmp && pak->from->resource) {
if (!strcasecmp(tmp->resource, pak->from->resource)) {
tmp->status = status;
if (tmp->description) {
ast_free(tmp->description);
}
tmp->description = descrip;
found = tmp;
if (status == 6) { /* Sign off Destroy resource */
if (last && found->next) {
last->next = found->next;
} else if (!last) {
if (found->next) {
buddy->resources = found->next;
} else {
buddy->resources = NULL;
}
} else if (!found->next) {
if (last) {
last->next = NULL;
} else {
buddy->resources = NULL;
}
}
ast_free(found);
found = NULL;
break;
}
/* resource list is sorted by descending priority */
if (tmp->priority != priority) {
found->priority = priority;
if (!last && !found->next) {
/* resource was found to be unique,
leave loop */
break;
}
/* search for resource in our list
and take it out for the moment */
if (last) {
last->next = found->next;
} else {
buddy->resources = found->next;
}
last = NULL;
tmp = buddy->resources;
if (!buddy->resources) {
buddy->resources = found;
}
/* priority processing */
while (tmp) {
/* insert resource back according to
its priority value */
if (found->priority > tmp->priority) {
if (last) {
/* insert within list */
last->next = found;
}
found->next = tmp;
if (!last) {
/* insert on top */
buddy->resources = found;
}
break;
}
if (!tmp->next) {
/* insert at the end of the list */
tmp->next = found;
found->next = NULL;
break;
}
last = tmp;
tmp = tmp->next;
}
}
break;
}
last = tmp;
tmp = tmp->next;
}
/* resource not found in our list, create it */
if (!found && status != 6 && pak->from->resource) {
found = ast_calloc(1, sizeof(*found));
if (!found) {
ast_log(LOG_ERROR, "Out of memory!\n");
ASTOBJ_UNLOCK(buddy);
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
return;
}
ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
found->status = status;
found->description = descrip;
found->priority = priority;
found->next = NULL;
last = NULL;
tmp = buddy->resources;
while (tmp) {
if (found->priority > tmp->priority) {
if (last) {
last->next = found;
}
found->next = tmp;
if (!last) {
buddy->resources = found;
}
break;
}
if (!tmp->next) {
tmp->next = found;
break;
}
last = tmp;
tmp = tmp->next;
}
if (!tmp) {
buddy->resources = found;
}
}
ASTOBJ_UNLOCK(buddy);
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
node = iks_find_attrib(iks_find(pak->x, "c"), "node");
ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
/* handle gmail client's special caps:c tag */
if (!node && !ver) {
node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
}
/* retrieve capabilites of the new resource */
if (status != 6 && found && !found->cap) {
found->cap = aji_find_version(node, ver, pak);
if (gtalk_yuck(pak->x)) { /* gtalk should do discover */
found->cap->jingle = 1;
}
if (found->cap->jingle) {
ast_debug(1, "Special case for google till they support discover.\n");
} else {
iks *iq, *query;
iq = iks_new("iq");
query = iks_new("query");
if (query && iq) {
iks_insert_attrib(iq, "type", "get");
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "from", client->jid->full);
iks_insert_attrib(iq, "id", client->mid);
ast_aji_increment_mid(client->mid);
iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
iks_insert_node(iq, query);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(query);
iks_delete(iq);
}
}
switch (pak->subtype) {
case IKS_TYPE_AVAILABLE:
ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
break;
case IKS_TYPE_UNAVAILABLE:
ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
break;
default:
ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
}
switch (pak->show) {
case IKS_SHOW_UNAVAILABLE:
ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
case IKS_SHOW_AVAILABLE:
ast_debug(3, "JABBER: type is available\n");
break;
case IKS_SHOW_CHAT:
ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
case IKS_SHOW_AWAY:
ast_debug(3, "JABBER: type is away\n");
break;
case IKS_SHOW_XA:
ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
case IKS_SHOW_DND:
ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
default:
ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
}
if (found) {
manager_event(EVENT_FLAG_USER, "JabberStatus",
"Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
"\r\nDescription: %s\r\n",
client->name, pak->from->partial, found->resource, found->status,
found->priority, S_OR(found->description, ""));
} else {
manager_event(EVENT_FLAG_USER, "JabberStatus",
"Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
}
}
| static int aji_handle_pubsub_error | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 3461 of file res_jabber.c.
References aji_create_pubsub_collection(), aji_create_pubsub_leaf(), aji_create_pubsub_node(), aji_pubsub_iq_create(), AJI_XEP0248, ast_aji_client_destroy(), ast_aji_send(), ast_log(), ast_test_flag, ASTOBJ_REF, ASTOBJ_UNREF, and LOG_ERROR.
Referenced by aji_init_event_distribution().
{
char *node_name;
char *error;
int error_num;
iks *orig_request;
iks *orig_pubsub = iks_find(pak->x, "pubsub");
struct aji_client *client;
if (!orig_pubsub) {
ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
return IKS_FILTER_EAT;
}
orig_request = iks_child(orig_pubsub);
error = iks_find_attrib(iks_find(pak->x, "error"), "code");
node_name = iks_find_attrib(orig_request, "node");
if (!sscanf(error, "%30d", &error_num)) {
return IKS_FILTER_EAT;
}
if (error_num > 399 && error_num < 500 && error_num != 404) {
ast_log(LOG_ERROR,
"Error performing operation on PubSub node %s, %s.\n", node_name, error);
return IKS_FILTER_EAT;
} else if (error_num > 499 && error_num < 600) {
ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
return IKS_FILTER_EAT;
}
client = ASTOBJ_REF((struct aji_client *) data);
if (!strcasecmp(iks_name(orig_request), "publish")) {
iks *request;
if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
if (iks_find(iks_find(orig_request, "item"), "state")) {
aji_create_pubsub_leaf(client, "device_state", node_name);
} else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
aji_create_pubsub_leaf(client, "message_waiting", node_name);
}
} else {
aji_create_pubsub_node(client, NULL, node_name, NULL);
}
request = aji_pubsub_iq_create(client, "set");
iks_insert_node(request, orig_pubsub);
ast_aji_send(client, request);
iks_delete(request);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
} else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
aji_create_pubsub_collection(client, node_name);
} else {
aji_create_pubsub_node(client, NULL, node_name, NULL);
}
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static int aji_handle_pubsub_event | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Callback for handling PubSub events.
| data | void pointer to aji_client structure |
Definition at line 3251 of file res_jabber.c.
References ast_devstate_val(), ast_eid_cmp(), ast_eid_default, AST_EVENT_DEVICE_STATE_CHANGE, AST_EVENT_IE_CONTEXT, AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_RAW, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_IE_STATE, AST_EVENT_MWI, ast_event_new(), ast_event_queue_and_cache(), ast_log(), ast_str_to_eid(), context, LOG_DEBUG, LOG_ERROR, and strsep().
Referenced by aji_init_event_distribution().
{
char *item_id, *device_state, *context;
int oldmsgs, newmsgs;
iks *item, *item_content;
struct ast_eid pubsub_eid;
struct ast_event *event;
item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
if (!item) {
ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
return IKS_FILTER_EAT;
}
item_id = iks_find_attrib(item, "id");
item_content = iks_child(item);
ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
ast_log(LOG_DEBUG, "Returning here, eid of incoming event matches ours!\n");
return IKS_FILTER_EAT;
}
if (!strcasecmp(iks_name(item_content), "state")) {
device_state = iks_find_cdata(item, "state");
if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
AST_EVENT_IE_END))) {
return IKS_FILTER_EAT;
}
} else if (!strcasecmp(iks_name(item_content), "mailbox")) {
context = strsep(&item_id, "@");
sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
&pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
return IKS_FILTER_EAT;
}
} else {
ast_log(LOG_DEBUG, "Don't know how to handle PubSub event of type %s\n",
iks_name(item_content));
return IKS_FILTER_EAT;
}
ast_event_queue_and_cache(event);
return IKS_FILTER_EAT;
}
| static void aji_handle_subscribe | ( | struct aji_client * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 2520 of file res_jabber.c.
References AJI_AUTOACCEPT, aji_create_buddy(), aji_set_presence(), ast_aji_buddy_destroy(), ast_aji_send(), ast_log(), ast_test_flag, ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, aji_client::component, aji_client::flags, aji_client::jid, LOG_ERROR, option_verbose, status, aji_client::status, aji_client::statusmessage, and VERBOSE_PREFIX_3.
Referenced by aji_act_hook().
{
iks *presence = NULL, *status = NULL;
struct aji_buddy* buddy = NULL;
switch (pak->subtype) {
case IKS_TYPE_SUBSCRIBE:
if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
presence = iks_new("presence");
status = iks_new("status");
if (presence && status) {
iks_insert_attrib(presence, "type", "subscribed");
iks_insert_attrib(presence, "to", pak->from->full);
iks_insert_attrib(presence, "from", client->jid->full);
if (pak->id)
iks_insert_attrib(presence, "id", pak->id);
iks_insert_cdata(status, "Asterisk has approved subscription", 0);
iks_insert_node(presence, status);
ast_aji_send(client, presence);
} else {
ast_log(LOG_ERROR, "Unable to allocate nodes\n");
}
iks_delete(presence);
iks_delete(status);
}
if (client->component)
aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
case IKS_TYPE_SUBSCRIBED:
buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
if (!buddy && pak->from->partial) {
aji_create_buddy(pak->from->partial, client);
} else if (buddy) {
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
}
default:
if (option_verbose > 4) {
ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
}
}
}
| static void aji_init_event_distribution | ( | struct aji_client * | client | ) | [static] |
Initialize collections for event distribution.
| client | the configured XMPP client we use to connect to a XMPP server |
Definition at line 3222 of file res_jabber.c.
References aji_devstate_cb(), aji_handle_pubsub_error(), aji_handle_pubsub_event(), aji_mwi_cb(), aji_pubsub_subscribe(), ast_enable_distributed_devstate(), AST_EVENT_DEVICE_STATE_CHANGE, ast_event_dump_cache(), AST_EVENT_IE_END, AST_EVENT_MWI, ast_event_subscribe(), aji_client::f, and aji_client::pubsub_node.
Referenced by aji_client_connect(), and aji_reload().
{
if (!mwi_sub) {
mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
client, AST_EVENT_IE_END);
}
if (!device_state_sub) {
if (ast_enable_distributed_devstate()) {
return;
}
device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
ast_event_dump_cache(device_state_sub);
}
aji_pubsub_subscribe(client, "device_state");
aji_pubsub_subscribe(client, "message_waiting");
iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
}
| static int aji_initialize | ( | struct aji_client * | client | ) | [static] |
Definition at line 3114 of file res_jabber.c.
References ast_log(), aji_client::component, connected, aji_client::jid, LOG_ERROR, aji_client::name, aji_client::p, aji_client::port, S_OR, aji_client::serverhost, aji_client::stream_flags, and aji_client::user.
Referenced by aji_reconnect().
{
int connected = IKS_NET_NOCONN;
#ifdef HAVE_OPENSSL
/* reset stream flags */
client->stream_flags = 0;
#endif
/* If it's a component, connect to user, otherwise, connect to server */
connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
if (connected == IKS_NET_NOCONN) {
ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
return IKS_HOOK;
} 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;
}
return IKS_OK;
}
| static int aji_io_recv | ( | struct aji_client * | client, |
| char * | buffer, | ||
| size_t | buf_len, | ||
| int | timeout | ||
| ) | [static] |
Definition at line 1296 of file res_jabber.c.
References aji_is_secure(), ast_poll, len(), aji_client::p, and aji_client::ssl_session.
Referenced by aji_recv().
{
struct pollfd pfd = { .events = POLLIN };
int len, res;
#ifdef HAVE_OPENSSL
if (aji_is_secure(client)) {
pfd.fd = SSL_get_fd(client->ssl_session);
if (pfd.fd < 0) {
return -1;
}
} else
#endif /* HAVE_OPENSSL */
pfd.fd = iks_fd(client->p);
res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
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(pfd.fd, buffer, buf_len, 0);
if (len > 0) {
return len;
} else if (len <= 0) {
return -1;
}
}
return res;
}
| static int aji_is_secure | ( | struct aji_client * | client | ) | [static] |
Definition at line 1206 of file res_jabber.c.
References SECURE, and aji_client::stream_flags.
Referenced by aji_act_hook(), aji_io_recv(), aji_send_raw(), and aji_start_sasl().
{
#ifdef HAVE_OPENSSL
return client->stream_flags & SECURE;
#else
return 0;
#endif
}
| static int aji_join_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Application to join a chat room.
| chan | ast_channel |
| data | Data is sender|jid|nickname. |
| 0 | success |
| -1 | error |
Definition at line 991 of file res_jabber.c.
References AJI_MAX_RESJIDLEN, args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_join_chat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, aji_client::component, aji_client::jid, and LOG_ERROR.
Referenced by load_module().
{
struct aji_client *client = NULL;
char *s;
char nick[AJI_MAX_RESJIDLEN];
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(jid);
AST_APP_ARG(nick);
);
if (!data) {
ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
return -1;
}
s = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, s);
if (args.argc < 2 || args.argc > 3) {
ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
return -1;
}
if (strchr(args.jid, '/')) {
ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
return -1;
}
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
if (!ast_strlen_zero(args.nick)) {
snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
} else {
if (client->component) {
sprintf(nick, "asterisk");
} else {
snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
}
}
if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
ast_aji_join_chat(client, args.jid, nick);
} else {
ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return 0;
}
| static int aji_leave_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Application to leave a chat room.
| chan | ast_channel |
| data | Data is sender|jid|nickname. |
| 0 | success |
| -1 | error |
Definition at line 1052 of file res_jabber.c.
References AJI_MAX_RESJIDLEN, args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_leave_chat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, aji_client::component, aji_client::jid, and LOG_ERROR.
Referenced by load_module().
{
struct aji_client *client = NULL;
char *s;
char nick[AJI_MAX_RESJIDLEN];
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(jid);
AST_APP_ARG(nick);
);
if (!data) {
ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
return -1;
}
s = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, s);
if (args.argc < 2 || args.argc > 3) {
ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
return -1;
}
if (strchr(args.jid, '/')) {
ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
return -1;
}
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
if (!ast_strlen_zero(args.nick)) {
snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
} else {
if (client->component) {
sprintf(nick, "asterisk");
} else {
snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
}
}
if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
ast_aji_leave_chat(client, args.jid, nick);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return 0;
}
| static int aji_load_config | ( | int | reload | ) | [static] |
Definition at line 4537 of file res_jabber.c.
References AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_create_client(), AJI_PUBSUB_AUTOCREATE, AJI_XEP0248, ast_category_browse(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_false(), ast_log(), ast_set2_flag, ast_set_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, debug, JABBER_CONFIG, LOG_WARNING, ast_variable::name, ast_variable::next, ast_variable::value, and var.
Referenced by aji_reload().
{
char *cat = NULL;
int debug = 0;
struct ast_config *cfg = NULL;
struct ast_variable *var = NULL;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
return -1;
}
/* Reset flags to default value */
ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT);
if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
return 0;
}
cat = ast_category_browse(cfg, NULL);
for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
if (!strcasecmp(var->name, "debug")) {
debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
} else if (!strcasecmp(var->name, "autoprune")) {
ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
} else if (!strcasecmp(var->name, "autoregister")) {
ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
} else if (!strcasecmp(var->name, "collection_nodes")) {
ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248);
} else if (!strcasecmp(var->name, "pubsub_autocreate")) {
ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE);
} else if (!strcasecmp(var->name, "auth_policy")) {
if (!strcasecmp(var->value, "accept")) {
ast_set_flag(&globalflags, AJI_AUTOACCEPT);
} else {
ast_clear_flag(&globalflags, AJI_AUTOACCEPT);
}
}
}
while (cat) {
if (strcasecmp(cat, "general")) {
var = ast_variable_browse(cfg, cat);
aji_create_client(cat, var, debug);
}
cat = ast_category_browse(cfg, cat);
}
ast_config_destroy(cfg); /* or leak memory */
return 1;
}
| static void aji_log_hook | ( | void * | data, |
| const char * | xmpp, | ||
| size_t | size, | ||
| int | is_incoming | ||
| ) | [static] |
Definition at line 1487 of file res_jabber.c.
References ast_aji_client_destroy(), ast_strlen_zero(), ast_verbose(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::debug, EVENT_FLAG_USER, manager_event, aji_client::name, and option_debug.
Referenced by aji_create_client(), aji_recv(), and aji_send_raw().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
if (!ast_strlen_zero(xmpp)) {
manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
}
if (client->debug) {
if (is_incoming) {
ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
} else {
if (strlen(xmpp) == 1) {
if (option_debug > 2 && xmpp[0] == ' ') {
ast_verbose("\nJABBER: Keep alive packet\n");
}
} else {
ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
}
}
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
}
| static void aji_message_destroy | ( | struct aji_message * | obj | ) | [static] |
Definition at line 453 of file res_jabber.c.
References ast_free, aji_message::from, and aji_message::message.
Referenced by acf_jabberreceive_read(), ast_aji_client_destroy(), and delete_old_messages().
| static void aji_mwi_cb | ( | const struct ast_event * | ast_event, |
| void * | data | ||
| ) | [static] |
Callback function for MWI events.
| ast_event | |
| data | void pointer to ast_client structure |
Definition at line 3167 of file res_jabber.c.
References aji_publish_mwi(), ast_aji_client_destroy(), ast_eid_cmp(), ast_eid_default, ast_event_get_ie_raw(), ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_EID, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_OLDMSGS, ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, context, LOG_DEBUG, and mailbox.
Referenced by aji_init_event_distribution().
{
const char *mailbox;
const char *context;
char oldmsgs[10];
char newmsgs[10];
struct aji_client *client;
if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
{
/* If the event didn't originate from this server, don't send it back out. */
ast_log(LOG_DEBUG, "Returning here\n");
return;
}
client = ASTOBJ_REF((struct aji_client *) data);
mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
snprintf(oldmsgs, sizeof(oldmsgs), "%d",
ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
snprintf(newmsgs, sizeof(newmsgs), "%d",
ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
}
| static void aji_pruneregister | ( | struct aji_client * | client | ) | [static] |
Definition at line 2888 of file res_jabber.c.
References AJI_AUTOPRUNE, ast_aji_send(), ast_log(), ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, aji_client::buddies, aji_client::jid, and LOG_ERROR.
{
iks *removeiq = iks_new("iq");
iks *removequery = iks_new("query");
iks *removeitem = iks_new("item");
iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
if (!client || !removeiq || !removequery || !removeitem || !send) {
ast_log(LOG_ERROR, "Out of memory.\n");
goto safeout;
}
iks_insert_node(removeiq, removequery);
iks_insert_node(removequery, removeitem);
ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
ASTOBJ_RDLOCK(iterator);
/* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
* be called at the same time */
if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
ast_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"));
ast_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);
iks_insert_attrib(removeiq, "type", "set");
iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
iks_insert_attrib(removeitem, "jid", iterator->name);
iks_insert_attrib(removeitem, "subscription", "remove");
ast_aji_send(client, removeiq);
} else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
ast_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->flags, AJI_AUTOREGISTER);
}
ASTOBJ_UNLOCK(iterator);
});
safeout:
iks_delete(removeiq);
iks_delete(removequery);
iks_delete(removeitem);
iks_delete(send);
ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
}
| static void aji_publish_device_state | ( | struct aji_client * | client, |
| const char * | device, | ||
| const char * | device_state | ||
| ) | [static] |
Publish device state to a PubSub node.
| client | the configured XMPP client we use to connect to a XMPP server |
| device | the name of the device whose state to publish |
| device_state | the state to publish |
Definition at line 3396 of file res_jabber.c.
References aji_build_publish_skeleton(), aji_create_pubsub_node(), AJI_PUBSUB_AUTOCREATE, AJI_XEP0248, ast_aji_send(), ast_eid_default, ast_eid_to_str(), ast_test_flag, and state.
Referenced by aji_devstate_cb().
{
iks *request = aji_build_publish_skeleton(client, device, "device_state");
iks *state;
char eid_str[20];
if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
aji_create_pubsub_node(client, "leaf", device, "device_state");
} else {
aji_create_pubsub_node(client, NULL, device, NULL);
}
}
ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
state = iks_insert(request, "state");
iks_insert_attrib(state, "xmlns", "http://asterisk.org");
iks_insert_attrib(state, "eid", eid_str);
iks_insert_cdata(state, device_state, strlen(device_state));
ast_aji_send(client, iks_root(request));
iks_delete(request);
}
| static void aji_publish_mwi | ( | struct aji_client * | client, |
| const char * | mailbox, | ||
| const char * | context, | ||
| const char * | oldmsgs, | ||
| const char * | newmsgs | ||
| ) | [static] |
Publish MWI to a PubSub node.
| client | the configured XMPP client we use to connect to a XMPP server |
| device | the name of the device whose state to publish |
| device_state | the state to publish |
Definition at line 3425 of file res_jabber.c.
References aji_build_publish_skeleton(), ast_aji_send(), ast_eid_default, ast_eid_to_str(), AST_MAX_CONTEXT, and AST_MAX_EXTENSION.
Referenced by aji_mwi_cb().
{
char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
char eid_str[20];
iks *mailbox_node, *request;
snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
mailbox_node = iks_insert(request, "mailbox");
iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
iks_insert_attrib(mailbox_node, "eid", eid_str);
iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
ast_aji_send(client, iks_root(request));
iks_delete(request);
}
| static iks * aji_pubsub_iq_create | ( | struct aji_client * | client, |
| const char * | type | ||
| ) | [static] |
Create an IQ packet.
| client | the configured XMPP client we use to connect to a XMPP server |
| type | the type of IQ packet to create |
Definition at line 3449 of file res_jabber.c.
References ast_aji_increment_mid(), aji_client::jid, aji_client::mid, and aji_client::pubsub_node.
Referenced by aji_build_node_request(), aji_build_publish_skeleton(), aji_create_affiliations(), aji_create_pubsub_node(), aji_delete_pubsub_node(), aji_handle_pubsub_error(), and aji_pubsub_subscribe().
{
iks *request = iks_new("iq");
iks_insert_attrib(request, "to", client->pubsub_node);
iks_insert_attrib(request, "from", client->jid->full);
iks_insert_attrib(request, "type", type);
ast_aji_increment_mid(client->mid);
iks_insert_attrib(request, "id", client->mid);
return request;
}
| static void aji_pubsub_purge_nodes | ( | struct aji_client * | client, |
| const char * | collection_name | ||
| ) | [static] |
Definition at line 3669 of file res_jabber.c.
References aji_build_node_request(), aji_delete_node_list(), ast_aji_send(), aji_client::f, and aji_client::mid.
Referenced by aji_cli_purge_pubsub_nodes().
{
iks *request = aji_build_node_request(client, collection_name);
ast_aji_send(client, request);
iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
IKS_RULE_DONE);
ast_aji_send(client, request);
iks_delete(request);
}
| static void aji_pubsub_subscribe | ( | struct aji_client * | client, |
| const char * | node | ||
| ) | [static] |
Subscribe to a PubSub node.
| client | the configured XMPP client we use to connect to a XMPP server |
| node | the name of the node to which to subscribe |
Definition at line 3331 of file res_jabber.c.
References aji_pubsub_iq_create(), AJI_XEP0248, ast_aji_send(), ast_test_flag, and aji_client::jid.
Referenced by aji_init_event_distribution().
{
iks *request = aji_pubsub_iq_create(client, "set");
iks *pubsub, *subscribe;
pubsub = iks_insert(request, "pubsub");
iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
subscribe = iks_insert(pubsub, "subscribe");
iks_insert_attrib(subscribe, "jid", client->jid->partial);
iks_insert_attrib(subscribe, "node", node);
if (ast_test_flag(&globalflags, AJI_XEP0248)) {
iks *options, *x, *sub_options, *sub_type, *sub_depth;
options = iks_insert(pubsub, "options");
x = iks_insert(options, "x");
iks_insert_attrib(x, "xmlns", "jabber:x:data");
iks_insert_attrib(x, "type", "submit");
sub_options = iks_insert(x, "field");
iks_insert_attrib(sub_options, "var", "FORM_TYPE");
iks_insert_attrib(sub_options, "type", "hidden");
iks_insert_cdata(iks_insert(sub_options, "value"),
"http://jabber.org/protocol/pubsub#subscribe_options", 51);
sub_type = iks_insert(x, "field");
iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
sub_depth = iks_insert(x, "field");
iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
}
ast_aji_send(client, request);
iks_delete(request);
}
| static int aji_receive_node_list | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Receive pubsub item lists.
| data | pointer to aji_client structure |
| pak | response from pubsub diso::items query |
Definition at line 3560 of file res_jabber.c.
References ast_aji_client_destroy(), ast_verbose(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::jid, and aji_client::name.
Referenced by aji_request_pubsub_nodes().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
iks *item = NULL;
if (iks_has_children(pak->query)) {
item = iks_first_tag(pak->query);
ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
iks_find_attrib(item, "node"));
while ((item = iks_next_tag(item))) {
ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
}
}
if (item) {
iks_delete(item);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static int aji_reconnect | ( | struct aji_client * | client | ) | [static] |
Definition at line 3030 of file res_jabber.c.
References AJI_DISCONNECTED, aji_initialize(), aji_client::authorized, aji_client::p, aji_client::state, and aji_client::timeout.
Referenced by aji_recv_loop().
{
int res = 0;
if (client->state) {
client->state = AJI_DISCONNECTED;
}
client->timeout = 50;
if (client->p) {
iks_parser_reset(client->p);
}
if (client->authorized) {
client->authorized = 0;
}
res = aji_initialize(client);
return res;
}
| static int aji_recv | ( | struct aji_client * | client, |
| int | timeout | ||
| ) | [static] |
Definition at line 1341 of file res_jabber.c.
References aji_io_recv(), aji_log_hook(), ast_debug, ast_log(), IKS_NET_EXPIRED, len(), LOG_WARNING, NET_IO_BUF_SIZE, and aji_client::p.
Referenced by aji_act_hook(), and aji_recv_loop().
{
int len, ret;
char buf[NET_IO_BUF_SIZE - 1];
char newbuf[NET_IO_BUF_SIZE - 1];
int pos = 0;
int newbufpos = 0;
unsigned char c;
memset(buf, 0, sizeof(buf));
memset(newbuf, 0, sizeof(newbuf));
while (1) {
len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
if (len < 0) return IKS_NET_RWERR;
if (len == 0) return IKS_NET_EXPIRED;
buf[len] = '\0';
/* our iksemel parser won't work as expected if we feed
it with XML packets that contain multiple whitespace
characters between tags */
while (pos < len) {
c = buf[pos];
/* if we stumble on the ending tag character,
we skip any whitespace that follows it*/
if (c == '>') {
while (isspace(buf[pos+1])) {
pos++;
}
}
newbuf[newbufpos] = c;
newbufpos ++;
pos++;
}
pos = 0;
newbufpos = 0;
/* Log the message here, because iksemel's logHook is
unaccessible */
aji_log_hook(client, buf, len, 1);
/* let iksemel deal with the string length,
and reset our buffer */
ret = iks_parse(client->p, newbuf, 0, 0);
memset(newbuf, 0, sizeof(newbuf));
switch (ret) {
case IKS_NOMEM:
ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
break;
case IKS_BADXML:
ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
break;
case IKS_HOOK:
ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
break;
}
if (ret != IKS_OK) {
return ret;
}
ast_debug(3, "XML parsing successful\n");
}
return IKS_OK;
}
| static void * aji_recv_loop | ( | void * | data | ) | [static] |
Definition at line 2722 of file res_jabber.c.
References AJI_CONNECTED, AJI_DISCONNECTING, aji_reconnect(), aji_recv(), aji_send_raw(), ast_aji_client_destroy(), ast_debug, ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, delete_old_messages_all(), IKS_NET_EXPIRED, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::state, and aji_client::timeout.
Referenced by aji_reload().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
int res = IKS_HOOK;
while (res != IKS_OK) {
ast_debug(3, "JABBER: Connecting.\n");
res = aji_reconnect(client);
sleep(4);
}
do {
if (res == IKS_NET_RWERR || client->timeout == 0) {
while (res != IKS_OK) {
ast_debug(3, "JABBER: reconnecting.\n");
res = aji_reconnect(client);
sleep(4);
}
}
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);
}
/* Decrease timeout if no data received, and delete
* old messages globally */
if (res == IKS_NET_EXPIRED) {
client->timeout--;
delete_old_messages_all(client);
}
if (res == IKS_HOOK) {
ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
} else if (res == IKS_NET_TLSFAIL) {
ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
} else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
if (res == IKS_OK) {
client->timeout = 50;
} else {
ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
}
} else if (res == IKS_NET_RWERR) {
ast_log(LOG_WARNING, "JABBER: socket read error\n");
}
} while (client);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return 0;
}
| static int aji_register_approve_handler | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 1792 of file res_jabber.c.
References ast_aji_client_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::jid, LOG_ERROR, and aji_client::mid.
Referenced by aji_create_client().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
iks *iq = NULL, *presence = NULL, *x = NULL;
iq = iks_new("iq");
presence = iks_new("presence");
x = iks_new("x");
if (client && iq && presence && x) {
if (!iks_find(pak->query, "remove")) {
iks_insert_attrib(iq, "from", client->jid->full);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
ast_aji_send(client, iq);
iks_insert_attrib(presence, "from", client->jid->full);
iks_insert_attrib(presence, "to", pak->from->partial);
iks_insert_attrib(presence, "id", client->mid);
ast_aji_increment_mid(client->mid);
iks_insert_attrib(presence, "type", "subscribe");
iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
iks_insert_node(presence, x);
ast_aji_send(client, presence);
}
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
iks_delete(presence);
iks_delete(x);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static int aji_register_query_handler | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 1835 of file res_jabber.c.
References ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, LOG_ERROR, and aji_client::user.
Referenced by aji_create_client().
{
struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
struct aji_buddy *buddy = NULL;
char *node = NULL;
iks *iq = NULL, *query = NULL;
client = (struct aji_client *) data;
buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
if (!buddy) {
iks *error = NULL, *notacceptable = NULL;
ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
iq = iks_new("iq");
query = iks_new("query");
error = iks_new("error");
notacceptable = iks_new("not-acceptable");
if (iq && query && error && notacceptable) {
iks_insert_attrib(iq, "type", "error");
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(query, "xmlns", "jabber:iq:register");
iks_insert_attrib(error, "code" , "406");
iks_insert_attrib(error, "type", "modify");
iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
iks_insert_node(iq, query);
iks_insert_node(iq, error);
iks_insert_node(error, notacceptable);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(error);
iks_delete(notacceptable);
} else if (!(node = iks_find_attrib(pak->query, "node"))) {
iks *instructions = NULL;
char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
iq = iks_new("iq");
query = iks_new("query");
instructions = iks_new("instructions");
if (iq && query && instructions && client) {
iks_insert_attrib(iq, "from", client->user);
iks_insert_attrib(iq, "to", pak->from->full);
iks_insert_attrib(iq, "id", pak->id);
iks_insert_attrib(iq, "type", "result");
iks_insert_attrib(query, "xmlns", "jabber:iq:register");
iks_insert_cdata(instructions, explain, 0);
iks_insert_node(iq, query);
iks_insert_node(query, instructions);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(instructions);
}
iks_delete(iq);
iks_delete(query);
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return IKS_FILTER_EAT;
}
| static int aji_reload | ( | int | reload | ) | [static] |
Definition at line 4674 of file res_jabber.c.
References AJI_CONNECTING, AJI_DISCONNECTED, aji_get_roster(), aji_init_event_distribution(), aji_load_config(), aji_recv_loop(), ast_aji_client_destroy(), ast_log(), ast_pthread_create_background, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_CONTAINER_PRUNE_MARKED, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, clients, and LOG_ERROR.
Referenced by aji_do_reload(), load_module(), and reload().
{
int res;
ASTOBJ_CONTAINER_MARKALL(&clients);
if (!(res = aji_load_config(reload))) {
ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
return 0;
} else if (res == -1)
return 1;
ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
ASTOBJ_RDLOCK(iterator);
if (iterator->state == AJI_DISCONNECTED) {
if (!iterator->thread)
ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
} else if (iterator->state == AJI_CONNECTING) {
aji_get_roster(iterator);
if (iterator->distribute_events) {
aji_init_event_distribution(iterator);
}
}
ASTOBJ_UNLOCK(iterator);
});
return 1;
}
| static void aji_request_pubsub_nodes | ( | struct aji_client * | client, |
| const char * | collection | ||
| ) | [static] |
Request item list from pubsub.
| client | the configured XMPP client we use to connect to a XMPP server |
| collection | name of the collection for request |
Definition at line 3524 of file res_jabber.c.
References aji_build_node_request(), aji_receive_node_list(), ast_aji_send(), aji_client::f, and aji_client::mid.
Referenced by aji_cli_list_pubsub_nodes().
{
iks *request = aji_build_node_request(client, collection);
iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
IKS_RULE_DONE);
ast_aji_send(client, request);
iks_delete(request);
}
| static int aji_send_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 1110 of file res_jabber.c.
References args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_send_chat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, and LOG_WARNING.
Referenced by load_module().
{
struct aji_client *client = NULL;
char *s;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(recipient);
AST_APP_ARG(message);
);
if (!data) {
ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
return -1;
}
s = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, s);
if (args.argc < 3) {
ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
return -1;
}
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
ast_aji_send_chat(client, args.recipient, args.message);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return 0;
}
| static int aji_send_header | ( | struct aji_client * | client, |
| const char * | to | ||
| ) | [static] |
Definition at line 1413 of file res_jabber.c.
References aji_send_raw(), len(), and aji_client::name_space.
Referenced by aji_act_hook(), and aji_tls_handshake().
{
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;
}
| static int aji_send_raw | ( | struct aji_client * | client, |
| const char * | xmlstr | ||
| ) | [static] |
Definition at line 1453 of file res_jabber.c.
References aji_is_secure(), aji_log_hook(), len(), aji_client::p, and aji_client::ssl_session.
Referenced by aji_act_hook(), aji_recv_loop(), aji_send_header(), and ast_aji_send().
{
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;
}
| static int aji_send_raw_chat | ( | struct aji_client * | client, |
| int | groupchat, | ||
| const char * | nick, | ||
| const char * | address, | ||
| const char * | message | ||
| ) | [static] |
sends messages.
| client | the configured XMPP client we use to connect to a XMPP server |
| groupchat | |
| nick | the nickname we use in chatrooms |
| address | |
| message |
Definition at line 2598 of file res_jabber.c.
References AJI_CONNECTED, AJI_MAX_JIDLEN, ast_aji_send(), ast_log(), aji_client::component, aji_client::jid, LOG_ERROR, LOG_WARNING, and aji_client::state.
Referenced by ast_aji_send_chat(), and ast_aji_send_groupchat().
{
int res = 0;
iks *message_packet = NULL;
char from[AJI_MAX_JIDLEN];
/* the nickname is used only in component mode */
if (nick && client->component) {
snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
} else {
snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
}
if (client->state != AJI_CONNECTED) {
ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
return -1;
}
message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
if (!message_packet) {
ast_log(LOG_ERROR, "Out of memory.\n");
return -1;
}
iks_insert_attrib(message_packet, "from", from);
res = ast_aji_send(client, message_packet);
iks_delete(message_packet);
return res;
}
| static int aji_sendgroup_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Application to send a message to a groupchat.
| chan | ast_channel |
| data | Data is sender|groupchat|message. |
| 0 | success |
| -1 | error |
Definition at line 1150 of file res_jabber.c.
References AJI_MAX_RESJIDLEN, args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_send_groupchat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, aji_client::component, aji_client::jid, and LOG_ERROR.
Referenced by load_module().
{
struct aji_client *client = NULL;
char *s;
char nick[AJI_MAX_RESJIDLEN];
int res = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(groupchat);
AST_APP_ARG(message);
AST_APP_ARG(nick);
);
if (!data) {
ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
return -1;
}
s = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, s);
if (args.argc < 3 || args.argc > 4) {
ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
return -1;
}
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
if (ast_strlen_zero(args.nick) || args.argc == 3) {
if (client->component) {
sprintf(nick, "asterisk");
} else {
snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
}
} else {
snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
}
if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
if (res != IKS_OK) {
return -1;
}
return 0;
}
| static int aji_set_group_presence | ( | struct aji_client * | client, |
| char * | room, | ||
| int | level, | ||
| char * | nick, | ||
| char * | desc | ||
| ) | [static] |
Definition at line 3990 of file res_jabber.c.
References AJI_MAX_JIDLEN, ast_aji_send(), ast_log(), aji_client::component, aji_client::jid, LOG_ERROR, and MUC_NS.
Referenced by ast_aji_join_chat(), and ast_aji_leave_chat().
{
int res = 0;
iks *presence = NULL, *x = NULL;
char from[AJI_MAX_JIDLEN];
char roomid[AJI_MAX_JIDLEN];
presence = iks_make_pres(level, NULL);
x = iks_new("x");
if (client->component) {
snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
} else {
snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
}
if (!presence || !x || !client) {
ast_log(LOG_ERROR, "Out of memory.\n");
res = -1;
goto safeout;
} else {
iks_insert_attrib(presence, "to", roomid);
iks_insert_attrib(presence, "from", from);
iks_insert_attrib(x, "xmlns", MUC_NS);
iks_insert_node(presence, x);
res = ast_aji_send(client, presence);
}
safeout:
iks_delete(presence);
iks_delete(x);
return res;
}
| static void aji_set_presence | ( | struct aji_client * | client, |
| char * | to, | ||
| char * | from, | ||
| int | level, | ||
| char * | desc | ||
| ) | [static] |
Definition at line 3948 of file res_jabber.c.
References ast_aji_send(), ast_log(), LOG_ERROR, and aji_client::priority.
Referenced by aji_get_roster(), aji_handle_presence(), and aji_handle_subscribe().
{
iks *presence = iks_make_pres(level, desc);
iks *cnode = iks_new("c");
iks *priority = iks_new("priority");
char priorityS[10];
if (presence && cnode && client && priority) {
if (to) {
iks_insert_attrib(presence, "to", to);
}
if (from) {
iks_insert_attrib(presence, "from", from);
}
snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
iks_insert_cdata(priority, priorityS, strlen(priorityS));
iks_insert_node(presence, priority);
iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
iks_insert_attrib(cnode, "ext", "voice-v1");
iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
iks_insert_node(presence, cnode);
ast_aji_send(client, presence);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(cnode);
iks_delete(presence);
iks_delete(priority);
}
| static char * aji_show_buddies | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 4142 of file res_jabber.c.
References ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_resource::cap, CLI_GENERATE, CLI_INIT, clients, ast_cli_entry::command, ast_cli_args::fd, aji_version::jingle, aji_resource::next, aji_capabilities::node, aji_version::parent, aji_resource::priority, aji_resource::resource, aji_resource::status, ast_cli_entry::usage, and aji_version::version.
{
struct aji_resource *resource;
struct aji_client *client;
switch (cmd) {
case CLI_INIT:
e->command = "jabber show buddies";
e->usage =
"Usage: jabber show buddies\n"
" Shows buddy lists of our clients\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
ast_cli(a->fd, "Jabber buddy lists\n");
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
ast_cli(a->fd, "Client: %s\n", iterator->user);
client = iterator;
ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
ASTOBJ_RDLOCK(iterator);
ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
if (!iterator->resources)
ast_cli(a->fd, "\t\tResource: None\n");
for (resource = iterator->resources; resource; resource = resource->next) {
ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
if (resource->cap) {
ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
}
ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
}
ASTOBJ_UNLOCK(iterator);
});
iterator = client;
});
return CLI_SUCCESS;
}
| static char * aji_show_clients | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 4096 of file res_jabber.c.
References AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, status, and ast_cli_entry::usage.
{
char *status;
int count = 0;
switch (cmd) {
case CLI_INIT:
e->command = "jabber show connections";
e->usage =
"Usage: jabber show connections\n"
" Shows state of client and component connections\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
ast_cli(a->fd, "Jabber Users and their status:\n");
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
ASTOBJ_RDLOCK(iterator);
count++;
switch (iterator->state) {
case AJI_DISCONNECTED:
status = "Disconnected";
break;
case AJI_CONNECTING:
status = "Connecting";
break;
case AJI_CONNECTED:
status = "Connected";
break;
default:
status = "Unknown";
}
ast_cli(a->fd, " [%s] %s - %s\n", iterator->name, iterator->user, status);
ASTOBJ_UNLOCK(iterator);
});
ast_cli(a->fd, "----\n");
ast_cli(a->fd, " Number of users: %d\n", count);
return CLI_SUCCESS;
}
| static int aji_start_sasl | ( | struct aji_client * | client, |
| enum ikssasltype | type, | ||
| char * | username, | ||
| char * | pass | ||
| ) | [static] |
Definition at line 1522 of file res_jabber.c.
References aji_is_secure(), ast_aji_send(), ast_base64encode(), ast_log(), base64, len(), LOG_ERROR, and aji_client::p.
Referenced by aji_act_hook().
{
iks *x = NULL;
int len;
char *s;
char *base64;
/* trigger SASL DIGEST-MD5 only over an unsecured connection.
iks_start_sasl is an iksemel API function and relies on GnuTLS,
whereas we use OpenSSL */
if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass);
if (!(type & IKS_STREAM_SASL_PLAIN)) {
ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
return IKS_NET_NOTSUPP;
}
x = iks_new("auth");
if (!x) {
ast_log(LOG_ERROR, "Out of memory.\n");
return IKS_NET_NOTSUPP;
}
iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
len = strlen(username) + strlen(pass) + 3;
s = alloca(len);
base64 = alloca((len + 2) * 4 / 3);
iks_insert_attrib(x, "mechanism", "PLAIN");
snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
/* exclude the NULL training byte from the base64 encoding operation
as some XMPP servers will refuse it.
The format for authentication is [authzid]\0authcid\0password
not [authzid]\0authcid\0password\0 */
ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
iks_insert_cdata(x, base64, 0);
ast_aji_send(client, x);
iks_delete(x);
return IKS_OK;
}
| static int aji_start_tls | ( | struct aji_client * | client | ) | [static] |
Definition at line 1223 of file res_jabber.c.
References aji_client::p, aji_client::stream_flags, and TRY_SECURE.
Referenced by aji_act_hook().
{
int ret;
/* This is sent not encrypted */
if ((ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"))) {
return ret;
}
client->stream_flags |= TRY_SECURE;
return IKS_OK;
}
| static int aji_status_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 622 of file res_jabber.c.
References aji_find_resource(), args, ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_get_client(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, LOG_ERROR, LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), aji_resource::resource, aji_buddy::resources, aji_resource::status, and status.
Referenced by load_module().
{
struct aji_client *client = NULL;
struct aji_buddy *buddy = NULL;
struct aji_resource *r = NULL;
char *s = NULL;
int stat = 7;
char status[2];
static int deprecation_warning = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(sender);
AST_APP_ARG(jid);
AST_APP_ARG(variable);
);
AST_DECLARE_APP_ARGS(jid,
AST_APP_ARG(screenname);
AST_APP_ARG(resource);
);
if (deprecation_warning++ % 10 == 0) {
ast_log(LOG_WARNING, "JabberStatus is deprecated. Please use the JABBER_STATUS dialplan function in the future.\n");
}
if (!data) {
ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
return 0;
}
s = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, s);
if (args.argc != 3) {
ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
return -1;
}
AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
if (jid.argc < 1 || jid.argc > 2) {
ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
return -1;
}
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
if (!buddy) {
ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return -1;
}
r = aji_find_resource(buddy, jid.resource);
if (!r && buddy->resources) {
r = buddy->resources;
}
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
if (!r) {
ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
} else {
stat = r->status;
}
snprintf(status, sizeof(status), "%d", stat);
pbx_builtin_setvar_helper(chan, args.variable, status);
return 0;
}
| static char * aji_test | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 4189 of file res_jabber.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_aji_send_chat(), ast_cli(), ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_resource::cap, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, clients, ast_cli_entry::command, aji_resource::description, ast_cli_args::fd, aji_version::jingle, name, aji_resource::next, aji_capabilities::node, aji_version::parent, aji_resource::priority, aji_resource::resource, S_OR, aji_resource::status, ast_cli_entry::usage, and aji_version::version.
{
struct aji_client *client;
struct aji_resource *resource;
const char *name;
struct aji_message *tmp;
switch (cmd) {
case CLI_INIT:
e->command = "jabber test";
e->usage =
"Usage: jabber test <connection>\n"
" Sends test message for debugging purposes. A specific client\n"
" as configured in jabber.conf must be specified.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 3) {
return CLI_SHOWUSAGE;
}
name = a->argv[2];
if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
ast_cli(a->fd, "Unable to find client '%s'!\n", name);
return CLI_FAILURE;
}
/* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
ASTOBJ_RDLOCK(iterator);
ast_verbose("User: %s\n", iterator->name);
for (resource = iterator->resources; resource; resource = resource->next) {
ast_verbose("Resource: %s\n", resource->resource);
if (resource->cap) {
ast_verbose(" client: %s\n", resource->cap->parent->node);
ast_verbose(" version: %s\n", resource->cap->version);
ast_verbose(" Jingle Capable: %d\n", resource->cap->jingle);
}
ast_verbose(" Priority: %d\n", resource->priority);
ast_verbose(" Status: %d\n", resource->status);
ast_verbose(" Message: %s\n", S_OR(resource->description, ""));
}
ASTOBJ_UNLOCK(iterator);
});
ast_verbose("\nOooh a working message stack!\n");
AST_LIST_LOCK(&client->messages);
AST_LIST_TRAVERSE(&client->messages, tmp, list) {
//ast_verbose(" Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
}
AST_LIST_UNLOCK(&client->messages);
ASTOBJ_UNREF(client, ast_aji_client_destroy);
return CLI_SUCCESS;
}
| static int aji_tls_handshake | ( | struct aji_client * | client | ) | [static] |
Definition at line 1242 of file res_jabber.c.
References aji_send_header(), ast_debug, aji_client::jid, aji_client::p, SECURE, aji_client::ssl_context, aji_client::ssl_method, aji_client::ssl_session, aji_client::stream_flags, and TRY_SECURE.
Referenced by aji_act_hook().
{
int ret;
int sock;
ast_debug(1, "Starting TLS handshake\n");
/* Choose an SSL/TLS protocol version, create SSL_CTX */
client->ssl_method = SSLv3_method();
if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
return IKS_NET_TLSFAIL;
}
/* Create new SSL session */
if (!(client->ssl_session = SSL_new(client->ssl_context))) {
return IKS_NET_TLSFAIL;
}
/* Enforce TLS on our XMPP connection */
sock = iks_fd(client->p);
if (!(ret = SSL_set_fd(client->ssl_session, sock))) {
return IKS_NET_TLSFAIL;
}
/* Perform SSL handshake */
if (!(ret = SSL_connect(client->ssl_session))) {
return IKS_NET_TLSFAIL;
}
client->stream_flags &= (~TRY_SECURE);
client->stream_flags |= SECURE;
/* Sent over the established TLS connection */
if ((ret = aji_send_header(client, client->jid->server)) != IKS_OK) {
return IKS_NET_TLSFAIL;
}
ast_debug(1, "TLS started with server\n");
return IKS_OK;
}
| void ast_aji_buddy_destroy | ( | struct aji_buddy * | obj | ) |
Destructor function for buddies to be used with ASTOBJ_UNREF
Definition at line 434 of file res_jabber.c.
References ast_free, aji_resource::description, aji_resource::next, and aji_buddy::resources.
Referenced by acf_jabberstatus_read(), aji_client_info_handler(), aji_create_buddy(), aji_dinfo_handler(), aji_handle_presence(), aji_handle_subscribe(), aji_register_query_handler(), aji_status_exec(), ast_aji_client_destroy(), gtalk_alloc(), and jingle_alloc().
{
struct aji_resource *tmp;
while ((tmp = obj->resources)) {
obj->resources = obj->resources->next;
ast_free(tmp->description);
ast_free(tmp);
}
ast_free(obj);
}
| void ast_aji_client_destroy | ( | struct aji_client * | obj | ) |
Destructor function for clients to be used with ASTOBJ_UNREF after calls to ast_aji_get_client
Definition at line 412 of file res_jabber.c.
References aji_message_destroy(), ast_aji_buddy_destroy(), ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, aji_client::buddies, aji_client::f, aji_message::list, aji_client::messages, aji_client::p, and aji_client::stack.
Referenced by acf_jabberreceive_read(), acf_jabberstatus_read(), aji_act_hook(), aji_cli_create_collection(), aji_cli_create_leafnode(), aji_cli_delete_pubsub_node(), aji_cli_list_pubsub_nodes(), aji_cli_purge_pubsub_nodes(), aji_client_connect(), aji_client_info_handler(), aji_create_client(), aji_devstate_cb(), aji_dinfo_handler(), aji_ditems_handler(), aji_handle_pubsub_error(), aji_join_exec(), aji_leave_exec(), aji_log_hook(), aji_mwi_cb(), aji_receive_node_list(), aji_recv_loop(), aji_register_approve_handler(), aji_register_query_handler(), aji_reload(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), ast_aji_disconnect(), gtalk_load_config(), gtalk_newcall(), gtalk_request(), jingle_load_config(), jingle_newcall(), jingle_request(), manager_jabber_send(), and unload_module().
{
struct aji_message *tmp;
ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy);
ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
iks_filter_delete(obj->f);
iks_parser_delete(obj->p);
iks_stack_delete(obj->stack);
AST_LIST_LOCK(&obj->messages);
while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
aji_message_destroy(tmp);
}
AST_LIST_HEAD_DESTROY(&obj->messages);
ast_free(obj);
}
| int ast_aji_create_chat | ( | struct aji_client * | client, |
| char * | room, | ||
| char * | server, | ||
| char * | topic | ||
| ) |
create a chatroom.
| client | the configured XMPP client we use to connect to a XMPP server |
| room | name of room |
| server | name of server |
| topic | topic for the room. |
Definition at line 2635 of file res_jabber.c.
References ast_aji_increment_mid(), ast_aji_send(), ast_log(), LOG_ERROR, and aji_client::mid.
{
int res = 0;
iks *iq = NULL;
iq = iks_new("iq");
if (iq && client) {
iks_insert_attrib(iq, "type", "get");
iks_insert_attrib(iq, "to", server);
iks_insert_attrib(iq, "id", client->mid);
ast_aji_increment_mid(client->mid);
ast_aji_send(client, iq);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(iq);
return res;
}
| int ast_aji_disconnect | ( | struct aji_client * | client | ) |
disconnect from jabber server.
| client | the configured XMPP client we use to connect to a XMPP server |
Definition at line 3142 of file res_jabber.c.
References ast_aji_client_destroy(), ast_verb, ASTOBJ_UNREF, aji_client::p, SECURE, aji_client::ssl_context, aji_client::ssl_session, and aji_client::stream_flags.
Referenced by unload_module().
{
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, ast_aji_client_destroy);
}
return 1;
}
| struct aji_client* ast_aji_get_client | ( | const char * | name | ) | [read] |
grab a aji_client structure by label name or JID. Bumps the refcount. (without the resource string)
| name | label or JID |
Definition at line 4595 of file res_jabber.c.
References ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, clients, and strsep().
Referenced by acf_jabberreceive_read(), acf_jabberstatus_read(), aji_join_exec(), aji_leave_exec(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), gtalk_create_member(), gtalk_newcall(), gtalk_request(), jingle_create_member(), jingle_newcall(), jingle_request(), and manager_jabber_send().
{
struct aji_client *client = NULL;
char *aux = NULL;
client = ASTOBJ_CONTAINER_FIND(&clients, name);
if (!client && strchr(name, '@')) {
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
aux = ast_strdupa(iterator->user);
if (strchr(aux, '/')) {
/* strip resource for comparison */
aux = strsep(&aux, "/");
}
if (!strncasecmp(aux, name, strlen(aux))) {
client = ASTOBJ_REF(iterator);
}
});
}
return client;
}
| struct aji_client_container* ast_aji_get_clients | ( | void | ) | [read] |
Definition at line 4617 of file res_jabber.c.
References clients.
Referenced by gtalk_load_config(), and jingle_load_config().
{
return &clients;
}
| void ast_aji_increment_mid | ( | char * | mid | ) |
increments the mid field for messages and other events.
| mid | char. |
Definition at line 2779 of file res_jabber.c.
Referenced by aji_act_hook(), aji_handle_presence(), aji_pubsub_iq_create(), aji_register_approve_handler(), ast_aji_create_chat(), ast_aji_invite_chat(), gtalk_action(), gtalk_create_candidates(), gtalk_invite(), jingle_accept_call(), jingle_action(), jingle_create_candidates(), jingle_digit(), and jingle_transmit_invite().
| int ast_aji_invite_chat | ( | struct aji_client * | client, |
| char * | user, | ||
| char * | room, | ||
| char * | message | ||
| ) |
invite to a chatroom.
| client | the configured XMPP client we use to connect to a XMPP server |
| user | |
| room | |
| message |
Definition at line 2687 of file res_jabber.c.
References ast_aji_increment_mid(), ast_aji_send(), ast_log(), LOG_ERROR, and aji_client::mid.
{
int res = 0;
iks *invite, *body, *namespace;
invite = iks_new("message");
body = iks_new("body");
namespace = iks_new("x");
if (client && invite && body && namespace) {
iks_insert_attrib(invite, "to", user);
iks_insert_attrib(invite, "id", client->mid);
ast_aji_increment_mid(client->mid);
iks_insert_cdata(body, message, 0);
iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
iks_insert_attrib(namespace, "jid", room);
iks_insert_node(invite, body);
iks_insert_node(invite, namespace);
res = ast_aji_send(client, invite);
} else {
ast_log(LOG_ERROR, "Out of memory.\n");
}
iks_delete(body);
iks_delete(namespace);
iks_delete(invite);
return res;
}
| int ast_aji_join_chat | ( | struct aji_client * | client, |
| char * | room, | ||
| char * | nick | ||
| ) |
join a chatroom.
| client | the configured XMPP client we use to connect to a XMPP server |
| room | room to join |
| nick | the nickname to use in this room |
Definition at line 2663 of file res_jabber.c.
References aji_set_group_presence().
Referenced by aji_join_exec().
{
return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
}
| int ast_aji_leave_chat | ( | struct aji_client * | client, |
| char * | room, | ||
| char * | nick | ||
| ) |
leave a chatroom.
| client | the configured XMPP client we use to connect to a XMPP server |
| room | room to leave |
| nick | the nickname used in this room |
Definition at line 2675 of file res_jabber.c.
References aji_set_group_presence().
Referenced by aji_leave_exec().
{
return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
}
| int ast_aji_send | ( | struct aji_client * | client, |
| iks * | x | ||
| ) |
Wraps raw sending.
| client | the configured XMPP client we use to connect to a XMPP server |
| x | the XMPP packet to send |
Definition at line 1439 of file res_jabber.c.
References aji_send_raw().
Referenced by aji_act_hook(), aji_client_info_handler(), aji_create_pubsub_node(), aji_delete_pubsub_node(), aji_dinfo_handler(), aji_ditems_handler(), aji_get_roster(), aji_handle_presence(), aji_handle_pubsub_error(), aji_handle_subscribe(), aji_pruneregister(), aji_publish_device_state(), aji_publish_mwi(), aji_pubsub_purge_nodes(), aji_pubsub_subscribe(), aji_register_approve_handler(), aji_register_query_handler(), aji_request_pubsub_nodes(), aji_send_raw_chat(), aji_set_group_presence(), aji_set_presence(), aji_start_sasl(), ast_aji_create_chat(), ast_aji_invite_chat(), gtalk_action(), gtalk_add_candidate(), gtalk_create_candidates(), gtalk_invite(), gtalk_response(), jingle_accept_call(), jingle_action(), jingle_add_candidate(), jingle_create_candidates(), jingle_digit(), jingle_response(), and jingle_transmit_invite().
{
return aji_send_raw(client, iks_string(iks_stack(x), x));
}
| int ast_aji_send_chat | ( | struct aji_client * | client, |
| const char * | address, | ||
| const char * | message | ||
| ) |
sends messages.
| client | the configured XMPP client we use to connect to a XMPP server |
| address | |
| message |
| IKS_OK | success |
| -1 | failure |
Definition at line 2571 of file res_jabber.c.
References aji_send_raw_chat().
Referenced by aji_send_exec(), aji_test(), gtalk_sendtext(), jingle_sendtext(), and manager_jabber_send().
{
return aji_send_raw_chat(client, 0, NULL, address, message);
}
| int ast_aji_send_groupchat | ( | struct aji_client * | client, |
| const char * | nick, | ||
| const char * | address, | ||
| const char * | message | ||
| ) |
sends message to a groupchat Prior to sending messages to a groupchat, one must be connected to it.
| client | the configured XMPP client we use to connect to a XMPP server |
| nick | the nickname we use in the chatroom |
| address | the user the messages must be sent to |
| message | the message to send |
Definition at line 2585 of file res_jabber.c.
References aji_send_raw_chat().
Referenced by aji_sendgroup_exec().
{
return aji_send_raw_chat(client, 1, nick, address, message);
}
| static int delete_old_messages | ( | struct aji_client * | client, |
| char * | from | ||
| ) | [static] |
Definition at line 932 of file res_jabber.c.
References aji_message_destroy(), aji_message::arrived, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_sec(), ast_tvnow(), aji_message::from, aji_message::list, LOG_ERROR, aji_client::message_timeout, and aji_client::messages.
Referenced by aji_handle_message(), and delete_old_messages_all().
{
int deleted = 0;
int isold = 0;
struct aji_message *tmp = NULL;
if (!client) {
ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
return -1;
}
/* remove old messages */
AST_LIST_LOCK(&client->messages);
if (AST_LIST_EMPTY(&client->messages)) {
AST_LIST_UNLOCK(&client->messages);
return 0;
}
AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
if (isold) {
if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
AST_LIST_REMOVE_CURRENT(list);
aji_message_destroy(tmp);
deleted ++;
}
} else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
isold = 1;
if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
AST_LIST_REMOVE_CURRENT(list);
aji_message_destroy(tmp);
deleted ++;
}
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&client->messages);
return deleted;
}
| static int delete_old_messages_all | ( | struct aji_client * | client | ) | [static] |
Definition at line 979 of file res_jabber.c.
References delete_old_messages().
Referenced by aji_recv_loop().
{
return delete_old_messages(client, NULL);
}
| static int gtalk_yuck | ( | iks * | node | ) | [static] |
Definition at line 568 of file res_jabber.c.
References ast_debug.
Referenced by aji_handle_presence().
{
if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
ast_debug(1, "Found resource with Googletalk voice capabilities\n");
return 1;
} else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) {
ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n");
return 1;
} else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) {
ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n");
return 1;
}
return 0;
}
| static iks * jabber_make_auth | ( | iksid * | id, |
| const char * | pass, | ||
| const char * | sid | ||
| ) | [static] |
Definition at line 592 of file res_jabber.c.
References ast_sha1_hash().
Referenced by aji_act_hook().
{
iks *x, *y;
x = iks_new("iq");
iks_insert_attrib(x, "type", "set");
y = iks_insert(x, "query");
iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
if (sid) {
char buf[41];
char sidpass[100];
snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
ast_sha1_hash(buf, sidpass);
iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
} else {
iks_insert_cdata(iks_insert(y, "password"), pass, 0);
}
return x;
}
| static int load_module | ( | void | ) | [static] |
Definition at line 4749 of file res_jabber.c.
References aji_join_exec(), aji_leave_exec(), aji_reload(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_cond_init, ast_custom_function_register, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, ast_mutex_init, ast_register_application_xml, ASTOBJ_CONTAINER_INIT, clients, EVENT_FLAG_SYSTEM, and manager_jabber_send().
{
ASTOBJ_CONTAINER_INIT(&clients);
if (!aji_reload(0))
return AST_MODULE_LOAD_DECLINE;
ast_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send);
ast_register_application_xml(app_ajisend, aji_send_exec);
ast_register_application_xml(app_ajisendgroup, aji_sendgroup_exec);
ast_register_application_xml(app_ajistatus, aji_status_exec);
ast_register_application_xml(app_ajijoin, aji_join_exec);
ast_register_application_xml(app_ajileave, aji_leave_exec);
ast_cli_register_multiple(aji_cli, ARRAY_LEN(aji_cli));
ast_custom_function_register(&jabberstatus_function);
ast_custom_function_register(&jabberreceive_function);
ast_mutex_init(&messagelock);
ast_cond_init(&message_received_condition, NULL);
return 0;
}
| static int manager_jabber_send | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 4629 of file res_jabber.c.
References ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_send_chat(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), astman_send_error(), and ASTOBJ_UNREF.
Referenced by load_module().
{
struct aji_client *client = NULL;
const char *id = astman_get_header(m, "ActionID");
const char *jabber = astman_get_header(m, "Jabber");
const char *screenname = astman_get_header(m, "ScreenName");
const char *message = astman_get_header(m, "Message");
if (ast_strlen_zero(jabber)) {
astman_send_error(s, m, "No transport specified");
return 0;
}
if (ast_strlen_zero(screenname)) {
astman_send_error(s, m, "No ScreenName specified");
return 0;
}
if (ast_strlen_zero(message)) {
astman_send_error(s, m, "No Message specified");
return 0;
}
astman_send_ack(s, m, "Attempting to send Jabber Message");
client = ast_aji_get_client(jabber);
if (!client) {
astman_send_error(s, m, "Could not find Sender");
return 0;
}
if (strchr(screenname, '@') && message) {
ast_aji_send_chat(client, screenname, message);
astman_append(s, "Response: Success\r\n");
} else {
astman_append(s, "Response: Error\r\n");
}
ASTOBJ_UNREF(client, ast_aji_client_destroy);
if (!ast_strlen_zero(id)) {
astman_append(s, "ActionID: %s\r\n", id);
}
astman_append(s, "\r\n");
return 0;
}
| static int reload | ( | void | ) | [static] |
| static int unload_module | ( | void | ) | [static] |
Definition at line 4708 of file res_jabber.c.
References AJI_DISCONNECTING, ARRAY_LEN, ast_aji_client_destroy(), ast_aji_disconnect(), ast_cli_unregister_multiple(), ast_cond_destroy, ast_custom_function_unregister(), ast_debug, ast_event_unsubscribe(), ast_manager_unregister(), ast_mutex_destroy, ast_unregister_application(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, and clients.
{
ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
ast_unregister_application(app_ajisend);
ast_unregister_application(app_ajisendgroup);
ast_unregister_application(app_ajistatus);
ast_unregister_application(app_ajijoin);
ast_unregister_application(app_ajileave);
ast_manager_unregister("JabberSend");
ast_custom_function_unregister(&jabberstatus_function);
if (mwi_sub) {
ast_event_unsubscribe(mwi_sub);
}
if (device_state_sub) {
ast_event_unsubscribe(device_state_sub);
}
ast_custom_function_unregister(&jabberreceive_function);
ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
ASTOBJ_WRLOCK(iterator);
ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
iterator->state = AJI_DISCONNECTING;
ASTOBJ_UNLOCK(iterator);
pthread_join(iterator->thread, NULL);
ast_aji_disconnect(iterator);
});
ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
ASTOBJ_CONTAINER_DESTROY(&clients);
ast_cond_destroy(&message_received_condition);
ast_mutex_destroy(&messagelock);
return 0;
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "AJI - Asterisk Jabber Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static] |
Definition at line 4784 of file res_jabber.c.
struct ast_cli_entry aji_cli[] [static] |
Definition at line 375 of file res_jabber.c.
char* app_ajijoin = "JabberJoin" [static] |
Definition at line 391 of file res_jabber.c.
char* app_ajileave = "JabberLeave" [static] |
Definition at line 392 of file res_jabber.c.
char* app_ajisend = "JabberSend" [static] |
Definition at line 388 of file res_jabber.c.
char* app_ajisendgroup = "JabberSendGroup" [static] |
Definition at line 389 of file res_jabber.c.
char* app_ajistatus = "JabberStatus" [static] |
Definition at line 390 of file res_jabber.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 4784 of file res_jabber.c.
struct aji_capabilities* capabilities = NULL [static] |
Definition at line 395 of file res_jabber.c.
Referenced by aji_find_version(), ast_request(), and set_peer_capabilities().
struct aji_client_container clients [static] |
Definition at line 394 of file res_jabber.c.
Referenced by aji_cli_create_collection(), aji_cli_create_leafnode(), aji_cli_delete_pubsub_node(), aji_cli_list_pubsub_nodes(), aji_cli_purge_pubsub_nodes(), aji_create_client(), aji_do_set_debug(), aji_reload(), aji_show_buddies(), aji_show_clients(), aji_test(), ast_aji_get_client(), ast_aji_get_clients(), gtalk_load_config(), jingle_load_config(), load_module(), and unload_module().
struct ast_event_sub* device_state_sub = NULL [static] |
Definition at line 397 of file res_jabber.c.
struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT } [static] |
Global flags, initialized to default values.
Definition at line 402 of file res_jabber.c.
struct ast_custom_function jabberreceive_function [static] |
{
.name = "JABBER_RECEIVE",
.read = acf_jabberreceive_read,
}
Definition at line 918 of file res_jabber.c.
struct ast_custom_function jabberstatus_function [static] |
{
.name = "JABBER_STATUS",
.read = acf_jabberstatus_read,
}
Definition at line 755 of file res_jabber.c.
ast_cond_t message_received_condition [static] |
Definition at line 398 of file res_jabber.c.
ast_mutex_t messagelock [static] |
Definition at line 399 of file res_jabber.c.
struct ast_event_sub* mwi_sub = NULL [static] |
Definition at line 396 of file res_jabber.c.
Referenced by handle_subscribe(), handle_unsubscribe(), and poll_subscribed_mailboxes().
struct ast_flags pubsubflags = { 0 } [static] |
PubSub flags, initialized to default values.
Definition at line 405 of file res_jabber.c.