Fri Aug 17 00:17:47 2018

Asterisk developer's documentation


res_jabber.c File Reference

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, unsigned int cachable)
 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_resourceaji_find_resource (struct aji_buddy *buddy, char *name)
static struct aji_versionaji_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, unsigned int cachable)
 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 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_clientast_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_containerast_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 = "ac1f6a56484a8820659555499174e588" , .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_infoast_module_info = &__mod_info
static struct aji_capabilitiescapabilities = NULL
static struct aji_client_container clients
static struct ast_event_subdevice_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_submwi_sub = NULL
static struct ast_flags pubsubflags = { 0 }
 PubSub flags, initialized to default values.

Detailed Description

A resource for interfacing Asterisk directly as a client or a component to a XMPP/Jabber compliant server.

References:

ExtRef:
Iksemel http://code.google.com/p/iksemel/
Todo:

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 Documentation

#define JABBER_CONFIG   "jabber.conf"
Todo:
This should really be renamed to xmpp.conf. For backwards compatibility, we need to read both files

Definition at line 285 of file res_jabber.c.

Referenced by aji_load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4764 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

Definition at line 4764 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 767 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, and parse().

00768 {
00769    char *parse = NULL;
00770    int timeout;
00771    int jidlen, resourcelen;
00772    struct timeval start;
00773    long diff = 0;
00774    struct aji_client *client = NULL;
00775    int found = 0;
00776    struct aji_message *tmp = NULL;
00777    AST_DECLARE_APP_ARGS(args,
00778          AST_APP_ARG(account);
00779          AST_APP_ARG(jid);
00780          AST_APP_ARG(timeout);
00781          );
00782    AST_DECLARE_APP_ARGS(jid,
00783          AST_APP_ARG(screenname);
00784          AST_APP_ARG(resource);
00785    );
00786 
00787    if (ast_strlen_zero(data)) {
00788       ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
00789       return -1;
00790    }
00791 
00792    parse = ast_strdupa(data);
00793    AST_STANDARD_APP_ARGS(args, parse);
00794 
00795    if (args.argc < 2 || args.argc > 3) {
00796       ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
00797       return -1;
00798    }
00799 
00800    parse = ast_strdupa(args.jid);
00801    AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
00802    if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
00803       ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
00804       return -1;
00805    }
00806 
00807    if (ast_strlen_zero(args.timeout)) {
00808       timeout = 20;
00809    } else {
00810       sscanf(args.timeout, "%d", &timeout);
00811       if (timeout <= 0) {
00812          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
00813          return -1;
00814       }
00815    }
00816 
00817    jidlen = strlen(jid.screenname);
00818    resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
00819 
00820    client = ast_aji_get_client(args.account);
00821    if (!client) {
00822       ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
00823       return -1;
00824    }
00825 
00826    ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
00827 
00828    start = ast_tvnow();
00829 
00830    if (chan && ast_autoservice_start(chan) < 0) {
00831       ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", chan->name);
00832       ASTOBJ_UNREF(client, ast_aji_client_destroy);
00833       return -1;
00834    }
00835 
00836    /* search the messages list, grab the first message that matches with
00837     * the from JID we're expecting, and remove it from the messages list */
00838    while (diff < timeout) {
00839       struct timespec ts = { 0, };
00840       struct timeval wait;
00841       int res;
00842 
00843       wait = ast_tvadd(start, ast_tv(timeout, 0));
00844       ts.tv_sec = wait.tv_sec;
00845       ts.tv_nsec = wait.tv_usec * 1000;
00846 
00847       /* wait up to timeout seconds for an incoming message */
00848       ast_mutex_lock(&messagelock);
00849       res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
00850       ast_mutex_unlock(&messagelock);
00851       if (res == ETIMEDOUT) {
00852          ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
00853          break;
00854       }
00855 
00856       AST_LIST_LOCK(&client->messages);
00857       AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
00858          if (jid.argc == 1) {
00859             /* no resource provided, compare bare JIDs */
00860             if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
00861                continue;
00862             }
00863          } else {
00864             /* resource appended, compare bare JIDs and resources */
00865             char *resource = strchr(tmp->from, '/');
00866             if (!resource || strlen(resource) == 0) {
00867                ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from);
00868                if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
00869                   continue;
00870                }
00871             } else {
00872                resource ++;
00873                if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
00874                   continue;
00875                }
00876             }
00877          }
00878          /* check if the message is not too old */
00879          if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
00880             ast_debug(3, "Found old message from %s, deleting it\n", tmp->from);
00881             AST_LIST_REMOVE_CURRENT(list);
00882             aji_message_destroy(tmp);
00883             continue;
00884          }
00885          found = 1;
00886          ast_copy_string(buf, tmp->message, buflen);
00887          AST_LIST_REMOVE_CURRENT(list);
00888          aji_message_destroy(tmp);
00889          break;
00890       }
00891       AST_LIST_TRAVERSE_SAFE_END;
00892       AST_LIST_UNLOCK(&client->messages);
00893       if (found) {
00894          break;
00895       }
00896 
00897       /* check timeout */
00898       diff = ast_tvdiff_ms(ast_tvnow(), start);
00899    }
00900 
00901    ASTOBJ_UNREF(client, ast_aji_client_destroy);
00902    if (chan && ast_autoservice_stop(chan) < 0) {
00903       ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", chan->name);
00904    }
00905 
00906    /* return if we timed out */
00907    if (!found) {
00908       ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
00909       return -1;
00910    }
00911 
00912    return 0;
00913 }

static int acf_jabberstatus_read ( struct ast_channel chan,
const char *  name,
char *  data,
char *  buf,
size_t  buflen 
) [static]

Definition at line 696 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.

00697 {
00698    struct aji_client *client = NULL;
00699    struct aji_buddy *buddy = NULL;
00700    struct aji_resource *r = NULL;
00701    int stat = 7;
00702    AST_DECLARE_APP_ARGS(args,
00703       AST_APP_ARG(sender);
00704       AST_APP_ARG(jid);
00705    );
00706    AST_DECLARE_APP_ARGS(jid,
00707       AST_APP_ARG(screenname);
00708       AST_APP_ARG(resource);
00709    );
00710 
00711    if (!data) {
00712       ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
00713       return 0;
00714    }
00715    AST_STANDARD_APP_ARGS(args, data);
00716 
00717    if (args.argc != 2) {
00718       ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
00719       return -1;
00720    }
00721 
00722    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00723    if (jid.argc < 1 || jid.argc > 2) {
00724       ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
00725       return -1;
00726    }
00727 
00728    if (!(client = ast_aji_get_client(args.sender))) {
00729       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00730       return -1;
00731    }
00732    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00733    if (!buddy) {
00734       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00735       ASTOBJ_UNREF(client, ast_aji_client_destroy);
00736       return -1;
00737    }
00738    r = aji_find_resource(buddy, jid.resource);
00739    if (!r && buddy->resources) {
00740       r = buddy->resources;
00741    }
00742    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
00743    ASTOBJ_UNREF(client, ast_aji_client_destroy);
00744    if (!r) {
00745       ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
00746    } else {
00747       stat = r->status;
00748    }
00749    snprintf(buf, buflen, "%d", stat);
00750    return 0;
00751 }

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(), ast_aji_client_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_asprintf, 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().

01573 {
01574    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01575    ikspak *pak = NULL;
01576    iks *auth = NULL;
01577    int features = 0;
01578 
01579    if (!node) {
01580       ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
01581       ASTOBJ_UNREF(client, ast_aji_client_destroy);
01582       return IKS_HOOK;
01583    }
01584 
01585    if (client->state == AJI_DISCONNECTING) {
01586       ASTOBJ_UNREF(client, ast_aji_client_destroy);
01587       return IKS_HOOK;
01588    }
01589 
01590    pak = iks_packet(node);
01591 
01592    /* work around iksemel's impossibility to recognize node names
01593     * containing a semicolon. Set the namespace of the corresponding
01594     * node accordingly. */
01595    if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
01596       char *node_ns = NULL;
01597       char attr[AJI_MAX_ATTRLEN];
01598       char *node_name = iks_name(iks_child(node));
01599       char *aux = strchr(node_name, ':') + 1;
01600       snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
01601       node_ns = iks_find_attrib(iks_child(node), attr);
01602       if (node_ns) {
01603          pak->ns = node_ns;
01604          pak->query = iks_child(node);
01605       }
01606    }
01607 
01608 
01609    if (!client->component) { /*client */
01610       switch (type) {
01611       case IKS_NODE_START:
01612          if (client->usetls && !aji_is_secure(client)) {
01613 #ifndef HAVE_OPENSSL
01614             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");
01615             ASTOBJ_UNREF(client, ast_aji_client_destroy);
01616             return IKS_HOOK;
01617 #else
01618             if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
01619                ast_log(LOG_ERROR, "Could not start TLS\n");
01620                ASTOBJ_UNREF(client, ast_aji_client_destroy);
01621                return IKS_HOOK;
01622             }
01623 #endif
01624             break;
01625          }
01626          if (!client->usesasl) {
01627             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);
01628             auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
01629             if (auth) {
01630                iks_insert_attrib(auth, "id", client->mid);
01631                iks_insert_attrib(auth, "to", client->jid->server);
01632                ast_aji_increment_mid(client->mid);
01633                ast_aji_send(client, auth);
01634                iks_delete(auth);
01635             } else {
01636                ast_log(LOG_ERROR, "Out of memory.\n");
01637             }
01638          }
01639          break;
01640 
01641       case IKS_NODE_NORMAL:
01642 #ifdef HAVE_OPENSSL
01643          if (client->stream_flags & TRY_SECURE) {
01644             if (!strcmp("proceed", iks_name(node))) {
01645                return aji_tls_handshake(client);
01646             }
01647          }
01648 #endif
01649          if (!strcmp("stream:features", iks_name(node))) {
01650             features = iks_stream_features(node);
01651             if (client->usesasl) {
01652                if (client->usetls && !aji_is_secure(client)) {
01653                   break;
01654                }
01655                if (client->authorized) {
01656                   if (features & IKS_STREAM_BIND) {
01657                      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);
01658                      auth = iks_make_resource_bind(client->jid);
01659                      if (auth) {
01660                         iks_insert_attrib(auth, "id", client->mid);
01661                         ast_aji_increment_mid(client->mid);
01662                         ast_aji_send(client, auth);
01663                         iks_delete(auth);
01664                      } else {
01665                         ast_log(LOG_ERROR, "Out of memory.\n");
01666                         break;
01667                      }
01668                   }
01669                   if (features & IKS_STREAM_SESSION) {
01670                      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);
01671                      auth = iks_make_session();
01672                      if (auth) {
01673                         iks_insert_attrib(auth, "id", "auth");
01674                         ast_aji_increment_mid(client->mid);
01675                         ast_aji_send(client, auth);
01676                         iks_delete(auth);
01677                      } else {
01678                         ast_log(LOG_ERROR, "Out of memory.\n");
01679                      }
01680                   }
01681                } else {
01682                   int ret;
01683                   if (!client->jid->user) {
01684                      ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
01685                      break;
01686                   }
01687 
01688                   ret = aji_start_sasl(client, features, client->jid->user, client->password);
01689                   if (ret != IKS_OK) {
01690                      ASTOBJ_UNREF(client, ast_aji_client_destroy);
01691                      return IKS_HOOK;
01692                   }
01693                   break;
01694                }
01695             }
01696          } else if (!strcmp("failure", iks_name(node))) {
01697             ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
01698          } else if (!strcmp("success", iks_name(node))) {
01699             client->authorized = 1;
01700             aji_send_header(client, client->jid->server);
01701          }
01702          break;
01703       case IKS_NODE_ERROR:
01704          ast_log(LOG_ERROR, "JABBER: Node Error\n");
01705          ASTOBJ_UNREF(client, ast_aji_client_destroy);
01706          return IKS_HOOK;
01707          break;
01708       case IKS_NODE_STOP:
01709          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01710          ASTOBJ_UNREF(client, ast_aji_client_destroy);
01711          return IKS_HOOK;
01712          break;
01713       }
01714    } else if (client->state != AJI_CONNECTED && client->component) {
01715       switch (type) {
01716       case IKS_NODE_START:
01717          if (client->state == AJI_DISCONNECTED) {
01718             char secret[160], shasum[320], *handshake;
01719 
01720             sprintf(secret, "%s%s", pak->id, client->password);
01721             ast_sha1_hash(shasum, secret);
01722             if (ast_asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
01723                aji_send_raw(client, handshake);
01724                ast_free(handshake);
01725             }
01726             client->state = AJI_CONNECTING;
01727             if (aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
01728                client->state = AJI_CONNECTED;
01729             else
01730                ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
01731             break;
01732          }
01733          break;
01734 
01735       case IKS_NODE_NORMAL:
01736          break;
01737 
01738       case IKS_NODE_ERROR:
01739          ast_log(LOG_ERROR, "JABBER: Node Error\n");
01740          ASTOBJ_UNREF(client, ast_aji_client_destroy);
01741          return IKS_HOOK;
01742 
01743       case IKS_NODE_STOP:
01744          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01745          ASTOBJ_UNREF(client, ast_aji_client_destroy);
01746          return IKS_HOOK;
01747       }
01748    }
01749 
01750    switch (pak->type) {
01751    case IKS_PAK_NONE:
01752       ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
01753       break;
01754    case IKS_PAK_MESSAGE:
01755       aji_handle_message(client, pak);
01756       ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
01757       break;
01758    case IKS_PAK_PRESENCE:
01759       aji_handle_presence(client, pak);
01760       ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
01761       break;
01762    case IKS_PAK_S10N:
01763       aji_handle_subscribe(client, pak);
01764       ast_debug(1, "JABBER: Handling paktype S10N\n");
01765       break;
01766    case IKS_PAK_IQ:
01767       ast_debug(1, "JABBER: Handling paktype IQ\n");
01768       aji_handle_iq(client, node);
01769       break;
01770    default:
01771       ast_debug(1, "JABBER: I don't know anything about paktype '%u'\n", pak->type);
01772       break;
01773    }
01774 
01775    iks_filter_packet(client->f, pak);
01776 
01777    if (node)
01778       iks_delete(node);
01779 
01780    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01781    return IKS_OK;
01782 }

static iks * aji_build_node_config ( iks *  pubsub,
const char *  node_type,
const char *  collection_name 
) [static]

Definition at line 3856 of file res_jabber.c.

Referenced by aji_create_pubsub_node().

03857 {
03858    iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
03859       *field_deliver_payload, *field_persist_items, *field_access_model,
03860       *field_pubsub_collection;
03861    configure = iks_insert(pubsub, "configure");
03862    x = iks_insert(configure, "x");
03863    iks_insert_attrib(x, "xmlns", "jabber:x:data");
03864    iks_insert_attrib(x, "type", "submit");
03865    field_owner = iks_insert(x, "field");
03866    iks_insert_attrib(field_owner, "var", "FORM_TYPE");
03867    iks_insert_attrib(field_owner, "type", "hidden");
03868    iks_insert_cdata(iks_insert(field_owner, "value"),
03869       "http://jabber.org/protocol/pubsub#owner", 39);
03870    if (node_type) {
03871       field_node_type = iks_insert(x, "field");
03872       iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
03873       iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
03874    }
03875    field_node_config = iks_insert(x, "field");
03876    iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
03877    iks_insert_attrib(field_node_config, "type", "hidden");
03878    iks_insert_cdata(iks_insert(field_node_config, "value"),
03879       "http://jabber.org/protocol/pubsub#node_config", 45);
03880    field_deliver_payload = iks_insert(x, "field");
03881    iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
03882    iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
03883    field_persist_items = iks_insert(x, "field");
03884    iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
03885    iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
03886    field_access_model = iks_insert(x, "field");
03887    iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
03888    iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
03889    if (node_type && !strcasecmp(node_type, "leaf")) {
03890       field_pubsub_collection = iks_insert(x, "field");
03891       iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
03892       iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
03893          strlen(collection_name));
03894    }
03895    return configure;
03896 }

