Sat Feb 11 06:36:30 2012

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 "asterisk/message.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)
 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)
 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_status_exec (struct ast_channel *chan, const char *data)
static char * aji_test (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 msg_send_cb (const struct ast_msg *msg, const char *to, const char *from)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "AJI - Asterisk Jabber Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static struct ast_cli_entry aji_cli []
static char * app_ajijoin = "JabberJoin"
static char * app_ajileave = "JabberLeave"
static char * app_ajisend = "JabberSend"
static char * app_ajisendgroup = "JabberSendGroup"
static char * app_ajistatus = "JabberStatus"
static struct ast_module_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_msg_tech msg_tech
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?
Todo:
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 286 of file res_jabber.c.

Referenced by aji_load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4850 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

Definition at line 4850 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 777 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_channel_name(), ast_cond_timedwait, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvdiff_sec(), ast_tvnow(), ASTOBJ_UNREF, aji_message::from, LOG_NOTICE, LOG_WARNING, aji_message::message, aji_client::message_timeout, aji_client::messages, and parse().

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

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

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

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

static int aji_act_hook ( void *  data,
int  type,
iks *  node 
) [static]

Definition at line 1613 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(), asprintf, ast_aji_client_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_debug, ast_free, ast_log(), ast_sha1_hash(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::authorized, aji_client::component, aji_client::f, jabber_make_auth(), aji_client::jid, LOG_ERROR, LOG_WARNING, aji_client::mid, aji_client::password, secret, aji_client::state, aji_client::usesasl, and aji_client::usetls.

Referenced by aji_create_client().

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

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

Definition at line 3871 of file res_jabber.c.

Referenced by aji_create_pubsub_node().

03872 {
03873    iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
03874       *field_deliver_payload, *field_persist_items, *field_access_model,
03875       *field_pubsub_collection;
03876    configure = iks_insert(pubsub, "configure");
03877    x = iks_insert(configure, "x");
03878    iks_insert_attrib(x, "xmlns", "jabber:x:data");
03879    iks_insert_attrib(x, "type", "submit");
03880    field_owner = iks_insert(x, "field");
03881    iks_insert_attrib(field_owner, "var", "FORM_TYPE");
03882    iks_insert_attrib(field_owner, "type", "hidden");
03883    iks_insert_cdata(iks_insert(field_owner, "value"),
03884       "http://jabber.org/protocol/pubsub#owner", 39);
03885    if (node_type) {
03886       field_node_type = iks_insert(x, "field");
03887       iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
03888       iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
03889    }
03890    field_node_config = iks_insert(x, "field");
03891    iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
03892    iks_insert_attrib(field_node_config, "type", "hidden");
03893    iks_insert_cdata(iks_insert(field_node_config, "value"),
03894       "http://jabber.org/protocol/pubsub#node_config", 45);
03895    field_deliver_payload = iks_insert(x, "field");
03896    iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
03897    iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
03898    field_persist_items = iks_insert(x, "field");
03899    iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
03900    iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
03901    field_access_model = iks_insert(x, "field");
03902    iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
03903    iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
03904    if (node_type && !strcasecmp(node_type, "leaf")) {
03905       field_pubsub_collection = iks_insert(x, "field");
03906       iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
03907       iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
03908          strlen(collection_name));
03909    }
03910    return configure;
03911 }

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

References aji_pubsub_iq_create().

Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().

03602 {
03603    iks *request = aji_pubsub_iq_create(client, "get");
03604    iks *query;
03605    query = iks_insert(request, "query");
03606    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03607    if (collection) {
03608       iks_insert_attrib(query, "node", collection);
03609    }
03610    return request;
03611 }

static iks * aji_build_publish_skeleton ( struct aji_client client,
const char *  node,
const char *  event_type 
) [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 3429 of file res_jabber.c.

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

Referenced by aji_publish_device_state(), and aji_publish_mwi().

03431 {
03432    iks *request = aji_pubsub_iq_create(client, "set");
03433    iks *pubsub, *publish, *item;
03434    pubsub = iks_insert(request, "pubsub");
03435    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03436    publish = iks_insert(pubsub, "publish");
03437    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03438       iks_insert_attrib(publish, "node", node);
03439    } else {
03440       iks_insert_attrib(publish, "node", event_type);
03441    }
03442    item = iks_insert(publish, "item");
03443    iks_insert_attrib(item, "id", node);
03444    return item;
03445 
03446 }

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

03920 {
03921       struct aji_client *client;
03922       const char *name;
03923       const char *collection_name;
03924 
03925       switch (cmd) {
03926       case CLI_INIT:
03927             e->command = "jabber create collection";
03928             e->usage =
03929                "Usage: jabber create collection <connection> <collection>\n"
03930                "       Creates a PubSub collection node using the account\n"
03931                "       as configured in jabber.conf.\n";
03932          return NULL;
03933       case CLI_GENERATE:
03934          return NULL;
03935       }
03936 
03937       if (a->argc != 5) {
03938          return CLI_SHOWUSAGE;
03939       }
03940       name = a->argv[3];
03941       collection_name = a->argv[4];
03942 
03943       if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03944          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03945          return CLI_FAILURE;
03946       }
03947 
03948       ast_cli(a->fd, "Creating test PubSub node collection.\n");
03949       aji_create_pubsub_collection(client, collection_name);
03950       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03951       return CLI_SUCCESS;
03952 }

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

03959 {
03960    struct aji_client *client;
03961    const char *name;
03962    const char *collection_name;
03963    const char *leaf_name;
03964 
03965    switch (cmd) {
03966       case CLI_INIT:
03967          e->command = "jabber create leaf";
03968          e->usage =
03969                "Usage: jabber create leaf <connection> <collection> <leaf>\n"
03970                "       Creates a PubSub leaf node using the account\n"
03971                "       as configured in jabber.conf.\n";
03972          return NULL;
03973       case CLI_GENERATE:
03974          return NULL;
03975    }
03976 
03977    if (a->argc != 6) {
03978       return CLI_SHOWUSAGE;
03979    }
03980    name = a->argv[3];
03981    collection_name = a->argv[4];
03982    leaf_name = a->argv[5];
03983 
03984    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03985       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03986       return CLI_FAILURE;
03987    }
03988 
03989    ast_cli(a->fd, "Creating test PubSub node collection.\n");
03990    aji_create_pubsub_leaf(client, collection_name, leaf_name);
03991    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03992    return CLI_SUCCESS;
03993 }

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

03774 {
03775    struct aji_client *client;
03776    const char *name;
03777 
03778    switch (cmd) {
03779       case CLI_INIT:
03780          e->command = "jabber delete node";
03781          e->usage =
03782                "Usage: jabber delete node <connection> <node>\n"
03783                "       Deletes a node on PubSub server\n"
03784                "       as configured in jabber.conf.\n";
03785          return NULL;
03786       case CLI_GENERATE:
03787          return NULL;
03788    }
03789 
03790    if (a->argc != 5) {
03791       return CLI_SHOWUSAGE;
03792    }
03793    name = a->argv[3];
03794 
03795    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03796       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03797       return CLI_FAILURE;
03798    }
03799    aji_delete_pubsub_node(client, a->argv[4]);
03800    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03801    return CLI_SUCCESS;
03802 }

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

03649 {
03650       struct aji_client *client;
03651       const char *name = NULL;
03652       const char *collection = NULL;
03653 
03654       switch (cmd) {
03655       case CLI_INIT:
03656             e->command = "jabber list nodes";
03657             e->usage =
03658                "Usage: jabber list nodes <connection> [collection]\n"
03659                "       Lists the user's nodes on the respective connection\n"
03660                "       ([connection] as configured in jabber.conf.)\n";
03661          return NULL;
03662       case CLI_GENERATE:
03663          return NULL;
03664       }
03665 
03666       if (a->argc > 5 || a->argc < 4) {
03667          return CLI_SHOWUSAGE;
03668       } else if (a->argc == 4 || a->argc == 5) {
03669          name = a->argv[3];
03670       }
03671       if (a->argc == 5) {
03672          collection = a->argv[4];
03673       }
03674       if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03675          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03676          return CLI_FAILURE;
03677       }
03678 
03679       ast_cli(a->fd, "Listing pubsub nodes.\n");
03680       aji_request_pubsub_nodes(client, collection);
03681       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03682       return CLI_SUCCESS;
03683 }

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

03694 {
03695    struct aji_client *client;
03696    const char *name;
03697 
03698    switch (cmd) {
03699       case CLI_INIT:
03700          e->command = "jabber purge nodes";
03701          e->usage =
03702                "Usage: jabber purge nodes <connection> <node>\n"
03703                "       Purges nodes on PubSub server\n"
03704                "       as configured in jabber.conf.\n";
03705          return NULL;
03706       case CLI_GENERATE:
03707          return NULL;
03708    }
03709 
03710    if (a->argc != 5) {
03711       return CLI_SHOWUSAGE;
03712    }
03713    name = a->argv[3];
03714 
03715    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03716       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03717       return CLI_FAILURE;
03718    }
03719    if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03720       aji_pubsub_purge_nodes(client, a->argv[4]);
03721    } else {
03722       aji_delete_pubsub_node(client, a->argv[4]);
03723    }
03724    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03725    return CLI_SUCCESS;
03726 }

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

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

03139 {
03140    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03141    int res = IKS_FILTER_PASS;
03142 
03143    if (client) {
03144       if (client->state == AJI_DISCONNECTED) {
03145          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);
03146          client->state = AJI_CONNECTING;
03147          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
03148          if (!client->component) { /*client*/
03149             aji_get_roster(client);
03150          }
03151          if (client->distribute_events) {
03152             aji_init_event_distribution(client);
03153          }
03154 
03155          iks_filter_remove_hook(client->f, aji_client_connect);
03156          /* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */
03157          res = IKS_FILTER_EAT;
03158       }
03159    } else {
03160       ast_log(LOG_ERROR, "Out of memory.\n");
03161    }
03162 
03163    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03164    return res;
03165 }

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

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

02047 {
02048    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02049    struct aji_resource *resource = NULL;
02050    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02051 
02052    resource = aji_find_resource(buddy, pak->from->resource);
02053    if (pak->subtype == IKS_TYPE_RESULT) {
02054       if (!resource) {
02055          ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
02056          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02057          ASTOBJ_UNREF(client, ast_aji_client_destroy);
02058          return IKS_FILTER_EAT;
02059       }
02060       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
02061          resource->cap->jingle = 1;
02062       } else {
02063          resource->cap->jingle = 0;
02064       }
02065    } else if (pak->subtype == IKS_TYPE_GET) {
02066       iks *iq, *disco, *ident, *google, *query;
02067       iq = iks_new("iq");
02068       query = iks_new("query");
02069       ident = iks_new("identity");
02070       disco = iks_new("feature");
02071       google = iks_new("feature");
02072       if (iq && ident && disco && google) {
02073          iks_insert_attrib(iq, "from", client->jid->full);
02074          iks_insert_attrib(iq, "to", pak->from->full);
02075          iks_insert_attrib(iq, "type", "result");
02076          iks_insert_attrib(iq, "id", pak->id);
02077          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02078          iks_insert_attrib(ident, "category", "client");
02079          iks_insert_attrib(ident, "type", "pc");
02080          iks_insert_attrib(ident, "name", "asterisk");
02081          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
02082          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
02083          iks_insert_node(iq, query);
02084          iks_insert_node(query, ident);
02085          iks_insert_node(query, google);
02086          iks_insert_node(query, disco);
02087          ast_aji_send(client, iq);
02088       } else {
02089          ast_log(LOG_ERROR, "Out of Memory.\n");
02090       }
02091 
02092       iks_delete(iq);
02093       iks_delete(query);
02094       iks_delete(ident);
02095       iks_delete(google);
02096       iks_delete(disco);
02097    } else if (pak->subtype == IKS_TYPE_ERROR) {
02098       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
02099    }
02100    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02101    ASTOBJ_UNREF(client, ast_aji_client_destroy);
02102    return IKS_FILTER_EAT;
02103 }

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

