Mon Mar 19 11:30:53 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"

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_start_tls (struct aji_client *client)
static int aji_status_exec (struct ast_channel *chan, const char *data)
static char * aji_test (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int aji_tls_handshake (struct aji_client *client)
void ast_aji_buddy_destroy (struct aji_buddy *obj)
void ast_aji_client_destroy (struct aji_client *obj)
int ast_aji_create_chat (struct aji_client *client, char *room, char *server, char *topic)
 create a chatroom.
int ast_aji_disconnect (struct aji_client *client)
 disconnect from jabber server.
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)
aji_client_containerast_aji_get_clients (void)
void ast_aji_increment_mid (char *mid)
 increments the mid field for messages and other events.
int ast_aji_invite_chat (struct aji_client *client, char *user, char *room, char *message)
 invite to a chatroom.
int ast_aji_join_chat (struct aji_client *client, char *room, char *nick)
 join a chatroom.
int ast_aji_leave_chat (struct aji_client *client, char *room, char *nick)
 leave a chatroom.
int ast_aji_send (struct aji_client *client, iks *x)
 Wraps raw sending.
int ast_aji_send_chat (struct aji_client *client, const char *address, const char *message)
 sends messages.
int ast_aji_send_groupchat (struct aji_client *client, const char *nick, const char *address, const char *message)
 sends message to a groupchat Prior to sending messages to a groupchat, one must be connected to it.
static int delete_old_messages (struct aji_client *client, char *from)
static int delete_old_messages_all (struct aji_client *client)
static int gtalk_yuck (iks *node)
static iks * jabber_make_auth (iksid *id, const char *pass, const char *sid)
static int load_module (void)
static int manager_jabber_send (struct mansession *s, const struct message *m)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "AJI - Asterisk Jabber Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static struct ast_cli_entry aji_cli []
static char * app_ajijoin = "JabberJoin"
static char * app_ajileave = "JabberLeave"
static char * app_ajisend = "JabberSend"
static char * app_ajisendgroup = "JabberSendGroup"
static char * app_ajistatus = "JabberStatus"
static struct ast_module_infoast_module_info = &__mod_info
static struct aji_capabilitiescapabilities = NULL
static struct aji_client_container clients
static struct ast_event_subdevice_state_sub = NULL
static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT }
 Global flags, initialized to default values.
static struct ast_custom_function jabberreceive_function
static struct ast_custom_function jabberstatus_function
static ast_cond_t message_received_condition
static ast_mutex_t messagelock
static struct ast_event_submwi_sub = NULL
static struct ast_flags pubsubflags = { 0 }
 PubSub flags, initialized to default values.


Detailed Description

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

References:

ExtRef:
Iksemel http://code.google.com/p/iksemel/
Todo:
If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?

Dialplan applications need RETURN variable, like JABBERSENDSTATUS

Definition in file res_jabber.c.


Define Documentation

#define JABBER_CONFIG   "jabber.conf"

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

Definition at line 285 of file res_jabber.c.

Referenced by aji_load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4784 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

Definition at line 4784 of file res_jabber.c.

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

Definition at line 769 of file res_jabber.c.

References AJI_MAX_JIDLEN, aji_message_destroy(), args, aji_message::arrived, ast_aji_client_destroy(), ast_aji_get_client(), AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_cond_timedwait, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvdiff_sec(), ast_tvnow(), ASTOBJ_UNREF, aji_message::from, LOG_NOTICE, LOG_WARNING, aji_message::message, aji_client::message_timeout, messagelock, aji_client::messages, ast_channel::name, and parse().

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

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

Definition at line 698 of file res_jabber.c.

References aji_find_resource(), args, ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_get_client(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_resource::resource, aji_buddy::resources, and aji_resource::status.

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

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

Definition at line 1572 of file res_jabber.c.

References aji_client_connect(), AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, AJI_DISCONNECTING, aji_handle_iq(), aji_handle_message(), aji_handle_presence(), aji_handle_subscribe(), aji_is_secure(), AJI_MAX_ATTRLEN, aji_recv(), aji_send_header(), aji_send_raw(), aji_start_sasl(), aji_start_tls(), aji_tls_handshake(), asprintf, ast_aji_client_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_debug, ast_free, ast_log(), ast_sha1_hash(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::authorized, aji_client::component, aji_client::f, jabber_make_auth(), aji_client::jid, LOG_ERROR, LOG_WARNING, aji_client::mid, aji_client::password, secret, aji_client::state, aji_client::stream_flags, aji_client::usesasl, and aji_client::usetls.

Referenced by aji_create_client().

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

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

Definition at line 3812 of file res_jabber.c.

Referenced by aji_create_pubsub_node().

03813 {
03814    iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
03815       *field_deliver_payload, *field_persist_items, *field_access_model,
03816       *field_pubsub_collection;
03817    configure = iks_insert(pubsub, "configure");
03818    x = iks_insert(configure, "x");
03819    iks_insert_attrib(x, "xmlns", "jabber:x:data");
03820    iks_insert_attrib(x, "type", "submit");
03821    field_owner = iks_insert(x, "field");
03822    iks_insert_attrib(field_owner, "var", "FORM_TYPE");
03823    iks_insert_attrib(field_owner, "type", "hidden");
03824    iks_insert_cdata(iks_insert(field_owner, "value"),
03825       "http://jabber.org/protocol/pubsub#owner", 39);
03826    if (node_type) {
03827       field_node_type = iks_insert(x, "field");
03828       iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
03829       iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
03830    }
03831    field_node_config = iks_insert(x, "field");
03832    iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
03833    iks_insert_attrib(field_node_config, "type", "hidden");
03834    iks_insert_cdata(iks_insert(field_node_config, "value"),
03835       "http://jabber.org/protocol/pubsub#node_config", 45);
03836    field_deliver_payload = iks_insert(x, "field");
03837    iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
03838    iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
03839    field_persist_items = iks_insert(x, "field");
03840    iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
03841    iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
03842    field_access_model = iks_insert(x, "field");
03843    iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
03844    iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
03845    if (node_type && !strcasecmp(node_type, "leaf")) {
03846       field_pubsub_collection = iks_insert(x, "field");
03847       iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
03848       iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
03849          strlen(collection_name));
03850    }
03851    return configure;
03852 }

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

References aji_pubsub_iq_create().

Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().

03543 {
03544    iks *request = aji_pubsub_iq_create(client, "get");
03545    iks *query;
03546    query = iks_insert(request, "query");
03547    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03548    if (collection) {
03549       iks_insert_attrib(query, "node", collection);
03550    }
03551    return request;
03552 }

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

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

Referenced by aji_publish_device_state(), and aji_publish_mwi().

03372 {
03373    iks *request = aji_pubsub_iq_create(client, "set");
03374    iks *pubsub, *publish, *item;
03375    pubsub = iks_insert(request, "pubsub");
03376    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03377    publish = iks_insert(pubsub, "publish");
03378    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03379       iks_insert_attrib(publish, "node", node);
03380    } else {
03381       iks_insert_attrib(publish, "node", event_type);
03382    }
03383    item = iks_insert(publish, "item");
03384    iks_insert_attrib(item, "id", node);
03385    return item;
03386 
03387 }

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