static iks * aji_build_node_request ( struct aji_client client,
const char *  collection 
) [static]

Build the a node request.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
collection name of the collection for request
Returns:
iks*

Definition at line 3586 of file res_jabber.c.

References aji_pubsub_iq_create().

Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().

03587 {
03588    iks *request = aji_pubsub_iq_create(client, "get");
03589    iks *query;
03590    query = iks_insert(request, "query");
03591    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03592    if (collection) {
03593       iks_insert_attrib(query, "node", collection);
03594    }
03595    return request;
03596 }

static iks * aji_build_publish_skeleton ( struct aji_client client,
const char *  node,
const char *  event_type,
unsigned int  cachable 
) [static]

Build the skeleton of a publish.

Parameters:
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 
Returns:
iks *

Definition at line 3396 of file res_jabber.c.

References aji_pubsub_iq_create(), AJI_XEP0248, AST_DEVSTATE_NOT_CACHABLE, and ast_test_flag.

Referenced by aji_publish_device_state(), and aji_publish_mwi().

03398 {
03399    iks *request = aji_pubsub_iq_create(client, "set");
03400    iks *pubsub, *publish, *item;
03401    pubsub = iks_insert(request, "pubsub");
03402    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03403    publish = iks_insert(pubsub, "publish");
03404    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03405       iks_insert_attrib(publish, "node", node);
03406    } else {
03407       iks_insert_attrib(publish, "node", event_type);
03408    }
03409    item = iks_insert(publish, "item");
03410    iks_insert_attrib(item, "id", node);
03411 
03412    if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
03413       iks *options, *x, *field_form_type, *field_persist;
03414 
03415       options = iks_insert(pubsub, "publish-options");
03416       x = iks_insert(options, "x");
03417       iks_insert_attrib(x, "xmlns", "jabber:x:data");
03418       iks_insert_attrib(x, "type", "submit");
03419       field_form_type = iks_insert(x, "field");
03420       iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
03421       iks_insert_attrib(field_form_type, "type", "hidden");
03422       iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
03423       field_persist = iks_insert(x, "field");
03424       iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
03425       iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
03426    }
03427 
03428    return item;
03429 }

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.

Returns:
char *.

Definition at line 3904 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.

03905 {
03906       struct aji_client *client;
03907       const char *name;
03908       const char *collection_name;
03909 
03910       switch (cmd) {
03911       case CLI_INIT:
03912             e->command = "jabber create collection";
03913             e->usage =
03914                "Usage: jabber create collection <connection> <collection>\n"
03915                "       Creates a PubSub collection node using the account\n"
03916                "       as configured in jabber.conf.\n";
03917          return NULL;
03918       case CLI_GENERATE:
03919          return NULL;
03920       }
03921 
03922       if (a->argc != 5) {
03923          return CLI_SHOWUSAGE;
03924       }
03925       name = a->argv[3];
03926       collection_name = a->argv[4];
03927 
03928       if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03929          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03930          return CLI_FAILURE;
03931       }
03932 
03933       ast_cli(a->fd, "Creating test PubSub node collection.\n");
03934       aji_create_pubsub_collection(client, collection_name);
03935       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03936       return CLI_SUCCESS;
03937 }

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.

Returns:
char *.

Definition at line 3943 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.

03944 {
03945    struct aji_client *client;
03946    const char *name;
03947    const char *collection_name;
03948    const char *leaf_name;
03949 
03950    switch (cmd) {
03951       case CLI_INIT:
03952          e->command = "jabber create leaf";
03953          e->usage =
03954                "Usage: jabber create leaf <connection> <collection> <leaf>\n"
03955                "       Creates a PubSub leaf node using the account\n"
03956                "       as configured in jabber.conf.\n";
03957          return NULL;
03958       case CLI_GENERATE:
03959          return NULL;
03960    }
03961 
03962    if (a->argc != 6) {
03963       return CLI_SHOWUSAGE;
03964    }
03965    name = a->argv[3];
03966    collection_name = a->argv[4];
03967    leaf_name = a->argv[5];
03968 
03969    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03970       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03971       return CLI_FAILURE;
03972    }
03973 
03974    ast_cli(a->fd, "Creating test PubSub node collection.\n");
03975    aji_create_pubsub_leaf(client, collection_name, leaf_name);
03976    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03977    return CLI_SUCCESS;
03978 }

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.

Parameters:
e pointer to ast_cli_entry structure
cmd 
a pointer to ast_cli_args structure
Returns:
char *

Definition at line 3757 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.

03759 {
03760    struct aji_client *client;
03761    const char *name;
03762 
03763    switch (cmd) {
03764       case CLI_INIT:
03765          e->command = "jabber delete node";
03766          e->usage =
03767                "Usage: jabber delete node <connection> <node>\n"
03768                "       Deletes a node on PubSub server\n"
03769                "       as configured in jabber.conf.\n";
03770          return NULL;
03771       case CLI_GENERATE:
03772          return NULL;
03773    }
03774 
03775    if (a->argc != 5) {
03776       return CLI_SHOWUSAGE;
03777    }
03778    name = a->argv[3];
03779 
03780    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03781       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03782       return CLI_FAILURE;
03783    }
03784    aji_delete_pubsub_node(client, a->argv[4]);
03785    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03786    return CLI_SUCCESS;
03787 }

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.

Parameters:
e pointer to ast_cli_entry structure
cmd 
a pointer to ast_cli_args structure
Returns:
char *

Definition at line 3632 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.

03634 {
03635       struct aji_client *client;
03636       const char *name = NULL;
03637       const char *collection = NULL;
03638 
03639       switch (cmd) {
03640       case CLI_INIT:
03641             e->command = "jabber list nodes";
03642             e->usage =
03643                "Usage: jabber list nodes <connection> [collection]\n"
03644                "       Lists the user's nodes on the respective connection\n"
03645                "       ([connection] as configured in jabber.conf.)\n";
03646          return NULL;
03647       case CLI_GENERATE:
03648          return NULL;
03649       }
03650 
03651       if (a->argc > 5 || a->argc < 4) {
03652          return CLI_SHOWUSAGE;
03653       } else if (a->argc == 4 || a->argc == 5) {
03654          name = a->argv[3];
03655       }
03656       if (a->argc == 5) {
03657          collection = a->argv[4];
03658       }
03659       if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03660          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03661          return CLI_FAILURE;
03662       }
03663 
03664       ast_cli(a->fd, "Listing pubsub nodes.\n");
03665       aji_request_pubsub_nodes(client, collection);
03666       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03667       return CLI_SUCCESS;
03668 }

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.

Parameters:
e pointer to ast_cli_entry structure
cmd 
a pointer to ast_cli_args structure
Returns:
char *

Definition at line 3677 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.

03679 {
03680    struct aji_client *client;
03681    const char *name;
03682 
03683    switch (cmd) {
03684       case CLI_INIT:
03685          e->command = "jabber purge nodes";
03686          e->usage =
03687                "Usage: jabber purge nodes <connection> <node>\n"
03688                "       Purges nodes on PubSub server\n"
03689                "       as configured in jabber.conf.\n";
03690          return NULL;
03691       case CLI_GENERATE:
03692          return NULL;
03693    }
03694 
03695    if (a->argc != 5) {
03696       return CLI_SHOWUSAGE;
03697    }
03698    name = a->argv[3];
03699 
03700    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03701       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03702       return CLI_FAILURE;
03703    }
03704    if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03705       aji_pubsub_purge_nodes(client, a->argv[4]);
03706    } else {
03707       aji_delete_pubsub_node(client, a->argv[4]);
03708    }
03709    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03710    return CLI_SUCCESS;
03711 }

static int aji_client_connect ( void *  data,
ikspak *  pak 
) [static]

Definition at line 3090 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().

03091 {
03092    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03093    int res = IKS_FILTER_PASS;
03094 
03095    if (client) {
03096       if (client->state == AJI_DISCONNECTED) {
03097          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);
03098          client->state = AJI_CONNECTING;
03099          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
03100          if (!client->component) { /*client*/
03101             aji_get_roster(client);
03102          }
03103          if (client->distribute_events) {
03104             aji_init_event_distribution(client);
03105          }
03106 
03107          iks_filter_remove_hook(client->f, aji_client_connect);
03108          /* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */
03109          res = IKS_FILTER_EAT;
03110       }
03111    } else {
03112       ast_log(LOG_ERROR, "Out of memory.\n");
03113    }
03114 
03115    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03116    return res;
03117 }

static int aji_client_info_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 2003 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().

02004 {
02005    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02006    struct aji_resource *resource = NULL;
02007    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02008 
02009    if (!buddy) {
02010       ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
02011       ASTOBJ_UNREF(client, ast_aji_client_destroy);
02012       return IKS_FILTER_EAT;
02013    }
02014 
02015    resource = aji_find_resource(buddy, pak->from->resource);
02016    if (pak->subtype == IKS_TYPE_RESULT) {
02017       if (!resource) {
02018          ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
02019          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02020          ASTOBJ_UNREF(client, ast_aji_client_destroy);
02021          return IKS_FILTER_EAT;
02022       }
02023       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
02024          resource->cap->jingle = 1;
02025       } else {
02026          resource->cap->jingle = 0;
02027       }
02028    } else if (pak->subtype == IKS_TYPE_GET) {
02029       iks *iq, *disco, *ident, *google, *query;
02030       iq = iks_new("iq");
02031       query = iks_new("query");
02032       ident = iks_new("identity");
02033       disco = iks_new("feature");
02034       google = iks_new("feature");
02035       if (iq && ident && disco && google) {
02036          iks_insert_attrib(iq, "from", client->jid->full);
02037          iks_insert_attrib(iq, "to", pak->from->full);
02038          iks_insert_attrib(iq, "type", "result");
02039          iks_insert_attrib(iq, "id", pak->id);
02040          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02041          iks_insert_attrib(ident, "category", "client");
02042          iks_insert_attrib(ident, "type", "pc");
02043          iks_insert_attrib(ident, "name", "asterisk");
02044          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
02045          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
02046          iks_insert_node(iq, query);
02047          iks_insert_node(query, ident);
02048          iks_insert_node(query, google);
02049          iks_insert_node(query, disco);
02050          ast_aji_send(client, iq);
02051       } else {
02052          ast_log(LOG_ERROR, "Out of Memory.\n");
02053       }
02054 
02055       iks_delete(iq);
02056       iks_delete(query);
02057       iks_delete(ident);
02058       iks_delete(google);
02059       iks_delete(disco);
02060    } else if (pak->subtype == IKS_TYPE_ERROR) {
02061       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
02062    }
02063    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02064    ASTOBJ_UNREF(client, ast_aji_client_destroy);
02065    return IKS_FILTER_EAT;
02066 }

static void aji_create_affiliations ( struct aji_client client,
const char *  node 
) [static]

Add Owner affiliations for pubsub node.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
node the name of the node to which to add affiliations
Returns:
void

Definition at line 3332 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().

03333 {
03334    iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
03335    iks *pubsub, *affiliations, *affiliate;
03336    pubsub = iks_insert(modify_affiliates, "pubsub");
03337    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03338    affiliations = iks_insert(pubsub, "affiliations");
03339    iks_insert_attrib(affiliations, "node", node);
03340    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03341       ASTOBJ_RDLOCK(iterator);
03342       affiliate = iks_insert(affiliations, "affiliation");
03343       iks_insert_attrib(affiliate, "jid", iterator->name);
03344       iks_insert_attrib(affiliate, "affiliation", "owner");
03345       ASTOBJ_UNLOCK(iterator);
03346    });
03347    ast_aji_send(client, modify_affiliates);
03348    iks_delete(modify_affiliates);
03349 }

static int aji_create_buddy ( char *  label,
struct aji_client client 
) [static]
static int aji_create_client ( char *  label,
struct ast_variable var,
int  debug 
) [static]

Definition at line 4236 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(), ast_aji_client_destroy(), ast_asprintf, 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, 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::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().