03366 {
03367    iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
03368    iks *pubsub, *affiliations, *affiliate;
03369    pubsub = iks_insert(modify_affiliates, "pubsub");
03370    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03371    affiliations = iks_insert(pubsub, "affiliations");
03372    iks_insert_attrib(affiliations, "node", node);
03373    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03374       ASTOBJ_RDLOCK(iterator);
03375       affiliate = iks_insert(affiliations, "affiliation");
03376       iks_insert_attrib(affiliate, "jid", iterator->name);
03377       iks_insert_attrib(affiliate, "affiliation", "owner");
03378       ASTOBJ_UNLOCK(iterator);
03379    });
03380    ast_aji_send(client, modify_affiliates);
03381    iks_delete(modify_affiliates);
03382 }

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

References aji_act_hook(), AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_client_info_handler(), aji_create_buddy(), aji_dinfo_handler(), AJI_DISCONNECTED, aji_ditems_handler(), aji_log_hook(), AJI_PUBSUB, aji_register_approve_handler(), aji_register_query_handler(), asprintf, ast_aji_client_destroy(), ast_calloc, ast_clear_flag, ast_copy_flags, ast_copy_string(), ast_false(), AST_FLAGS_ALL, ast_free, AST_LIST_HEAD_INIT, ast_log(), ast_set2_flag, ast_set_flag, ast_test_flag, ast_true(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_INIT, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::authorized, aji_client::buddies, clients, aji_client::component, aji_client::context, 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::messages, aji_client::mid, ast_variable::name, aji_client::name, aji_client::name_space, ast_variable::next, aji_client::p, aji_client::password, aji_client::port, aji_client::priority, aji_client::pubsub_node, aji_client::send_to_dialplan, 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().

04315 {
04316    char *resource;
04317    struct aji_client *client = NULL;
04318    int flag = 0;
04319 
04320    client = ASTOBJ_CONTAINER_FIND(&clients, label);
04321    if (!client) {
04322       flag = 1;
04323       client = ast_calloc(1, sizeof(*client));
04324       if (!client) {
04325          ast_log(LOG_ERROR, "Out of memory!\n");
04326          return 0;
04327       }
04328       ASTOBJ_INIT(client);
04329       ASTOBJ_WRLOCK(client);
04330       ASTOBJ_CONTAINER_INIT(&client->buddies);
04331    } else {
04332       ASTOBJ_WRLOCK(client);
04333       ASTOBJ_UNMARK(client);
04334    }
04335    ASTOBJ_CONTAINER_MARKALL(&client->buddies);
04336    ast_copy_string(client->name, label, sizeof(client->name));
04337    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
04338    ast_copy_string(client->context, "default", sizeof(client->context));
04339 
04340    /* Set default values for the client object */
04341    client->debug = debug;
04342    ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
04343    client->port = 5222;
04344    client->usetls = 1;
04345    client->usesasl = 1;
04346    client->forcessl = 0;
04347    client->keepalive = 1;
04348    client->timeout = 50;
04349    client->message_timeout = 5;
04350    client->distribute_events = 0;
04351    AST_LIST_HEAD_INIT(&client->messages);
04352    client->component = 0;
04353    ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
04354    client->priority = 0;
04355    client->status = IKS_SHOW_AVAILABLE;
04356    client->send_to_dialplan = 0;
04357 
04358    if (flag) {
04359       client->authorized = 0;
04360       client->state = AJI_DISCONNECTED;
04361    }
04362    while (var) {
04363       if (!strcasecmp(var->name, "username")) {
04364          ast_copy_string(client->user, var->value, sizeof(client->user));
04365       } else if (!strcasecmp(var->name, "serverhost")) {
04366          ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
04367       } else if (!strcasecmp(var->name, "secret")) {
04368          ast_copy_string(client->password, var->value, sizeof(client->password));
04369       } else if (!strcasecmp(var->name, "statusmessage")) {
04370          ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
04371       } else if (!strcasecmp(var->name, "port")) {
04372          client->port = atoi(var->value);
04373       } else if (!strcasecmp(var->name, "timeout")) {
04374          client->message_timeout = atoi(var->value);
04375       } else if (!strcasecmp(var->name, "debug")) {
04376          client->debug = (ast_false(var->value)) ? 0 : 1;
04377       } else if (!strcasecmp(var->name, "type")) {
04378          if (!strcasecmp(var->value, "component")) {
04379             client->component = 1;
04380             if (client->distribute_events) {
04381                ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events!  Event distribution will be disabled.\n");
04382                client->distribute_events = 0;
04383             }
04384          }
04385       } else if (!strcasecmp(var->name, "distribute_events")) {
04386          if (ast_true(var->value)) {
04387             if (client->component) {
04388                ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events!  Event distribution will be disabled.\n");
04389             } else {
04390                if (ast_test_flag(&pubsubflags, AJI_PUBSUB)) {
04391                   ast_log(LOG_ERROR, "Only one connection can be configured for distributed events.\n");
04392                } else {
04393                   ast_set_flag(&pubsubflags, AJI_PUBSUB);
04394                   client->distribute_events = 1;
04395                }
04396             }
04397          }
04398       } else if (!strcasecmp(var->name, "pubsub_node")) {
04399          ast_copy_string(client->pubsub_node, var->value, sizeof(client->pubsub_node));
04400       } else if (!strcasecmp(var->name, "usetls")) {
04401          client->usetls = (ast_false(var->value)) ? 0 : 1;
04402       } else if (!strcasecmp(var->name, "usesasl")) {
04403          client->usesasl = (ast_false(var->value)) ? 0 : 1;
04404       } else if (!strcasecmp(var->name, "forceoldssl")) {
04405          client->forcessl = (ast_false(var->value)) ? 0 : 1;
04406       } else if (!strcasecmp(var->name, "keepalive")) {
04407          client->keepalive = (ast_false(var->value)) ? 0 : 1;
04408       } else if (!strcasecmp(var->name, "autoprune")) {
04409          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
04410       } else if (!strcasecmp(var->name, "autoregister")) {
04411          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
04412       } else if (!strcasecmp(var->name, "auth_policy")) {
04413          if (!strcasecmp(var->value, "accept")) {
04414             ast_set_flag(&client->flags, AJI_AUTOACCEPT);
04415          } else {
04416             ast_clear_flag(&client->flags, AJI_AUTOACCEPT);
04417          }
04418       } else if (!strcasecmp(var->name, "buddy")) {
04419          aji_create_buddy((char *)var->value, client);
04420       } else if (!strcasecmp(var->name, "priority")) {
04421          client->priority = atoi(var->value);
04422       } else if (!strcasecmp(var->name, "status")) {
04423          if (!strcasecmp(var->value, "unavailable")) {
04424             client->status = IKS_SHOW_UNAVAILABLE;
04425          } else if (!strcasecmp(var->value, "available")
04426           || !strcasecmp(var->value, "online")) {
04427             client->status = IKS_SHOW_AVAILABLE;
04428          } else if (!strcasecmp(var->value, "chat")
04429           || !strcasecmp(var->value, "chatty")) {
04430             client->status = IKS_SHOW_CHAT;
04431          } else if (!strcasecmp(var->value, "away")) {
04432             client->status = IKS_SHOW_AWAY;
04433          } else if (!strcasecmp(var->value, "xa")
04434           || !strcasecmp(var->value, "xaway")) {
04435             client->status = IKS_SHOW_XA;
04436          } else if (!strcasecmp(var->value, "dnd")) {
04437             client->status = IKS_SHOW_DND;
04438          } else if (!strcasecmp(var->value, "invisible")) {
04439          #ifdef IKS_SHOW_INVISIBLE
04440             client->status = IKS_SHOW_INVISIBLE;
04441          #else
04442             ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
04443             client->status = IKS_SHOW_DND;
04444          #endif
04445          } else {
04446             ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
04447          }
04448       } else if (!strcasecmp(var->name, "context")) {
04449          ast_copy_string(client->context, var->value, sizeof(client->context));
04450       } else if (!strcasecmp(var->name, "sendtodialplan")) {
04451          client->send_to_dialplan = ast_true(var->value) ? 1 : 0;
04452       }
04453    /* no transport support in this version */
04454    /* else if (!strcasecmp(var->name, "transport"))
04455             aji_create_transport(var->value, client);
04456    */
04457       var = var->next;
04458    }
04459    if (!flag) {
04460       ASTOBJ_UNLOCK(client);
04461       ASTOBJ_UNREF(client, ast_aji_client_destroy);
04462       return 1;
04463    }
04464 
04465    ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
04466    client->p = iks_stream_new(client->name_space, client, aji_act_hook);
04467    if (!client->p) {
04468       ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
04469       return 0;
04470    }
04471    client->stack = iks_stack_new(8192, 8192);
04472    if (!client->stack) {
04473       ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
04474       return 0;
04475    }
04476    client->f = iks_filter_new();
04477    if (!client->f) {
04478       ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
04479       return 0;
04480    }
04481    if (!strchr(client->user, '/') && !client->component) { /*client */
04482       resource = NULL;
04483       if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
04484          client->jid = iks_id_new(client->stack, resource);
04485          ast_free(resource);
04486       }
04487    } else {
04488       client->jid = iks_id_new(client->stack, client->user);
04489    }
04490    if (client->component) {
04491       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04492       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
04493       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);
04494       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);
04495    } else {
04496       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04497    }
04498 
04499    iks_set_log_hook(client->p, aji_log_hook);
04500    ASTOBJ_UNLOCK(client);
04501    ASTOBJ_CONTAINER_LINK(&clients, client);
04502    return 1;
04503 }

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().

03829 {
03830    aji_create_pubsub_node(client, "collection", collection_name, NULL);
03831 }

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().

03842 {
03843    aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
03844 }

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

03855 {
03856    iks *node = aji_pubsub_iq_create(client, "set");
03857    iks *pubsub, *create;
03858    pubsub = iks_insert(node, "pubsub");
03859    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03860    create = iks_insert(pubsub, "create");
03861    iks_insert_attrib(create, "node", name);
03862    aji_build_node_config(pubsub, node_type, collection_name);
03863    ast_aji_send(client, node);
03864    aji_create_affiliations(client, name);
03865    iks_delete(node);
03866    return 0;
03867 }

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

03746 {
03747 
03748    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03749    iks *item = NULL;
03750    if (iks_has_children(pak->query)) {
03751       item = iks_first_tag(pak->query);
03752       ast_log(LOG_WARNING, "Connection: %s  Node name: %s\n", client->jid->partial,
03753             iks_find_attrib(item, "node"));
03754       while ((item = iks_next_tag(item))) {
03755          aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
03756       }
03757    }
03758    if (item) {
03759       iks_delete(item);
03760    }
03761    return IKS_FILTER_EAT;
03762 }

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