References aji_create_pubsub_collection(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.

03861 {
03862       struct aji_client *client;
03863       const char *name;
03864       const char *collection_name;
03865 
03866       switch (cmd) {
03867       case CLI_INIT:
03868             e->command = "jabber create collection";
03869             e->usage =
03870                "Usage: jabber create collection <connection> <collection>\n"
03871                "       Creates a PubSub collection node using the account\n"
03872                "       as configured in jabber.conf.\n";
03873          return NULL;
03874       case CLI_GENERATE:
03875          return NULL;
03876       }
03877 
03878       if (a->argc != 5) {
03879          return CLI_SHOWUSAGE;
03880       }
03881       name = a->argv[3];
03882       collection_name = a->argv[4];
03883 
03884       if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03885          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03886          return CLI_FAILURE;
03887       }
03888 
03889       ast_cli(a->fd, "Creating test PubSub node collection.\n");
03890       aji_create_pubsub_collection(client, collection_name);
03891       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03892       return CLI_SUCCESS;
03893 }

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

References aji_create_pubsub_leaf(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.

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

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

References aji_delete_pubsub_node(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.

03715 {
03716    struct aji_client *client;
03717    const char *name;
03718 
03719    switch (cmd) {
03720       case CLI_INIT:
03721          e->command = "jabber delete node";
03722          e->usage =
03723                "Usage: jabber delete node <connection> <node>\n"
03724                "       Deletes a node on PubSub server\n"
03725                "       as configured in jabber.conf.\n";
03726          return NULL;
03727       case CLI_GENERATE:
03728          return NULL;
03729    }
03730 
03731    if (a->argc != 5) {
03732       return CLI_SHOWUSAGE;
03733    }
03734    name = a->argv[3];
03735 
03736    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03737       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03738       return CLI_FAILURE;
03739    }
03740    aji_delete_pubsub_node(client, a->argv[4]);
03741    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03742    return CLI_SUCCESS;
03743 }

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

References aji_request_pubsub_nodes(), ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, and ast_cli_entry::usage.

03590 {
03591       struct aji_client *client;
03592       const char *name = NULL;
03593       const char *collection = NULL;
03594 
03595       switch (cmd) {
03596       case CLI_INIT:
03597             e->command = "jabber list nodes";
03598             e->usage =
03599                "Usage: jabber list nodes <connection> [collection]\n"
03600                "       Lists the user's nodes on the respective connection\n"
03601                "       ([connection] as configured in jabber.conf.)\n";
03602          return NULL;
03603       case CLI_GENERATE:
03604          return NULL;
03605       }
03606 
03607       if (a->argc > 5 || a->argc < 4) {
03608          return CLI_SHOWUSAGE;
03609       } else if (a->argc == 4 || a->argc == 5) {
03610          name = a->argv[3];
03611       }
03612       if (a->argc == 5) {
03613          collection = a->argv[4];
03614       }
03615       if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03616          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03617          return CLI_FAILURE;
03618       }
03619 
03620       ast_cli(a->fd, "Listing pubsub nodes.\n");
03621       aji_request_pubsub_nodes(client, collection);
03622       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03623       return CLI_SUCCESS;
03624 }

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

References aji_delete_pubsub_node(), aji_pubsub_purge_nodes(), AJI_XEP0248, ast_cli_args::argc, ast_cli_args::argv, ast_aji_client_destroy(), ast_cli(), ast_test_flag, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, name, pubsubflags, and ast_cli_entry::usage.

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

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

Definition at line 3079 of file res_jabber.c.

References AJI_CONNECTING, AJI_DISCONNECTED, aji_filter_roster(), aji_get_roster(), aji_init_event_distribution(), ast_aji_client_destroy(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::component, aji_client::distribute_events, aji_client::f, aji_client::jid, LOG_ERROR, aji_client::stack, and aji_client::state.

Referenced by aji_act_hook().

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

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

Definition at line 2005 of file res_jabber.c.

References aji_find_resource(), ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, aji_resource::cap, aji_client::jid, aji_version::jingle, LOG_ERROR, LOG_NOTICE, and aji_resource::resource.

Referenced by aji_create_client().

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

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

References aji_pubsub_iq_create(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, and aji_client::buddies.

Referenced by aji_create_pubsub_node().

03307 {
03308    iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
03309    iks *pubsub, *affiliations, *affiliate;
03310    pubsub = iks_insert(modify_affiliates, "pubsub");
03311    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03312    affiliations = iks_insert(pubsub, "affiliations");
03313    iks_insert_attrib(affiliations, "node", node);
03314    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03315       ASTOBJ_RDLOCK(iterator);
03316       affiliate = iks_insert(affiliations, "affiliation");
03317       iks_insert_attrib(affiliate, "jid", iterator->name);
03318       iks_insert_attrib(affiliate, "affiliation", "owner");
03319       ASTOBJ_UNLOCK(iterator);
03320    });
03321    ast_aji_send(client, modify_affiliates);
03322    iks_delete(modify_affiliates);
03323 }

static int aji_create_buddy ( char *  label,
struct aji_client client 
) [static]

load config file.

Returns:
1.

Definition at line 4510 of file res_jabber.c.

