Mon Oct 8 12:39:27 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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static struct ast_cli_entry aji_cli []
static char * app_ajijoin = "JabberJoin"
static char * app_ajileave = "JabberLeave"
static char * app_ajisend = "JabberSend"
static char * app_ajisendgroup = "JabberSendGroup"
static char * app_ajistatus = "JabberStatus"
static struct ast_module_infoast_module_info = &__mod_info
static struct aji_capabilitiescapabilities = NULL
static struct aji_client_container clients
static struct ast_event_subdevice_state_sub = NULL
static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT }
 Global flags, initialized to default values.
static struct ast_custom_function jabberreceive_function
static struct ast_custom_function jabberstatus_function
static ast_cond_t message_received_condition
static ast_mutex_t messagelock
static struct ast_event_submwi_sub = NULL
static struct ast_flags pubsubflags = { 0 }
 PubSub flags, initialized to default values.


Detailed Description

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

References:

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

Dialplan applications need RETURN variable, like JABBERSENDSTATUS

Definition in file res_jabber.c.


Define Documentation

#define JABBER_CONFIG   "jabber.conf"

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

Definition at line 285 of file res_jabber.c.

Referenced by aji_load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4785 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

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

Referenced by aji_create_pubsub_node().

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

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

References aji_pubsub_iq_create().

Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

load config file.

Returns:
1.

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

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

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().

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

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_tvnow(), delete_old_messages(), aji_message::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_free(insert);
02256          ast_log(LOG_ERROR, "Memory allocation failure\n");
02257          return;
02258       }
02259       ast_debug(3, "message comes from %s\n", insert->from);
02260    }
02261 
02262    /* remove old messages received from this JID
02263     * and insert received message */
02264    deleted = delete_old_messages(client, pak->from->partial);
02265    ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
02266    AST_LIST_LOCK(&client->messages);
02267    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
02268    AST_LIST_UNLOCK(&client->messages);
02269 }

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

Definition at line 2277 of file res_jabber.c.

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

Referenced by aji_act_hook().

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

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

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

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

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

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

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

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

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

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

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

static int aji_initialize ( struct aji_client client  )  [static]

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

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

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 4538 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_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, globalflags, JABBER_CONFIG, LOG_WARNING, and var.

Referenced by aji_reload().

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

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

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

static void aji_pruneregister ( struct aji_client client  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static int aji_reconnect ( struct aji_client client  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

struct aji_client_container* ast_aji_get_clients ( void   ) 

Definition at line 4618 of file res_jabber.c.

References clients.

04619 {
04620    return &clients;
04621 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

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

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

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

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

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

References aji_set_group_presence().

Referenced by aji_join_exec().

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

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

References aji_set_group_presence().

Referenced by aji_leave_exec().

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

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

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

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

References aji_send_raw_chat().

Referenced by aji_sendgroup_exec().

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

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

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

static int reload ( void   )  [static]

Definition at line 4774 of file res_jabber.c.

References aji_reload().

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

static int unload_module ( void   )  [static]

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

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


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "AJI - Asterisk Jabber Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static]

Definition at line 4785 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 4785 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 Oct 8 12:39:28 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7