Tue Aug 20 16:35:13 2013

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 4760 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

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

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

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

Definition at line 3852 of file res_jabber.c.

Referenced by aji_create_pubsub_node().

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

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 3582 of file res_jabber.c.

References aji_pubsub_iq_create().

Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().

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

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

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

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 3900 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.

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

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 3939 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.

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

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 3753 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.

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

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 3628 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.

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

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 3673 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.

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

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

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

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

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

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

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

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

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

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

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

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 3808 of file res_jabber.c.

References aji_create_pubsub_node().

Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().

03810 {
03811    aji_create_pubsub_node(client, "collection", collection_name, NULL);
03812 }

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 3821 of file res_jabber.c.

References aji_create_pubsub_node().

Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().

03823 {
03824    aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
03825 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 2222 of file res_jabber.c.

Referenced by aji_act_hook().

02223 {
02224    /*Nothing to see here */
02225 }

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

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

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

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

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

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

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

Definition at line 3501 of file res_jabber.c.

References aji_create_pubsub_collection(), aji_create_pubsub_leaf(), aji_create_pubsub_node(), aji_pubsub_iq_create(), AJI_XEP0248, ast_aji_client_destroy(), ast_aji_send(), ast_log(), ast_test_flag, ASTOBJ_REF, ASTOBJ_UNREF, and LOG_ERROR.

Referenced by aji_init_event_distribution().

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

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 3261 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(), context, LOG_DEBUG, and LOG_ERROR.

Referenced by aji_init_event_distribution().

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

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

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

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

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

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

static int aji_initialize ( struct aji_client client  )  [static]

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

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

static int aji_io_recv ( struct aji_client client,
char *  buffer,
size_t  buf_len,
int  timeout 
) [static]

Definition at line 1293 of file res_jabber.c.

References aji_is_secure(), ast_poll, len(), aji_client::p, and aji_client::ssl_session.

Referenced by aji_recv().

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

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

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

static void aji_log_hook ( void *  data,
const char *  xmpp,
size_t  size,
int  is_incoming 
) [static]

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

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

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

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

static void aji_pruneregister ( struct aji_client client  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static int aji_reconnect ( struct aji_client client  )  [static]

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

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

static int aji_recv ( struct aji_client client,
int  timeout 
) [static]

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

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

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

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

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

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

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

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

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

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

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

static int aji_reload ( int  reload  )  [static]

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

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

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

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

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 1410 of file res_jabber.c.

References aji_send_raw(), len(), and aji_client::name_space.

Referenced by aji_act_hook(), and aji_tls_handshake().

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

static int aji_send_raw ( struct aji_client client,
const char *  xmlstr 
) [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static int aji_start_sasl ( struct aji_client client,
enum ikssasltype  type,
char *  username,
char *  pass 
) [static]

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

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

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

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 2643 of file res_jabber.c.

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

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

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

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

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

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

struct aji_client_container* ast_aji_get_clients ( void   )  [read]

Definition at line 4593 of file res_jabber.c.

References clients.

Referenced by gtalk_load_config(), and jingle_load_config().

04594 {
04595    return &clients;
04596 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

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

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 2695 of file res_jabber.c.

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

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

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 2671 of file res_jabber.c.

References aji_set_group_presence().

Referenced by aji_join_exec().

02672 {
02673    return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
02674 }

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 2683 of file res_jabber.c.

References aji_set_group_presence().

Referenced by aji_leave_exec().

02684 {
02685    return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
02686 }

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 2579 of file res_jabber.c.

References aji_send_raw_chat().

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

02580 {
02581    return aji_send_raw_chat(client, 0, NULL, address, message);
02582 }

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 2593 of file res_jabber.c.

References aji_send_raw_chat().

Referenced by aji_sendgroup_exec().

02593                                                                                                                   {
02594    return aji_send_raw_chat(client, 1, nick, address, message);
02595 }

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

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

static int reload ( void   )  [static]

Definition at line 4749 of file res_jabber.c.

References aji_reload().

04750 {
04751    aji_reload(1);
04752    return 0;
04753 }

static int unload_module ( void   )  [static]

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

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


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 4760 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 4760 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 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1