04237 {
04238    char *resource;
04239    struct aji_client *client = NULL;
04240    int flag = 0;
04241 
04242    client = ASTOBJ_CONTAINER_FIND(&clients, label);
04243    if (!client) {
04244       flag = 1;
04245       client = ast_calloc(1, sizeof(*client));
04246       if (!client) {
04247          ast_log(LOG_ERROR, "Out of memory!\n");
04248          return 0;
04249       }
04250       ASTOBJ_INIT(client);
04251       ASTOBJ_WRLOCK(client);
04252       ASTOBJ_CONTAINER_INIT(&client->buddies);
04253    } else {
04254       ASTOBJ_WRLOCK(client);
04255       ASTOBJ_UNMARK(client);
04256    }
04257    ASTOBJ_CONTAINER_MARKALL(&client->buddies);
04258    ast_copy_string(client->name, label, sizeof(client->name));
04259    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
04260 
04261    /* Set default values for the client object */
04262    client->debug = debug;
04263    ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
04264    client->port = 5222;
04265    client->usetls = 1;
04266    client->usesasl = 1;
04267    client->forcessl = 0;
04268    client->keepalive = 1;
04269    client->timeout = 50;
04270    client->message_timeout = 5;
04271    client->distribute_events = 0;
04272    AST_LIST_HEAD_INIT(&client->messages);
04273    client->component = 0;
04274    ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
04275    client->priority = 0;
04276    client->status = IKS_SHOW_AVAILABLE;
04277 
04278    if (flag) {
04279       client->authorized = 0;
04280       client->state = AJI_DISCONNECTED;
04281    }
04282    while (var) {
04283       if (!strcasecmp(var->name, "username")) {
04284          ast_copy_string(client->user, var->value, sizeof(client->user));
04285       } else if (!strcasecmp(var->name, "serverhost")) {
04286          ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
04287       } else if (!strcasecmp(var->name, "secret")) {
04288          ast_copy_string(client->password, var->value, sizeof(client->password));
04289       } else if (!strcasecmp(var->name, "statusmessage")) {
04290          ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
04291       } else if (!strcasecmp(var->name, "port")) {
04292          client->port = atoi(var->value);
04293       } else if (!strcasecmp(var->name, "timeout")) {
04294          client->message_timeout = atoi(var->value);
04295       } else if (!strcasecmp(var->name, "debug")) {
04296          client->debug = (ast_false(var->value)) ? 0 : 1;
04297       } else if (!strcasecmp(var->name, "type")) {
04298          if (!strcasecmp(var->value, "component")) {
04299             client->component = 1;
04300             if (client->distribute_events) {
04301                ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events!  Event distribution will be disabled.\n");
04302                client->distribute_events = 0;
04303             }
04304          }
04305       } else if (!strcasecmp(var->name, "distribute_events")) {
04306          if (ast_true(var->value)) {
04307             if (client->component) {
04308                ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events!  Event distribution will be disabled.\n");
04309             } else {
04310                if (ast_test_flag(&pubsubflags, AJI_PUBSUB)) {
04311                   ast_log(LOG_ERROR, "Only one connection can be configured for distributed events.\n");
04312                } else {
04313                   ast_set_flag(&pubsubflags, AJI_PUBSUB);
04314                   client->distribute_events = 1;
04315                }
04316             }
04317          }
04318       } else if (!strcasecmp(var->name, "pubsub_node")) {
04319          ast_copy_string(client->pubsub_node, var->value, sizeof(client->pubsub_node));
04320       } else if (!strcasecmp(var->name, "usetls")) {
04321          client->usetls = (ast_false(var->value)) ? 0 : 1;
04322       } else if (!strcasecmp(var->name, "usesasl")) {
04323          client->usesasl = (ast_false(var->value)) ? 0 : 1;
04324       } else if (!strcasecmp(var->name, "forceoldssl")) {
04325          client->forcessl = (ast_false(var->value)) ? 0 : 1;
04326       } else if (!strcasecmp(var->name, "keepalive")) {
04327          client->keepalive = (ast_false(var->value)) ? 0 : 1;
04328       } else if (!strcasecmp(var->name, "autoprune")) {
04329          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
04330       } else if (!strcasecmp(var->name, "autoregister")) {
04331          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
04332       } else if (!strcasecmp(var->name, "auth_policy")) {
04333          if (!strcasecmp(var->value, "accept")) {
04334             ast_set_flag(&client->flags, AJI_AUTOACCEPT);
04335          } else {
04336             ast_clear_flag(&client->flags, AJI_AUTOACCEPT);
04337          }
04338       } else if (!strcasecmp(var->name, "buddy")) {
04339          aji_create_buddy((char *)var->value, client);
04340       } else if (!strcasecmp(var->name, "priority")) {
04341          client->priority = atoi(var->value);
04342       } else if (!strcasecmp(var->name, "status")) {
04343          if (!strcasecmp(var->value, "unavailable")) {
04344             client->status = IKS_SHOW_UNAVAILABLE;
04345          } else if (!strcasecmp(var->value, "available")
04346           || !strcasecmp(var->value, "online")) {
04347             client->status = IKS_SHOW_AVAILABLE;
04348          } else if (!strcasecmp(var->value, "chat")
04349           || !strcasecmp(var->value, "chatty")) {
04350             client->status = IKS_SHOW_CHAT;
04351          } else if (!strcasecmp(var->value, "away")) {
04352             client->status = IKS_SHOW_AWAY;
04353          } else if (!strcasecmp(var->value, "xa")
04354           || !strcasecmp(var->value, "xaway")) {
04355             client->status = IKS_SHOW_XA;
04356          } else if (!strcasecmp(var->value, "dnd")) {
04357             client->status = IKS_SHOW_DND;
04358          } else if (!strcasecmp(var->value, "invisible")) {
04359          #ifdef IKS_SHOW_INVISIBLE
04360             client->status = IKS_SHOW_INVISIBLE;
04361          #else
04362             ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
04363             client->status = IKS_SHOW_DND;
04364          #endif
04365          } else {
04366             ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
04367          }
04368       }
04369    /* no transport support in this version */
04370    /* else if (!strcasecmp(var->name, "transport"))
04371             aji_create_transport(var->value, client);
04372    */
04373       var = var->next;
04374    }
04375    if (!flag) {
04376       ASTOBJ_UNLOCK(client);
04377       ASTOBJ_UNREF(client, ast_aji_client_destroy);
04378       return 1;
04379    }
04380 
04381    ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
04382    client->p = iks_stream_new(client->name_space, client, aji_act_hook);
04383    if (!client->p) {
04384       ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
04385       return 0;
04386    }
04387    client->stack = iks_stack_new(8192, 8192);
04388    if (!client->stack) {
04389       ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
04390       return 0;
04391    }
04392    client->f = iks_filter_new();
04393    if (!client->f) {
04394       ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
04395       return 0;
04396    }
04397    if (!strchr(client->user, '/') && !client->component) { /*client */
04398       if (ast_asprintf(&resource, "%s/asterisk", client->user) >= 0) {
04399          client->jid = iks_id_new(client->stack, resource);
04400          ast_free(resource);
04401       }
04402    } else {
04403       client->jid = iks_id_new(client->stack, client->user);
04404    }
04405    if (client->component) {
04406       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04407       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
04408       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);
04409       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);
04410    } else {
04411       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04412    }
04413 
04414    iks_set_log_hook(client->p, aji_log_hook);
04415    ASTOBJ_UNLOCK(client);
04416    ASTOBJ_CONTAINER_LINK(&clients, client);
04417    return 1;
04418 }

static void aji_create_pubsub_collection ( struct aji_client client,
const char *  collection_name 
) [static]

Create a PubSub collection node.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
collection_name The name to use for this collection
Returns:
void.

Definition at line 3812 of file res_jabber.c.

References aji_create_pubsub_node().

Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().

03814 {
03815    aji_create_pubsub_node(client, "collection", collection_name, NULL);
03816 }

static void aji_create_pubsub_leaf ( struct aji_client client,
const char *  collection_name,
const char *  leaf_name 
) [static]

Create a PubSub leaf node.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
leaf_name The name to use for this collection
Returns:
void.

Definition at line 3825 of file res_jabber.c.

References aji_create_pubsub_node().

Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().

03827 {
03828    aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
03829 }

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.

Parameters:
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
Returns:
iks*

Definition at line 3838 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().

03840 {
03841    iks *node = aji_pubsub_iq_create(client, "set");
03842    iks *pubsub, *create;
03843    pubsub = iks_insert(node, "pubsub");
03844    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03845    create = iks_insert(pubsub, "create");
03846    iks_insert_attrib(create, "node", name);
03847    aji_build_node_config(pubsub, node_type, collection_name);
03848    ast_aji_send(client, node);
03849    aji_create_affiliations(client, name);
03850    iks_delete(node);
03851    return 0;
03852 }

static int aji_delete_node_list ( void *  data,
ikspak *  pak 
) [static]

Delete pubsub item lists.

Parameters:
data pointer to aji_client structure
pak response from pubsub diso::items query
Returns:
IKS_FILTER_EAT

Definition at line 3730 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().

03731 {
03732 
03733    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03734    iks *item = NULL;
03735    if (iks_has_children(pak->query)) {
03736       item = iks_first_tag(pak->query);
03737       ast_log(LOG_WARNING, "Connection: %s  Node name: %s\n", client->jid->partial,
03738             iks_find_attrib(item, "node"));
03739       while ((item = iks_next_tag(item))) {
03740          aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
03741       }
03742    }
03743    if (item) {
03744       iks_delete(item);
03745    }
03746    return IKS_FILTER_EAT;
03747 }

static void aji_delete_pubsub_node ( struct aji_client client,
const char *  node_name 
) [static]

Delete a PubSub node.

Parameters:
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 3795 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().

03796 {
03797    iks *request = aji_pubsub_iq_create(client, "set");
03798    iks *pubsub, *delete;
03799    pubsub = iks_insert(request, "pubsub");
03800    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03801    delete = iks_insert(pubsub, "delete");
03802    iks_insert_attrib(delete, "node", node_name);
03803    ast_aji_send(client, request);
03804 }

static void aji_devstate_cb ( const struct ast_event ast_event,
void *  data 
) [static]

Callback function for device state events.

Parameters:
ast_event 
data void pointer to ast_client structure
Returns:
void

Definition at line 3209 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_CACHABLE, 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().

03210 {
03211    const char *device;
03212    const char *device_state;
03213    unsigned int cachable;
03214    struct aji_client *client;
03215    if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03216    {
03217       /* If the event didn't originate from this server, don't send it back out. */
03218       ast_log(LOG_DEBUG, "Returning here\n");
03219       return;
03220    }
03221 
03222    client = ASTOBJ_REF((struct aji_client *) data);
03223    device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
03224    device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
03225    cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE);
03226    aji_publish_device_state(client, device, device_state, cachable);
03227    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03228 }

static int aji_dinfo_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 2075 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().

02076 {
02077    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02078    char *node = NULL;
02079    struct aji_resource *resource = NULL;
02080    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02081 
02082    if (!buddy) {
02083       ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
02084       ASTOBJ_UNREF(client, ast_aji_client_destroy);
02085       return IKS_FILTER_EAT;
02086    }
02087 
02088    if (pak->subtype == IKS_TYPE_ERROR) {
02089       ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
02090       ASTOBJ_UNREF(client, ast_aji_client_destroy);
02091       return IKS_FILTER_EAT;
02092    }
02093    resource = aji_find_resource(buddy, pak->from->resource);
02094    if (pak->subtype == IKS_TYPE_RESULT) {
02095       if (!resource) {
02096          ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
02097          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02098          ASTOBJ_UNREF(client, ast_aji_client_destroy);
02099          return IKS_FILTER_EAT;
02100       }
02101       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
02102          resource->cap->jingle = 1;
02103       } else {
02104          resource->cap->jingle = 0;
02105       }
02106    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
02107       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
02108 
02109       iq = iks_new("iq");
02110       query = iks_new("query");
02111       identity = iks_new("identity");
02112       disco = iks_new("feature");
02113       reg = iks_new("feature");
02114       commands = iks_new("feature");
02115       gateway = iks_new("feature");
02116       version = iks_new("feature");
02117       vcard = iks_new("feature");
02118       search = iks_new("feature");
02119       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
02120          iks_insert_attrib(iq, "from", client->user);
02121          iks_insert_attrib(iq, "to", pak->from->full);
02122          iks_insert_attrib(iq, "id", pak->id);
02123          iks_insert_attrib(iq, "type", "result");
02124          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02125          iks_insert_attrib(identity, "category", "gateway");
02126          iks_insert_attrib(identity, "type", "pstn");
02127          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
02128          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
02129          iks_insert_attrib(reg, "var", "jabber:iq:register");
02130          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
02131          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
02132          iks_insert_attrib(version, "var", "jabber:iq:version");
02133          iks_insert_attrib(vcard, "var", "vcard-temp");
02134          iks_insert_attrib(search, "var", "jabber:iq:search");
02135 
02136          iks_insert_node(iq, query);
02137          iks_insert_node(query, identity);
02138          iks_insert_node(query, disco);
02139          iks_insert_node(query, reg);
02140          iks_insert_node(query, commands);
02141          iks_insert_node(query, gateway);
02142          iks_insert_node(query, version);
02143          iks_insert_node(query, vcard);
02144          iks_insert_node(query, search);
02145          ast_aji_send(client, iq);
02146       } else {
02147          ast_log(LOG_ERROR, "Out of memory.\n");
02148       }
02149 
02150       iks_delete(iq);
02151       iks_delete(query);
02152       iks_delete(identity);
02153       iks_delete(disco);
02154       iks_delete(reg);
02155       iks_delete(commands);
02156       iks_delete(gateway);
02157       iks_delete(version);
02158       iks_delete(vcard);
02159       iks_delete(search);
02160    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
02161       iks *iq, *query, *confirm;
02162       iq = iks_new("iq");
02163       query = iks_new("query");
02164       confirm = iks_new("item");
02165 
02166       if (iq && query && confirm && client) {
02167          iks_insert_attrib(iq, "from", client->user);
02168          iks_insert_attrib(iq, "to", pak->from->full);
02169          iks_insert_attrib(iq, "id", pak->id);
02170          iks_insert_attrib(iq, "type", "result");
02171          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
02172          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
02173          iks_insert_attrib(confirm, "node", "confirmaccount");
02174          iks_insert_attrib(confirm, "name", "Confirm AIM account");
02175          iks_insert_attrib(confirm, "jid", client->user);
02176          iks_insert_node(iq, query);
02177          iks_insert_node(query, confirm);
02178          ast_aji_send(client, iq);
02179       } else {
02180          ast_log(LOG_ERROR, "Out of memory.\n");
02181       }
02182 
02183       iks_delete(iq);
02184       iks_delete(query);
02185       iks_delete(confirm);
02186 
02187    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
02188       iks *iq, *query, *feature;
02189 
02190       iq = iks_new("iq");
02191       query = iks_new("query");
02192       feature = iks_new("feature");
02193 
02194       if (iq && query && feature && client) {
02195          iks_insert_attrib(iq, "from", client->user);
02196          iks_insert_attrib(iq, "to", pak->from->full);
02197          iks_insert_attrib(iq, "id", pak->id);
02198          iks_insert_attrib(iq, "type", "result");
02199          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02200          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
02201          iks_insert_node(iq, query);
02202          iks_insert_node(query, feature);
02203          ast_aji_send(client, iq);
02204       } else {
02205          ast_log(LOG_ERROR, "Out of memory.\n");
02206       }
02207 
02208       iks_delete(iq);
02209       iks_delete(query);
02210       iks_delete(feature);
02211    }
02212 
02213    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02214    ASTOBJ_UNREF(client, ast_aji_client_destroy);
02215    return IKS_FILTER_EAT;
02216 }

static int aji_ditems_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 1906 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().

01907 {
01908    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01909    char *node = NULL;
01910 
01911    if (!(node = iks_find_attrib(pak->query, "node"))) {
01912       iks *iq = NULL, *query = NULL, *item = NULL;
01913       iq = iks_new("iq");
01914       query = iks_new("query");
01915       item = iks_new("item");
01916 
01917       if (iq && query && item) {
01918          iks_insert_attrib(iq, "from", client->user);
01919          iks_insert_attrib(iq, "to", pak->from->full);
01920          iks_insert_attrib(iq, "id", pak->id);
01921          iks_insert_attrib(iq, "type", "result");
01922          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01923          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01924          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01925          iks_insert_attrib(item, "jid", client->user);
01926 
01927          iks_insert_node(iq, query);
01928          iks_insert_node(query, item);
01929          ast_aji_send(client, iq);
01930       } else {
01931          ast_log(LOG_ERROR, "Out of memory.\n");
01932       }
01933 
01934       iks_delete(iq);
01935       iks_delete(query);
01936       iks_delete(item);
01937 
01938    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01939       iks *iq, *query, *confirm;
01940       iq = iks_new("iq");
01941       query = iks_new("query");
01942       confirm = iks_new("item");
01943       if (iq && query && confirm && client) {
01944          iks_insert_attrib(iq, "from", client->user);
01945          iks_insert_attrib(iq, "to", pak->from->full);
01946          iks_insert_attrib(iq, "id", pak->id);
01947          iks_insert_attrib(iq, "type", "result");
01948          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01949          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01950          iks_insert_attrib(confirm, "node", "confirmaccount");
01951          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01952          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01953 
01954          iks_insert_node(iq, query);
01955          iks_insert_node(query, confirm);
01956          ast_aji_send(client, iq);
01957       } else {
01958          ast_log(LOG_ERROR, "Out of memory.\n");
01959       }
01960 
01961       iks_delete(iq);
01962       iks_delete(query);
01963       iks_delete(confirm);
01964 
01965    } else if (!strcasecmp(node, "confirmaccount")) {
01966       iks *iq = NULL, *query = NULL, *feature = NULL;
01967 
01968       iq = iks_new("iq");
01969       query = iks_new("query");
01970       feature = iks_new("feature");
01971 
01972       if (iq && query && feature && client) {
01973          iks_insert_attrib(iq, "from", client->user);
01974          iks_insert_attrib(iq, "to", pak->from->full);
01975          iks_insert_attrib(iq, "id", pak->id);
01976          iks_insert_attrib(iq, "type", "result");
01977          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01978          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01979          iks_insert_node(iq, query);
01980          iks_insert_node(query, feature);
01981          ast_aji_send(client, iq);
01982       } else {
01983          ast_log(LOG_ERROR, "Out of memory.\n");
01984       }
01985 
01986       iks_delete(iq);
01987       iks_delete(query);
01988       iks_delete(feature);
01989    }
01990 
01991    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01992    return IKS_FILTER_EAT;
01993 
01994 }