03811 {
03812    iks *request = aji_pubsub_iq_create(client, "set");
03813    iks *pubsub, *delete;
03814    pubsub = iks_insert(request, "pubsub");
03815    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03816    delete = iks_insert(pubsub, "delete");
03817    iks_insert_attrib(delete, "node", node_name);
03818    ast_aji_send(client, request);
03819 }

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

References aji_publish_device_state(), ast_aji_client_destroy(), ast_debug, ast_devstate_str(), ast_eid_cmp(), ast_eid_default, ast_event_get_ie_raw(), ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, AST_EVENT_IE_STATE, ASTOBJ_REF, and ASTOBJ_UNREF.

Referenced by aji_init_event_distribution().

03258 {
03259    const char *device;
03260    const char *device_state;
03261    struct aji_client *client;
03262    if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03263    {
03264       /* If the event didn't originate from this server, don't send it back out. */
03265       ast_debug(1, "Returning here\n");
03266       return;
03267    }
03268 
03269    client = ASTOBJ_REF((struct aji_client *) data);
03270    device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
03271    device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
03272    aji_publish_device_state(client, device, device_state);
03273    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03274 }

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

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

02113 {
02114    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02115    char *node = NULL;
02116    struct aji_resource *resource = NULL;
02117    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02118 
02119    if (pak->subtype == IKS_TYPE_ERROR) {
02120       ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
02121       ASTOBJ_UNREF(client, ast_aji_client_destroy);
02122       return IKS_FILTER_EAT;
02123    }
02124    resource = aji_find_resource(buddy, pak->from->resource);
02125    if (pak->subtype == IKS_TYPE_RESULT) {
02126       if (!resource) {
02127          ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
02128          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02129          ASTOBJ_UNREF(client, ast_aji_client_destroy);
02130          return IKS_FILTER_EAT;
02131       }
02132       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
02133          resource->cap->jingle = 1;
02134       } else {
02135          resource->cap->jingle = 0;
02136       }
02137    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
02138       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
02139 
02140       iq = iks_new("iq");
02141       query = iks_new("query");
02142       identity = iks_new("identity");
02143       disco = iks_new("feature");
02144       reg = iks_new("feature");
02145       commands = iks_new("feature");
02146       gateway = iks_new("feature");
02147       version = iks_new("feature");
02148       vcard = iks_new("feature");
02149       search = iks_new("feature");
02150       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
02151          iks_insert_attrib(iq, "from", client->user);
02152          iks_insert_attrib(iq, "to", pak->from->full);
02153          iks_insert_attrib(iq, "id", pak->id);
02154          iks_insert_attrib(iq, "type", "result");
02155          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02156          iks_insert_attrib(identity, "category", "gateway");
02157          iks_insert_attrib(identity, "type", "pstn");
02158          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
02159          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
02160          iks_insert_attrib(reg, "var", "jabber:iq:register");
02161          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
02162          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
02163          iks_insert_attrib(version, "var", "jabber:iq:version");
02164          iks_insert_attrib(vcard, "var", "vcard-temp");
02165          iks_insert_attrib(search, "var", "jabber:iq:search");
02166 
02167          iks_insert_node(iq, query);
02168          iks_insert_node(query, identity);
02169          iks_insert_node(query, disco);
02170          iks_insert_node(query, reg);
02171          iks_insert_node(query, commands);
02172          iks_insert_node(query, gateway);
02173          iks_insert_node(query, version);
02174          iks_insert_node(query, vcard);
02175          iks_insert_node(query, search);
02176          ast_aji_send(client, iq);
02177       } else {
02178          ast_log(LOG_ERROR, "Out of memory.\n");
02179       }
02180 
02181       iks_delete(iq);
02182       iks_delete(query);
02183       iks_delete(identity);
02184       iks_delete(disco);
02185       iks_delete(reg);
02186       iks_delete(commands);
02187       iks_delete(gateway);
02188       iks_delete(version);
02189       iks_delete(vcard);
02190       iks_delete(search);
02191    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
02192       iks *iq, *query, *confirm;
02193       iq = iks_new("iq");
02194       query = iks_new("query");
02195       confirm = iks_new("item");
02196 
02197       if (iq && query && confirm && client) {
02198          iks_insert_attrib(iq, "from", client->user);
02199          iks_insert_attrib(iq, "to", pak->from->full);
02200          iks_insert_attrib(iq, "id", pak->id);
02201          iks_insert_attrib(iq, "type", "result");
02202          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
02203          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
02204          iks_insert_attrib(confirm, "node", "confirmaccount");
02205          iks_insert_attrib(confirm, "name", "Confirm AIM account");
02206          iks_insert_attrib(confirm, "jid", client->user);
02207          iks_insert_node(iq, query);
02208          iks_insert_node(query, confirm);
02209          ast_aji_send(client, iq);
02210       } else {
02211          ast_log(LOG_ERROR, "Out of memory.\n");
02212       }
02213 
02214       iks_delete(iq);
02215       iks_delete(query);
02216       iks_delete(confirm);
02217 
02218    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
02219       iks *iq, *query, *feature;
02220 
02221       iq = iks_new("iq");
02222       query = iks_new("query");
02223       feature = iks_new("feature");
02224 
02225       if (iq && query && feature && client) {
02226          iks_insert_attrib(iq, "from", client->user);
02227          iks_insert_attrib(iq, "to", pak->from->full);
02228          iks_insert_attrib(iq, "id", pak->id);
02229          iks_insert_attrib(iq, "type", "result");
02230          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02231          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
02232          iks_insert_node(iq, query);
02233          iks_insert_node(query, feature);
02234          ast_aji_send(client, iq);
02235       } else {
02236          ast_log(LOG_ERROR, "Out of memory.\n");
02237       }
02238 
02239       iks_delete(iq);
02240       iks_delete(query);
02241       iks_delete(feature);
02242    }
02243 
02244    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02245    ASTOBJ_UNREF(client, ast_aji_client_destroy);
02246    return IKS_FILTER_EAT;
02247 }

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

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

01950 {
01951    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01952    char *node = NULL;
01953 
01954    if (!(node = iks_find_attrib(pak->query, "node"))) {
01955       iks *iq = NULL, *query = NULL, *item = NULL;
01956       iq = iks_new("iq");
01957       query = iks_new("query");
01958       item = iks_new("item");
01959 
01960       if (iq && query && item) {
01961          iks_insert_attrib(iq, "from", client->user);
01962          iks_insert_attrib(iq, "to", pak->from->full);
01963          iks_insert_attrib(iq, "id", pak->id);
01964          iks_insert_attrib(iq, "type", "result");
01965          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01966          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01967          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01968          iks_insert_attrib(item, "jid", client->user);
01969 
01970          iks_insert_node(iq, query);
01971          iks_insert_node(query, item);
01972          ast_aji_send(client, iq);
01973       } else {
01974          ast_log(LOG_ERROR, "Out of memory.\n");
01975       }
01976 
01977       iks_delete(iq);
01978       iks_delete(query);
01979       iks_delete(item);
01980 
01981    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01982       iks *iq, *query, *confirm;
01983       iq = iks_new("iq");
01984       query = iks_new("query");
01985       confirm = iks_new("item");
01986       if (iq && query && confirm && client) {
01987          iks_insert_attrib(iq, "from", client->user);
01988          iks_insert_attrib(iq, "to", pak->from->full);
01989          iks_insert_attrib(iq, "id", pak->id);
01990          iks_insert_attrib(iq, "type", "result");
01991          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01992          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01993          iks_insert_attrib(confirm, "node", "confirmaccount");
01994          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01995          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01996 
01997          iks_insert_node(iq, query);
01998          iks_insert_node(query, confirm);
01999          ast_aji_send(client, iq);
02000       } else {
02001          ast_log(LOG_ERROR, "Out of memory.\n");
02002       }
02003 
02004       iks_delete(iq);
02005       iks_delete(query);
02006       iks_delete(confirm);
02007 
02008    } else if (!strcasecmp(node, "confirmaccount")) {
02009       iks *iq = NULL, *query = NULL, *feature = NULL;
02010 
02011       iq = iks_new("iq");
02012       query = iks_new("query");
02013       feature = iks_new("feature");
02014 
02015       if (iq && query && feature && client) {
02016          iks_insert_attrib(iq, "from", client->user);
02017          iks_insert_attrib(iq, "to", pak->from->full);
02018          iks_insert_attrib(iq, "id", pak->id);
02019          iks_insert_attrib(iq, "type", "result");
02020          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
02021          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
02022          iks_insert_node(iq, query);
02023          iks_insert_node(query, feature);
02024          ast_aji_send(client, iq);
02025       } else {
02026          ast_log(LOG_ERROR, "Out of memory.\n");
02027       }
02028 
02029       iks_delete(iq);
02030       iks_delete(query);
02031       iks_delete(feature);
02032    }
02033 
02034    ASTOBJ_UNREF(client, ast_aji_client_destroy);
02035    return IKS_FILTER_EAT;
02036 
02037 }

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

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

04133 {
04134    switch (cmd) {
04135    case CLI_INIT:
04136       e->command = "jabber reload";
04137       e->usage =
04138          "Usage: jabber reload\n"
04139          "       Reloads the Jabber module.\n";
04140       return NULL;
04141    case CLI_GENERATE:
04142       return NULL;
04143    }
04144 
04145    aji_reload(1);
04146    ast_cli(a->fd, "Jabber Reloaded.\n");
04147    return CLI_SUCCESS;
04148 }

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

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

04091 {
04092    switch (cmd) {
04093    case CLI_INIT:
04094       e->command = "jabber set debug {on|off}";
04095       e->usage =
04096          "Usage: jabber set debug {on|off}\n"
04097          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
04098       return NULL;
04099    case CLI_GENERATE:
04100       return NULL;
04101    }
04102 
04103    if (a->argc != e->args) {
04104       return CLI_SHOWUSAGE;
04105    }
04106 
04107    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
04108       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04109          ASTOBJ_RDLOCK(iterator);
04110          iterator->debug = 1;
04111          ASTOBJ_UNLOCK(iterator);
04112       });
04113       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
04114       return CLI_SUCCESS;
04115    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
04116       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04117          ASTOBJ_RDLOCK(iterator);
04118          iterator->debug = 0;
04119          ASTOBJ_UNLOCK(iterator);
04120       });
04121       ast_cli(a->fd, "Jabber Debugging Disabled.\n");
04122       return CLI_SUCCESS;
04123    }
04124    return CLI_SHOWUSAGE; /* defaults to invalid */
04125 }

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

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