References ast_aji_buddy_destroy(), ast_calloc, ast_copy_string(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_LINK, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::buddies, LOG_WARNING, and aji_buddy::name.

Referenced by aji_create_client(), aji_handle_presence(), and aji_handle_subscribe().

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

Definition at line 4255 of file res_jabber.c.

References aji_act_hook(), AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_client_info_handler(), aji_create_buddy(), aji_dinfo_handler(), AJI_DISCONNECTED, aji_ditems_handler(), aji_log_hook(), AJI_PUBSUB, aji_register_approve_handler(), aji_register_query_handler(), asprintf, ast_aji_client_destroy(), ast_calloc, ast_clear_flag, ast_copy_flags, ast_copy_string(), ast_false(), AST_FLAGS_ALL, ast_free, AST_LIST_HEAD_INIT, ast_log(), ast_set2_flag, ast_set_flag, ast_test_flag, ast_true(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_INIT, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::authorized, aji_client::buddies, clients, aji_client::component, aji_client::debug, aji_client::distribute_events, aji_client::f, aji_client::flags, aji_client::forcessl, globalflags, aji_client::jid, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::message_timeout, aji_client::messages, aji_client::mid, aji_client::name, aji_client::name_space, aji_client::p, aji_client::password, aji_client::port, aji_client::priority, aji_client::pubsub_node, pubsubflags, 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 var.

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

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().

03770 {
03771    aji_create_pubsub_node(client, "collection", collection_name, NULL);
03772 }

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().

03783 {
03784    aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
03785 }

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

References aji_build_node_config(), aji_create_affiliations(), aji_pubsub_iq_create(), and ast_aji_send().

Referenced by aji_create_pubsub_collection(), aji_create_pubsub_leaf(), aji_handle_pubsub_error(), and aji_publish_device_state().

03796 {
03797    iks *node = aji_pubsub_iq_create(client, "set");
03798    iks *pubsub, *create;
03799    pubsub = iks_insert(node, "pubsub");
03800    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03801    create = iks_insert(pubsub, "create");
03802    iks_insert_attrib(create, "node", name);
03803    aji_build_node_config(pubsub, node_type, collection_name);
03804    ast_aji_send(client, node);
03805    aji_create_affiliations(client, name);
03806    iks_delete(node);
03807    return 0;
03808 }

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

References aji_delete_pubsub_node(), ast_log(), ASTOBJ_REF, aji_client::jid, and LOG_WARNING.

Referenced by aji_pubsub_purge_nodes().

03687 {
03688 
03689    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03690    iks *item = NULL;
03691    if (iks_has_children(pak->query)) {
03692       item = iks_first_tag(pak->query);
03693       ast_log(LOG_WARNING, "Connection: %s  Node name: %s\n", client->jid->partial,
03694             iks_find_attrib(item, "node"));
03695       while ((item = iks_next_tag(item))) {
03696          aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
03697       }
03698    }
03699    if (item) {
03700       iks_delete(item);
03701    }
03702    return IKS_FILTER_EAT;
03703 }

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

References aji_pubsub_iq_create(), and ast_aji_send().

Referenced by aji_cli_delete_pubsub_node(), aji_cli_purge_pubsub_nodes(), and aji_delete_node_list().

03752 {
03753    iks *request = aji_pubsub_iq_create(client, "set");
03754    iks *pubsub, *delete;
03755    pubsub = iks_insert(request, "pubsub");
03756    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03757    delete = iks_insert(pubsub, "delete");
03758    iks_insert_attrib(delete, "node", node_name);
03759    ast_aji_send(client, request);
03760 }

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

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

Referenced by aji_init_event_distribution().

03199 {
03200    const char *device;
03201    const char *device_state;
03202    struct aji_client *client;
03203    if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03204    {
03205       /* If the event didn't originate from this server, don't send it back out. */
03206       ast_log(LOG_DEBUG, "Returning here\n");
03207       return;
03208    }
03209 
03210    client = ASTOBJ_REF((struct aji_client *) data);
03211    device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
03212    device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
03213    aji_publish_device_state(client, device, device_state);
03214    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03215 }

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

Definition at line 2071 of file res_jabber.c.

References aji_find_resource(), ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, aji_resource::cap, commands, aji_version::jingle, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_resource::resource, aji_client::user, and version.

Referenced by aji_create_client().

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

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

Definition at line 1908 of file res_jabber.c.

References ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, LOG_ERROR, and aji_client::user.

Referenced by aji_create_client().

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

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

Definition at line 4073 of file res_jabber.c.

References aji_reload(), ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

04074 {
04075    switch (cmd) {
04076    case CLI_INIT:
04077       e->command = "jabber reload";
04078       e->usage =
04079          "Usage: jabber reload\n"
04080          "       Reloads the Jabber module.\n";
04081       return NULL;
04082    case CLI_GENERATE:
04083       return NULL;
04084    }
04085 
04086    aji_reload(1);
04087    ast_cli(a->fd, "Jabber Reloaded.\n");
04088    return CLI_SUCCESS;
04089 }

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

Definition at line 4031 of file res_jabber.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

04032 {
04033    switch (cmd) {
04034    case CLI_INIT:
04035       e->command = "jabber set debug {on|off}";
04036       e->usage =
04037          "Usage: jabber set debug {on|off}\n"
04038          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
04039       return NULL;
04040    case CLI_GENERATE:
04041       return NULL;
04042    }
04043 
04044    if (a->argc != e->args) {
04045       return CLI_SHOWUSAGE;
04046    }
04047 
04048    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
04049       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04050          ASTOBJ_RDLOCK(iterator);
04051          iterator->debug = 1;
04052          ASTOBJ_UNLOCK(iterator);
04053       });
04054       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
04055       return CLI_SUCCESS;
04056    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
04057       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04058          ASTOBJ_RDLOCK(iterator);
04059          iterator->debug = 0;
04060          ASTOBJ_UNLOCK(iterator);
04061       });
04062       ast_cli(a->fd, "Jabber Debugging Disabled.\n");
04063       return CLI_SUCCESS;
04064    }
04065    return CLI_SHOWUSAGE; /* defaults to invalid */
04066 }

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

Definition at line 2942 of file res_jabber.c.

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, AJI_CONNECTED, ast_clear_flag, ast_copy_flags, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_REF, ASTOBJ_UNLOCK, aji_client::buddies, aji_client::flags, and aji_client::state.

Referenced by aji_client_connect().

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

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

Definition at line 546 of file res_jabber.c.

References aji_resource::next, aji_resource::resource, and aji_buddy::resources.

Referenced by acf_jabberstatus_read(), aji_client_info_handler(), aji_dinfo_handler(), and aji_status_exec().

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

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

Definition at line 474 of file res_jabber.c.

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

Referenced by aji_handle_presence().

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

static int aji_get_roster ( struct aji_client client  )  [static]

Definition at line 3056 of file res_jabber.c.

References aji_set_presence(), ast_aji_send(), aji_client::jid, aji_client::status, and aji_client::statusmessage.

Referenced by aji_client_connect(), and aji_reload().

03057 {
03058    iks *roster = NULL;
03059    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
03060 
03061    if (roster) {
03062       iks_insert_attrib(roster, "id", "roster");
03063       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
03064       ast_aji_send(client, roster);
03065    }
03066 
03067    iks_delete(roster);
03068 
03069    return 1;
03070 }

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

Definition at line 2215 of file res_jabber.c.

Referenced by aji_act_hook().

02216 {
02217    /*Nothing to see here */
02218 }

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

Definition at line 2227 of file res_jabber.c.

References ast_calloc, ast_cond_broadcast, ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_tvnow(), delete_old_messages(), aji_message::list, LOG_ERROR, messagelock, aji_client::messages, and aji_client::name.

Referenced by aji_act_hook().

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

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

Definition at line 2276 of file res_jabber.c.

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

Referenced by aji_act_hook().

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

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

Definition at line 3461 of file res_jabber.c.

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

Referenced by aji_init_event_distribution().

03462 {
03463    char *node_name;
03464    char *error;
03465    int error_num;
03466    iks *orig_request;
03467    iks *orig_pubsub = iks_find(pak->x, "pubsub");
03468    struct aji_client *client;
03469    if (!orig_pubsub) {
03470       ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
03471       return IKS_FILTER_EAT;
03472    }
03473    orig_request = iks_child(orig_pubsub);
03474    error = iks_find_attrib(iks_find(pak->x, "error"), "code");
03475    node_name = iks_find_attrib(orig_request, "node");
03476    if (!sscanf(error, "%30d", &error_num)) {
03477       return IKS_FILTER_EAT;
03478    }
03479    if (error_num > 399 && error_num < 500 && error_num != 404) {
03480       ast_log(LOG_ERROR,
03481          "Error performing operation on PubSub node %s, %s.\n", node_name, error);
03482       return IKS_FILTER_EAT;
03483    } else if (error_num > 499 && error_num < 600) {
03484       ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
03485       return IKS_FILTER_EAT;
03486    }
03487 
03488    client = ASTOBJ_REF((struct aji_client *) data);
03489 
03490    if (!strcasecmp(iks_name(orig_request), "publish")) {
03491       iks *request;
03492       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03493          if (iks_find(iks_find(orig_request, "item"), "state")) {
03494             aji_create_pubsub_leaf(client, "device_state", node_name);
03495          } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
03496             aji_create_pubsub_leaf(client, "message_waiting", node_name);
03497          }
03498       } else {
03499          aji_create_pubsub_node(client, NULL, node_name, NULL);
03500       }
03501       request = aji_pubsub_iq_create(client, "set");
03502       iks_insert_node(request, orig_pubsub);
03503       ast_aji_send(client, request);
03504       iks_delete(request);
03505       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03506       return IKS_FILTER_EAT;
03507    } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
03508       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03509          aji_create_pubsub_collection(client, node_name);
03510       } else {
03511          aji_create_pubsub_node(client, NULL, node_name, NULL);
03512       }
03513    }
03514    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03515    return IKS_FILTER_EAT;
03516 }

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

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

Referenced by aji_init_event_distribution().