static char * aji_do_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4117 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.

04118 {
04119    switch (cmd) {
04120    case CLI_INIT:
04121       e->command = "jabber reload";
04122       e->usage =
04123          "Usage: jabber reload\n"
04124          "       Reloads the Jabber module.\n";
04125       return NULL;
04126    case CLI_GENERATE:
04127       return NULL;
04128    }
04129 
04130    aji_reload(1);
04131    ast_cli(a->fd, "Jabber Reloaded.\n");
04132    return CLI_SUCCESS;
04133 }

static char * aji_do_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4075 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.

04076 {
04077    switch (cmd) {
04078    case CLI_INIT:
04079       e->command = "jabber set debug {on|off}";
04080       e->usage =
04081          "Usage: jabber set debug {on|off}\n"
04082          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
04083       return NULL;
04084    case CLI_GENERATE:
04085       return NULL;
04086    }
04087 
04088    if (a->argc != e->args) {
04089       return CLI_SHOWUSAGE;
04090    }
04091 
04092    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
04093       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04094          ASTOBJ_RDLOCK(iterator);
04095          iterator->debug = 1;
04096          ASTOBJ_UNLOCK(iterator);
04097       });
04098       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
04099       return CLI_SUCCESS;
04100    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
04101       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04102          ASTOBJ_RDLOCK(iterator);
04103          iterator->debug = 0;
04104          ASTOBJ_UNLOCK(iterator);
04105       });
04106       ast_cli(a->fd, "Jabber Debugging Disabled.\n");
04107       return CLI_SUCCESS;
04108    }
04109    return CLI_SHOWUSAGE; /* defaults to invalid */
04110 }

static int aji_filter_roster ( void *  data,
ikspak *  pak 
) [static]

Definition at line 2953 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().

02954 {
02955    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02956    int flag = 0;
02957    iks *x = NULL;
02958    struct aji_buddy *buddy;
02959 
02960    client->state = AJI_CONNECTED;
02961    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02962       ASTOBJ_RDLOCK(iterator);
02963       x = iks_child(pak->query);
02964       flag = 0;
02965       while (x) {
02966          if (!iks_strcmp(iks_name(x), "item")) {
02967             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02968                flag = 1;
02969                ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02970             }
02971          }
02972          x = iks_next(x);
02973       }
02974       if (!flag) {
02975          ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02976       }
02977       iks_delete(x);
02978 
02979       ASTOBJ_UNLOCK(iterator);
02980    });
02981 
02982    x = iks_child(pak->query);
02983    while (x) {
02984       flag = 0;
02985       if (iks_strcmp(iks_name(x), "item") == 0) {
02986          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02987             ASTOBJ_RDLOCK(iterator);
02988             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02989                flag = 1;
02990             ASTOBJ_UNLOCK(iterator);
02991          });
02992 
02993          if (flag) {
02994             /* found buddy, don't create a new one */
02995             x = iks_next(x);
02996             continue;
02997          }
02998 
02999          buddy = ast_calloc(1, sizeof(*buddy));
03000          if (!buddy) {
03001             ast_log(LOG_WARNING, "Out of memory\n");
03002             ASTOBJ_UNREF(client, ast_aji_client_destroy);
03003             return 0;
03004          }
03005          ASTOBJ_INIT(buddy);
03006          ASTOBJ_WRLOCK(buddy);
03007          ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
03008          ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
03009          if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
03010             ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
03011             ASTOBJ_MARK(buddy);
03012          } else if (ast_test_flag(&client->flags, AJI_AUTOREGISTER)) {
03013             if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
03014                /* subscribe to buddy's presence only
03015                   if we really need to */
03016                ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
03017             }
03018          }
03019          ASTOBJ_UNLOCK(buddy);
03020          if (buddy) {
03021             ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
03022             ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
03023          }
03024       }
03025       x = iks_next(x);
03026    }
03027 
03028    iks_delete(x);
03029    aji_pruneregister(client);
03030 
03031    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03032    return IKS_FILTER_EAT;
03033 }

static struct aji_resource* aji_find_resource ( struct aji_buddy buddy,
char *  name 
) [static, read]

Definition at line 544 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().

00545 {
00546    struct aji_resource *res = NULL;
00547    if (!buddy || !name) {
00548       return res;
00549    }
00550    res = buddy->resources;
00551    while (res) {
00552       if (!strcasecmp(res->resource, name)) {
00553          break;
00554       }
00555       res = res->next;
00556    }
00557    return res;
00558 }

static struct aji_version* aji_find_version ( char *  node,
char *  version,
ikspak *  pak 
) [static, read]

Definition at line 472 of file res_jabber.c.

References ast_copy_string(), ast_free, ast_log(), ast_malloc, aji_version::jingle, LOG_ERROR, aji_capabilities::next, aji_version::next, aji_capabilities::node, aji_version::parent, aji_version::version, and aji_capabilities::versions.

Referenced by aji_handle_presence().

00473 {
00474    struct aji_capabilities *list = NULL;
00475    struct aji_version *res = NULL;
00476 
00477    list = capabilities;
00478 
00479    if (!node) {
00480       node = pak->from->full;
00481    }
00482    if (!version) {
00483       version = "none supplied.";
00484    }
00485    while (list) {
00486       if (!strcasecmp(list->node, node)) {
00487          res = list->versions;
00488          while(res) {
00489             if (!strcasecmp(res->version, version)) {
00490                return res;
00491             }
00492             res = res->next;
00493          }
00494          /* Specified version not found. Let's add it to
00495             this node in our capabilities list */
00496          if (!res) {
00497             res = ast_malloc(sizeof(*res));
00498             if (!res) {
00499                ast_log(LOG_ERROR, "Out of memory!\n");
00500                return NULL;
00501             }
00502             res->jingle = 0;
00503             res->parent = list;
00504             ast_copy_string(res->version, version, sizeof(res->version));
00505             res->next = list->versions;
00506             list->versions = res;
00507             return res;
00508          }
00509       }
00510       list = list->next;
00511    }
00512    /* Specified node not found. Let's add it our capabilities list */
00513    if (!list) {
00514       list = ast_malloc(sizeof(*list));
00515       if (!list) {
00516          ast_log(LOG_ERROR, "Out of memory!\n");
00517          return NULL;
00518       }
00519       res = ast_malloc(sizeof(*res));
00520       if (!res) {
00521          ast_log(LOG_ERROR, "Out of memory!\n");
00522          ast_free(list);
00523          return NULL;
00524       }
00525       ast_copy_string(list->node, node, sizeof(list->node));
00526       ast_copy_string(res->version, version, sizeof(res->version));
00527       res->jingle = 0;
00528       res->parent = list;
00529       res->next = NULL;
00530       list->versions = res;
00531       list->next = capabilities;
00532       capabilities = list;
00533    }
00534    return res;
00535 }

static int aji_get_roster ( struct aji_client client  )  [static]

Definition at line 3067 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().

03068 {
03069    iks *roster = NULL;
03070    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
03071 
03072    if (roster) {
03073       iks_insert_attrib(roster, "id", "roster");
03074       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
03075       ast_aji_send(client, roster);
03076    }
03077 
03078    iks_delete(roster);
03079 
03080    return 1;
03081 }

static void aji_handle_iq ( struct aji_client client,
iks *  node 
) [static]

Definition at line 2225 of file res_jabber.c.

Referenced by aji_act_hook().

02226 {
02227    /*Nothing to see here */
02228 }

static void aji_handle_message ( struct aji_client client,
ikspak *  pak 
) [static]

Definition at line 2237 of file res_jabber.c.

References aji_message::arrived, ast_calloc, ast_cond_broadcast, ast_copy_string(), ast_debug, ast_free, 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, LOG_ERROR, aji_message::message, and aji_client::name.

Referenced by aji_act_hook().

02238 {
02239    struct aji_message *insert;
02240    int deleted = 0;
02241 
02242    ast_debug(3, "client %s received a message\n", client->name);
02243 
02244    if (!(insert = ast_calloc(1, sizeof(*insert)))) {
02245       return;
02246    }
02247 
02248    insert->arrived = ast_tvnow();
02249 
02250    /* wake up threads waiting for messages */
02251    ast_mutex_lock(&messagelock);
02252    ast_cond_broadcast(&message_received_condition);
02253    ast_mutex_unlock(&messagelock);
02254 
02255    if (iks_find_cdata(pak->x, "body")) {
02256       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
02257    }
02258    if (pak->id) {
02259       ast_copy_string(insert->id, pak->id, sizeof(insert->id));
02260    }
02261    if (pak->from){
02262       /* insert will furtherly be added to message list */
02263       insert->from = ast_strdup(pak->from->full);
02264       if (!insert->from) {
02265          ast_free(insert);
02266          ast_log(LOG_ERROR, "Memory allocation failure\n");
02267          return;
02268       }
02269       ast_debug(3, "message comes from %s\n", insert->from);
02270    }
02271 
02272    /* remove old messages received from this JID
02273     * and insert received message */
02274    deleted = delete_old_messages(client, pak->from->partial);
02275    ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
02276    AST_LIST_LOCK(&client->messages);
02277    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
02278    AST_LIST_UNLOCK(&client->messages);
02279 }

static void aji_handle_presence ( struct aji_client client,
ikspak *  pak 
) [static]

Definition at line 2287 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, 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, aji_client::status, status, aji_client::statusmessage, and type.

Referenced by aji_act_hook().

02288 {
02289    int status, priority;
02290    struct aji_buddy *buddy;
02291    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
02292    char *ver, *node, *descrip, *type;
02293 
02294    if (client->state != AJI_CONNECTED)
02295       aji_create_buddy(pak->from->partial, client);
02296 
02297    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02298    if (!buddy && pak->from->partial) {
02299       /* allow our jid to be used to log in with another resource */
02300       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
02301          aji_create_buddy(pak->from->partial, client);
02302       else
02303          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
02304       return;
02305    }
02306    type = iks_find_attrib(pak->x, "type");
02307    if (client->component && type &&!strcasecmp("probe", type)) {
02308       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02309       ast_verbose("what i was looking for \n");
02310    }
02311    ASTOBJ_WRLOCK(buddy);
02312    status = (pak->show) ? pak->show : 6;
02313    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
02314    tmp = buddy->resources;
02315    descrip = ast_strdup(iks_find_cdata(pak->x, "status"));
02316 
02317    while (tmp && pak->from->resource) {
02318       if (!strcasecmp(tmp->resource, pak->from->resource)) {
02319          tmp->status = status;
02320          if (tmp->description) {
02321             ast_free(tmp->description);
02322          }
02323          tmp->description = descrip;
02324          found = tmp;
02325          if (status == 6) {   /* Sign off Destroy resource */
02326             if (last && found->next) {
02327                last->next = found->next;
02328             } else if (!last) {
02329                if (found->next) {
02330                   buddy->resources = found->next;
02331                } else {
02332                   buddy->resources = NULL;
02333                }
02334             } else if (!found->next) {
02335                if (last) {
02336                   last->next = NULL;
02337                } else {
02338                   buddy->resources = NULL;
02339                }
02340             }
02341             ast_free(found);
02342             found = NULL;
02343             break;
02344          }
02345          /* resource list is sorted by descending priority */
02346          if (tmp->priority != priority) {
02347             found->priority = priority;
02348             if (!last && !found->next) {
02349                /* resource was found to be unique,
02350                   leave loop */
02351                break;
02352             }
02353             /* search for resource in our list
02354                and take it out for the moment */
02355             if (last) {
02356                last->next = found->next;
02357             } else {
02358                buddy->resources = found->next;
02359             }
02360 
02361             last = NULL;
02362             tmp = buddy->resources;
02363             if (!buddy->resources) {
02364                buddy->resources = found;
02365             }
02366             /* priority processing */
02367             while (tmp) {
02368                /* insert resource back according to
02369                   its priority value */
02370                if (found->priority > tmp->priority) {
02371                   if (last) {
02372                      /* insert within list */
02373                      last->next = found;
02374                   }
02375                   found->next = tmp;
02376                   if (!last) {
02377                      /* insert on top */
02378                      buddy->resources = found;
02379                   }
02380                   break;
02381                }
02382                if (!tmp->next) {
02383                   /* insert at the end of the list */
02384                   tmp->next = found;
02385                   found->next = NULL;
02386                   break;
02387                }
02388                last = tmp;
02389                tmp = tmp->next;
02390             }
02391          }
02392          break;
02393       }
02394       last = tmp;
02395       tmp = tmp->next;
02396    }
02397 
02398    /* resource not found in our list, create it */
02399    if (!found && status != 6 && pak->from->resource) {
02400       found = ast_calloc(1, sizeof(*found));
02401 
02402       if (!found) {
02403          ast_log(LOG_ERROR, "Out of memory!\n");
02404          ASTOBJ_UNLOCK(buddy);
02405          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02406          return;
02407       }
02408       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
02409       found->status = status;
02410       found->description = descrip;
02411       found->priority = priority;
02412       found->next = NULL;
02413       last = NULL;
02414       tmp = buddy->resources;
02415       while (tmp) {
02416          if (found->priority > tmp->priority) {
02417             if (last) {
02418                last->next = found;
02419             }
02420             found->next = tmp;
02421             if (!last) {
02422                buddy->resources = found;
02423             }
02424             break;
02425          }
02426          if (!tmp->next) {
02427             tmp->next = found;
02428             break;
02429          }
02430          last = tmp;
02431          tmp = tmp->next;
02432       }
02433       if (!tmp) {
02434          buddy->resources = found;
02435       }
02436    }
02437 
02438    ASTOBJ_UNLOCK(buddy);
02439    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02440 
02441    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
02442    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
02443 
02444    /* handle gmail client's special caps:c tag */
02445    if (!node && !ver) {
02446       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
02447       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
02448    }
02449 
02450    /* retrieve capabilites of the new resource */
02451    if (status != 6 && found && !found->cap) {
02452       found->cap = aji_find_version(node, ver, pak);
02453       if (gtalk_yuck(pak->x)) { /* gtalk should do discover */
02454          found->cap->jingle = 1;
02455       }
02456       if (found->cap->jingle) {
02457          ast_debug(1, "Special case for google till they support discover.\n");
02458       } else {
02459          iks *iq, *query;
02460          iq = iks_new("iq");
02461          query = iks_new("query");
02462          if (query && iq) {
02463             iks_insert_attrib(iq, "type", "get");
02464             iks_insert_attrib(iq, "to", pak->from->full);
02465             iks_insert_attrib(iq, "from", client->jid->full);
02466             iks_insert_attrib(iq, "id", client->mid);
02467             ast_aji_increment_mid(client->mid);
02468             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02469             iks_insert_node(iq, query);
02470             ast_aji_send(client, iq);
02471          } else {
02472             ast_log(LOG_ERROR, "Out of memory.\n");
02473          }
02474          iks_delete(query);
02475          iks_delete(iq);
02476       }
02477    }
02478    switch (pak->subtype) {
02479    case IKS_TYPE_AVAILABLE:
02480       ast_debug(3, "JABBER: I am available ^_* %u\n", pak->subtype);
02481       break;
02482    case IKS_TYPE_UNAVAILABLE:
02483       ast_debug(3, "JABBER: I am unavailable ^_* %u\n", pak->subtype);
02484       break;
02485    default:
02486       ast_debug(3, "JABBER: Ohh sexy and the wrong type: %u\n", pak->subtype);
02487    }
02488    switch (pak->show) {
02489    case IKS_SHOW_UNAVAILABLE:
02490       ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
02491       break;
02492    case IKS_SHOW_AVAILABLE:
02493       ast_debug(3, "JABBER: type is available\n");
02494       break;
02495    case IKS_SHOW_CHAT:
02496       ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
02497       break;
02498    case IKS_SHOW_AWAY:
02499       ast_debug(3, "JABBER: type is away\n");
02500       break;
02501    case IKS_SHOW_XA:
02502       ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
02503       break;
02504    case IKS_SHOW_DND:
02505       ast_debug(3, "JABBER: type: %u subtype %u\n", pak->subtype, pak->show);
02506       break;
02507    default:
02508       ast_debug(3, "JABBER: Kinky! how did that happen %u\n", pak->show);
02509    }
02510 
02511    if (found) {
02512       manager_event(EVENT_FLAG_USER, "JabberStatus",
02513          "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
02514          "\r\nDescription: %s\r\n",
02515          client->name, pak->from->partial, found->resource, found->status,
02516          found->priority, S_OR(found->description, ""));
02517    } else {
02518       manager_event(EVENT_FLAG_USER, "JabberStatus",
02519          "Account: %s\r\nJID: %s\r\nStatus: %u\r\n",
02520          client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
02521    }
02522 }

static int aji_handle_pubsub_error ( void *  data,
ikspak *  pak 
) [static]

Definition at line 3505 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_debug, ast_log(), ast_test_flag, ASTOBJ_REF, ASTOBJ_UNREF, and LOG_ERROR.

Referenced by aji_init_event_distribution().

03506 {
03507    char *node_name;
03508    char *error;
03509    int error_num;
03510    iks *orig_request;
03511    iks *orig_pubsub = iks_find(pak->x, "pubsub");
03512    struct aji_client *client;
03513    if (!orig_pubsub) {
03514       ast_debug(1, "Error isn't a PubSub error, why are we here?\n");
03515       return IKS_FILTER_EAT;
03516    }
03517    orig_request = iks_child(orig_pubsub);
03518    error = iks_find_attrib(iks_find(pak->x, "error"), "code");
03519    node_name = iks_find_attrib(orig_request, "node");
03520    if (!sscanf(error, "%30d", &error_num)) {
03521       return IKS_FILTER_EAT;
03522    }
03523    if (error_num > 399 && error_num < 500 && error_num != 404) {
03524       ast_log(LOG_ERROR,
03525          "Error performing operation on PubSub node %s, %s.\n", node_name, error);
03526       return IKS_FILTER_EAT;
03527    } else if (error_num > 499 && error_num < 600) {
03528       ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
03529       return IKS_FILTER_EAT;
03530    }
03531 
03532    client = ASTOBJ_REF((struct aji_client *) data);
03533 
03534    if (!strcasecmp(iks_name(orig_request), "publish")) {
03535       iks *request;
03536       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03537          if (iks_find(iks_find(orig_request, "item"), "state")) {
03538             aji_create_pubsub_leaf(client, "device_state", node_name);
03539          } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
03540             aji_create_pubsub_leaf(client, "message_waiting", node_name);
03541          }
03542       } else {
03543          aji_create_pubsub_node(client, NULL, node_name, NULL);
03544       }
03545       request = aji_pubsub_iq_create(client, "set");
03546       iks_insert_node(request, orig_pubsub);
03547       ast_aji_send(client, request);
03548       iks_delete(request);
03549       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03550       return IKS_FILTER_EAT;
03551    } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
03552       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03553          aji_create_pubsub_collection(client, node_name);
03554       } else {
03555          aji_create_pubsub_node(client, NULL, node_name, NULL);
03556       }
03557    }
03558    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03559    return IKS_FILTER_EAT;
03560 }