03002 {
03003    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03004    int flag = 0;
03005    iks *x = NULL;
03006    struct aji_buddy *buddy;
03007 
03008    client->state = AJI_CONNECTED;
03009    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03010       ASTOBJ_RDLOCK(iterator);
03011       x = iks_child(pak->query);
03012       flag = 0;
03013       while (x) {
03014          if (!iks_strcmp(iks_name(x), "item")) {
03015             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
03016                flag = 1;
03017                ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
03018             }
03019          }
03020          x = iks_next(x);
03021       }
03022       if (!flag) {
03023          ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
03024       }
03025       iks_delete(x);
03026 
03027       ASTOBJ_UNLOCK(iterator);
03028    });
03029 
03030    x = iks_child(pak->query);
03031    while (x) {
03032       flag = 0;
03033       if (iks_strcmp(iks_name(x), "item") == 0) {
03034          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03035             ASTOBJ_RDLOCK(iterator);
03036             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
03037                flag = 1;
03038             ASTOBJ_UNLOCK(iterator);
03039          });
03040 
03041          if (flag) {
03042             /* found buddy, don't create a new one */
03043             x = iks_next(x);
03044             continue;
03045          }
03046 
03047          buddy = ast_calloc(1, sizeof(*buddy));
03048          if (!buddy) {
03049             ast_log(LOG_WARNING, "Out of memory\n");
03050             ASTOBJ_UNREF(client, ast_aji_client_destroy);
03051             return 0;
03052          }
03053          ASTOBJ_INIT(buddy);
03054          ASTOBJ_WRLOCK(buddy);
03055          ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
03056          ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
03057          if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
03058             ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
03059             ASTOBJ_MARK(buddy);
03060          } else if (ast_test_flag(&client->flags, AJI_AUTOREGISTER)) {
03061             if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
03062                /* subscribe to buddy's presence only
03063                   if we really need to */
03064                ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
03065             }
03066          }
03067          ASTOBJ_UNLOCK(buddy);
03068          if (buddy) {
03069             ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
03070             ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
03071          }
03072       }
03073       x = iks_next(x);
03074    }
03075 
03076    iks_delete(x);
03077    aji_pruneregister(client);
03078 
03079    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03080    return IKS_FILTER_EAT;
03081 }

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

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

00555 {
00556    struct aji_resource *res = NULL;
00557    if (!buddy || !name) {
00558       return res;
00559    }
00560    res = buddy->resources;
00561    while (res) {
00562       if (!strcasecmp(res->resource, name)) {
00563          break;
00564       }
00565       res = res->next;
00566    }
00567    return res;
00568 }

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

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

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

static int aji_get_roster ( struct aji_client client  )  [static]

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

03116 {
03117    iks *roster = NULL;
03118    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
03119 
03120    if (roster) {
03121       iks_insert_attrib(roster, "id", "roster");
03122       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
03123       ast_aji_send(client, roster);
03124    }
03125 
03126    iks_delete(roster);
03127 
03128    return 1;
03129 }

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

Definition at line 2256 of file res_jabber.c.

Referenced by aji_act_hook().

02257 {
02258    /*Nothing to see here */
02259 }

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

Definition at line 2268 of file res_jabber.c.

References aji_message::arrived, ast_calloc, ast_cond_broadcast, ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_msg_alloc(), ast_msg_destroy(), ast_msg_queue(), ast_msg_set_body(), ast_msg_set_context(), ast_msg_set_from(), ast_msg_set_to(), ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_tvnow(), aji_client::context, delete_old_messages(), aji_message::from, aji_message::id, LOG_ERROR, aji_message::message, aji_client::messages, aji_client::name, aji_client::send_to_dialplan, and aji_client::user.

Referenced by aji_act_hook().

02269 {
02270    struct aji_message *insert;
02271    int deleted = 0;
02272    struct ast_msg *msg;
02273 
02274    ast_debug(3, "client %s received a message\n", client->name);
02275 
02276    if (!(insert = ast_calloc(1, sizeof(*insert)))) {
02277       return;
02278    }
02279 
02280    insert->arrived = ast_tvnow();
02281 
02282    /* wake up threads waiting for messages */
02283    ast_mutex_lock(&messagelock);
02284    ast_cond_broadcast(&message_received_condition);
02285    ast_mutex_unlock(&messagelock);
02286 
02287    if (iks_find_cdata(pak->x, "body")) {
02288       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
02289    }
02290    if (pak->id) {
02291       ast_copy_string(insert->id, pak->id, sizeof(insert->id));
02292    }
02293    if (pak->from){
02294       /* insert will furtherly be added to message list */
02295       insert->from = ast_strdup(pak->from->full);
02296       if (!insert->from) {
02297          ast_log(LOG_ERROR, "Memory allocation failure\n");
02298          return;
02299       }
02300       ast_debug(3, "message comes from %s\n", insert->from);
02301    }
02302 
02303    if (client->send_to_dialplan) {
02304       if ((msg = ast_msg_alloc())) {
02305          int res;
02306 
02307          res = ast_msg_set_to(msg, "xmpp:%s", client->user);
02308          res |= ast_msg_set_from(msg, "xmpp:%s", insert->from);
02309          res |= ast_msg_set_body(msg, "%s", insert->message);
02310          res |= ast_msg_set_context(msg, "%s", client->context);
02311 
02312          if (res) {
02313             ast_msg_destroy(msg);
02314          } else {
02315             ast_msg_queue(msg);
02316          }
02317 
02318          msg = NULL;
02319       }
02320    }
02321 
02322    /* remove old messages received from this JID
02323     * and insert received message */
02324    deleted = delete_old_messages(client, pak->from->partial);
02325    ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
02326    AST_LIST_LOCK(&client->messages);
02327    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
02328    AST_LIST_UNLOCK(&client->messages);
02329 }

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

Definition at line 2337 of file res_jabber.c.

References AJI_CONNECTED, aji_create_buddy(), aji_find_version(), aji_set_presence(), ast_aji_buddy_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_strdup, ast_verbose, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::buddies, aji_client::component, descrip, aji_resource::description, EVENT_FLAG_USER, gtalk_yuck(), aji_client::jid, last, LOG_ERROR, LOG_NOTICE, manager_event, aji_client::mid, aji_client::name, aji_resource::next, aji_resource::priority, aji_resource::resource, aji_buddy::resources, S_OR, aji_client::state, aji_resource::status, aji_client::status, status, aji_client::statusmessage, and type.

Referenced by aji_act_hook().

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

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

Definition at line 3520 of file res_jabber.c.

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

Referenced by aji_init_event_distribution().

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

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

References ast_debug, ast_devstate_val(), ast_eid_cmp(), ast_eid_default, AST_EVENT_DEVICE_STATE_CHANGE, AST_EVENT_IE_CONTEXT, AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_RAW, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_IE_STATE, AST_EVENT_MWI, ast_event_new(), ast_event_queue_and_cache(), ast_log(), ast_str_to_eid(), context, LOG_ERROR, and strsep().

Referenced by aji_init_event_distribution().

03311 {
03312    char *item_id, *device_state, *context;
03313    int oldmsgs, newmsgs;
03314    iks *item, *item_content;
03315    struct ast_eid pubsub_eid;
03316    struct ast_event *event;
03317    item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
03318    if (!item) {
03319       ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
03320       return IKS_FILTER_EAT;
03321    }
03322    item_id = iks_find_attrib(item, "id");
03323    item_content = iks_child(item);
03324    ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
03325    if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
03326       ast_debug(1, "Returning here, eid of incoming event matches ours!\n");
03327       return IKS_FILTER_EAT;
03328    }
03329    if (!strcasecmp(iks_name(item_content), "state")) {
03330       device_state = iks_find_cdata(item, "state");
03331       if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
03332          AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
03333          AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
03334          AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03335          AST_EVENT_IE_END))) {
03336          return IKS_FILTER_EAT;
03337       }
03338    } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
03339       context = strsep(&item_id, "@");
03340       sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
03341       sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
03342       if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
03343          AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
03344          AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
03345          AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
03346          AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
03347          &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
03348          return IKS_FILTER_EAT;
03349       }
03350    } else {
03351       ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
03352          iks_name(item_content));
03353       return IKS_FILTER_EAT;
03354    }
03355    ast_event_queue_and_cache(event);
03356    return IKS_FILTER_EAT;
03357 }

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

Definition at line 2581 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_verb, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, aji_client::component, aji_client::flags, aji_client::jid, LOG_ERROR, aji_client::status, status, and aji_client::statusmessage.

Referenced by aji_act_hook().

02582 {
02583    iks *presence = NULL, *status = NULL;
02584    struct aji_buddy* buddy = NULL;
02585 
02586    switch (pak->subtype) {
02587    case IKS_TYPE_SUBSCRIBE:
02588       if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
02589          presence = iks_new("presence");
02590          status = iks_new("status");
02591          if (presence && status) {
02592             iks_insert_attrib(presence, "type", "subscribed");
02593             iks_insert_attrib(presence, "to", pak->from->full);
02594             iks_insert_attrib(presence, "from", client->jid->full);
02595             if (pak->id)
02596                iks_insert_attrib(presence, "id", pak->id);
02597             iks_insert_cdata(status, "Asterisk has approved subscription", 0);
02598             iks_insert_node(presence, status);
02599             ast_aji_send(client, presence);
02600          } else {
02601             ast_log(LOG_ERROR, "Unable to allocate nodes\n");
02602          }
02603 
02604          iks_delete(presence);
02605          iks_delete(status);
02606       }
02607 
02608       if (client->component)
02609          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02610    case IKS_TYPE_SUBSCRIBED:
02611       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02612       if (!buddy && pak->from->partial) {
02613          aji_create_buddy(pak->from->partial, client);
02614       } else if (buddy) {
02615          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02616       }
02617    default:
02618       ast_verb(5, "JABBER: This is a subcription of type %i\n", pak->subtype);
02619    }
02620 }

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

03282 {
03283    if (!mwi_sub) {
03284       mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
03285          client, AST_EVENT_IE_END);
03286    }
03287    if (!device_state_sub) {
03288       if (ast_enable_distributed_devstate()) {
03289          return;
03290       }
03291       device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
03292          aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
03293       ast_event_dump_cache(device_state_sub);
03294    }
03295 
03296    aji_pubsub_subscribe(client, "device_state");
03297    aji_pubsub_subscribe(client, "message_waiting");
03298    iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
03299       IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
03300    iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
03301       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
03302 
03303 }

static int aji_initialize ( struct aji_client client  )  [static]

Definition at line 3173 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, and aji_client::user.

Referenced by aji_reconnect().

03174 {
03175    int connected = IKS_NET_NOCONN;
03176 
03177 #ifdef HAVE_OPENSSL
03178    /* reset stream flags */
03179    client->stream_flags = 0;
03180 #endif
03181    /* If it's a component, connect to user, otherwise, connect to server */
03182    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
03183 
03184    if (connected == IKS_NET_NOCONN) {
03185       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
03186       return IKS_HOOK;
03187    } else if (connected == IKS_NET_NODNS) {
03188       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name,
03189          S_OR(client->serverhost, client->jid->server));
03190       return IKS_HOOK;
03191    }
03192 
03193    return IKS_OK;
03194 }

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

Definition at line 1337 of file res_jabber.c.

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

Referenced by aji_recv().

01338 {
01339    struct pollfd pfd = { .events = POLLIN };
01340    int len, res;
01341 
01342 #ifdef HAVE_OPENSSL
01343    if (aji_is_secure(client)) {
01344       pfd.fd = SSL_get_fd(client->ssl_session);
01345       if (pfd.fd < 0) {
01346          return -1;
01347       }
01348    } else
01349 #endif /* HAVE_OPENSSL */
01350       pfd.fd = iks_fd(client->p);
01351 
01352    res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
01353    if (res > 0) {
01354 #ifdef HAVE_OPENSSL
01355       if (aji_is_secure(client)) {
01356          len = SSL_read(client->ssl_session, buffer, buf_len);
01357       } else
01358 #endif /* HAVE_OPENSSL */
01359          len = recv(pfd.fd, buffer, buf_len, 0);
01360 
01361       if (len > 0) {
01362          return len;
01363       } else if (len <= 0) {
01364          return -1;
01365       }
01366    }
01367    return res;
01368 }

static int aji_is_secure ( struct aji_client client  )  [static]

Definition at line 1247 of file res_jabber.c.

Referenced by aji_act_hook(), aji_io_recv(), aji_send_raw(), and aji_start_sasl().