03252 {
03253    char *item_id, *device_state, *context;
03254    int oldmsgs, newmsgs;
03255    iks *item, *item_content;
03256    struct ast_eid pubsub_eid;
03257    struct ast_event *event;
03258    item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
03259    if (!item) {
03260       ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
03261       return IKS_FILTER_EAT;
03262    }
03263    item_id = iks_find_attrib(item, "id");
03264    item_content = iks_child(item);
03265    ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
03266    if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
03267       ast_log(LOG_DEBUG, "Returning here, eid of incoming event matches ours!\n");
03268       return IKS_FILTER_EAT;
03269    }
03270    if (!strcasecmp(iks_name(item_content), "state")) {
03271       device_state = iks_find_cdata(item, "state");
03272       if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
03273          AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
03274          AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
03275          AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03276          AST_EVENT_IE_END))) {
03277          return IKS_FILTER_EAT;
03278       }
03279    } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
03280       context = strsep(&item_id, "@");
03281       sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
03282       sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
03283       if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
03284          AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
03285          AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
03286          AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
03287          AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
03288          &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
03289          return IKS_FILTER_EAT;
03290       }
03291    } else {
03292       ast_log(LOG_DEBUG, "Don't know how to handle PubSub event of type %s\n",
03293          iks_name(item_content));
03294       return IKS_FILTER_EAT;
03295    }
03296    ast_event_queue_and_cache(event);
03297    return IKS_FILTER_EAT;
03298 }

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

Definition at line 2520 of file res_jabber.c.

References AJI_AUTOACCEPT, aji_create_buddy(), aji_set_presence(), ast_aji_buddy_destroy(), ast_aji_send(), ast_log(), ast_test_flag, ast_verbose, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, aji_client::component, aji_client::flags, aji_client::jid, LOG_ERROR, option_verbose, aji_client::status, status, aji_client::statusmessage, and VERBOSE_PREFIX_3.

Referenced by aji_act_hook().

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

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

References aji_devstate_cb(), aji_handle_pubsub_error(), aji_handle_pubsub_event(), aji_mwi_cb(), aji_pubsub_subscribe(), ast_enable_distributed_devstate(), AST_EVENT_DEVICE_STATE_CHANGE, ast_event_dump_cache(), AST_EVENT_IE_END, AST_EVENT_MWI, ast_event_subscribe(), device_state_sub, aji_client::f, mwi_sub, and aji_client::pubsub_node.

Referenced by aji_client_connect(), and aji_reload().

03223 {
03224    if (!mwi_sub) {
03225       mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
03226          client, AST_EVENT_IE_END);
03227    }
03228    if (!device_state_sub) {
03229       if (ast_enable_distributed_devstate()) {
03230          return;
03231       }
03232       device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
03233          aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
03234       ast_event_dump_cache(device_state_sub);
03235    }
03236 
03237    aji_pubsub_subscribe(client, "device_state");
03238    aji_pubsub_subscribe(client, "message_waiting");
03239    iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
03240       IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
03241    iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
03242       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
03243 
03244 }

static int aji_initialize ( struct aji_client client  )  [static]

Definition at line 3114 of file res_jabber.c.

References ast_log(), aji_client::component, connected, aji_client::jid, LOG_ERROR, aji_client::name, aji_client::p, aji_client::port, S_OR, aji_client::serverhost, aji_client::stream_flags, and aji_client::user.

Referenced by aji_reconnect().

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

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

Definition at line 1296 of file res_jabber.c.

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

Referenced by aji_recv().

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

static int aji_is_secure ( struct aji_client client  )  [static]

Definition at line 1206 of file res_jabber.c.

References aji_client::stream_flags.

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

01207 {
01208 #ifdef HAVE_OPENSSL
01209    return client->stream_flags & SECURE;
01210 #else
01211    return 0;
01212 #endif
01213 }

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

References AJI_MAX_RESJIDLEN, args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_join_chat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, aji_client::component, aji_client::jid, and LOG_ERROR.

Referenced by load_module().

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

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

References AJI_MAX_RESJIDLEN, args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_leave_chat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, aji_client::component, aji_client::jid, and LOG_ERROR.

Referenced by load_module().

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

static int aji_load_config ( int  reload  )  [static]

Definition at line 4537 of file res_jabber.c.

References AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, ast_category_browse(), 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_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, debug, globalflags, JABBER_CONFIG, LOG_WARNING, and var.

Referenced by aji_reload().

04538 {
04539    char *cat = NULL;
04540    int debug = 0;
04541    struct ast_config *cfg = NULL;
04542    struct ast_variable *var = NULL;
04543    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04544 
04545    if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
04546       return -1;
04547    }
04548 
04549    /* Reset flags to default value */
04550    ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT);
04551 
04552    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
04553       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
04554       return 0;
04555    }
04556 
04557    cat = ast_category_browse(cfg, NULL);
04558    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04559       if (!strcasecmp(var->name, "debug")) {
04560          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
04561       } else if (!strcasecmp(var->name, "autoprune")) {
04562          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
04563       } else if (!strcasecmp(var->name, "autoregister")) {
04564          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
04565       } else if (!strcasecmp(var->name, "collection_nodes")) {
04566          ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248);
04567       } else if (!strcasecmp(var->name, "pubsub_autocreate")) {
04568          ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE);
04569       } else if (!strcasecmp(var->name, "auth_policy")) {
04570          if (!strcasecmp(var->value, "accept")) {
04571             ast_set_flag(&globalflags, AJI_AUTOACCEPT);
04572          } else {
04573             ast_clear_flag(&globalflags, AJI_AUTOACCEPT);
04574          }
04575       }
04576    }
04577 
04578    while (cat) {
04579       if (strcasecmp(cat, "general")) {
04580          var = ast_variable_browse(cfg, cat);
04581          aji_create_client(cat, var, debug);
04582       }
04583       cat = ast_category_browse(cfg, cat);
04584    }
04585    ast_config_destroy(cfg); /* or leak memory */
04586    return 1;
04587 }

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

Definition at line 1487 of file res_jabber.c.

References ast_aji_client_destroy(), ast_strlen_zero(), ast_verbose, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::debug, EVENT_FLAG_USER, manager_event, aji_client::name, and option_debug.

Referenced by aji_create_client(), aji_recv(), and aji_send_raw().

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

static void aji_message_destroy ( struct aji_message obj  )  [static]

Definition at line 453 of file res_jabber.c.

References ast_free, aji_message::from, and aji_message::message.

Referenced by acf_jabberreceive_read(), ast_aji_client_destroy(), and delete_old_messages().

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

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

References aji_publish_mwi(), ast_aji_client_destroy(), ast_eid_cmp(), ast_eid_default, ast_event_get_ie_raw(), ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_EID, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_OLDMSGS, ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, context, LOG_DEBUG, and mailbox.

Referenced by aji_init_event_distribution().

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

static void aji_pruneregister ( struct aji_client client  )  [static]

Definition at line 2888 of file res_jabber.c.

References AJI_AUTOPRUNE, ast_aji_send(), ast_log(), ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, aji_client::buddies, and LOG_ERROR.

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

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

References aji_build_publish_skeleton(), aji_create_pubsub_node(), AJI_PUBSUB_AUTOCREATE, AJI_XEP0248, ast_aji_send(), ast_eid_default, ast_eid_to_str(), ast_test_flag, and pubsubflags.

Referenced by aji_devstate_cb().

03398 {
03399    iks *request = aji_build_publish_skeleton(client, device, "device_state");
03400    iks *state;
03401    char eid_str[20];
03402    if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
03403       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03404          aji_create_pubsub_node(client, "leaf", device, "device_state");
03405       } else {
03406          aji_create_pubsub_node(client, NULL, device, NULL);
03407       }
03408    }
03409    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03410    state = iks_insert(request, "state");
03411    iks_insert_attrib(state, "xmlns", "http://asterisk.org");
03412    iks_insert_attrib(state, "eid", eid_str);
03413    iks_insert_cdata(state, device_state, strlen(device_state));
03414    ast_aji_send(client, iks_root(request));
03415    iks_delete(request);
03416 }

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

