Thu Apr 3 08:22:30 2014

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"
Include dependency graph for res_jabber.c:

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 = "95089850e3c922fa176f9bd274fd8109" , .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 4761 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

Definition at line 4761 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 3853 of file res_jabber.c.

Referenced by aji_create_pubsub_node().

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

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

References aji_pubsub_iq_create().

Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().

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

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Referenced by aji_init_event_distribution().

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

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

Referenced by aji_init_event_distribution().

03262 {
03263    char *item_id, *device_state, *mailbox, *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       mailbox = 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,
03300          AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
03301          AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, item_id,
03302          AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, oldmsgs,
03303          AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, newmsgs,
03304          AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03305          AST_EVENT_IE_END))) {
03306          return IKS_FILTER_EAT;
03307       }
03308    } else {
03309       ast_log(LOG_DEBUG, "Don't know how to handle PubSub event of type %s\n",
03310          iks_name(item_content));
03311       return IKS_FILTER_EAT;
03312    }
03313 
03314    if (cachable == AST_DEVSTATE_CACHABLE) {
03315       ast_event_queue_and_cache(event);
03316    } else {
03317       ast_event_queue(event);
03318    }
03319 
03320    return IKS_FILTER_EAT;
03321 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

struct aji_client_container* ast_aji_get_clients ( void   )  [read]

Definition at line 4594 of file res_jabber.c.

References clients.

Referenced by gtalk_load_config(), and jingle_load_config().

04595 {
04596    return &clients;
04597 }

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

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

static int reload ( void   )  [static]

Definition at line 4750 of file res_jabber.c.

References aji_reload().

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

static int unload_module ( void   )  [static]

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

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


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

Definition at line 4761 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 4761 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 3 Apr 2014 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1