static int aji_handle_pubsub_event ( void *  data,
ikspak *  pak 
) [static]

Callback for handling PubSub events.

Parameters:
data void pointer to aji_client structure
Returns:
IKS_FILTER_EAT

Definition at line 3264 of file res_jabber.c.

References AST_DEVSTATE_CACHABLE, ast_devstate_val(), ast_eid_cmp(), ast_eid_default, AST_EVENT_DEVICE_STATE_CHANGE, AST_EVENT_IE_CACHABLE, 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(), ast_event_queue_and_cache(), ast_log(), ast_str_to_eid(), LOG_DEBUG, LOG_ERROR, and mailbox.

Referenced by aji_init_event_distribution().

03265 {
03266    char *item_id, *device_state, *mailbox, *cachable_str;
03267    int oldmsgs, newmsgs;
03268    iks *item, *item_content;
03269    struct ast_eid pubsub_eid;
03270    struct ast_event *event;
03271    unsigned int cachable = AST_DEVSTATE_CACHABLE;
03272 
03273    item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
03274    if (!item) {
03275       ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
03276       return IKS_FILTER_EAT;
03277    }
03278    item_id = iks_find_attrib(item, "id");
03279    item_content = iks_child(item);
03280    ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
03281    if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
03282       ast_log(LOG_DEBUG, "Returning here, eid of incoming event matches ours!\n");
03283       return IKS_FILTER_EAT;
03284    }
03285    if (!strcasecmp(iks_name(item_content), "state")) {
03286       if ((cachable_str = iks_find_attrib(item_content, "cachable"))) {
03287          sscanf(cachable_str, "%30u", &cachable);
03288       }
03289       device_state = iks_find_cdata(item, "state");
03290       if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
03291                    AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
03292                    AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
03293                    AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03294                    AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable,
03295                    AST_EVENT_IE_END))) {
03296          return IKS_FILTER_EAT;
03297       }
03298    } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
03299       mailbox = strsep(&item_id, "@");
03300       sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
03301       sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
03302       if (!(event = ast_event_new(AST_EVENT_MWI,
03303          AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
03304          AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, item_id,
03305          AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, oldmsgs,
03306          AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, newmsgs,
03307          AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03308          AST_EVENT_IE_END))) {
03309          return IKS_FILTER_EAT;
03310       }
03311    } else {
03312       ast_log(LOG_DEBUG, "Don't know how to handle PubSub event of type %s\n",
03313          iks_name(item_content));
03314       return IKS_FILTER_EAT;
03315    }
03316 
03317    if (cachable == AST_DEVSTATE_CACHABLE) {
03318       ast_event_queue_and_cache(event);
03319    } else {
03320       ast_event_queue(event);
03321    }
03322 
03323    return IKS_FILTER_EAT;
03324 }

static void aji_handle_subscribe ( struct aji_client client,
ikspak *  pak 
) [static]

Definition at line 2531 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, aji_client::status, status, aji_client::statusmessage, and VERBOSE_PREFIX_3.

Referenced by aji_act_hook().

02532 {
02533    iks *presence = NULL, *status = NULL;
02534    struct aji_buddy* buddy = NULL;
02535 
02536    switch (pak->subtype) {
02537    case IKS_TYPE_SUBSCRIBE:
02538       if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
02539          presence = iks_new("presence");
02540          status = iks_new("status");
02541          if (presence && status) {
02542             iks_insert_attrib(presence, "type", "subscribed");
02543             iks_insert_attrib(presence, "to", pak->from->full);
02544             iks_insert_attrib(presence, "from", client->jid->full);
02545             if (pak->id)
02546                iks_insert_attrib(presence, "id", pak->id);
02547             iks_insert_cdata(status, "Asterisk has approved subscription", 0);
02548             iks_insert_node(presence, status);
02549             ast_aji_send(client, presence);
02550          } else {
02551             ast_log(LOG_ERROR, "Unable to allocate nodes\n");
02552          }
02553 
02554          iks_delete(presence);
02555          iks_delete(status);
02556       }
02557 
02558       if (client->component)
02559          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02560    case IKS_TYPE_SUBSCRIBED:
02561       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02562       if (!buddy && pak->from->partial) {
02563          aji_create_buddy(pak->from->partial, client);
02564       } else if (buddy) {
02565          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02566       }
02567    default:
02568       if (option_verbose > 4) {
02569          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %u\n", pak->subtype);
02570       }
02571    }
02572 }

static void aji_init_event_distribution ( struct aji_client client  )  [static]

Initialize collections for event distribution.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
void

Definition at line 3235 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().

03236 {
03237    if (!mwi_sub) {
03238       mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
03239          client, AST_EVENT_IE_END);
03240    }
03241    if (!device_state_sub) {
03242       if (ast_enable_distributed_devstate()) {
03243          return;
03244       }
03245       device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
03246          aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
03247       ast_event_dump_cache(device_state_sub);
03248    }
03249 
03250    aji_pubsub_subscribe(client, "device_state");
03251    aji_pubsub_subscribe(client, "message_waiting");
03252    iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
03253       IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
03254    iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
03255       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
03256 
03257 }

static int aji_initialize ( struct aji_client client  )  [static]

Definition at line 3125 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().

03126 {
03127    int connected = IKS_NET_NOCONN;
03128 
03129 #ifdef HAVE_OPENSSL
03130    /* reset stream flags */
03131    client->stream_flags = 0;
03132 #endif
03133    /* If it's a component, connect to user, otherwise, connect to server */
03134    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
03135 
03136    if (connected == IKS_NET_NOCONN) {
03137       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
03138       return IKS_HOOK;
03139    } else if (connected == IKS_NET_NODNS) {
03140       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name,
03141          S_OR(client->serverhost, client->jid->server));
03142       return IKS_HOOK;
03143    }
03144 
03145    return IKS_OK;
03146 }

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().

01297 {
01298    struct pollfd pfd = { .events = POLLIN };
01299    int len, res;
01300 
01301 #ifdef HAVE_OPENSSL
01302    if (aji_is_secure(client)) {
01303       pfd.fd = SSL_get_fd(client->ssl_session);
01304       if (pfd.fd < 0) {
01305          return -1;
01306       }
01307    } else
01308 #endif /* HAVE_OPENSSL */
01309       pfd.fd = iks_fd(client->p);
01310 
01311    res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
01312    if (res > 0) {
01313 #ifdef HAVE_OPENSSL
01314       if (aji_is_secure(client)) {
01315          len = SSL_read(client->ssl_session, buffer, buf_len);
01316       } else
01317 #endif /* HAVE_OPENSSL */
01318          len = recv(pfd.fd, buffer, buf_len, 0);
01319 
01320       if (len > 0) {
01321          return len;
01322       } else if (len <= 0) {
01323          return -1;
01324       }
01325    }
01326    return res;
01327 }

static int aji_is_secure ( struct aji_client client  )  [static]

Definition at line 1203 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().

01204 {
01205 #ifdef HAVE_OPENSSL
01206    return client->stream_flags & SECURE;
01207 #else
01208    return 0;
01209 #endif
01210 }

static int aji_join_exec ( struct ast_channel chan,
const char *  data 
) [static]

Application to join a chat room.

Parameters:
chan ast_channel
data Data is sender|jid|nickname.
Return values:
0 success
-1 error

Definition at line 988 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().

00989 {
00990    struct aji_client *client = NULL;
00991    char *s;
00992    char nick[AJI_MAX_RESJIDLEN];
00993 
00994    AST_DECLARE_APP_ARGS(args,
00995       AST_APP_ARG(sender);
00996       AST_APP_ARG(jid);
00997       AST_APP_ARG(nick);
00998    );
00999 
01000    if (!data) {
01001       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
01002       return -1;
01003    }
01004    s = ast_strdupa(data);
01005 
01006    AST_STANDARD_APP_ARGS(args, s);
01007    if (args.argc < 2 || args.argc > 3) {
01008       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
01009       return -1;
01010    }
01011 
01012    if (strchr(args.jid, '/')) {
01013       ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
01014       return -1;
01015    }
01016 
01017    if (!(client = ast_aji_get_client(args.sender))) {
01018       ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01019       return -1;
01020    }
01021 
01022    if (!ast_strlen_zero(args.nick)) {
01023       snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
01024    } else {
01025       if (client->component) {
01026          sprintf(nick, "asterisk");
01027       } else {
01028          snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
01029       }
01030    }
01031 
01032    if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
01033       ast_aji_join_chat(client, args.jid, nick);
01034    } else {
01035       ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
01036    }
01037 
01038    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01039    return 0;
01040 }

static int aji_leave_exec ( struct ast_channel chan,
const char *  data 
) [static]

Application to leave a chat room.

Parameters:
chan ast_channel
data Data is sender|jid|nickname.
Return values:
0 success
-1 error

Definition at line 1049 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().

01050 {
01051    struct aji_client *client = NULL;
01052    char *s;
01053    char nick[AJI_MAX_RESJIDLEN];
01054    AST_DECLARE_APP_ARGS(args,
01055       AST_APP_ARG(sender);
01056       AST_APP_ARG(jid);
01057       AST_APP_ARG(nick);
01058    );
01059 
01060    if (!data) {
01061       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
01062       return -1;
01063    }
01064    s = ast_strdupa(data);
01065 
01066    AST_STANDARD_APP_ARGS(args, s);
01067    if (args.argc < 2 || args.argc > 3) {
01068       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
01069       return -1;
01070    }
01071 
01072    if (strchr(args.jid, '/')) {
01073       ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
01074       return -1;
01075    }
01076 
01077    if (!(client = ast_aji_get_client(args.sender))) {
01078       ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01079       return -1;
01080    }
01081 
01082    if (!ast_strlen_zero(args.nick)) {
01083       snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
01084    } else {
01085       if (client->component) {
01086          sprintf(nick, "asterisk");
01087       } else {
01088          snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
01089       }
01090    }
01091 
01092    if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
01093       ast_aji_leave_chat(client, args.jid, nick);
01094    }
01095    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01096    return 0;
01097 }

static int aji_load_config ( int  reload  )  [static]

Definition at line 4517 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, JABBER_CONFIG, LOG_WARNING, ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by aji_reload().

04518 {
04519    char *cat = NULL;
04520    int debug = 0;
04521    struct ast_config *cfg = NULL;
04522    struct ast_variable *var = NULL;
04523    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04524 
04525    if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
04526       return -1;
04527    }
04528 
04529    /* Reset flags to default value */
04530    ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT);
04531 
04532    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
04533       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
04534       return 0;
04535    }
04536 
04537    cat = ast_category_browse(cfg, NULL);
04538    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04539       if (!strcasecmp(var->name, "debug")) {
04540          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
04541       } else if (!strcasecmp(var->name, "autoprune")) {
04542          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
04543       } else if (!strcasecmp(var->name, "autoregister")) {
04544          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
04545       } else if (!strcasecmp(var->name, "collection_nodes")) {
04546          ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248);
04547       } else if (!strcasecmp(var->name, "pubsub_autocreate")) {
04548          ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE);
04549       } else if (!strcasecmp(var->name, "auth_policy")) {
04550          if (!strcasecmp(var->value, "accept")) {
04551             ast_set_flag(&globalflags, AJI_AUTOACCEPT);
04552          } else {
04553             ast_clear_flag(&globalflags, AJI_AUTOACCEPT);
04554          }
04555       }
04556    }
04557 
04558    while (cat) {
04559       if (strcasecmp(cat, "general")) {
04560          var = ast_variable_browse(cfg, cat);
04561          aji_create_client(cat, var, debug);
04562       }
04563       cat = ast_category_browse(cfg, cat);
04564    }
04565    ast_config_destroy(cfg); /* or leak memory */
04566    return 1;
04567 }

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().