References aji_build_publish_skeleton(), ast_aji_send(), ast_eid_default, ast_eid_to_str(), AST_MAX_CONTEXT, and AST_MAX_EXTENSION.

Referenced by aji_mwi_cb().

03427 {
03428    char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
03429    char eid_str[20];
03430    iks *mailbox_node, *request;
03431    snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
03432    request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
03433    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03434    mailbox_node = iks_insert(request, "mailbox");
03435    iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
03436    iks_insert_attrib(mailbox_node, "eid", eid_str);
03437    iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
03438    iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
03439    ast_aji_send(client, iks_root(request));
03440    iks_delete(request);
03441 }

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

References ast_aji_increment_mid(), aji_client::jid, aji_client::mid, and aji_client::pubsub_node.

Referenced by aji_build_node_request(), aji_build_publish_skeleton(), aji_create_affiliations(), aji_create_pubsub_node(), aji_delete_pubsub_node(), aji_handle_pubsub_error(), and aji_pubsub_subscribe().

03450 {
03451    iks *request = iks_new("iq");
03452 
03453    iks_insert_attrib(request, "to", client->pubsub_node);
03454    iks_insert_attrib(request, "from", client->jid->full);
03455    iks_insert_attrib(request, "type", type);
03456    ast_aji_increment_mid(client->mid);
03457    iks_insert_attrib(request, "id", client->mid);
03458    return request;
03459 }

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

Definition at line 3669 of file res_jabber.c.

References aji_build_node_request(), aji_delete_node_list(), ast_aji_send(), aji_client::f, and aji_client::mid.

Referenced by aji_cli_purge_pubsub_nodes().

03670 {
03671    iks *request = aji_build_node_request(client, collection_name);
03672    ast_aji_send(client, request);
03673    iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
03674       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03675       IKS_RULE_DONE);
03676    ast_aji_send(client, request);
03677    iks_delete(request);
03678 }

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

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

Referenced by aji_init_event_distribution().

03332 {
03333    iks *request = aji_pubsub_iq_create(client, "set");
03334    iks *pubsub, *subscribe;
03335 
03336    pubsub = iks_insert(request, "pubsub");
03337    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03338    subscribe = iks_insert(pubsub, "subscribe");
03339    iks_insert_attrib(subscribe, "jid", client->jid->partial);
03340    iks_insert_attrib(subscribe, "node", node);
03341    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03342       iks *options, *x, *sub_options, *sub_type, *sub_depth;
03343       options = iks_insert(pubsub, "options");
03344       x = iks_insert(options, "x");
03345       iks_insert_attrib(x, "xmlns", "jabber:x:data");
03346       iks_insert_attrib(x, "type", "submit");
03347       sub_options = iks_insert(x, "field");
03348       iks_insert_attrib(sub_options, "var", "FORM_TYPE");
03349       iks_insert_attrib(sub_options, "type", "hidden");
03350       iks_insert_cdata(iks_insert(sub_options, "value"),
03351          "http://jabber.org/protocol/pubsub#subscribe_options", 51);
03352       sub_type = iks_insert(x, "field");
03353       iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
03354       iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
03355       sub_depth = iks_insert(x, "field");
03356       iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
03357       iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
03358    }
03359    ast_aji_send(client, request);
03360    iks_delete(request);
03361 }

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

References ast_aji_client_destroy(), ast_verbose, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::jid, and aji_client::name.

Referenced by aji_request_pubsub_nodes().

03561 {
03562 
03563    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03564    iks *item = NULL;
03565    if (iks_has_children(pak->query)) {
03566       item = iks_first_tag(pak->query);
03567       ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
03568          iks_find_attrib(item, "node"));
03569       while ((item = iks_next_tag(item))) {
03570          ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
03571       }
03572    }
03573    if (item) {
03574       iks_delete(item);
03575    }
03576    ASTOBJ_UNREF(client, ast_aji_client_destroy);
03577    return IKS_FILTER_EAT;
03578 }

static int aji_reconnect ( struct aji_client client  )  [static]

Definition at line 3030 of file res_jabber.c.

References AJI_DISCONNECTED, aji_initialize(), aji_client::authorized, aji_client::p, aji_client::state, and aji_client::timeout.

Referenced by aji_recv_loop().

03031 {
03032    int res = 0;
03033 
03034    if (client->state) {
03035       client->state = AJI_DISCONNECTED;
03036    }
03037    client->timeout = 50;
03038    if (client->p) {
03039       iks_parser_reset(client->p);
03040    }
03041    if (client->authorized) {
03042       client->authorized = 0;
03043    }
03044 
03045    res = aji_initialize(client);
03046 
03047    return res;
03048 }

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

Definition at line 1341 of file res_jabber.c.

References aji_io_recv(), aji_log_hook(), ast_debug, ast_log(), IKS_NET_EXPIRED, len(), LOG_WARNING, NET_IO_BUF_SIZE, and aji_client::p.

Referenced by aji_act_hook(), and aji_recv_loop().

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

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

Definition at line 2722 of file res_jabber.c.

References AJI_CONNECTED, AJI_DISCONNECTING, aji_reconnect(), aji_recv(), aji_send_raw(), ast_aji_client_destroy(), ast_debug, ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, delete_old_messages_all(), IKS_NET_EXPIRED, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::state, and aji_client::timeout.

Referenced by aji_reload().

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

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

Definition at line 1792 of file res_jabber.c.

References ast_aji_client_destroy(), ast_aji_increment_mid(), ast_aji_send(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::jid, LOG_ERROR, and aji_client::mid.

Referenced by aji_create_client().

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

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

Definition at line 1835 of file res_jabber.c.

References ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_send(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, LOG_ERROR, and aji_client::user.

Referenced by aji_create_client().

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

static int aji_reload ( int  reload  )  [static]

Definition at line 4674 of file res_jabber.c.

References AJI_CONNECTING, AJI_DISCONNECTED, aji_get_roster(), aji_init_event_distribution(), aji_load_config(), aji_recv_loop(), ast_aji_client_destroy(), ast_log(), ast_pthread_create_background, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_CONTAINER_PRUNE_MARKED, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, clients, and LOG_ERROR.

Referenced by aji_do_reload(), load_module(), and reload().

04675 {
04676    int res;
04677 
04678    ASTOBJ_CONTAINER_MARKALL(&clients);
04679    if (!(res = aji_load_config(reload))) {
04680       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
04681       return 0;
04682    } else if (res == -1)
04683       return 1;
04684 
04685    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
04686    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04687       ASTOBJ_RDLOCK(iterator);
04688       if (iterator->state == AJI_DISCONNECTED) {
04689          if (!iterator->thread)
04690             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
04691       } else if (iterator->state == AJI_CONNECTING) {
04692          aji_get_roster(iterator);
04693          if (iterator->distribute_events) {
04694             aji_init_event_distribution(iterator);
04695          }
04696       }
04697 
04698       ASTOBJ_UNLOCK(iterator);
04699    });
04700 
04701    return 1;
04702 }

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

References aji_build_node_request(), aji_receive_node_list(), ast_aji_send(), aji_client::f, and aji_client::mid.

Referenced by aji_cli_list_pubsub_nodes().