01248 {
01249 #ifdef HAVE_OPENSSL
01250    return client->stream_flags & SECURE;
01251 #else
01252    return 0;
01253 #endif
01254 }

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

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

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

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

static int aji_load_config ( int  reload  )  [static]

Definition at line 4602 of file res_jabber.c.

References AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_create_client(), AJI_PUBSUB_AUTOCREATE, AJI_XEP0248, ast_category_browse(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_false(), ast_log(), ast_set2_flag, ast_set_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, debug, JABBER_CONFIG, LOG_WARNING, ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by aji_reload().

04603 {
04604    char *cat = NULL;
04605    int debug = 0;
04606    struct ast_config *cfg = NULL;
04607    struct ast_variable *var = NULL;
04608    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04609 
04610    if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
04611       return -1;
04612    }
04613 
04614    /* Reset flags to default value */
04615    ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT);
04616 
04617    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
04618       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
04619       return 0;
04620    }
04621 
04622    cat = ast_category_browse(cfg, NULL);
04623    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04624       if (!strcasecmp(var->name, "debug")) {
04625          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
04626       } else if (!strcasecmp(var->name, "autoprune")) {
04627          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
04628       } else if (!strcasecmp(var->name, "autoregister")) {
04629          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
04630       } else if (!strcasecmp(var->name, "collection_nodes")) {
04631          ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248);
04632       } else if (!strcasecmp(var->name, "pubsub_autocreate")) {
04633          ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE);
04634       } else if (!strcasecmp(var->name, "auth_policy")) {
04635          if (!strcasecmp(var->value, "accept")) {
04636             ast_set_flag(&globalflags, AJI_AUTOACCEPT);
04637          } else {
04638             ast_clear_flag(&globalflags, AJI_AUTOACCEPT);
04639          }
04640       }
04641    }
04642 
04643    while (cat) {
04644       if (strcasecmp(cat, "general")) {
04645          var = ast_variable_browse(cfg, cat);
04646          aji_create_client(cat, var, debug);
04647       }
04648       cat = ast_category_browse(cfg, cat);
04649    }
04650    ast_config_destroy(cfg); /* or leak memory */
04651    return 1;
04652 }

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

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

01529 {
01530    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01531 
01532    if (!ast_strlen_zero(xmpp)) {
01533       manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
01534    }
01535 
01536    if (client->debug) {
01537       if (is_incoming) {
01538          ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
01539       } else {
01540          if (strlen(xmpp) == 1) {
01541             if (option_debug > 2  && xmpp[0] == ' ') {
01542                ast_verbose("\nJABBER: Keep alive packet\n");
01543             }
01544          } else {
01545             ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
01546          }
01547       }
01548 
01549    }
01550    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01551 }

static void aji_message_destroy ( struct aji_message obj  )  [static]

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

00462 {
00463    if (obj->from) {
00464       ast_free(obj->from);
00465    }
00466    if (obj->message) {
00467       ast_free(obj->message);
00468    }
00469    ast_free(obj);
00470 }

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

References aji_publish_mwi(), ast_aji_client_destroy(), ast_debug, 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, ASTOBJ_REF, ASTOBJ_UNREF, context, and mailbox.

Referenced by aji_init_event_distribution().

03227 {
03228    const char *mailbox;
03229    const char *context;
03230    char oldmsgs[10];
03231    char newmsgs[10];
03232    struct aji_client *client;
03233    if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03234    {
03235       /* If the event didn't originate from this server, don't send it back out. */
03236       ast_debug(1, "Returning here\n");
03237       return;
03238    }
03239 
03240    client = ASTOBJ_REF((struct aji_client *) data);
03241    mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
03242    context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
03243    snprintf(oldmsgs, sizeof(oldmsgs), "%d",
03244       ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
03245    snprintf(newmsgs, sizeof(newmsgs), "%d",
03246       ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
03247    aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
03248    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03249 
03250 }

static void aji_pruneregister ( struct aji_client client  )  [static]

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

02948 {
02949    iks *removeiq = iks_new("iq");
02950    iks *removequery = iks_new("query");
02951    iks *removeitem = iks_new("item");
02952    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02953    if (!client || !removeiq || !removequery || !removeitem || !send) {
02954       ast_log(LOG_ERROR, "Out of memory.\n");
02955       goto safeout;
02956    }
02957 
02958    iks_insert_node(removeiq, removequery);
02959    iks_insert_node(removequery, removeitem);
02960    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02961       ASTOBJ_RDLOCK(iterator);
02962       /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
02963        * be called at the same time */
02964       if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
02965          ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02966                          "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02967                          " so I am no longer subscribing to your presence.\n"));
02968          ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02969                          "GoodBye.  You are no longer in the Asterisk config file so I am removing"
02970                          " your access to my presence.\n"));
02971          iks_insert_attrib(removeiq, "from", client->jid->full);
02972          iks_insert_attrib(removeiq, "type", "set");
02973          iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02974          iks_insert_attrib(removeitem, "jid", iterator->name);
02975          iks_insert_attrib(removeitem, "subscription", "remove");
02976          ast_aji_send(client, removeiq);
02977       } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02978          ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
02979                          "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02980          ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02981       }
02982       ASTOBJ_UNLOCK(iterator);
02983    });
02984 
02985  safeout:
02986    iks_delete(removeiq);
02987    iks_delete(removequery);
02988    iks_delete(removeitem);
02989    iks_delete(send);
02990 
02991    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
02992 }

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

Publish device state to a PubSub node.

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

03457 {
03458    iks *request = aji_build_publish_skeleton(client, device, "device_state");
03459    iks *state;
03460    char eid_str[20];
03461    if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
03462       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03463          aji_create_pubsub_node(client, "leaf", device, "device_state");
03464       } else {
03465          aji_create_pubsub_node(client, NULL, device, NULL);
03466       }
03467    }
03468    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03469    state = iks_insert(request, "state");
03470    iks_insert_attrib(state, "xmlns", "http://asterisk.org");
03471    iks_insert_attrib(state, "eid", eid_str);
03472    iks_insert_cdata(state, device_state, strlen(device_state));
03473    ast_aji_send(client, iks_root(request));
03474    iks_delete(request);
03475 }

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

03486 {
03487    char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
03488    char eid_str[20];
03489    iks *mailbox_node, *request;
03490    snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
03491    request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
03492    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03493    mailbox_node = iks_insert(request, "mailbox");
03494    iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
03495    iks_insert_attrib(mailbox_node, "eid", eid_str);
03496    iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
03497    iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
03498    ast_aji_send(client, iks_root(request));
03499    iks_delete(request);
03500 }

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

03509 {
03510    iks *request = iks_new("iq");
03511 
03512    iks_insert_attrib(request, "to", client->pubsub_node);
03513    iks_insert_attrib(request, "from", client->jid->full);
03514    iks_insert_attrib(request, "type", type);
03515    ast_aji_increment_mid(client->mid);
03516    iks_insert_attrib(request, "id", client->mid);
03517    return request;
03518 }

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

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

03729 {
03730    iks *request = aji_build_node_request(client, collection_name);
03731    ast_aji_send(client, request);
03732    iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
03733       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03734       IKS_RULE_DONE);
03735    ast_aji_send(client, request);
03736    iks_delete(request);
03737 }

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

References aji_pubsub_iq_create(), AJI_XEP0248, ast_aji_send(), ast_test_flag, aji_client::jid, and subscribe.

Referenced by aji_init_event_distribution().

03391 {
03392    iks *request = aji_pubsub_iq_create(client, "set");
03393    iks *pubsub, *subscribe;
03394 
03395    pubsub = iks_insert(request, "pubsub");
03396    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03397    subscribe = iks_insert(pubsub, "subscribe");
03398    iks_insert_attrib(subscribe, "jid", client->jid->partial);
03399    iks_insert_attrib(subscribe, "node", node);
03400    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03401       iks *options, *x, *sub_options, *sub_type, *sub_depth;
03402       options = iks_insert(pubsub, "options");
03403       x = iks_insert(options, "x");
03404       iks_insert_attrib(x, "xmlns", "jabber:x:data");
03405       iks_insert_attrib(x, "type", "submit");
03406       sub_options = iks_insert(x, "field");
03407       iks_insert_attrib(sub_options, "var", "FORM_TYPE");
03408       iks_insert_attrib(sub_options, "type", "hidden");
03409       iks_insert_cdata(iks_insert(sub_options, "value"),
03410          "http://jabber.org/protocol/pubsub#subscribe_options", 51);
03411       sub_type = iks_insert(x, "field");
03412       iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
03413       iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
03414       sub_depth = iks_insert(x, "field");
03415       iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
03416       iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
03417    }
03418    ast_aji_send(client, request);
03419    iks_delete(request);
03420 }

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

03620 {
03621 
03622    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03623    iks *item = NULL;
03624    if (iks_has_children(pak->query)) {
03625       item = iks_first_tag(pak->query);
03626       ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
03627          iks_find_attrib(item, "node"));
03628       while ((item = iks_next_tag(item))) {
03629          ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
03630       }
03631    }
03632    if (item) {
03633       iks_delete(item);
03634    }
03635    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03636    return IKS_FILTER_EAT;
03637 }

static int aji_reconnect ( struct aji_client client  )  [static]

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

03090 {
03091    int res = 0;
03092 
03093    if (client->state) {
03094       client->state = AJI_DISCONNECTED;
03095    }
03096    client->timeout = 50;
03097    if (client->p) {
03098       iks_parser_reset(client->p);
03099    }
03100    if (client->authorized) {
03101       client->authorized = 0;
03102    }
03103 
03104    res = aji_initialize(client);
03105 
03106    return res;
03107 }

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

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

01383 {
01384    int len, ret;
01385    char buf[NET_IO_BUF_SIZE - 1];
01386    char newbuf[NET_IO_BUF_SIZE - 1];
01387    int pos = 0;
01388    int newbufpos = 0;
01389    unsigned char c;
01390 
01391    memset(buf, 0, sizeof(buf));
01392    memset(newbuf, 0, sizeof(newbuf));
01393 
01394    while (1) {
01395       len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
01396       if (len < 0) return IKS_NET_RWERR;
01397       if (len == 0) return IKS_NET_EXPIRED;
01398       buf[len] = '\0';
01399 
01400       /* our iksemel parser won't work as expected if we feed
01401          it with XML packets that contain multiple whitespace
01402          characters between tags */
01403       while (pos < len) {
01404          c = buf[pos];
01405          /* if we stumble on the ending tag character,
01406             we skip any whitespace that follows it*/
01407          if (c == '>') {
01408             while (isspace(buf[pos+1])) {
01409                pos++;
01410             }
01411          }
01412          newbuf[newbufpos] = c;
01413          newbufpos ++;
01414          pos++;
01415       }
01416       pos = 0;
01417       newbufpos = 0;
01418 
01419       /* Log the message here, because iksemel's logHook is
01420          unaccessible */
01421       aji_log_hook(client, buf, len, 1);
01422 
01423       /* let iksemel deal with the string length,
01424          and reset our buffer */
01425       ret = iks_parse(client->p, newbuf, 0, 0);
01426       memset(newbuf, 0, sizeof(newbuf));
01427 
01428       switch (ret) {
01429       case IKS_NOMEM:
01430          ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
01431          break;
01432       case IKS_BADXML:
01433          ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
01434          break;
01435       case IKS_HOOK:
01436          ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
01437          break;
01438       }
01439       if (ret != IKS_OK) {
01440          return ret;
01441       }
01442       ast_debug(3, "XML parsing successful\n");
01443    }
01444    return IKS_OK;
01445 }

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

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