01488 {
01489    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01490 
01491    if (!ast_strlen_zero(xmpp)) {
01492       manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
01493    }
01494 
01495    if (client->debug) {
01496       if (is_incoming) {
01497          ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
01498       } else {
01499          if (strlen(xmpp) == 1) {
01500             if (option_debug > 2  && xmpp[0] == ' ') {
01501                ast_verbose("\nJABBER: Keep alive packet\n");
01502             }
01503          } else {
01504             ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
01505          }
01506       }
01507 
01508    }
01509    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01510 }

static void aji_message_destroy ( struct aji_message obj  )  [static]

Definition at line 451 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().

00452 {
00453    if (obj->from) {
00454       ast_free(obj->from);
00455    }
00456    if (obj->message) {
00457       ast_free(obj->message);
00458    }
00459    ast_free(obj);
00460 }

static void aji_mwi_cb ( const struct ast_event ast_event,
void *  data 
) [static]

Callback function for MWI events.

Parameters:
ast_event 
data void pointer to ast_client structure
Returns:
void

Definition at line 3178 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().

03179 {
03180    const char *mailbox;
03181    const char *context;
03182    char oldmsgs[10];
03183    char newmsgs[10];
03184    struct aji_client *client;
03185    if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03186    {
03187       /* If the event didn't originate from this server, don't send it back out. */
03188       ast_log(LOG_DEBUG, "Returning here\n");
03189       return;
03190    }
03191 
03192    client = ASTOBJ_REF((struct aji_client *) data);
03193    mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
03194    context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
03195    snprintf(oldmsgs, sizeof(oldmsgs), "%u",
03196       ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
03197    snprintf(newmsgs, sizeof(newmsgs), "%u",
03198       ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
03199    aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
03200    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03201 
03202 }

static void aji_pruneregister ( struct aji_client client  )  [static]

Definition at line 2899 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.

02900 {
02901    iks *removeiq = iks_new("iq");
02902    iks *removequery = iks_new("query");
02903    iks *removeitem = iks_new("item");
02904    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02905    if (!client || !removeiq || !removequery || !removeitem || !send) {
02906       ast_log(LOG_ERROR, "Out of memory.\n");
02907       goto safeout;
02908    }
02909 
02910    iks_insert_node(removeiq, removequery);
02911    iks_insert_node(removequery, removeitem);
02912    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02913       ASTOBJ_RDLOCK(iterator);
02914       /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
02915        * be called at the same time */
02916       if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
02917          ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02918                          "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02919                          " so I am no longer subscribing to your presence.\n"));
02920          ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02921                          "GoodBye.  You are no longer in the Asterisk config file so I am removing"
02922                          " your access to my presence.\n"));
02923          iks_insert_attrib(removeiq, "from", client->jid->full);
02924          iks_insert_attrib(removeiq, "type", "set");
02925          iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02926          iks_insert_attrib(removeitem, "jid", iterator->name);
02927          iks_insert_attrib(removeitem, "subscription", "remove");
02928          ast_aji_send(client, removeiq);
02929       } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02930          ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
02931                          "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02932          ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02933       }
02934       ASTOBJ_UNLOCK(iterator);
02935    });
02936 
02937  safeout:
02938    iks_delete(removeiq);
02939    iks_delete(removequery);
02940    iks_delete(removeitem);
02941    iks_delete(send);
02942 
02943    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
02944 }

static void aji_publish_device_state ( struct aji_client client,
const char *  device,
const char *  device_state,
unsigned int  cachable 
) [static]

Publish device state to a PubSub node.

Parameters:
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
Returns:
void

Definition at line 3438 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(), and ast_test_flag.

Referenced by aji_devstate_cb().

03440 {
03441    iks *request = aji_build_publish_skeleton(client, device, "device_state", cachable);
03442    iks *state;
03443    char eid_str[20], cachable_str[2];
03444    if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
03445       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03446          aji_create_pubsub_node(client, "leaf", device, "device_state");
03447       } else {
03448          aji_create_pubsub_node(client, NULL, device, NULL);
03449       }
03450    }
03451    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03452    state = iks_insert(request, "state");
03453    iks_insert_attrib(state, "xmlns", "http://asterisk.org");
03454    iks_insert_attrib(state, "eid", eid_str);
03455    snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
03456    iks_insert_attrib(state, "cachable", cachable_str);
03457    iks_insert_cdata(state, device_state, strlen(device_state));
03458    ast_aji_send(client, iks_root(request));
03459    iks_delete(request);
03460 }

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.

Parameters:
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
Returns:
void

Definition at line 3469 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().

03471 {
03472    char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
03473    char eid_str[20];
03474    iks *mailbox_node, *request;
03475    snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
03476    request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting", 1);
03477    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03478    mailbox_node = iks_insert(request, "mailbox");
03479    iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
03480    iks_insert_attrib(mailbox_node, "eid", eid_str);
03481    iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
03482    iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
03483    ast_aji_send(client, iks_root(request));
03484    iks_delete(request);
03485 }

static iks * aji_pubsub_iq_create ( struct aji_client client,
const char *  type 
) [static]

Create an IQ packet.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
type the type of IQ packet to create
Returns:
iks*

Definition at line 3493 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().

03494 {
03495    iks *request = iks_new("iq");
03496 
03497    iks_insert_attrib(request, "to", client->pubsub_node);
03498    iks_insert_attrib(request, "from", client->jid->full);
03499    iks_insert_attrib(request, "type", type);
03500    ast_aji_increment_mid(client->mid);
03501    iks_insert_attrib(request, "id", client->mid);
03502    return request;
03503 }

static void aji_pubsub_purge_nodes ( struct aji_client client,
const char *  collection_name 
) [static]

Definition at line 3713 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().

03714 {
03715    iks *request = aji_build_node_request(client, collection_name);
03716    ast_aji_send(client, request);
03717    iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
03718       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03719       IKS_RULE_DONE);
03720    ast_aji_send(client, request);
03721    iks_delete(request);
03722 }

static void aji_pubsub_subscribe ( struct aji_client client,
const char *  node 
) [static]

Subscribe to a PubSub node.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
node the name of the node to which to subscribe
Returns:
void

Definition at line 3357 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().

03358 {
03359    iks *request = aji_pubsub_iq_create(client, "set");
03360    iks *pubsub, *subscribe;
03361 
03362    pubsub = iks_insert(request, "pubsub");
03363    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03364    subscribe = iks_insert(pubsub, "subscribe");
03365    iks_insert_attrib(subscribe, "jid", client->jid->partial);
03366    iks_insert_attrib(subscribe, "node", node);
03367    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03368       iks *options, *x, *sub_options, *sub_type, *sub_depth;
03369       options = iks_insert(pubsub, "options");
03370       x = iks_insert(options, "x");
03371       iks_insert_attrib(x, "xmlns", "jabber:x:data");
03372       iks_insert_attrib(x, "type", "submit");
03373       sub_options = iks_insert(x, "field");
03374       iks_insert_attrib(sub_options, "var", "FORM_TYPE");
03375       iks_insert_attrib(sub_options, "type", "hidden");
03376       iks_insert_cdata(iks_insert(sub_options, "value"),
03377          "http://jabber.org/protocol/pubsub#subscribe_options", 51);
03378       sub_type = iks_insert(x, "field");
03379       iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
03380       iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
03381       sub_depth = iks_insert(x, "field");
03382       iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
03383       iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
03384    }
03385    ast_aji_send(client, request);
03386    iks_delete(request);
03387 }

static int aji_receive_node_list ( void *  data,
ikspak *  pak 
) [static]

Receive pubsub item lists.

Parameters:
data pointer to aji_client structure
pak response from pubsub diso::items query
Returns:
IKS_FILTER_EAT

Definition at line 3604 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().

03605 {
03606 
03607    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03608    iks *item = NULL;
03609    if (iks_has_children(pak->query)) {
03610       item = iks_first_tag(pak->query);
03611       ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
03612          iks_find_attrib(item, "node"));
03613       while ((item = iks_next_tag(item))) {
03614          ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
03615       }
03616    }
03617    if (item) {
03618       iks_delete(item);
03619    }
03620    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03621    return IKS_FILTER_EAT;
03622 }

static int aji_reconnect ( struct aji_client client  )  [static]

Definition at line 3041 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().

03042 {
03043    int res = 0;
03044 
03045    if (client->state) {
03046       client->state = AJI_DISCONNECTED;
03047    }
03048    client->timeout = 50;
03049    if (client->p) {
03050       iks_parser_reset(client->p);
03051    }
03052    if (client->authorized) {
03053       client->authorized = 0;
03054    }
03055 
03056    res = aji_initialize(client);
03057 
03058    return res;
03059 }

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().

01342 {
01343    int len, ret;
01344    char buf[NET_IO_BUF_SIZE - 1];
01345    char newbuf[NET_IO_BUF_SIZE - 1];
01346    int pos = 0;
01347    int newbufpos = 0;
01348    unsigned char c;
01349 
01350    memset(buf, 0, sizeof(buf));
01351    memset(newbuf, 0, sizeof(newbuf));
01352 
01353    while (1) {
01354       len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
01355       if (len < 0) return IKS_NET_RWERR;
01356       if (len == 0) return IKS_NET_EXPIRED;
01357       buf[len] = '\0';
01358 
01359       /* our iksemel parser won't work as expected if we feed
01360          it with XML packets that contain multiple whitespace
01361          characters between tags */
01362       while (pos < len) {
01363          c = buf[pos];
01364          /* if we stumble on the ending tag character,
01365             we skip any whitespace that follows it*/
01366          if (c == '>') {
01367             while (isspace(buf[pos+1])) {
01368                pos++;
01369             }
01370          }
01371          newbuf[newbufpos] = c;
01372          newbufpos ++;
01373          pos++;
01374       }
01375       pos = 0;
01376       newbufpos = 0;
01377 
01378       /* Log the message here, because iksemel's logHook is
01379          unaccessible */
01380       aji_log_hook(client, buf, len, 1);
01381 
01382       /* let iksemel deal with the string length,
01383          and reset our buffer */
01384       ret = iks_parse(client->p, newbuf, 0, 0);
01385       memset(newbuf, 0, sizeof(newbuf));
01386 
01387       switch (ret) {
01388       case IKS_NOMEM:
01389          ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
01390          break;
01391       case IKS_BADXML:
01392          ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
01393          break;
01394       case IKS_HOOK:
01395          ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
01396          break;
01397       }
01398       if (ret != IKS_OK) {
01399          return ret;
01400       }
01401       ast_debug(3, "XML parsing successful\n");
01402    }
01403    return IKS_OK;
01404 }

static void * aji_recv_loop ( void *  data  )  [static]

Definition at line 2733 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().

02734 {
02735    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02736    int res = IKS_HOOK;
02737 
02738    while (res != IKS_OK) {
02739       ast_debug(3, "JABBER: Connecting.\n");
02740       res = aji_reconnect(client);
02741       sleep(4);
02742    }
02743 
02744    do {
02745       if (res == IKS_NET_RWERR || client->timeout == 0) {
02746          while (res != IKS_OK) {
02747             ast_debug(3, "JABBER: reconnecting.\n");
02748             res = aji_reconnect(client);
02749             sleep(4);
02750          }
02751       }
02752 
02753       res = aji_recv(client, 1);
02754 
02755       if (client->state == AJI_DISCONNECTING) {
02756          ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
02757          pthread_exit(NULL);
02758       }
02759 
02760       /* Decrease timeout if no data received, and delete
02761        * old messages globally */
02762       if (res == IKS_NET_EXPIRED) {
02763          client->timeout--;
02764          delete_old_messages_all(client);
02765       }
02766       if (res == IKS_HOOK) {
02767          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
02768       } else if (res == IKS_NET_TLSFAIL) {
02769          ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
02770       } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
02771          res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
02772          if (res == IKS_OK) {
02773             client->timeout = 50;
02774          } else {
02775             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
02776          }
02777       } else if (res == IKS_NET_RWERR) {
02778          ast_log(LOG_WARNING, "JABBER: socket read error\n");
02779       }
02780    } while (client);
02781    ASTOBJ_UNREF(client, ast_aji_client_destroy);
02782    return 0;
02783 }

static int aji_register_approve_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 1790 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().

01791 {
01792    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01793    iks *iq = NULL, *presence = NULL, *x = NULL;
01794 
01795    iq = iks_new("iq");
01796    presence = iks_new("presence");
01797    x = iks_new("x");
01798    if (client && iq && presence && x) {
01799       if (!iks_find(pak->query, "remove")) {
01800          iks_insert_attrib(iq, "from", client->jid->full);
01801          iks_insert_attrib(iq, "to", pak->from->full);
01802          iks_insert_attrib(iq, "id", pak->id);
01803          iks_insert_attrib(iq, "type", "result");
01804          ast_aji_send(client, iq);
01805 
01806          iks_insert_attrib(presence, "from", client->jid->full);
01807          iks_insert_attrib(presence, "to", pak->from->partial);
01808          iks_insert_attrib(presence, "id", client->mid);
01809          ast_aji_increment_mid(client->mid);
01810          iks_insert_attrib(presence, "type", "subscribe");
01811          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01812          iks_insert_node(presence, x);
01813          ast_aji_send(client, presence);
01814       }
01815    } else {
01816       ast_log(LOG_ERROR, "Out of memory.\n");
01817    }
01818 
01819    iks_delete(iq);
01820    iks_delete(presence);
01821    iks_delete(x);
01822 
01823    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01824    return IKS_FILTER_EAT;
01825 }

static int aji_register_query_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 1833 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().

01834 {
01835    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01836    struct aji_buddy *buddy = NULL;
01837    char *node = NULL;
01838    iks *iq = NULL, *query = NULL;
01839 
01840    client = (struct aji_client *) data;
01841 
01842    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01843    if (!buddy) {
01844       iks  *error = NULL, *notacceptable = NULL;
01845 
01846       ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01847       iq = iks_new("iq");
01848       query = iks_new("query");
01849       error = iks_new("error");
01850       notacceptable = iks_new("not-acceptable");
01851       if (iq && query && error && notacceptable) {
01852          iks_insert_attrib(iq, "type", "error");
01853          iks_insert_attrib(iq, "from", client->user);
01854          iks_insert_attrib(iq, "to", pak->from->full);
01855          iks_insert_attrib(iq, "id", pak->id);
01856          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01857          iks_insert_attrib(error, "code" , "406");
01858          iks_insert_attrib(error, "type", "modify");
01859          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01860          iks_insert_node(iq, query);
01861          iks_insert_node(iq, error);
01862          iks_insert_node(error, notacceptable);
01863          ast_aji_send(client, iq);
01864       } else {
01865          ast_log(LOG_ERROR, "Out of memory.\n");
01866       }
01867 
01868       iks_delete(error);
01869       iks_delete(notacceptable);
01870    } else if (!(node = iks_find_attrib(pak->query, "node"))) {
01871       iks *instructions = NULL;
01872       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01873       iq = iks_new("iq");
01874       query = iks_new("query");
01875       instructions = iks_new("instructions");
01876       if (iq && query && instructions && client) {
01877          iks_insert_attrib(iq, "from", client->user);
01878          iks_insert_attrib(iq, "to", pak->from->full);
01879          iks_insert_attrib(iq, "id", pak->id);
01880          iks_insert_attrib(iq, "type", "result");
01881          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01882          iks_insert_cdata(instructions, explain, 0);
01883          iks_insert_node(iq, query);
01884          iks_insert_node(query, instructions);
01885          ast_aji_send(client, iq);
01886       } else {
01887          ast_log(LOG_ERROR, "Out of memory.\n");
01888       }
01889 
01890       iks_delete(instructions);
01891    }
01892    iks_delete(iq);
01893    iks_delete(query);
01894    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01895    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01896    return IKS_FILTER_EAT;
01897 }