03525 {
03526    iks *request = aji_build_node_request(client, collection);
03527 
03528    iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
03529       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03530       IKS_RULE_DONE);
03531    ast_aji_send(client, request);
03532    iks_delete(request);
03533 
03534 }

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

Definition at line 1110 of file res_jabber.c.

References args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_send_chat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, and LOG_WARNING.

Referenced by load_module().

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

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

Definition at line 1413 of file res_jabber.c.

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

Referenced by aji_act_hook(), and aji_tls_handshake().

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

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

Definition at line 1453 of file res_jabber.c.

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

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

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

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

sends messages.

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

Definition at line 2598 of file res_jabber.c.

References AJI_CONNECTED, AJI_MAX_JIDLEN, ast_aji_send(), ast_log(), aji_client::component, aji_client::jid, LOG_ERROR, LOG_WARNING, and aji_client::state.

Referenced by ast_aji_send_chat(), and ast_aji_send_groupchat().

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

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

References AJI_MAX_RESJIDLEN, args, ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_send_groupchat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ASTOBJ_UNREF, aji_client::component, aji_client::jid, and LOG_ERROR.

Referenced by load_module().

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

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

Definition at line 3990 of file res_jabber.c.

References AJI_MAX_JIDLEN, ast_aji_send(), ast_log(), aji_client::component, aji_client::jid, LOG_ERROR, and MUC_NS.

Referenced by ast_aji_join_chat(), and ast_aji_leave_chat().

03991 {
03992    int res = 0;
03993    iks *presence = NULL, *x = NULL;
03994    char from[AJI_MAX_JIDLEN];
03995    char roomid[AJI_MAX_JIDLEN];
03996 
03997    presence = iks_make_pres(level, NULL);
03998    x = iks_new("x");
03999 
04000    if (client->component) {
04001       snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
04002       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
04003    } else {
04004       snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
04005       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
04006    }
04007 
04008    if (!presence || !x || !client) {
04009       ast_log(LOG_ERROR, "Out of memory.\n");
04010       res = -1;
04011       goto safeout;
04012    } else {
04013       iks_insert_attrib(presence, "to", roomid);
04014       iks_insert_attrib(presence, "from", from);
04015       iks_insert_attrib(x, "xmlns", MUC_NS);
04016       iks_insert_node(presence, x);
04017       res = ast_aji_send(client, presence);
04018    }
04019 
04020 safeout:
04021    iks_delete(presence);
04022    iks_delete(x);
04023    return res;
04024 }

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

Definition at line 3948 of file res_jabber.c.

References ast_aji_send(), ast_log(), LOG_ERROR, and aji_client::priority.

Referenced by aji_get_roster(), aji_handle_presence(), and aji_handle_subscribe().

03949 {
03950    iks *presence = iks_make_pres(level, desc);
03951    iks *cnode = iks_new("c");
03952    iks *priority = iks_new("priority");
03953    char priorityS[10];
03954 
03955    if (presence && cnode && client && priority) {
03956       if (to) {
03957          iks_insert_attrib(presence, "to", to);
03958       }
03959       if (from) {
03960          iks_insert_attrib(presence, "from", from);
03961       }
03962       snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
03963       iks_insert_cdata(priority, priorityS, strlen(priorityS));
03964       iks_insert_node(presence, priority);
03965       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
03966       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
03967       iks_insert_attrib(cnode, "ext", "voice-v1");
03968       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
03969       iks_insert_node(presence, cnode);
03970       ast_aji_send(client, presence);
03971    } else {
03972       ast_log(LOG_ERROR, "Out of memory.\n");
03973    }
03974 
03975    iks_delete(cnode);
03976    iks_delete(presence);
03977    iks_delete(priority);
03978 }

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

Definition at line 4142 of file res_jabber.c.

References ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_resource::cap, CLI_GENERATE, CLI_INIT, clients, ast_cli_entry::command, ast_cli_args::fd, aji_version::jingle, aji_resource::next, aji_capabilities::node, aji_version::parent, aji_resource::priority, aji_resource::resource, aji_resource::status, ast_cli_entry::usage, and aji_version::version.

04143 {
04144    struct aji_resource *resource;
04145    struct aji_client *client;
04146 
04147    switch (cmd) {
04148    case CLI_INIT:
04149       e->command = "jabber show buddies";
04150       e->usage =
04151          "Usage: jabber show buddies\n"
04152          "       Shows buddy lists of our clients\n";
04153       return NULL;
04154    case CLI_GENERATE:
04155       return NULL;
04156    }
04157 
04158    ast_cli(a->fd, "Jabber buddy lists\n");
04159    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04160       ast_cli(a->fd, "Client: %s\n", iterator->user);
04161       client = iterator;
04162       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04163          ASTOBJ_RDLOCK(iterator);
04164          ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
04165          if (!iterator->resources)
04166             ast_cli(a->fd, "\t\tResource: None\n");
04167          for (resource = iterator->resources; resource; resource = resource->next) {
04168             ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
04169             if (resource->cap) {
04170                ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
04171                ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
04172                ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
04173             }
04174             ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
04175             ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
04176          }
04177          ASTOBJ_UNLOCK(iterator);
04178       });
04179       iterator = client;
04180    });
04181    return CLI_SUCCESS;
04182 }

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

Definition at line 4096 of file res_jabber.c.

References AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, CLI_GENERATE, CLI_INIT, clients, ast_cli_entry::command, ast_cli_args::fd, status, and ast_cli_entry::usage.

04097 {
04098    char *status;
04099    int count = 0;
04100 
04101    switch (cmd) {
04102    case CLI_INIT:
04103       e->command = "jabber show connections";
04104       e->usage =
04105          "Usage: jabber show connections\n"
04106          "       Shows state of client and component connections\n";
04107       return NULL;
04108    case CLI_GENERATE:
04109       return NULL;
04110    }
04111 
04112    ast_cli(a->fd, "Jabber Users and their status:\n");
04113    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04114       ASTOBJ_RDLOCK(iterator);
04115       count++;
04116       switch (iterator->state) {
04117       case AJI_DISCONNECTED:
04118          status = "Disconnected";
04119          break;
04120       case AJI_CONNECTING:
04121          status = "Connecting";
04122          break;
04123       case AJI_CONNECTED:
04124          status = "Connected";
04125          break;
04126       default:
04127          status = "Unknown";
04128       }
04129       ast_cli(a->fd, "       [%s] %s     - %s\n", iterator->name, iterator->user, status);
04130       ASTOBJ_UNLOCK(iterator);
04131    });
04132    ast_cli(a->fd, "----\n");
04133    ast_cli(a->fd, "   Number of users: %d\n", count);
04134    return CLI_SUCCESS;
04135 }

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

Definition at line 1522 of file res_jabber.c.

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

Referenced by aji_act_hook().

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

static int aji_start_tls ( struct aji_client client  )  [static]

Definition at line 1223 of file res_jabber.c.

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

Referenced by aji_act_hook().

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

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

Definition at line 622 of file res_jabber.c.

References aji_find_resource(), args, ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_aji_get_client(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, LOG_ERROR, LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), aji_resource::resource, aji_buddy::resources, aji_resource::status, and status.

Referenced by load_module().

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

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

Definition at line 4189 of file res_jabber.c.

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