02782 {
02783    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02784    int res = IKS_HOOK;
02785 
02786    while (res != IKS_OK) {
02787       ast_debug(3, "JABBER: Connecting.\n");
02788       res = aji_reconnect(client);
02789       sleep(4);
02790    }
02791 
02792    do {
02793       if (res == IKS_NET_RWERR || client->timeout == 0) {
02794          while (res != IKS_OK) {
02795             ast_debug(3, "JABBER: reconnecting.\n");
02796             res = aji_reconnect(client);
02797             sleep(4);
02798          }
02799       }
02800 
02801       res = aji_recv(client, 1);
02802 
02803       if (client->state == AJI_DISCONNECTING) {
02804          ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
02805          pthread_exit(NULL);
02806       }
02807 
02808       /* Decrease timeout if no data received, and delete
02809        * old messages globally */
02810       if (res == IKS_NET_EXPIRED) {
02811          client->timeout--;
02812          delete_old_messages_all(client);
02813       }
02814       if (res == IKS_HOOK) {
02815          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
02816       } else if (res == IKS_NET_TLSFAIL) {
02817          ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
02818       } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
02819          res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
02820          if (res == IKS_OK) {
02821             client->timeout = 50;
02822          } else {
02823             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
02824          }
02825       } else if (res == IKS_NET_RWERR) {
02826          ast_log(LOG_WARNING, "JABBER: socket read error\n");
02827       }
02828    } while (client);
02829    ASTOBJ_UNREF(client, ast_aji_client_destroy);
02830    return 0;
02831 }

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

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

01834 {
01835    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01836    iks *iq = NULL, *presence = NULL, *x = NULL;
01837 
01838    iq = iks_new("iq");
01839    presence = iks_new("presence");
01840    x = iks_new("x");
01841    if (client && iq && presence && x) {
01842       if (!iks_find(pak->query, "remove")) {
01843          iks_insert_attrib(iq, "from", client->jid->full);
01844          iks_insert_attrib(iq, "to", pak->from->full);
01845          iks_insert_attrib(iq, "id", pak->id);
01846          iks_insert_attrib(iq, "type", "result");
01847          ast_aji_send(client, iq);
01848 
01849          iks_insert_attrib(presence, "from", client->jid->full);
01850          iks_insert_attrib(presence, "to", pak->from->partial);
01851          iks_insert_attrib(presence, "id", client->mid);
01852          ast_aji_increment_mid(client->mid);
01853          iks_insert_attrib(presence, "type", "subscribe");
01854          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01855          iks_insert_node(presence, x);
01856          ast_aji_send(client, presence);
01857       }
01858    } else {
01859       ast_log(LOG_ERROR, "Out of memory.\n");
01860    }
01861 
01862    iks_delete(iq);
01863    iks_delete(presence);
01864    iks_delete(x);
01865 
01866    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01867    return IKS_FILTER_EAT;
01868 }

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

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

01877 {
01878    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01879    struct aji_buddy *buddy = NULL;
01880    char *node = NULL;
01881    iks *iq = NULL, *query = NULL;
01882 
01883    client = (struct aji_client *) data;
01884 
01885    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01886    if (!buddy) {
01887       iks  *error = NULL, *notacceptable = NULL;
01888 
01889       ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01890       iq = iks_new("iq");
01891       query = iks_new("query");
01892       error = iks_new("error");
01893       notacceptable = iks_new("not-acceptable");
01894       if (iq && query && error && notacceptable) {
01895          iks_insert_attrib(iq, "type", "error");
01896          iks_insert_attrib(iq, "from", client->user);
01897          iks_insert_attrib(iq, "to", pak->from->full);
01898          iks_insert_attrib(iq, "id", pak->id);
01899          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01900          iks_insert_attrib(error, "code" , "406");
01901          iks_insert_attrib(error, "type", "modify");
01902          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01903          iks_insert_node(iq, query);
01904          iks_insert_node(iq, error);
01905          iks_insert_node(error, notacceptable);
01906          ast_aji_send(client, iq);
01907       } else {
01908          ast_log(LOG_ERROR, "Out of memory.\n");
01909       }
01910 
01911       iks_delete(error);
01912       iks_delete(notacceptable);
01913    } else if (!(node = iks_find_attrib(pak->query, "node"))) {
01914       iks *instructions = NULL;
01915       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01916       iq = iks_new("iq");
01917       query = iks_new("query");
01918       instructions = iks_new("instructions");
01919       if (iq && query && instructions && client) {
01920          iks_insert_attrib(iq, "from", client->user);
01921          iks_insert_attrib(iq, "to", pak->from->full);
01922          iks_insert_attrib(iq, "id", pak->id);
01923          iks_insert_attrib(iq, "type", "result");
01924          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01925          iks_insert_cdata(instructions, explain, 0);
01926          iks_insert_node(iq, query);
01927          iks_insert_node(query, instructions);
01928          ast_aji_send(client, iq);
01929       } else {
01930          ast_log(LOG_ERROR, "Out of memory.\n");
01931       }
01932 
01933       iks_delete(instructions);
01934    }
01935    iks_delete(iq);
01936    iks_delete(query);
01937    ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01938    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01939    return IKS_FILTER_EAT;
01940 }

static int aji_reload ( int  reload  )  [static]

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

04740 {
04741    int res;
04742 
04743    ASTOBJ_CONTAINER_MARKALL(&clients);
04744    if (!(res = aji_load_config(reload))) {
04745       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
04746       return 0;
04747    } else if (res == -1)
04748       return 1;
04749 
04750    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
04751    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04752       ASTOBJ_RDLOCK(iterator);
04753       if (iterator->state == AJI_DISCONNECTED) {
04754          if (!iterator->thread)
04755             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
04756       } else if (iterator->state == AJI_CONNECTING) {
04757          aji_get_roster(iterator);
04758          if (iterator->distribute_events) {
04759             aji_init_event_distribution(iterator);
04760          }
04761       }
04762 
04763       ASTOBJ_UNLOCK(iterator);
04764    });
04765 
04766    return 1;
04767 }

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

03584 {
03585    iks *request = aji_build_node_request(client, collection);
03586 
03587    iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
03588       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03589       IKS_RULE_DONE);
03590    ast_aji_send(client, request);
03591    iks_delete(request);
03592 
03593 }

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

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

01119 {
01120    struct aji_client *client = NULL;
01121    char *s;
01122    AST_DECLARE_APP_ARGS(args,
01123       AST_APP_ARG(sender);
01124       AST_APP_ARG(recipient);
01125       AST_APP_ARG(message);
01126    );
01127 
01128    if (!data) {
01129       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01130       return -1;
01131    }
01132    s = ast_strdupa(data);
01133 
01134    AST_STANDARD_APP_ARGS(args, s);
01135    if (args.argc < 3) {
01136       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01137       return -1;
01138    }
01139 
01140    if (!(client = ast_aji_get_client(args.sender))) {
01141       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
01142       return -1;
01143    }
01144    if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
01145       ast_aji_send_chat(client, args.recipient, args.message);
01146    }
01147    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01148    return 0;
01149 }

static int aji_send_header ( struct aji_client client,
const char *  to 
) [static]

Definition at line 1454 of file res_jabber.c.

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

Referenced by aji_act_hook().

01455 {
01456    char *msg;
01457    int len, err;
01458 
01459    len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
01460    msg = iks_malloc(len);
01461    if (!msg)
01462       return IKS_NOMEM;
01463    sprintf(msg, "<?xml version='1.0'?>"
01464       "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
01465       "%s' to='%s' version='1.0'>", client->name_space, to);
01466    err = aji_send_raw(client, msg);
01467    iks_free(msg);
01468    if (err != IKS_OK)
01469       return err;
01470 
01471    return IKS_OK;
01472 }

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

Definition at line 1494 of file res_jabber.c.

References aji_is_secure(), aji_log_hook(), len(), and aji_client::p.

Referenced by aji_act_hook(), aji_recv_loop(), aji_send_header(), and ast_aji_send().

01495 {
01496    int ret;
01497 #ifdef HAVE_OPENSSL
01498    int len = strlen(xmlstr);
01499 
01500    if (aji_is_secure(client)) {
01501       ret = SSL_write(client->ssl_session, xmlstr, len);
01502       if (ret) {
01503          /* Log the message here, because iksemel's logHook is
01504             unaccessible */
01505          aji_log_hook(client, xmlstr, len, 0);
01506          return IKS_OK;
01507       }
01508    }
01509 #endif
01510    /* If needed, data will be sent unencrypted, and logHook will
01511       be called inside iks_send_raw */
01512    ret = iks_send_raw(client->p, xmlstr);
01513    if (ret != IKS_OK) {
01514       return ret;
01515    }
01516 
01517    return IKS_OK;
01518 }

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

02658 {
02659    int res = 0;
02660    iks *message_packet = NULL;
02661    char from[AJI_MAX_JIDLEN];
02662    /* the nickname is used only in component mode */
02663    if (nick && client->component) {
02664       snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
02665    } else {
02666       snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
02667    }
02668 
02669    if (client->state != AJI_CONNECTED) {
02670       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
02671       return -1;
02672    }
02673 
02674    message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
02675    if (!message_packet) {
02676       ast_log(LOG_ERROR, "Out of memory.\n");
02677       return -1;
02678    }
02679    iks_insert_attrib(message_packet, "from", from);
02680    res = ast_aji_send(client, message_packet);
02681    iks_delete(message_packet);
02682 
02683    return res;
02684 }

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

01192 {
01193    struct aji_client *client = NULL;
01194    char *s;
01195    char nick[AJI_MAX_RESJIDLEN];
01196    int res = 0;
01197    AST_DECLARE_APP_ARGS(args,
01198       AST_APP_ARG(sender);
01199       AST_APP_ARG(groupchat);
01200       AST_APP_ARG(message);
01201       AST_APP_ARG(nick);
01202    );
01203 
01204    if (!data) {
01205       ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01206       return -1;
01207    }
01208    s = ast_strdupa(data);
01209 
01210    AST_STANDARD_APP_ARGS(args, s);
01211    if (args.argc < 3 || args.argc > 4) {
01212       ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01213       return -1;
01214    }
01215 
01216    if (!(client = ast_aji_get_client(args.sender))) {
01217       ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01218       return -1;
01219    }
01220 
01221    if (ast_strlen_zero(args.nick) || args.argc == 3) {
01222       if (client->component) {
01223          sprintf(nick, "asterisk");
01224       } else {
01225          snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
01226       }
01227    } else {
01228       snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
01229    }
01230 
01231    if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
01232       res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
01233    }
01234 
01235    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01236    if (res != IKS_OK) {
01237       return -1;
01238    }
01239    return 0;
01240 }

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

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

04050 {
04051    int res = 0;
04052    iks *presence = NULL, *x = NULL;
04053    char from[AJI_MAX_JIDLEN];
04054    char roomid[AJI_MAX_JIDLEN];
04055 
04056    presence = iks_make_pres(level, NULL);
04057    x = iks_new("x");
04058 
04059    if (client->component) {
04060       snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
04061       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
04062    } else {
04063       snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
04064       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
04065    }
04066 
04067    if (!presence || !x || !client) {
04068       ast_log(LOG_ERROR, "Out of memory.\n");
04069       res = -1;
04070       goto safeout;
04071    } else {
04072       iks_insert_attrib(presence, "to", roomid);
04073       iks_insert_attrib(presence, "from", from);
04074       iks_insert_attrib(x, "xmlns", MUC_NS);
04075       iks_insert_node(presence, x);
04076       res = ast_aji_send(client, presence);
04077    }
04078 
04079 safeout:
04080    iks_delete(presence);
04081    iks_delete(x);
04082    return res;
04083 }

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

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