static int aji_reload ( int  reload  )  [static]

Definition at line 4654 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().

04655 {
04656    int res;
04657 
04658    ASTOBJ_CONTAINER_MARKALL(&clients);
04659    if (!(res = aji_load_config(reload))) {
04660       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
04661       return 0;
04662    } else if (res == -1)
04663       return 1;
04664 
04665    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
04666    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04667       ASTOBJ_RDLOCK(iterator);
04668       if (iterator->state == AJI_DISCONNECTED) {
04669          if (!iterator->thread)
04670             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
04671       } else if (iterator->state == AJI_CONNECTING) {
04672          aji_get_roster(iterator);
04673          if (iterator->distribute_events) {
04674             aji_init_event_distribution(iterator);
04675          }
04676       }
04677 
04678       ASTOBJ_UNLOCK(iterator);
04679    });
04680 
04681    return 1;
04682 }

static void aji_request_pubsub_nodes ( struct aji_client client,
const char *  collection 
) [static]

Request item list from pubsub.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
collection name of the collection for request
Returns:
void

Definition at line 3568 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().

03569 {
03570    iks *request = aji_build_node_request(client, collection);
03571 
03572    iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
03573       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03574       IKS_RULE_DONE);
03575    ast_aji_send(client, request);
03576    iks_delete(request);
03577 
03578 }

static int aji_send_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 1107 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().

01108 {
01109    struct aji_client *client = NULL;
01110    char *s;
01111    AST_DECLARE_APP_ARGS(args,
01112       AST_APP_ARG(sender);
01113       AST_APP_ARG(recipient);
01114       AST_APP_ARG(message);
01115    );
01116 
01117    if (!data) {
01118       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01119       return -1;
01120    }
01121    s = ast_strdupa(data);
01122 
01123    AST_STANDARD_APP_ARGS(args, s);
01124    if (args.argc < 3) {
01125       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01126       return -1;
01127    }
01128 
01129    if (!(client = ast_aji_get_client(args.sender))) {
01130       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
01131       return -1;
01132    }
01133    if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
01134       ast_aji_send_chat(client, args.recipient, args.message);
01135    }
01136    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01137    return 0;
01138 }

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().

01414 {
01415    char *msg;
01416    int len, err;
01417 
01418    len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
01419    msg = iks_malloc(len);
01420    if (!msg)
01421       return IKS_NOMEM;
01422    sprintf(msg, "<?xml version='1.0'?>"
01423       "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
01424       "%s' to='%s' version='1.0'>", client->name_space, to);
01425    err = aji_send_raw(client, msg);
01426    iks_free(msg);
01427    if (err != IKS_OK)
01428       return err;
01429 
01430    return IKS_OK;
01431 }

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().

01454 {
01455    int ret;
01456 #ifdef HAVE_OPENSSL
01457    int len = strlen(xmlstr);
01458 
01459    if (aji_is_secure(client)) {
01460       ret = SSL_write(client->ssl_session, xmlstr, len);
01461       if (ret) {
01462          /* Log the message here, because iksemel's logHook is
01463             unaccessible */
01464          aji_log_hook(client, xmlstr, len, 0);
01465          return IKS_OK;
01466       }
01467    }
01468 #endif
01469    /* If needed, data will be sent unencrypted, and logHook will
01470       be called inside iks_send_raw */
01471    ret = iks_send_raw(client->p, xmlstr);
01472    if (ret != IKS_OK) {
01473       return ret;
01474    }
01475 
01476    return IKS_OK;
01477 }

static int aji_send_raw_chat ( struct aji_client client,
int  groupchat,
const char *  nick,
const char *  address,
const char *  message 
) [static]

sends messages.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
groupchat 
nick the nickname we use in chatrooms
address 
message 
Returns:
IKS_OK on success, any other value on failure

Definition at line 2609 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().

02610 {
02611    int res = 0;
02612    iks *message_packet = NULL;
02613    char from[AJI_MAX_JIDLEN];
02614    /* the nickname is used only in component mode */
02615    if (nick && client->component) {
02616       snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
02617    } else {
02618       snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
02619    }
02620 
02621    if (client->state != AJI_CONNECTED) {
02622       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
02623       return -1;
02624    }
02625 
02626    message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
02627    if (!message_packet) {
02628       ast_log(LOG_ERROR, "Out of memory.\n");
02629       return -1;
02630    }
02631    iks_insert_attrib(message_packet, "from", from);
02632    res = ast_aji_send(client, message_packet);
02633    iks_delete(message_packet);
02634 
02635    return res;
02636 }

static int aji_sendgroup_exec ( struct ast_channel chan,
const char *  data 
) [static]

Application to send a message to a groupchat.

Parameters:
chan ast_channel
data Data is sender|groupchat|message.
Return values:
0 success
-1 error

Definition at line 1147 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().

01148 {
01149    struct aji_client *client = NULL;
01150    char *s;
01151    char nick[AJI_MAX_RESJIDLEN];
01152    int res = 0;
01153    AST_DECLARE_APP_ARGS(args,
01154       AST_APP_ARG(sender);
01155       AST_APP_ARG(groupchat);
01156       AST_APP_ARG(message);
01157       AST_APP_ARG(nick);
01158    );
01159 
01160    if (!data) {
01161       ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01162       return -1;
01163    }
01164    s = ast_strdupa(data);
01165 
01166    AST_STANDARD_APP_ARGS(args, s);
01167    if (args.argc < 3 || args.argc > 4) {
01168       ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01169       return -1;
01170    }
01171 
01172    if (!(client = ast_aji_get_client(args.sender))) {
01173       ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01174       return -1;
01175    }
01176 
01177    if (ast_strlen_zero(args.nick) || args.argc == 3) {
01178       if (client->component) {
01179          sprintf(nick, "asterisk");
01180       } else {
01181          snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
01182       }
01183    } else {
01184       snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
01185    }
01186 
01187    if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
01188       res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
01189    }
01190 
01191    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01192    if (res != IKS_OK) {
01193       return -1;
01194    }
01195    return 0;
01196 }

static int aji_set_group_presence ( struct aji_client client,
char *  room,
int  level,
char *  nick,
char *  desc 
) [static]

Definition at line 4034 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().

04035 {
04036    int res = 0;
04037    iks *presence = NULL, *x = NULL;
04038    char from[AJI_MAX_JIDLEN];
04039    char roomid[AJI_MAX_JIDLEN];
04040 
04041    presence = iks_make_pres(level, NULL);
04042    x = iks_new("x");
04043 
04044    if (client->component) {
04045       snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
04046       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
04047    } else {
04048       snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
04049       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
04050    }
04051 
04052    if (!presence || !x || !client) {
04053       ast_log(LOG_ERROR, "Out of memory.\n");
04054       res = -1;
04055       goto safeout;
04056    } else {
04057       iks_insert_attrib(presence, "to", roomid);
04058       iks_insert_attrib(presence, "from", from);
04059       iks_insert_attrib(x, "xmlns", MUC_NS);
04060       iks_insert_node(presence, x);
04061       res = ast_aji_send(client, presence);
04062    }
04063 
04064 safeout:
04065    iks_delete(presence);
04066    iks_delete(x);
04067    return res;
04068 }

static void aji_set_presence ( struct aji_client client,
char *  to,
char *  from,
int  level,
char *  desc 
) [static]

Definition at line 3992 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().

03993 {
03994    iks *presence = iks_make_pres(level, desc);
03995    iks *cnode = iks_new("c");
03996    iks *priority = iks_new("priority");
03997    char priorityS[10];
03998 
03999    if (presence && cnode && client && priority) {
04000       if (to) {
04001          iks_insert_attrib(presence, "to", to);
04002       }
04003       if (from) {
04004          iks_insert_attrib(presence, "from", from);
04005       }
04006       snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
04007       iks_insert_cdata(priority, priorityS, strlen(priorityS));
04008       iks_insert_node(presence, priority);
04009       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
04010       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
04011       iks_insert_attrib(cnode, "ext", "voice-v1");
04012       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
04013       iks_insert_node(presence, cnode);
04014       ast_aji_send(client, presence);
04015    } else {
04016       ast_log(LOG_ERROR, "Out of memory.\n");
04017    }
04018 
04019    iks_delete(cnode);
04020    iks_delete(presence);
04021    iks_delete(priority);
04022 }

static char * aji_show_buddies ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4186 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.

04187 {
04188    struct aji_resource *resource;
04189    struct aji_client *client;
04190 
04191    switch (cmd) {
04192    case CLI_INIT:
04193       e->command = "jabber show buddies";
04194       e->usage =
04195          "Usage: jabber show buddies\n"
04196          "       Shows buddy lists of our clients\n";
04197       return NULL;
04198    case CLI_GENERATE:
04199       return NULL;
04200    }
04201 
04202    ast_cli(a->fd, "Jabber buddy lists\n");
04203    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04204       ast_cli(a->fd, "Client: %s\n", iterator->user);
04205       client = iterator;
04206       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04207          ASTOBJ_RDLOCK(iterator);
04208          ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
04209          if (!iterator->resources)
04210             ast_cli(a->fd, "\t\tResource: None\n");
04211          for (resource = iterator->resources; resource; resource = resource->next) {
04212             ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
04213             if (resource->cap) {
04214                ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
04215                ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
04216                ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
04217             }
04218             ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
04219             ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
04220          }
04221          ASTOBJ_UNLOCK(iterator);
04222       });
04223       iterator = client;
04224    });
04225    return CLI_SUCCESS;
04226 }

static char * aji_show_clients ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4140 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.

04141 {
04142    char *status;
04143    int count = 0;
04144 
04145    switch (cmd) {
04146    case CLI_INIT:
04147       e->command = "jabber show connections";
04148       e->usage =
04149          "Usage: jabber show connections\n"
04150          "       Shows state of client and component connections\n";
04151       return NULL;
04152    case CLI_GENERATE:
04153       return NULL;
04154    }
04155 
04156    ast_cli(a->fd, "Jabber Users and their status:\n");
04157    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04158       ASTOBJ_RDLOCK(iterator);
04159       count++;
04160       switch (iterator->state) {
04161       case AJI_DISCONNECTED:
04162          status = "Disconnected";
04163          break;
04164       case AJI_CONNECTING:
04165          status = "Connecting";
04166          break;
04167       case AJI_CONNECTED:
04168          status = "Connected";
04169          break;
04170       default:
04171          status = "Unknown";
04172       }
04173       ast_cli(a->fd, "       [%s] %s     - %s\n", iterator->name, iterator->user, status);
04174       ASTOBJ_UNLOCK(iterator);
04175    });
04176    ast_cli(a->fd, "----\n");
04177    ast_cli(a->fd, "   Number of users: %d\n", count);
04178    return CLI_SUCCESS;
04179 }

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_alloca, ast_base64encode(), ast_log(), base64, len(), LOG_ERROR, and aji_client::p.

Referenced by aji_act_hook().

01523 {
01524    iks *x = NULL;
01525    int len;
01526    char *s;
01527    char *base64;
01528 
01529    /* trigger SASL DIGEST-MD5 only over an unsecured connection.
01530       iks_start_sasl is an iksemel API function and relies on GnuTLS,
01531       whereas we use OpenSSL */
01532    if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
01533       return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
01534    if (!(type & IKS_STREAM_SASL_PLAIN)) {
01535       ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
01536       return IKS_NET_NOTSUPP;
01537    }
01538 
01539    x = iks_new("auth"); 
01540    if (!x) {
01541       ast_log(LOG_ERROR, "Out of memory.\n");
01542       return IKS_NET_NOTSUPP;
01543    }
01544 
01545    iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
01546    len = strlen(username) + strlen(pass) + 3;
01547    s = ast_alloca(len);
01548    base64 = ast_alloca((len + 2) * 4 / 3);
01549    iks_insert_attrib(x, "mechanism", "PLAIN");
01550    snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
01551 
01552    /* exclude the NULL training byte from the base64 encoding operation
01553       as some XMPP servers will refuse it.
01554       The format for authentication is [authzid]\0authcid\0password
01555       not [authzid]\0authcid\0password\0 */
01556    ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
01557    iks_insert_cdata(x, base64, 0);
01558    ast_aji_send(client, x);
01559    iks_delete(x);
01560 
01561    return IKS_OK;
01562 }

static int aji_start_tls ( struct aji_client client  )  [static]

Definition at line 1220 of file res_jabber.c.

References aji_client::p, aji_client::stream_flags, and TRY_SECURE.

Referenced by aji_act_hook().

01221 {
01222    int ret;
01223 
01224    /* This is sent not encrypted */
01225    if ((ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"))) {
01226       return ret;
01227    }
01228 
01229    client->stream_flags |= TRY_SECURE;
01230    return IKS_OK;
01231 }

static int aji_status_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 620 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().

00621 {
00622    struct aji_client *client = NULL;
00623    struct aji_buddy *buddy = NULL;
00624    struct aji_resource *r = NULL;
00625    char *s = NULL;
00626    int stat = 7;
00627    char status[2];
00628    static int deprecation_warning = 0;
00629    AST_DECLARE_APP_ARGS(args,
00630       AST_APP_ARG(sender);
00631       AST_APP_ARG(jid);
00632       AST_APP_ARG(variable);
00633    );
00634    AST_DECLARE_APP_ARGS(jid,
00635       AST_APP_ARG(screenname);
00636       AST_APP_ARG(resource);
00637    );
00638 
00639    if (deprecation_warning++ % 10 == 0) {
00640       ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
00641    }
00642 
00643    if (!data) {
00644       ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
00645       return 0;
00646    }
00647    s = ast_strdupa(data);
00648    AST_STANDARD_APP_ARGS(args, s);
00649 
00650    if (args.argc != 3) {
00651       ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
00652       return -1;
00653    }
00654 
00655    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00656    if (jid.argc < 1 || jid.argc > 2) {
00657       ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
00658       return -1;
00659    }
00660 
00661    if (!(client = ast_aji_get_client(args.sender))) {
00662       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00663       return -1;
00664    }
00665    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00666    if (!buddy) {
00667       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00668       ASTOBJ_UNREF(client, ast_aji_client_destroy);
00669       return -1;
00670    }
00671    r = aji_find_resource(buddy, jid.resource);
00672    if (!r && buddy->resources) {
00673       r = buddy->resources;
00674    }
00675    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
00676    ASTOBJ_UNREF(client, ast_aji_client_destroy);
00677    if (!r) {
00678       ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
00679    } else {
00680       stat = r->status;
00681    }
00682    snprintf(status, sizeof(status), "%d", stat);
00683    pbx_builtin_setvar_helper(chan, args.variable, status);
00684    return 0;
00685 }

static int aji_tls_handshake ( struct aji_client client  )  [static]

Definition at line 1239 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().

01240 {
01241    int ret;
01242    int sock;
01243    long ssl_opts;
01244 
01245    ast_debug(1, "Starting TLS handshake\n");
01246 
01247    /* Choose an SSL/TLS protocol version, create SSL_CTX */
01248    client->ssl_method = SSLv23_method();
01249    if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
01250       return IKS_NET_TLSFAIL;
01251    }
01252    ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
01253    SSL_CTX_set_options(client->ssl_context, ssl_opts);
01254 
01255    /* Create new SSL session */
01256    if (!(client->ssl_session = SSL_new(client->ssl_context))) {
01257       return IKS_NET_TLSFAIL;
01258    }
01259 
01260    /* Enforce TLS on our XMPP connection */
01261    sock = iks_fd(client->p);
01262    if (!(ret = SSL_set_fd(client->ssl_session, sock))) {
01263       return IKS_NET_TLSFAIL;
01264    }
01265 
01266    /* Perform SSL handshake */
01267    if (!(ret = SSL_connect(client->ssl_session))) {
01268       return IKS_NET_TLSFAIL;
01269    }
01270 
01271    client->stream_flags &= (~TRY_SECURE);
01272    client->stream_flags |= SECURE;
01273 
01274    /* Sent over the established TLS connection */
01275    if ((ret = aji_send_header(client, client->jid->server)) != IKS_OK) {
01276       return IKS_NET_TLSFAIL;
01277    }
01278 
01279    ast_debug(1, "TLS started with server\n");
01280 
01281    return IKS_OK;
01282 }