04190 {
04191    struct aji_client *client;
04192    struct aji_resource *resource;
04193    const char *name;
04194    struct aji_message *tmp;
04195 
04196    switch (cmd) {
04197    case CLI_INIT:
04198       e->command = "jabber test";
04199       e->usage =
04200          "Usage: jabber test <connection>\n"
04201          "       Sends test message for debugging purposes.  A specific client\n"
04202          "       as configured in jabber.conf must be specified.\n";
04203       return NULL;
04204    case CLI_GENERATE:
04205       return NULL;
04206    }
04207 
04208    if (a->argc != 3) {
04209       return CLI_SHOWUSAGE;
04210    }
04211    name = a->argv[2];
04212 
04213    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
04214       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04215       return CLI_FAILURE;
04216    }
04217 
04218    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
04219    ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
04220    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04221       ASTOBJ_RDLOCK(iterator);
04222       ast_verbose("User: %s\n", iterator->name);
04223       for (resource = iterator->resources; resource; resource = resource->next) {
04224          ast_verbose("Resource: %s\n", resource->resource);
04225          if (resource->cap) {
04226             ast_verbose("   client: %s\n", resource->cap->parent->node);
04227             ast_verbose("   version: %s\n", resource->cap->version);
04228             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
04229          }
04230          ast_verbose("  Priority: %d\n", resource->priority);
04231          ast_verbose("  Status: %d\n", resource->status);
04232          ast_verbose("  Message: %s\n", S_OR(resource->description, ""));
04233       }
04234       ASTOBJ_UNLOCK(iterator);
04235    });
04236    ast_verbose("\nOooh a working message stack!\n");
04237    AST_LIST_LOCK(&client->messages);
04238    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
04239       //ast_verbose("   Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
04240    }
04241    AST_LIST_UNLOCK(&client->messages);
04242    ASTOBJ_UNREF(client, ast_aji_client_destroy);
04243 
04244    return CLI_SUCCESS;
04245 }

static int aji_tls_handshake ( struct aji_client client  )  [static]

Definition at line 1242 of file res_jabber.c.

References aji_send_header(), ast_debug, aji_client::jid, aji_client::p, aji_client::ssl_context, aji_client::ssl_method, aji_client::ssl_session, and aji_client::stream_flags.

Referenced by aji_act_hook().

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

void ast_aji_buddy_destroy ( struct aji_buddy obj  ) 

Destructor function for buddies to be used with ASTOBJ_UNREF

Definition at line 434 of file res_jabber.c.

References ast_free, aji_resource::description, aji_resource::next, and aji_buddy::resources.

Referenced by acf_jabberstatus_read(), aji_client_info_handler(), aji_create_buddy(), aji_dinfo_handler(), aji_handle_presence(), aji_handle_subscribe(), aji_register_query_handler(), aji_status_exec(), ast_aji_client_destroy(), gtalk_alloc(), and jingle_alloc().

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

void ast_aji_client_destroy ( struct aji_client obj  ) 

Destructor function for clients to be used with ASTOBJ_UNREF after calls to ast_aji_get_client

Definition at line 412 of file res_jabber.c.

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

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

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

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

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

02636 {
02637    int res = 0;
02638    iks *iq = NULL;
02639    iq = iks_new("iq");
02640 
02641    if (iq && client) {
02642       iks_insert_attrib(iq, "type", "get");
02643       iks_insert_attrib(iq, "to", server);
02644       iks_insert_attrib(iq, "id", client->mid);
02645       ast_aji_increment_mid(client->mid);
02646       ast_aji_send(client, iq);
02647    } else {
02648       ast_log(LOG_ERROR, "Out of memory.\n");
02649    }
02650 
02651    iks_delete(iq);
02652 
02653    return res;
02654 }

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

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

Referenced by unload_module().

03143 {
03144    if (client) {
03145       ast_verb(4, "JABBER: Disconnecting\n");
03146 #ifdef HAVE_OPENSSL
03147       if (client->stream_flags & SECURE) {
03148          SSL_shutdown(client->ssl_session);
03149          SSL_CTX_free(client->ssl_context);
03150          SSL_free(client->ssl_session);
03151       }
03152 #endif
03153       iks_disconnect(client->p);
03154       iks_parser_delete(client->p);
03155       ASTOBJ_UNREF(client, ast_aji_client_destroy);
03156    }
03157 
03158    return 1;
03159 }

struct aji_client* ast_aji_get_client ( const char *  name  ) 

grab a aji_client structure by label name or JID. Bumps the refcount. (without the resource string)

Parameters:
name label or JID
Returns:
aji_client.

Definition at line 4595 of file res_jabber.c.

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

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

04596 {
04597    struct aji_client *client = NULL;
04598    char *aux = NULL;
04599 
04600    client = ASTOBJ_CONTAINER_FIND(&clients, name);
04601    if (!client && strchr(name, '@')) {
04602       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04603          aux = ast_strdupa(iterator->user);
04604          if (strchr(aux, '/')) {
04605             /* strip resource for comparison */
04606             aux = strsep(&aux, "/");
04607          }
04608          if (!strncasecmp(aux, name, strlen(aux))) {
04609             client = ASTOBJ_REF(iterator);
04610          }
04611       });
04612    }
04613 
04614    return client;
04615 }

struct aji_client_container* ast_aji_get_clients ( void   ) 

Definition at line 4617 of file res_jabber.c.

References clients.