04008 {
04009    iks *presence = iks_make_pres(level, desc);
04010    iks *cnode = iks_new("c");
04011    iks *priority = iks_new("priority");
04012    char priorityS[10];
04013 
04014    if (presence && cnode && client && priority) {
04015       if (to) {
04016          iks_insert_attrib(presence, "to", to);
04017       }
04018       if (from) {
04019          iks_insert_attrib(presence, "from", from);
04020       }
04021       snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
04022       iks_insert_cdata(priority, priorityS, strlen(priorityS));
04023       iks_insert_node(presence, priority);
04024       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
04025       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
04026       iks_insert_attrib(cnode, "ext", "voice-v1");
04027       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
04028       iks_insert_node(presence, cnode);
04029       ast_aji_send(client, presence);
04030    } else {
04031       ast_log(LOG_ERROR, "Out of memory.\n");
04032    }
04033 
04034    iks_delete(cnode);
04035    iks_delete(presence);
04036    iks_delete(priority);
04037 }

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

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

04202 {
04203    struct aji_resource *resource;
04204    struct aji_client *client;
04205 
04206    switch (cmd) {
04207    case CLI_INIT:
04208       e->command = "jabber show buddies";
04209       e->usage =
04210          "Usage: jabber show buddies\n"
04211          "       Shows buddy lists of our clients\n";
04212       return NULL;
04213    case CLI_GENERATE:
04214       return NULL;
04215    }
04216 
04217    ast_cli(a->fd, "Jabber buddy lists\n");
04218    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04219       ast_cli(a->fd, "Client: %s\n", iterator->user);
04220       client = iterator;
04221       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04222          ASTOBJ_RDLOCK(iterator);
04223          ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
04224          if (!iterator->resources)
04225             ast_cli(a->fd, "\t\tResource: None\n");
04226          for (resource = iterator->resources; resource; resource = resource->next) {
04227             ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
04228             if (resource->cap) {
04229                ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
04230                ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
04231                ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
04232             }
04233             ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
04234             ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
04235          }
04236          ASTOBJ_UNLOCK(iterator);
04237       });
04238       iterator = client;
04239    });
04240    return CLI_SUCCESS;
04241 }

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

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

04156 {
04157    char *status;
04158    int count = 0;
04159 
04160    switch (cmd) {
04161    case CLI_INIT:
04162       e->command = "jabber show connections";
04163       e->usage =
04164          "Usage: jabber show connections\n"
04165          "       Shows state of client and component connections\n";
04166       return NULL;
04167    case CLI_GENERATE:
04168       return NULL;
04169    }
04170 
04171    ast_cli(a->fd, "Jabber Users and their status:\n");
04172    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04173       ASTOBJ_RDLOCK(iterator);
04174       count++;
04175       switch (iterator->state) {
04176       case AJI_DISCONNECTED:
04177          status = "Disconnected";
04178          break;
04179       case AJI_CONNECTING:
04180          status = "Connecting";
04181          break;
04182       case AJI_CONNECTED:
04183          status = "Connected";
04184          break;
04185       default:
04186          status = "Unknown";
04187       }
04188       ast_cli(a->fd, "       [%s] %s     - %s\n", iterator->name, iterator->user, status);
04189       ASTOBJ_UNLOCK(iterator);
04190    });
04191    ast_cli(a->fd, "----\n");
04192    ast_cli(a->fd, "   Number of users: %d\n", count);
04193    return CLI_SUCCESS;
04194 }

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

Definition at line 1563 of file res_jabber.c.

References aji_is_secure(), ast_aji_send(), ast_base64encode(), ast_log(), base64, len(), LOG_ERROR, and aji_client::p.

Referenced by aji_act_hook().

01564 {
01565    iks *x = NULL;
01566    int len;
01567    char *s;
01568    char *base64;
01569 
01570    /* trigger SASL DIGEST-MD5 only over an unsecured connection.
01571       iks_start_sasl is an iksemel API function and relies on GnuTLS,
01572       whereas we use OpenSSL */
01573    if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
01574       return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
01575    if (!(type & IKS_STREAM_SASL_PLAIN)) {
01576       ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
01577       return IKS_NET_NOTSUPP;
01578    }
01579 
01580    x = iks_new("auth"); 
01581    if (!x) {
01582       ast_log(LOG_ERROR, "Out of memory.\n");
01583       return IKS_NET_NOTSUPP;
01584    }
01585 
01586    iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
01587    len = strlen(username) + strlen(pass) + 3;
01588    s = alloca(len);
01589    base64 = alloca((len + 2) * 4 / 3);
01590    iks_insert_attrib(x, "mechanism", "PLAIN");
01591    snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
01592 
01593    /* exclude the NULL training byte from the base64 encoding operation
01594       as some XMPP servers will refuse it.
01595       The format for authentication is [authzid]\0authcid\0password
01596       not [authzid]\0authcid\0password\0 */
01597    ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
01598    iks_insert_cdata(x, base64, 0);
01599    ast_aji_send(client, x);
01600    iks_delete(x);
01601 
01602    return IKS_OK;
01603 }

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

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

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

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

Definition at line 4248 of file res_jabber.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_aji_send_chat(), ast_cli(), ast_verbose, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_resource::cap, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, clients, ast_cli_entry::command, aji_resource::description, ast_cli_args::fd, aji_version::jingle, name, aji_resource::next, aji_capabilities::node, aji_version::parent, aji_resource::priority, aji_resource::resource, S_OR, aji_resource::status, ast_cli_entry::usage, and aji_version::version.

04249 {
04250    struct aji_client *client;
04251    struct aji_resource *resource;
04252    const char *name;
04253    struct aji_message *tmp;
04254 
04255    switch (cmd) {
04256    case CLI_INIT:
04257       e->command = "jabber test";
04258       e->usage =
04259          "Usage: jabber test <connection>\n"
04260          "       Sends test message for debugging purposes.  A specific client\n"
04261          "       as configured in jabber.conf must be specified.\n";
04262       return NULL;
04263    case CLI_GENERATE:
04264       return NULL;
04265    }
04266 
04267    if (a->argc != 3) {
04268       return CLI_SHOWUSAGE;
04269    }
04270    name = a->argv[2];
04271 
04272    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
04273       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04274       return CLI_FAILURE;
04275    }
04276 
04277    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
04278    ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
04279    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04280       ASTOBJ_RDLOCK(iterator);
04281       ast_verbose("User: %s\n", iterator->name);
04282       for (resource = iterator->resources; resource; resource = resource->next) {
04283          ast_verbose("Resource: %s\n", resource->resource);
04284          if (resource->cap) {
04285             ast_verbose("   client: %s\n", resource->cap->parent->node);
04286             ast_verbose("   version: %s\n", resource->cap->version);
04287             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
04288          }
04289          ast_verbose("  Priority: %d\n", resource->priority);
04290          ast_verbose("  Status: %d\n", resource->status);
04291          ast_verbose("  Message: %s\n", S_OR(resource->description, ""));
04292       }
04293       ASTOBJ_UNLOCK(iterator);
04294    });
04295    ast_verbose("\nOooh a working message stack!\n");
04296    AST_LIST_LOCK(&client->messages);
04297    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
04298       //ast_verbose("   Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
04299    }
04300    AST_LIST_UNLOCK(&client->messages);
04301    ASTOBJ_UNREF(client, ast_aji_client_destroy);
04302 
04303    return CLI_SUCCESS;
04304 }

void ast_aji_buddy_destroy ( struct aji_buddy obj  ) 

Destructor function for buddies to be used with ASTOBJ_UNREF

Definition at line 442 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(), gtalk_member_destroy(), jingle_alloc(), and jingle_member_destroy().

00443 {
00444    struct aji_resource *tmp;
00445 
00446    while ((tmp = obj->resources)) {
00447       obj->resources = obj->resources->next;
00448       ast_free(tmp->description);
00449       ast_free(tmp);
00450    }
00451 
00452    ast_free(obj);
00453 }

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

References aji_message_destroy(), ast_aji_buddy_destroy(), ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, aji_client::buddies, aji_client::f, aji_message::list, aji_client::messages, aji_client::p, and aji_client::stack.

Referenced by acf_jabberreceive_read(), acf_jabberstatus_read(), aji_act_hook(), aji_cli_create_collection(), aji_cli_create_leafnode(), aji_cli_delete_pubsub_node(), aji_cli_list_pubsub_nodes(), aji_cli_purge_pubsub_nodes(), aji_client_connect(), aji_client_info_handler(), aji_create_client(), aji_devstate_cb(), aji_dinfo_handler(), aji_ditems_handler(), aji_handle_pubsub_error(), aji_join_exec(), aji_leave_exec(), aji_log_hook(), aji_mwi_cb(), aji_receive_node_list(), aji_recv_loop(), aji_register_approve_handler(), aji_register_query_handler(), aji_reload(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), ast_aji_disconnect(), gtalk_load_config(), gtalk_member_destroy(), gtalk_newcall(), gtalk_request(), jingle_load_config(), jingle_member_destroy(), jingle_newcall(), jingle_request(), manager_jabber_send(), msg_send_cb(), and unload_module().

00421 {
00422    struct aji_message *tmp;
00423    ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy);
00424    ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00425    iks_filter_delete(obj->f);
00426    iks_parser_delete(obj->p);
00427    iks_stack_delete(obj->stack);
00428    AST_LIST_LOCK(&obj->messages);
00429    while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00430       aji_message_destroy(tmp);
00431    }
00432    AST_LIST_HEAD_DESTROY(&obj->messages);
00433    ast_free(obj);
00434 }

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

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

02695 {
02696    int res = 0;
02697    iks *iq = NULL;
02698    iq = iks_new("iq");
02699 
02700    if (iq && client) {
02701       iks_insert_attrib(iq, "type", "get");
02702       iks_insert_attrib(iq, "to", server);
02703       iks_insert_attrib(iq, "id", client->mid);
02704       ast_aji_increment_mid(client->mid);
02705       ast_aji_send(client, iq);
02706    } else {
02707       ast_log(LOG_ERROR, "Out of memory.\n");
02708    }
02709 
02710    iks_delete(iq);
02711 
02712    return res;
02713 }

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

References ast_aji_client_destroy(), ast_verb, ASTOBJ_UNREF, and aji_client::p.

Referenced by unload_module().

03202 {
03203    if (client) {
03204       ast_verb(4, "JABBER: Disconnecting\n");
03205 #ifdef HAVE_OPENSSL
03206       if (client->stream_flags & SECURE) {
03207          SSL_shutdown(client->ssl_session);
03208          SSL_CTX_free(client->ssl_context);
03209          SSL_free(client->ssl_session);
03210       }
03211 #endif
03212       iks_disconnect(client->p);
03213       iks_parser_delete(client->p);
03214       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03215    }
03216 
03217    return 1;
03218 }

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

References ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_REF, clients, and strsep().

Referenced by acf_jabberreceive_read(), acf_jabberstatus_read(), aji_join_exec(), aji_leave_exec(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), gtalk_create_member(), gtalk_newcall(), gtalk_request(), jingle_create_member(), jingle_newcall(), jingle_request(), manager_jabber_send(), and msg_send_cb().