void ast_aji_buddy_destroy ( struct aji_buddy obj  ) 

Destructor function for buddies to be used with ASTOBJ_UNREF

Definition at line 432 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().

00433 {
00434    struct aji_resource *tmp;
00435 
00436    while ((tmp = obj->resources)) {
00437       obj->resources = obj->resources->next;
00438       ast_free(tmp->description);
00439       ast_free(tmp);
00440    }
00441 
00442    ast_free(obj);
00443 }

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 410 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_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().

00411 {
00412    struct aji_message *tmp;
00413    ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy);
00414    ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00415    iks_filter_delete(obj->f);
00416    iks_parser_delete(obj->p);
00417    iks_stack_delete(obj->stack);
00418    AST_LIST_LOCK(&obj->messages);
00419    while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00420       aji_message_destroy(tmp);
00421    }
00422    AST_LIST_HEAD_DESTROY(&obj->messages);
00423    ast_free(obj);
00424 }

int ast_aji_create_chat ( struct aji_client client,
char *  room,
char *  server,
char *  topic 
)

create a chatroom.

Parameters:
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.
Returns:
0.

Definition at line 2646 of file res_jabber.c.

References ast_aji_increment_mid(), ast_aji_send(), ast_log(), LOG_ERROR, and aji_client::mid.

02647 {
02648    int res = 0;
02649    iks *iq = NULL;
02650    iq = iks_new("iq");
02651 
02652    if (iq && client) {
02653       iks_insert_attrib(iq, "type", "get");
02654       iks_insert_attrib(iq, "to", server);
02655       iks_insert_attrib(iq, "id", client->mid);
02656       ast_aji_increment_mid(client->mid);
02657       ast_aji_send(client, iq);
02658    } else {
02659       ast_log(LOG_ERROR, "Out of memory.\n");
02660    }
02661 
02662    iks_delete(iq);
02663 
02664    return res;
02665 }

int ast_aji_disconnect ( struct aji_client client  ) 

disconnect from jabber server.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
1.

Definition at line 3153 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().

03154 {
03155    if (client) {
03156       ast_verb(4, "JABBER: Disconnecting\n");
03157 #ifdef HAVE_OPENSSL
03158       if (client->stream_flags & SECURE) {
03159          SSL_shutdown(client->ssl_session);
03160          SSL_CTX_free(client->ssl_context);
03161          SSL_free(client->ssl_session);
03162       }
03163 #endif
03164       iks_disconnect(client->p);
03165       iks_parser_delete(client->p);
03166       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03167    }
03168 
03169    return 1;
03170 }

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)

Parameters:
name label or JID
Returns:
aji_client.

Definition at line 4575 of file res_jabber.c.

References ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, and clients.

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().

04576 {
04577    struct aji_client *client = NULL;
04578    char *aux = NULL;
04579 
04580    client = ASTOBJ_CONTAINER_FIND(&clients, name);
04581    if (!client && strchr(name, '@')) {
04582       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04583          aux = ast_strdupa(iterator->user);
04584          if (strchr(aux, '/')) {
04585             /* strip resource for comparison */
04586             aux = strsep(&aux, "/");
04587          }
04588          if (!strncasecmp(aux, name, strlen(aux))) {
04589             client = ASTOBJ_REF(iterator);
04590          }
04591       });
04592    }
04593 
04594    return client;
04595 }

struct aji_client_container* ast_aji_get_clients ( void   )  [read]

Definition at line 4597 of file res_jabber.c.

References clients.

Referenced by gtalk_load_config(), and jingle_load_config().

04598 {
04599    return &clients;
04600 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

Definition at line 2790 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().

02791 {
02792    int i = 0;
02793 
02794    for (i = strlen(mid) - 1; i >= 0; i--) {
02795       if (mid[i] != 'z') {
02796          mid[i] = mid[i] + 1;
02797          i = 0;
02798       } else
02799          mid[i] = 'a';
02800    }
02801 }

int ast_aji_invite_chat ( struct aji_client client,
char *  user,
char *  room,
char *  message 
)

invite to a chatroom.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
user 
room 
message 
Returns:
res.

Definition at line 2698 of file res_jabber.c.

References ast_aji_increment_mid(), ast_aji_send(), ast_log(), LOG_ERROR, and aji_client::mid.

02699 {
02700    int res = 0;
02701    iks *invite, *body, *namespace;
02702 
02703    invite = iks_new("message");
02704    body = iks_new("body");
02705    namespace = iks_new("x");
02706    if (client && invite && body && namespace) {
02707       iks_insert_attrib(invite, "to", user);
02708       iks_insert_attrib(invite, "id", client->mid);
02709       ast_aji_increment_mid(client->mid);
02710       iks_insert_cdata(body, message, 0);
02711       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
02712       iks_insert_attrib(namespace, "jid", room);
02713       iks_insert_node(invite, body);
02714       iks_insert_node(invite, namespace);
02715       res = ast_aji_send(client, invite);
02716    } else {
02717       ast_log(LOG_ERROR, "Out of memory.\n");
02718    }
02719 
02720    iks_delete(body);
02721    iks_delete(namespace);
02722    iks_delete(invite);
02723 
02724    return res;
02725 }

int ast_aji_join_chat ( struct aji_client client,
char *  room,
char *  nick 
)

join a chatroom.

Parameters:
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
Returns:
IKS_OK on success, any other value on failure.

Definition at line 2674 of file res_jabber.c.

References aji_set_group_presence().

Referenced by aji_join_exec().

02675 {
02676    return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
02677 }

int ast_aji_leave_chat ( struct aji_client client,
char *  room,
char *  nick 
)

leave a chatroom.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
room room to leave
nick the nickname used in this room
Returns:
IKS_OK on success, any other value on failure.

Definition at line 2686 of file res_jabber.c.

References aji_set_group_presence().

Referenced by aji_leave_exec().

02687 {
02688    return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
02689 }

int ast_aji_send ( struct aji_client client,
iks *  x 
)
int ast_aji_send_chat ( struct aji_client client,
const char *  address,
const char *  message 
)

sends messages.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
address 
message 
Return values:
IKS_OK success
-1 failure

Definition at line 2582 of file res_jabber.c.

References aji_send_raw_chat().

Referenced by aji_send_exec(), gtalk_sendtext(), jingle_sendtext(), and manager_jabber_send().

02583 {
02584    return aji_send_raw_chat(client, 0, NULL, address, message);
02585 }

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.

Parameters:
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
Returns:
IKS_OK on success, any other value on failure

Definition at line 2596 of file res_jabber.c.

References aji_send_raw_chat().

Referenced by aji_sendgroup_exec().

02596                                                                                                                   {
02597    return aji_send_raw_chat(client, 1, nick, address, message);
02598 }

static int delete_old_messages ( struct aji_client client,
char *  from 
) [static]

Definition at line 929 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, LOG_ERROR, and aji_client::message_timeout.

Referenced by aji_handle_message(), and delete_old_messages_all().

00930 {
00931    int deleted = 0;
00932    int isold = 0;
00933    struct aji_message *tmp = NULL;
00934    if (!client) {
00935       ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
00936       return -1;
00937    }
00938 
00939    /* remove old messages */
00940    AST_LIST_LOCK(&client->messages);
00941    if (AST_LIST_EMPTY(&client->messages)) {
00942       AST_LIST_UNLOCK(&client->messages);
00943       return 0;
00944    }
00945 
00946    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
00947       if (isold) {
00948          if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00949             AST_LIST_REMOVE_CURRENT(list);
00950             aji_message_destroy(tmp);
00951             deleted ++;
00952          }
00953       } else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
00954          isold = 1;
00955          if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00956             AST_LIST_REMOVE_CURRENT(list);
00957             aji_message_destroy(tmp);
00958             deleted ++;
00959          }
00960       }
00961    }
00962    AST_LIST_TRAVERSE_SAFE_END;
00963    AST_LIST_UNLOCK(&client->messages);
00964 
00965    return deleted;
00966 }

static int delete_old_messages_all ( struct aji_client client  )  [static]

Definition at line 976 of file res_jabber.c.

References delete_old_messages().

Referenced by aji_recv_loop().

00977 {
00978    return delete_old_messages(client, NULL);
00979 }

static int gtalk_yuck ( iks *  node  )  [static]

Definition at line 566 of file res_jabber.c.

References ast_debug.

Referenced by aji_handle_presence().

00567 {
00568    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
00569       ast_debug(1, "Found resource with Googletalk voice capabilities\n");
00570       return 1;
00571    } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) {
00572       ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n");
00573       return 1;
00574    } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) {
00575       ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n");
00576       return 1;
00577    }
00578 
00579    return 0;
00580 }

static iks * jabber_make_auth ( iksid *  id,
const char *  pass,
const char *  sid 
) [static]

Definition at line 590 of file res_jabber.c.

References ast_sha1_hash().

Referenced by aji_act_hook().

00591 {
00592    iks *x, *y;
00593    x = iks_new("iq");
00594    iks_insert_attrib(x, "type", "set");
00595    y = iks_insert(x, "query");
00596    iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00597    iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00598    iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00599    if (sid) {
00600       char buf[41];
00601       char sidpass[100];
00602       snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00603       ast_sha1_hash(buf, sidpass);
00604       iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00605    } else {
00606       iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00607    }
00608    return x;
00609 }

static int load_module ( void   )  [static]
static int manager_jabber_send ( struct mansession s,
const struct message m 
) [static]

Definition at line 4609 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().

04610 {
04611    struct aji_client *client = NULL;
04612    const char *id = astman_get_header(m, "ActionID");
04613    const char *jabber = astman_get_header(m, "Jabber");
04614    const char *screenname = astman_get_header(m, "ScreenName");
04615    const char *message = astman_get_header(m, "Message");
04616 
04617    if (ast_strlen_zero(jabber)) {
04618       astman_send_error(s, m, "No transport specified");
04619       return 0;
04620    }
04621    if (ast_strlen_zero(screenname)) {
04622       astman_send_error(s, m, "No ScreenName specified");
04623       return 0;
04624    }
04625    if (ast_strlen_zero(message)) {
04626       astman_send_error(s, m, "No Message specified");
04627       return 0;
04628    }
04629 
04630    astman_send_ack(s, m, "Attempting to send Jabber Message");
04631    client = ast_aji_get_client(jabber);
04632    if (!client) {
04633       astman_send_error(s, m, "Could not find Sender");
04634       return 0;
04635    }
04636    if (strchr(screenname, '@') && message) {
04637       ast_aji_send_chat(client, screenname, message);
04638       astman_append(s, "Response: Success\r\n");
04639    } else {
04640       astman_append(s, "Response: Error\r\n");
04641    }
04642    ASTOBJ_UNREF(client, ast_aji_client_destroy);
04643    if (!ast_strlen_zero(id)) {
04644       astman_append(s, "ActionID: %s\r\n", id);
04645    }
04646    astman_append(s, "\r\n");
04647    return 0;
04648 }

static int reload ( void   )  [static]

Definition at line 4753 of file res_jabber.c.

References aji_reload().

04754 {
04755    aji_reload(1);
04756    return 0;
04757 }

static int unload_module ( void   )  [static]

Definition at line 4688 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.

04689 {
04690 
04691    ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
04692    ast_unregister_application(app_ajisend);
04693    ast_unregister_application(app_ajisendgroup);
04694    ast_unregister_application(app_ajistatus);
04695    ast_unregister_application(app_ajijoin);
04696    ast_unregister_application(app_ajileave);
04697    ast_manager_unregister("JabberSend");
04698    ast_custom_function_unregister(&jabberstatus_function);
04699    if (mwi_sub) {
04700       ast_event_unsubscribe(mwi_sub);
04701    }
04702    if (device_state_sub) {
04703       ast_event_unsubscribe(device_state_sub);
04704    }
04705    ast_custom_function_unregister(&jabberreceive_function);
04706 
04707    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04708       ASTOBJ_WRLOCK(iterator);
04709       ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
04710       iterator->state = AJI_DISCONNECTING;
04711       ASTOBJ_UNLOCK(iterator);
04712       pthread_join(iterator->thread, NULL);
04713       ast_aji_disconnect(iterator);
04714    });
04715 
04716    ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
04717    ASTOBJ_CONTAINER_DESTROY(&clients);
04718 
04719    ast_cond_destroy(&message_received_condition);
04720    ast_mutex_destroy(&messagelock);
04721 
04722    return 0;
04723 }


Variable Documentation

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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static]

Definition at line 4764 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 374 of file res_jabber.c.

char* app_ajijoin = "JabberJoin" [static]

Definition at line 389 of file res_jabber.c.

char* app_ajileave = "JabberLeave" [static]

Definition at line 390 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 386 of file res_jabber.c.

char* app_ajisendgroup = "JabberSendGroup" [static]

Definition at line 387 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 388 of file res_jabber.c.

Definition at line 4764 of file res_jabber.c.

struct aji_capabilities* capabilities = NULL [static]

Definition at line 393 of file res_jabber.c.

Referenced by ast_request().

struct aji_client_container clients [static]
struct ast_event_sub* device_state_sub = NULL [static]

Definition at line 395 of file res_jabber.c.

struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT } [static]

Global flags, initialized to default values.

Definition at line 400 of file res_jabber.c.

Initial value:
 {
   .name = "JABBER_RECEIVE",
   .read = acf_jabberreceive_read,
}

Definition at line 915 of file res_jabber.c.

Initial value:
 {
   .name = "JABBER_STATUS",
   .read = acf_jabberstatus_read,
}

Definition at line 753 of file res_jabber.c.

Definition at line 396 of file res_jabber.c.

Definition at line 397 of file res_jabber.c.

struct ast_event_sub* mwi_sub = NULL [static]

Definition at line 394 of file res_jabber.c.

struct ast_flags pubsubflags = { 0 } [static]

PubSub flags, initialized to default values.

Definition at line 403 of file res_jabber.c.


Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1