04618 {
04619    return &clients;
04620 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

Definition at line 2779 of file res_jabber.c.

Referenced by aji_act_hook(), aji_handle_presence(), aji_pubsub_iq_create(), aji_register_approve_handler(), ast_aji_create_chat(), ast_aji_invite_chat(), gtalk_action(), gtalk_create_candidates(), gtalk_invite(), jingle_accept_call(), jingle_action(), jingle_create_candidates(), jingle_digit(), and jingle_transmit_invite().

02780 {
02781    int i = 0;
02782 
02783    for (i = strlen(mid) - 1; i >= 0; i--) {
02784       if (mid[i] != 'z') {
02785          mid[i] = mid[i] + 1;
02786          i = 0;
02787       } else
02788          mid[i] = 'a';
02789    }
02790 }

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

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

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

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

References aji_set_group_presence().

Referenced by aji_join_exec().

02664 {
02665    return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
02666 }

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

References aji_set_group_presence().

Referenced by aji_leave_exec().

02676 {
02677    return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
02678 }

int ast_aji_send ( struct aji_client client,
iks *  x 
)

Wraps raw sending.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
x the XMPP packet to send
Returns:
IKS_OK on success, any other value on failure

Definition at line 1439 of file res_jabber.c.

References aji_send_raw().

Referenced by aji_act_hook(), aji_client_info_handler(), aji_create_pubsub_node(), aji_delete_pubsub_node(), aji_dinfo_handler(), aji_ditems_handler(), aji_get_roster(), aji_handle_presence(), aji_handle_pubsub_error(), aji_handle_subscribe(), aji_pruneregister(), aji_publish_device_state(), aji_publish_mwi(), aji_pubsub_purge_nodes(), aji_pubsub_subscribe(), aji_register_approve_handler(), aji_register_query_handler(), aji_request_pubsub_nodes(), aji_send_raw_chat(), aji_set_group_presence(), aji_set_presence(), aji_start_sasl(), ast_aji_create_chat(), ast_aji_invite_chat(), gtalk_action(), gtalk_add_candidate(), gtalk_create_candidates(), gtalk_invite(), gtalk_response(), jingle_accept_call(), jingle_action(), jingle_add_candidate(), jingle_create_candidates(), jingle_digit(), jingle_response(), and jingle_transmit_invite().

01440 {
01441    return aji_send_raw(client, iks_string(iks_stack(x), x));
01442 }

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

References aji_send_raw_chat().

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

02572 {
02573    return aji_send_raw_chat(client, 0, NULL, address, message);
02574 }

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

References aji_send_raw_chat().

Referenced by aji_sendgroup_exec().

02585                                                                                                                   {
02586    return aji_send_raw_chat(client, 1, nick, address, message);
02587 }

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

Definition at line 932 of file res_jabber.c.

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

Referenced by aji_handle_message(), and delete_old_messages_all().

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

static int delete_old_messages_all ( struct aji_client client  )  [static]

Definition at line 979 of file res_jabber.c.

References delete_old_messages().

Referenced by aji_recv_loop().

00980 {
00981    return delete_old_messages(client, NULL);
00982 }

static int gtalk_yuck ( iks *  node  )  [static]

Definition at line 568 of file res_jabber.c.

References ast_debug.

Referenced by aji_handle_presence().

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

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

Definition at line 592 of file res_jabber.c.

References ast_sha1_hash().

Referenced by aji_act_hook().

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

static int load_module ( void   )  [static]

Definition at line 4749 of file res_jabber.c.

References aji_cli, aji_join_exec(), aji_leave_exec(), aji_reload(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_cond_init, ast_custom_function_register, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, ast_mutex_init, ast_register_application_xml, ASTOBJ_CONTAINER_INIT, clients, EVENT_FLAG_SYSTEM, jabberreceive_function, jabberstatus_function, manager_jabber_send(), and messagelock.

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

Definition at line 4629 of file res_jabber.c.

References ast_aji_client_destroy(), ast_aji_get_client(), ast_aji_send_chat(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), astman_send_error(), and ASTOBJ_UNREF.

Referenced by load_module().

04630 {
04631    struct aji_client *client = NULL;
04632    const char *id = astman_get_header(m, "ActionID");
04633    const char *jabber = astman_get_header(m, "Jabber");
04634    const char *screenname = astman_get_header(m, "ScreenName");
04635    const char *message = astman_get_header(m, "Message");
04636 
04637    if (ast_strlen_zero(jabber)) {
04638       astman_send_error(s, m, "No transport specified");
04639       return 0;
04640    }
04641    if (ast_strlen_zero(screenname)) {
04642       astman_send_error(s, m, "No ScreenName specified");
04643       return 0;
04644    }
04645    if (ast_strlen_zero(message)) {
04646       astman_send_error(s, m, "No Message specified");
04647       return 0;
04648    }
04649 
04650    astman_send_ack(s, m, "Attempting to send Jabber Message");
04651    client = ast_aji_get_client(jabber);
04652    if (!client) {
04653       astman_send_error(s, m, "Could not find Sender");
04654       return 0;
04655    }
04656    if (strchr(screenname, '@') && message) {
04657       ast_aji_send_chat(client, screenname, message);
04658       astman_append(s, "Response: Success\r\n");
04659    } else {
04660       astman_append(s, "Response: Error\r\n");
04661    }
04662    ASTOBJ_UNREF(client, ast_aji_client_destroy);
04663    if (!ast_strlen_zero(id)) {
04664       astman_append(s, "ActionID: %s\r\n", id);
04665    }
04666    astman_append(s, "\r\n");
04667    return 0;
04668 }

static int reload ( void   )  [static]

Definition at line 4773 of file res_jabber.c.

References aji_reload().

04774 {
04775    aji_reload(1);
04776    return 0;
04777 }

static int unload_module ( void   )  [static]

Definition at line 4708 of file res_jabber.c.

References aji_cli, AJI_DISCONNECTING, ARRAY_LEN, ast_aji_client_destroy(), ast_aji_disconnect(), ast_cli_unregister_multiple(), ast_cond_destroy, ast_custom_function_unregister(), ast_debug, ast_event_unsubscribe(), ast_manager_unregister(), ast_mutex_destroy, ast_unregister_application(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, clients, device_state_sub, jabberreceive_function, jabberstatus_function, messagelock, and mwi_sub.

04709 {
04710 
04711    ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
04712    ast_unregister_application(app_ajisend);
04713    ast_unregister_application(app_ajisendgroup);
04714    ast_unregister_application(app_ajistatus);
04715    ast_unregister_application(app_ajijoin);
04716    ast_unregister_application(app_ajileave);
04717    ast_manager_unregister("JabberSend");
04718    ast_custom_function_unregister(&jabberstatus_function);
04719    if (mwi_sub) {
04720       ast_event_unsubscribe(mwi_sub);
04721    }
04722    if (device_state_sub) {
04723       ast_event_unsubscribe(device_state_sub);
04724    }
04725    ast_custom_function_unregister(&jabberreceive_function);
04726 
04727    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04728       ASTOBJ_WRLOCK(iterator);
04729       ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
04730       iterator->state = AJI_DISCONNECTING;
04731       ASTOBJ_UNLOCK(iterator);
04732       pthread_join(iterator->thread, NULL);
04733       ast_aji_disconnect(iterator);
04734    });
04735 
04736    ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
04737    ASTOBJ_CONTAINER_DESTROY(&clients);
04738 
04739    ast_cond_destroy(&message_received_condition);
04740    ast_mutex_destroy(&messagelock);
04741 
04742    return 0;
04743 }


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

Definition at line 4784 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 375 of file res_jabber.c.

Referenced by load_module(), and unload_module().

char* app_ajijoin = "JabberJoin" [static]

Definition at line 391 of file res_jabber.c.

char* app_ajileave = "JabberLeave" [static]

Definition at line 392 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 388 of file res_jabber.c.

char* app_ajisendgroup = "JabberSendGroup" [static]

Definition at line 389 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 390 of file res_jabber.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4784 of file res_jabber.c.

struct aji_capabilities* capabilities = NULL [static]

Definition at line 395 of file res_jabber.c.

Referenced by aji_find_version(), and ast_request().

struct aji_client_container clients [static]

Definition at line 394 of file res_jabber.c.

Referenced by aji_cli_create_collection(), aji_cli_create_leafnode(), aji_cli_delete_pubsub_node(), aji_cli_list_pubsub_nodes(), aji_cli_purge_pubsub_nodes(), aji_create_client(), aji_do_set_debug(), aji_reload(), aji_show_buddies(), aji_show_clients(), aji_test(), ast_aji_get_client(), ast_aji_get_clients(), gtalk_load_config(), jingle_load_config(), load_module(), and unload_module().

struct ast_event_sub* device_state_sub = NULL [static]

Definition at line 397 of file res_jabber.c.

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

Global flags, initialized to default values.

Definition at line 402 of file res_jabber.c.

struct ast_custom_function jabberreceive_function [static]

Initial value:

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

Definition at line 918 of file res_jabber.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function jabberstatus_function [static]

Initial value:

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

Definition at line 755 of file res_jabber.c.

Referenced by load_module(), and unload_module().

ast_cond_t message_received_condition [static]

Definition at line 398 of file res_jabber.c.

ast_mutex_t messagelock [static]

Definition at line 399 of file res_jabber.c.

Referenced by acf_jabberreceive_read(), aji_handle_message(), load_module(), and unload_module().

struct ast_event_sub* mwi_sub = NULL [static]

Definition at line 396 of file res_jabber.c.

Referenced by aji_init_event_distribution(), handle_subscribe(), handle_unsubscribe(), mwi_sub_destroy(), poll_subscribed_mailbox(), poll_subscribed_mailboxes(), and unload_module().

struct ast_flags pubsubflags = { 0 } [static]

PubSub flags, initialized to default values.

Definition at line 405 of file res_jabber.c.

Referenced by aji_cli_purge_pubsub_nodes(), aji_create_client(), aji_handle_pubsub_error(), and aji_publish_device_state().


Generated on Mon Mar 19 11:30:53 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7