04661 {
04662    struct aji_client *client = NULL;
04663    char *aux = NULL;
04664 
04665    client = ASTOBJ_CONTAINER_FIND(&clients, name);
04666    if (!client && strchr(name, '@')) {
04667       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04668          aux = ast_strdupa(iterator->user);
04669          if (strchr(aux, '/')) {
04670             /* strip resource for comparison */
04671             aux = strsep(&aux, "/");
04672          }
04673          if (!strncasecmp(aux, name, strlen(aux))) {
04674             client = ASTOBJ_REF(iterator);
04675          }
04676       });
04677    }
04678 
04679    return client;
04680 }

struct aji_client_container* ast_aji_get_clients ( void   )  [read]

Definition at line 4682 of file res_jabber.c.

References clients.

Referenced by gtalk_load_config(), and jingle_load_config().

04683 {
04684    return &clients;
04685 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

02839 {
02840    int i = 0;
02841 
02842    for (i = strlen(mid) - 1; i >= 0; i--) {
02843       if (mid[i] != 'z') {
02844          mid[i] = mid[i] + 1;
02845          i = 0;
02846       } else
02847          mid[i] = 'a';
02848    }
02849 }

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

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

02747 {
02748    int res = 0;
02749    iks *invite, *body, *namespace;
02750 
02751    invite = iks_new("message");
02752    body = iks_new("body");
02753    namespace = iks_new("x");
02754    if (client && invite && body && namespace) {
02755       iks_insert_attrib(invite, "to", user);
02756       iks_insert_attrib(invite, "id", client->mid);
02757       ast_aji_increment_mid(client->mid);
02758       iks_insert_cdata(body, message, 0);
02759       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
02760       iks_insert_attrib(namespace, "jid", room);
02761       iks_insert_node(invite, body);
02762       iks_insert_node(invite, namespace);
02763       res = ast_aji_send(client, invite);
02764    } else {
02765       ast_log(LOG_ERROR, "Out of memory.\n");
02766    }
02767 
02768    iks_delete(body);
02769    iks_delete(namespace);
02770    iks_delete(invite);
02771 
02772    return res;
02773 }

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

References aji_set_group_presence().

Referenced by aji_join_exec().

02723 {
02724    return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
02725 }

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

References aji_set_group_presence().

Referenced by aji_leave_exec().

02735 {
02736    return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
02737 }

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

References aji_send_raw_chat().

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

02631 {
02632    return aji_send_raw_chat(client, 0, NULL, address, message);
02633 }

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

References aji_send_raw_chat().

Referenced by aji_sendgroup_exec().

02644                                                                                                                   {
02645    return aji_send_raw_chat(client, 1, nick, address, message);
02646 }

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

Definition at line 940 of file res_jabber.c.

References aji_message_destroy(), aji_message::arrived, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_sec(), ast_tvnow(), aji_message::from, aji_message::list, LOG_ERROR, aji_client::message_timeout, and aji_client::messages.

Referenced by aji_handle_message(), and delete_old_messages_all().

00941 {
00942    int deleted = 0;
00943    int isold = 0;
00944    struct aji_message *tmp = NULL;
00945    if (!client) {
00946       ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
00947       return -1;
00948    }
00949 
00950    /* remove old messages */
00951    AST_LIST_LOCK(&client->messages);
00952    if (AST_LIST_EMPTY(&client->messages)) {
00953       AST_LIST_UNLOCK(&client->messages);
00954       return 0;
00955    }
00956 
00957    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
00958       if (isold) {
00959          if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00960             AST_LIST_REMOVE_CURRENT(list);
00961             aji_message_destroy(tmp);
00962             deleted ++;
00963          }
00964       } else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
00965          isold = 1;
00966          if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00967             AST_LIST_REMOVE_CURRENT(list);
00968             aji_message_destroy(tmp);
00969             deleted ++;
00970          }
00971       }
00972    }
00973    AST_LIST_TRAVERSE_SAFE_END;
00974    AST_LIST_UNLOCK(&client->messages);
00975 
00976    return deleted;
00977 }

static int delete_old_messages_all ( struct aji_client client  )  [static]

Definition at line 987 of file res_jabber.c.

References delete_old_messages().

Referenced by aji_recv_loop().

00988 {
00989    return delete_old_messages(client, NULL);
00990 }

static int gtalk_yuck ( iks *  node  )  [static]

Definition at line 576 of file res_jabber.c.

References ast_debug.

Referenced by aji_handle_presence().

00577 {
00578    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
00579       ast_debug(1, "Found resource with Googletalk voice capabilities\n");
00580       return 1;
00581    } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) {
00582       ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n");
00583       return 1;
00584    } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) {
00585       ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n");
00586       return 1;
00587    }
00588 
00589    return 0;
00590 }

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

Definition at line 600 of file res_jabber.c.

References ast_sha1_hash().

Referenced by aji_act_hook().

00601 {
00602    iks *x, *y;
00603    x = iks_new("iq");
00604    iks_insert_attrib(x, "type", "set");
00605    y = iks_insert(x, "query");
00606    iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00607    iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00608    iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00609    if (sid) {
00610       char buf[41];
00611       char sidpass[100];
00612       snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00613       ast_sha1_hash(buf, sidpass);
00614       iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00615    } else {
00616       iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00617    }
00618    return x;
00619 }

static int load_module ( void   )  [static]

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

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

04695 {
04696    struct aji_client *client = NULL;
04697    const char *id = astman_get_header(m, "ActionID");
04698    const char *jabber = astman_get_header(m, "Jabber");
04699    const char *screenname = astman_get_header(m, "ScreenName");
04700    const char *message = astman_get_header(m, "Message");
04701 
04702    if (ast_strlen_zero(jabber)) {
04703       astman_send_error(s, m, "No transport specified");
04704       return 0;
04705    }
04706    if (ast_strlen_zero(screenname)) {
04707       astman_send_error(s, m, "No ScreenName specified");
04708       return 0;
04709    }
04710    if (ast_strlen_zero(message)) {
04711       astman_send_error(s, m, "No Message specified");
04712       return 0;
04713    }
04714 
04715    astman_send_ack(s, m, "Attempting to send Jabber Message");
04716    client = ast_aji_get_client(jabber);
04717    if (!client) {
04718       astman_send_error(s, m, "Could not find Sender");
04719       return 0;
04720    }
04721    if (strchr(screenname, '@') && message) {
04722       ast_aji_send_chat(client, screenname, message);
04723       astman_append(s, "Response: Success\r\n");
04724    } else {
04725       astman_append(s, "Response: Error\r\n");
04726    }
04727    ASTOBJ_UNREF(client, ast_aji_client_destroy);
04728    if (!ast_strlen_zero(id)) {
04729       astman_append(s, "ActionID: %s\r\n", id);
04730    }
04731    astman_append(s, "\r\n");
04732    return 0;
04733 }

static int msg_send_cb ( const struct ast_msg msg,
const char *  to,
const char *  from 
) [static]

Definition at line 1151 of file res_jabber.c.

References ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_send_chat(), ast_debug, ast_log(), ast_msg_get_body(), ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, LOG_ERROR, LOG_WARNING, aji_client::name, and strsep().

01152 {
01153    struct aji_client *client;
01154    char *sender;
01155    char *dest;
01156    int res;
01157 
01158    sender = ast_strdupa(from);
01159    strsep(&sender, ":");
01160    dest = ast_strdupa(to);
01161    strsep(&dest, ":");
01162 
01163    if (ast_strlen_zero(sender)) {
01164       ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for xmpp\n", from);
01165       return -1;
01166    }
01167 
01168    if (!(client = ast_aji_get_client(sender))) {
01169       ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
01170       return -1;
01171    }
01172 
01173    ast_debug(1, "Sending message to '%s' from '%s'\n", dest, client->name);
01174 
01175    res = ast_aji_send_chat(client, dest, ast_msg_get_body(msg));
01176    if (res != IKS_OK) {
01177       ast_log(LOG_WARNING, "Failed to send xmpp message (%d).\n", res);
01178    }
01179 
01180    ASTOBJ_UNREF(client, ast_aji_client_destroy);
01181    return res == IKS_OK ? 0 : -1;
01182 }

static int reload ( void   )  [static]

Definition at line 4839 of file res_jabber.c.

References aji_reload().

04840 {
04841    aji_reload(1);
04842    return 0;
04843 }

static int unload_module ( void   )  [static]

Definition at line 4773 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_msg_tech_unregister(), ast_mutex_destroy, ast_unregister_application(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, and clients.

04774 {
04775    ast_msg_tech_unregister(&msg_tech);
04776    ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
04777    ast_unregister_application(app_ajisend);
04778    ast_unregister_application(app_ajisendgroup);
04779    ast_unregister_application(app_ajistatus);
04780    ast_unregister_application(app_ajijoin);
04781    ast_unregister_application(app_ajileave);
04782    ast_manager_unregister("JabberSend");
04783    ast_custom_function_unregister(&jabberstatus_function);
04784    if (mwi_sub) {
04785       ast_event_unsubscribe(mwi_sub);
04786    }
04787    if (device_state_sub) {
04788       ast_event_unsubscribe(device_state_sub);
04789    }
04790    ast_custom_function_unregister(&jabberreceive_function);
04791 
04792    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04793       ASTOBJ_WRLOCK(iterator);
04794       ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
04795       iterator->state = AJI_DISCONNECTING;
04796       ASTOBJ_UNLOCK(iterator);
04797       pthread_join(iterator->thread, NULL);
04798       ast_aji_disconnect(iterator);
04799    });
04800 
04801    ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
04802    ASTOBJ_CONTAINER_DESTROY(&clients);
04803 
04804    ast_cond_destroy(&message_received_condition);
04805    ast_mutex_destroy(&messagelock);
04806 
04807    return 0;
04808 }


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

Definition at line 4850 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 383 of file res_jabber.c.

char* app_ajijoin = "JabberJoin" [static]

Definition at line 399 of file res_jabber.c.

char* app_ajileave = "JabberLeave" [static]

Definition at line 400 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 396 of file res_jabber.c.

char* app_ajisendgroup = "JabberSendGroup" [static]

Definition at line 397 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 398 of file res_jabber.c.

Definition at line 4850 of file res_jabber.c.

struct aji_capabilities* capabilities = NULL [static]

Definition at line 403 of file res_jabber.c.

struct aji_client_container clients [static]

struct ast_event_sub* device_state_sub = NULL [static]

Definition at line 405 of file res_jabber.c.

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

Global flags, initialized to default values.

Definition at line 410 of file res_jabber.c.

Initial value:

 {
   .name = "JABBER_RECEIVE",
   .read = acf_jabberreceive_read,
}

Definition at line 926 of file res_jabber.c.

Initial value:

 {
   .name = "JABBER_STATUS",
   .read = acf_jabberstatus_read,
}

Definition at line 763 of file res_jabber.c.

Definition at line 406 of file res_jabber.c.

Definition at line 407 of file res_jabber.c.

struct ast_msg_tech msg_tech [static]

Initial value:

 {
   .name = "xmpp",
   .msg_send = msg_send_cb,
}

Definition at line 378 of file res_jabber.c.

struct ast_event_sub* mwi_sub = NULL [static]

Definition at line 404 of file res_jabber.c.

struct ast_flags pubsubflags = { 0 } [static]

PubSub flags, initialized to default values.

Definition at line 413 of file res_jabber.c.


Generated on Sat Feb 11 06:36:30 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6