Wed Apr 6 11:30:09 2011

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 void aji_buddy_destroy (struct aji_buddy *obj)
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 void aji_client_destroy (struct aji_client *obj)
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)
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 (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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 284 of file res_jabber.c.

Referenced by aji_load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4751 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

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

References aji_client_destroy(), AJI_MAX_JIDLEN, aji_message_destroy(), args, aji_message::arrived, 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().

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

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

Definition at line 696 of file res_jabber.c.

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

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

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

Definition at line 1568 of file res_jabber.c.

References aji_client_connect(), aji_client_destroy(), 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_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().

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

static void aji_buddy_destroy ( struct aji_buddy obj  )  [static]

Definition at line 435 of file res_jabber.c.

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

Referenced by aji_client_destroy(), aji_create_buddy(), and aji_handle_presence().

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

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

Definition at line 3791 of file res_jabber.c.

Referenced by aji_create_pubsub_node().

03792 {
03793    iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
03794       *field_deliver_payload, *field_persist_items, *field_access_model,
03795       *field_pubsub_collection;
03796    configure = iks_insert(pubsub, "configure");
03797    x = iks_insert(configure, "x");
03798    iks_insert_attrib(x, "xmlns", "jabber:x:data");
03799    iks_insert_attrib(x, "type", "submit");
03800    field_owner = iks_insert(x, "field");
03801    iks_insert_attrib(field_owner, "var", "FORM_TYPE");
03802    iks_insert_attrib(field_owner, "type", "hidden");
03803    iks_insert_cdata(iks_insert(field_owner, "value"),
03804       "http://jabber.org/protocol/pubsub#owner", 39);
03805    if (node_type) {
03806       field_node_type = iks_insert(x, "field");
03807       iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
03808       iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
03809    }
03810    field_node_config = iks_insert(x, "field");
03811    iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
03812    iks_insert_attrib(field_node_config, "type", "hidden");
03813    iks_insert_cdata(iks_insert(field_node_config, "value"),
03814       "http://jabber.org/protocol/pubsub#node_config", 45);
03815    field_deliver_payload = iks_insert(x, "field");
03816    iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
03817    iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
03818    field_persist_items = iks_insert(x, "field");
03819    iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
03820    iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
03821    field_access_model = iks_insert(x, "field");
03822    iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
03823    iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
03824    if (node_type && !strcasecmp(node_type, "leaf")) {
03825       field_pubsub_collection = iks_insert(x, "field");
03826       iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
03827       iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
03828          strlen(collection_name));
03829    }
03830    return configure;
03831 }

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

References aji_pubsub_iq_create().

Referenced by aji_pubsub_purge_nodes(), and aji_request_pubsub_nodes().

03524 {
03525    iks *request = aji_pubsub_iq_create(client, "get");
03526    iks *query;
03527    query = iks_insert(request, "query");
03528    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03529    if (collection) {
03530       iks_insert_attrib(query, "node", collection);
03531    }
03532    return request;
03533 }

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

03355 {
03356    iks *request = aji_pubsub_iq_create(client, "set");
03357    iks *pubsub, *publish, *item;
03358    pubsub = iks_insert(request, "pubsub");
03359    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03360    publish = iks_insert(pubsub, "publish");
03361    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03362       iks_insert_attrib(publish, "node", node);
03363    } else {
03364       iks_insert_attrib(publish, "node", event_type);
03365    }
03366    item = iks_insert(publish, "item");
03367    iks_insert_attrib(item, "id", node);
03368    return item;
03369 
03370 }

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

References aji_create_pubsub_collection(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ASTOBJ_CONTAINER_FIND, 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.

03840 {
03841       struct aji_client *client;
03842       const char *name;
03843       const char *collection_name;
03844 
03845       switch (cmd) {
03846       case CLI_INIT:
03847             e->command = "jabber create collection";
03848             e->usage =
03849                "Usage: jabber create collection <connection> <collection>\n"
03850                "       Creates a PubSub collection node using the account\n"
03851                "       as configured in jabber.conf.\n";
03852          return NULL;
03853       case CLI_GENERATE:
03854          return NULL;
03855       }
03856 
03857       if (a->argc != 5) {
03858          return CLI_SHOWUSAGE;
03859       }
03860       name = a->argv[3];
03861       collection_name = a->argv[4];
03862 
03863       if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03864          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03865          return CLI_FAILURE;
03866       }
03867 
03868       ast_cli(a->fd, "Creating test PubSub node collection.\n");
03869       aji_create_pubsub_collection(client, collection_name);
03870       return CLI_SUCCESS;
03871 }

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

References aji_create_pubsub_leaf(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ASTOBJ_CONTAINER_FIND, 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.

03878 {
03879    struct aji_client *client;
03880    const char *name;
03881    const char *collection_name;
03882    const char *leaf_name;
03883 
03884    switch (cmd) {
03885       case CLI_INIT:
03886          e->command = "jabber create leaf";
03887          e->usage =
03888                "Usage: jabber create leaf <connection> <collection> <leaf>\n"
03889                "       Creates a PubSub leaf node using the account\n"
03890                "       as configured in jabber.conf.\n";
03891          return NULL;
03892       case CLI_GENERATE:
03893          return NULL;
03894    }
03895 
03896    if (a->argc != 6) {
03897       return CLI_SHOWUSAGE;
03898    }
03899    name = a->argv[3];
03900    collection_name = a->argv[4];
03901    leaf_name = a->argv[5];
03902 
03903    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03904       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03905       return CLI_FAILURE;
03906    }
03907 
03908    ast_cli(a->fd, "Creating test PubSub node collection.\n");
03909    aji_create_pubsub_leaf(client, collection_name, leaf_name);
03910    return CLI_SUCCESS;
03911 }

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

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

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

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

References aji_request_pubsub_nodes(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ASTOBJ_CONTAINER_FIND, 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.

03570 {
03571       struct aji_client *client;
03572       const char *name = NULL;
03573       const char *collection = NULL;
03574 
03575       switch (cmd) {
03576       case CLI_INIT:
03577             e->command = "jabber list nodes";
03578             e->usage =
03579                "Usage: jabber list nodes <connection> [collection]\n"
03580                "       Lists the user's nodes on the respective connection\n"
03581                "       ([connection] as configured in jabber.conf.)\n";
03582          return NULL;
03583       case CLI_GENERATE:
03584          return NULL;
03585       }
03586 
03587       if (a->argc > 5 || a->argc < 4) {
03588          return CLI_SHOWUSAGE;
03589       } else if (a->argc == 4 || a->argc == 5) {
03590          name = a->argv[3];
03591       }
03592       if (a->argc == 5) {
03593          collection = a->argv[4];
03594       }
03595         if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03596          ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03597          return CLI_FAILURE;
03598       }
03599 
03600       ast_cli(a->fd, "Listing pubsub nodes.\n");
03601       aji_request_pubsub_nodes(client, collection);
03602       return CLI_SUCCESS;
03603 }

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 3612 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_cli(), ast_test_flag, ASTOBJ_CONTAINER_FIND, 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.

03614 {
03615    struct aji_client *client;
03616    const char *name;
03617 
03618    switch (cmd) {
03619       case CLI_INIT:
03620          e->command = "jabber purge nodes";
03621          e->usage =
03622                "Usage: jabber purge nodes <connection> <node>\n"
03623                "       Purges nodes on PubSub server\n"
03624                "       as configured in jabber.conf.\n";
03625          return NULL;
03626       case CLI_GENERATE:
03627          return NULL;
03628    }
03629 
03630    if (a->argc != 5) {
03631       return CLI_SHOWUSAGE;
03632    }
03633    name = a->argv[3];
03634 
03635    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03636       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03637       return CLI_FAILURE;
03638    }
03639    if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03640       aji_pubsub_purge_nodes(client, a->argv[4]);
03641    } else {
03642       aji_delete_pubsub_node(client, a->argv[4]);
03643    }
03644    return CLI_SUCCESS;
03645 }

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

Definition at line 3063 of file res_jabber.c.

References aji_client_destroy(), AJI_CONNECTING, AJI_DISCONNECTED, aji_filter_roster(), aji_get_roster(), aji_init_event_distribution(), 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().

03064 {
03065    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03066    int res = IKS_FILTER_PASS;
03067 
03068    if (client) {
03069       if (client->state == AJI_DISCONNECTED) {
03070          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);
03071          client->state = AJI_CONNECTING;
03072          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
03073          if (!client->component) { /*client*/
03074             aji_get_roster(client);
03075          }
03076          if (client->distribute_events) {
03077             aji_init_event_distribution(client);
03078          }
03079 
03080          iks_filter_remove_hook(client->f, aji_client_connect);
03081          /* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */
03082          res = IKS_FILTER_EAT;
03083       }
03084    } else {
03085       ast_log(LOG_ERROR, "Out of memory.\n");
03086    }
03087 
03088    ASTOBJ_UNREF(client, aji_client_destroy);
03089    return res;
03090 }

static void aji_client_destroy ( struct aji_client obj  )  [static]

Definition at line 413 of file res_jabber.c.

References aji_buddy_destroy(), aji_message_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(), aji_act_hook(), aji_client_connect(), aji_client_info_handler(), aji_create_client(), aji_dinfo_handler(), aji_ditems_handler(), aji_join_exec(), aji_leave_exec(), aji_log_hook(), aji_recv_loop(), aji_register_approve_handler(), aji_register_query_handler(), aji_reload(), aji_sendgroup_exec(), ast_aji_disconnect(), and unload_module().

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

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

Definition at line 2000 of file res_jabber.c.

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

Referenced by aji_create_client().

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

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

03289 {
03290    int res = 0;
03291    iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
03292    iks *pubsub, *affiliations, *affiliate;
03293    pubsub = iks_insert(modify_affiliates, "pubsub");
03294    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03295    affiliations = iks_insert(pubsub, "affiliations");
03296    iks_insert_attrib(affiliations, "node", node);
03297    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03298       ASTOBJ_RDLOCK(iterator);
03299       affiliate = iks_insert(affiliations, "affiliation");
03300       iks_insert_attrib(affiliate, "jid", iterator->name);
03301       iks_insert_attrib(affiliate, "affiliation", "owner");
03302       ASTOBJ_UNLOCK(iterator);
03303    });
03304    res = ast_aji_send(client, modify_affiliates);
03305    iks_delete(modify_affiliates);
03306 }

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

load config file.

Returns:
1.

Definition at line 4478 of file res_jabber.c.

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

References aji_act_hook(), AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_client_destroy(), 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_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.

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

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_collection(), and aji_handle_pubsub_error().

03748 {
03749    aji_create_pubsub_node(client, "collection", collection_name, NULL);
03750 }

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

References aji_create_pubsub_node().

Referenced by aji_cli_create_leafnode(), and aji_handle_pubsub_error().

03761 {
03762    aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
03763 }

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

03774 {
03775    int res = 0;
03776    iks *node = aji_pubsub_iq_create(client, "set");
03777    iks *pubsub, *create, *configure;
03778    pubsub = iks_insert(node, "pubsub");
03779    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03780    create = iks_insert(pubsub, "create");
03781    iks_insert_attrib(create, "node", name);
03782    configure = aji_build_node_config(pubsub, node_type, collection_name);
03783    res = ast_aji_send(client, node);
03784    aji_create_affiliations(client, name);
03785    iks_delete(node);
03786    return 0;
03787 }

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

03666 {
03667 
03668    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03669    iks *item = NULL;
03670    if (iks_has_children(pak->query)) {
03671       item = iks_first_tag(pak->query);
03672       ast_log(LOG_WARNING, "Connection: %s  Node name: %s\n", client->jid->partial,
03673             iks_find_attrib(item, "node"));
03674       while ((item = iks_next_tag(item))) {
03675          aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
03676       }
03677    }
03678    if (item) {
03679       iks_delete(item);
03680    }
03681    return IKS_FILTER_EAT;
03682 }

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

03730 {
03731    iks *request = aji_pubsub_iq_create(client, "set");
03732    iks *pubsub, *delete;
03733    pubsub = iks_insert(request, "pubsub");
03734    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03735    delete = iks_insert(pubsub, "delete");
03736    iks_insert_attrib(delete, "node", node_name);
03737    ast_aji_send(client, request);
03738 }

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

References aji_publish_device_state(), 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, and LOG_DEBUG.

Referenced by aji_init_event_distribution().

03182 {
03183    const char *device;
03184    const char *device_state;
03185    struct aji_client *client;
03186    if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03187    {
03188       /* If the event didn't originate from this server, don't send it back out. */
03189       ast_log(LOG_DEBUG, "Returning here\n");
03190       return;
03191    }
03192 
03193    client = ASTOBJ_REF((struct aji_client *) data);
03194    device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
03195    device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
03196    aji_publish_device_state(client, device, device_state);
03197 }

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

Definition at line 2064 of file res_jabber.c.

References aji_client_destroy(), aji_find_resource(), 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().

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

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

Definition at line 1903 of file res_jabber.c.

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

Referenced by aji_create_client().

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

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

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

04052 {
04053    switch (cmd) {
04054    case CLI_INIT:
04055       e->command = "jabber reload";
04056       e->usage =
04057          "Usage: jabber reload\n"
04058          "       Reloads the Jabber module.\n";
04059       return NULL;
04060    case CLI_GENERATE:
04061       return NULL;
04062    }
04063 
04064    aji_reload(1);
04065    ast_cli(a->fd, "Jabber Reloaded.\n");
04066    return CLI_SUCCESS;
04067 }

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

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

04010 {
04011    switch (cmd) {
04012    case CLI_INIT:
04013       e->command = "jabber set debug {on|off}";
04014       e->usage =
04015          "Usage: jabber set debug {on|off}\n"
04016          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
04017       return NULL;
04018    case CLI_GENERATE:
04019       return NULL;
04020    }
04021 
04022    if (a->argc != e->args) {
04023       return CLI_SHOWUSAGE;
04024    }
04025 
04026    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
04027       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04028          ASTOBJ_RDLOCK(iterator);
04029          iterator->debug = 1;
04030          ASTOBJ_UNLOCK(iterator);
04031       });
04032       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
04033       return CLI_SUCCESS;
04034    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
04035       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04036          ASTOBJ_RDLOCK(iterator);
04037          iterator->debug = 0;
04038          ASTOBJ_UNLOCK(iterator);
04039       });
04040       ast_cli(a->fd, "Jabber Debugging Disabled.\n");
04041       return CLI_SUCCESS;
04042    }
04043    return CLI_SHOWUSAGE; /* defaults to invalid */
04044 }

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

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

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

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

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

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

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

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

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

static int aji_get_roster ( struct aji_client client  )  [static]

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

03041 {
03042    iks *roster = NULL;
03043    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
03044 
03045    if (roster) {
03046       iks_insert_attrib(roster, "id", "roster");
03047       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
03048       ast_aji_send(client, roster);
03049    }
03050 
03051    iks_delete(roster);
03052 
03053    return 1;
03054 }

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

Definition at line 2205 of file res_jabber.c.

Referenced by aji_act_hook().

02206 {
02207    /*Nothing to see here */
02208 }

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

Definition at line 2217 of file res_jabber.c.

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

Referenced by aji_act_hook().

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

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

Definition at line 2266 of file res_jabber.c.

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

Referenced by aji_act_hook().

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

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

Definition at line 3444 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_send(), ast_log(), ast_test_flag, ASTOBJ_REF, LOG_ERROR, and pubsubflags.

Referenced by aji_init_event_distribution().

03445 {
03446    char *node_name;
03447    char *error;
03448    int error_num;
03449    iks *orig_request;
03450    iks *orig_pubsub = iks_find(pak->x, "pubsub");
03451    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03452    if (!orig_pubsub) {
03453       ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
03454       return IKS_FILTER_EAT;
03455    }
03456    orig_request = iks_child(orig_pubsub);
03457    error = iks_find_attrib(iks_find(pak->x, "error"), "code");
03458    node_name = iks_find_attrib(orig_request, "node");
03459    if (!sscanf(error, "%30d", &error_num)) {
03460       return IKS_FILTER_EAT;
03461    }
03462    if (error_num > 399 && error_num < 500 && error_num != 404) {
03463       ast_log(LOG_ERROR,
03464          "Error performing operation on PubSub node %s, %s.\n", node_name, error);
03465       return IKS_FILTER_EAT;
03466    } else if (error_num > 499 && error_num < 600) {
03467       ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
03468       return IKS_FILTER_EAT;
03469    }
03470 
03471    if (!strcasecmp(iks_name(orig_request), "publish")) {
03472       iks *request;
03473       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03474          if (iks_find(iks_find(orig_request, "item"), "state")) {
03475             aji_create_pubsub_leaf(client, "device_state", node_name);
03476          } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
03477             aji_create_pubsub_leaf(client, "message_waiting", node_name);
03478          }
03479       } else {
03480          aji_create_pubsub_node(client, NULL, node_name, NULL);
03481       }
03482       request = aji_pubsub_iq_create(client, "set");
03483       iks_insert_node(request, orig_pubsub);
03484       ast_aji_send(client, request);
03485       iks_delete(request);
03486       return IKS_FILTER_EAT;
03487    } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
03488       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03489          aji_create_pubsub_collection(client, node_name);
03490       } else {
03491          aji_create_pubsub_node(client, NULL, node_name, NULL);
03492       }
03493    }
03494 
03495    return IKS_FILTER_EAT;
03496 }

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

03234 {
03235    char *item_id, *device_state, *context;
03236    int oldmsgs, newmsgs;
03237    iks *item, *item_content;
03238    struct ast_eid pubsub_eid;
03239    struct ast_event *event;
03240    item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
03241    if (!item) {
03242       ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
03243       return IKS_FILTER_EAT;
03244    }
03245    item_id = iks_find_attrib(item, "id");
03246    item_content = iks_child(item);
03247    ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
03248    if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
03249       ast_log(LOG_DEBUG, "Returning here, eid of incoming event matches ours!\n");
03250       return IKS_FILTER_EAT;
03251    }
03252    if (!strcasecmp(iks_name(item_content), "state")) {
03253       device_state = iks_find_cdata(item, "state");
03254       if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
03255          AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
03256          AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
03257          AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03258          AST_EVENT_IE_END))) {
03259          return IKS_FILTER_EAT;
03260       }
03261    } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
03262       context = strsep(&item_id, "@");
03263       sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
03264       sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
03265       if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
03266          AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
03267          AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
03268          AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
03269          AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
03270          &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
03271          return IKS_FILTER_EAT;
03272       }
03273    } else {
03274       ast_log(LOG_DEBUG, "Don't know how to handle PubSub event of type %s\n",
03275          iks_name(item_content));
03276       return IKS_FILTER_EAT;
03277    }
03278    ast_event_queue_and_cache(event);
03279    return IKS_FILTER_EAT;
03280 }

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

Definition at line 2508 of file res_jabber.c.

References AJI_AUTOACCEPT, aji_create_buddy(), aji_set_presence(), ast_aji_send(), ast_log(), ast_test_flag, ast_verbose, ASTOBJ_CONTAINER_FIND, 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().

02509 {
02510    iks *presence = NULL, *status = NULL;
02511    struct aji_buddy* buddy = NULL;
02512 
02513    switch (pak->subtype) {
02514    case IKS_TYPE_SUBSCRIBE:
02515       if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
02516          presence = iks_new("presence");
02517          status = iks_new("status");
02518          if (presence && status) {
02519             iks_insert_attrib(presence, "type", "subscribed");
02520             iks_insert_attrib(presence, "to", pak->from->full);
02521             iks_insert_attrib(presence, "from", client->jid->full);
02522             if (pak->id)
02523                iks_insert_attrib(presence, "id", pak->id);
02524             iks_insert_cdata(status, "Asterisk has approved subscription", 0);
02525             iks_insert_node(presence, status);
02526             ast_aji_send(client, presence);
02527          } else {
02528             ast_log(LOG_ERROR, "Unable to allocate nodes\n");
02529          }
02530 
02531          iks_delete(presence);
02532          iks_delete(status);
02533       }
02534 
02535       if (client->component)
02536          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02537    case IKS_TYPE_SUBSCRIBED:
02538       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02539       if (!buddy && pak->from->partial) {
02540          aji_create_buddy(pak->from->partial, client);
02541       }
02542    default:
02543       if (option_verbose > 4) {
02544          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
02545       }
02546    }
02547 }

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

03205 {
03206    if (!mwi_sub) {
03207       mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
03208          client, AST_EVENT_IE_END);
03209    }
03210    if (!device_state_sub) {
03211       if (ast_enable_distributed_devstate()) {
03212          return;
03213       }
03214       device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
03215          aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
03216       ast_event_dump_cache(device_state_sub);
03217    }
03218 
03219    aji_pubsub_subscribe(client, "device_state");
03220    aji_pubsub_subscribe(client, "message_waiting");
03221    iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
03222       IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
03223    iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
03224       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
03225 
03226 }

static int aji_initialize ( struct aji_client client  )  [static]

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

03099 {
03100    int connected = IKS_NET_NOCONN;
03101 
03102 #ifdef HAVE_OPENSSL
03103    /* reset stream flags */
03104    client->stream_flags = 0;
03105 #endif
03106    /* If it's a component, connect to user, otherwise, connect to server */
03107    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
03108 
03109    if (connected == IKS_NET_NOCONN) {
03110       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
03111       return IKS_HOOK;
03112    } else if (connected == IKS_NET_NODNS) {
03113       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name,
03114          S_OR(client->serverhost, client->jid->server));
03115       return IKS_HOOK;
03116    }
03117 
03118    return IKS_OK;
03119 }

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

Definition at line 1292 of file res_jabber.c.

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

Referenced by aji_recv().

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

static int aji_is_secure ( struct aji_client client  )  [static]

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

01203 {
01204 #ifdef HAVE_OPENSSL
01205    return client->stream_flags & SECURE;
01206 #else
01207    return 0;
01208 #endif
01209 }

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

References aji_client_destroy(), AJI_MAX_RESJIDLEN, args, 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().

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

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

Application to leave a chat room.

Parameters:
chan ast_channel
data Data is sender|jid|nickname.
Return values:
0 success
-1 error

Definition at line 1049 of file res_jabber.c.

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

Referenced by load_module().

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

static int aji_load_config ( int  reload  )  [static]

Definition at line 4505 of file res_jabber.c.

References AJI_AUTOACCEPT, AJI_AUTOPRUNE, AJI_AUTOREGISTER, ast_category_browse(), ast_config_load, ast_false(), ast_log(), ast_set2_flag, ast_set_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, debug, globalflags, JABBER_CONFIG, LOG_WARNING, and var.

Referenced by aji_reload().

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

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

Definition at line 1483 of file res_jabber.c.

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

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

static void aji_message_destroy ( struct aji_message obj  )  [static]

Definition at line 454 of file res_jabber.c.

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

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

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

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

References aji_publish_mwi(), 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, context, LOG_DEBUG, and mailbox.

Referenced by aji_init_event_distribution().

03152 {
03153    const char *mailbox;
03154    const char *context;
03155    char oldmsgs[10];
03156    char newmsgs[10];
03157    struct aji_client *client;
03158    if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03159    {
03160       /* If the event didn't originate from this server, don't send it back out. */
03161       ast_log(LOG_DEBUG, "Returning here\n");
03162       return;
03163    }
03164 
03165    client = ASTOBJ_REF((struct aji_client *) data);
03166    mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
03167    context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
03168    snprintf(oldmsgs, sizeof(oldmsgs), "%d",
03169       ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
03170    snprintf(newmsgs, sizeof(newmsgs), "%d",
03171       ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
03172    aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
03173 
03174 }

static void aji_pruneregister ( struct aji_client client  )  [static]

Definition at line 2874 of file res_jabber.c.

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

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

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

03381 {
03382    iks *request = aji_build_publish_skeleton(client, device, "device_state");
03383    iks *state;
03384    char eid_str[20];
03385    if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
03386       if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03387          aji_create_pubsub_node(client, "leaf", device, "device_state");
03388       } else {
03389          aji_create_pubsub_node(client, NULL, device, NULL);
03390       }
03391    }
03392    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03393    state = iks_insert(request, "state");
03394    iks_insert_attrib(state, "xmlns", "http://asterisk.org");
03395    iks_insert_attrib(state, "eid", eid_str);
03396    iks_insert_cdata(state, device_state, strlen(device_state));
03397    ast_aji_send(client, iks_root(request));
03398    iks_delete(request);
03399 }

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

03410 {
03411    char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
03412    char eid_str[20];
03413    iks *mailbox_node, *request;
03414    snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
03415    request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
03416    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03417    mailbox_node = iks_insert(request, "mailbox");
03418    iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
03419    iks_insert_attrib(mailbox_node, "eid", eid_str);
03420    iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
03421    iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
03422    ast_aji_send(client, iks_root(request));
03423    iks_delete(request);
03424 }

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

03433 {
03434    iks *request = iks_new("iq");
03435 
03436    iks_insert_attrib(request, "to", client->pubsub_node);
03437    iks_insert_attrib(request, "from", client->jid->full);
03438    iks_insert_attrib(request, "type", type);
03439    ast_aji_increment_mid(client->mid);
03440    iks_insert_attrib(request, "id", client->mid);
03441    return request;
03442 }

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

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

03648 {
03649    int res = 0;
03650    iks *request = aji_build_node_request(client, collection_name);
03651    ast_aji_send(client, request);
03652    iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
03653       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03654       IKS_RULE_DONE);
03655    res = ast_aji_send(client, request);
03656    iks_delete(request);
03657 }

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

03315 {
03316    iks *request = aji_pubsub_iq_create(client, "set");
03317    iks *pubsub, *subscribe;
03318 
03319    pubsub = iks_insert(request, "pubsub");
03320    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03321    subscribe = iks_insert(pubsub, "subscribe");
03322    iks_insert_attrib(subscribe, "jid", client->jid->partial);
03323    iks_insert_attrib(subscribe, "node", node);
03324    if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03325       iks *options, *x, *sub_options, *sub_type, *sub_depth;
03326       options = iks_insert(pubsub, "options");
03327       x = iks_insert(options, "x");
03328       iks_insert_attrib(x, "xmlns", "jabber:x:data");
03329       iks_insert_attrib(x, "type", "submit");
03330       sub_options = iks_insert(x, "field");
03331       iks_insert_attrib(sub_options, "var", "FORM_TYPE");
03332       iks_insert_attrib(sub_options, "type", "hidden");
03333       iks_insert_cdata(iks_insert(sub_options, "value"),
03334          "http://jabber.org/protocol/pubsub#subscribe_options", 51);
03335       sub_type = iks_insert(x, "field");
03336       iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
03337       iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
03338       sub_depth = iks_insert(x, "field");
03339       iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
03340       iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
03341    }
03342    ast_aji_send(client, request);
03343    iks_delete(request);
03344 }

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

References ast_verbose, ASTOBJ_REF, aji_client::jid, and aji_client::name.

Referenced by aji_request_pubsub_nodes().

03542 {
03543 
03544    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03545    iks *item = NULL;
03546    if (iks_has_children(pak->query)) {
03547       item = iks_first_tag(pak->query);
03548       ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
03549          iks_find_attrib(item, "node"));
03550       while ((item = iks_next_tag(item))) {
03551          ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
03552       }
03553    }
03554    if (item) {
03555       iks_delete(item);
03556    }
03557    return IKS_FILTER_EAT;
03558 }

static int aji_reconnect ( struct aji_client client  )  [static]

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

03015 {
03016    int res = 0;
03017 
03018    if (client->state) {
03019       client->state = AJI_DISCONNECTED;
03020    }
03021    client->timeout = 50;
03022    if (client->p) {
03023       iks_parser_reset(client->p);
03024    }
03025    if (client->authorized) {
03026       client->authorized = 0;
03027    }
03028 
03029    res = aji_initialize(client);
03030 
03031    return res;
03032 }

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

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

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

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

Definition at line 2708 of file res_jabber.c.

References aji_client_destroy(), AJI_CONNECTED, AJI_DISCONNECTING, aji_reconnect(), aji_recv(), aji_send_raw(), 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().

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

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

Definition at line 1788 of file res_jabber.c.

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

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

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

Definition at line 1831 of file res_jabber.c.

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

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

static int aji_reload ( int  reload  )  [static]

Definition at line 4641 of file res_jabber.c.

References aji_client_destroy(), AJI_CONNECTING, AJI_DISCONNECTED, aji_get_roster(), aji_init_event_distribution(), aji_load_config(), aji_recv_loop(), 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().

04642 {
04643    int res;
04644 
04645    ASTOBJ_CONTAINER_MARKALL(&clients);
04646    if (!(res = aji_load_config(reload))) {
04647       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
04648       return 0;
04649    } else if (res == -1)
04650       return 1;
04651 
04652    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
04653    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04654       ASTOBJ_RDLOCK(iterator);
04655       if (iterator->state == AJI_DISCONNECTED) {
04656          if (!iterator->thread)
04657             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
04658       } else if (iterator->state == AJI_CONNECTING) {
04659          aji_get_roster(iterator);
04660          if (iterator->distribute_events) {
04661             aji_init_event_distribution(iterator);
04662          }
04663       }
04664 
04665       ASTOBJ_UNLOCK(iterator);
04666    });
04667 
04668    return 1;
04669 }

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

03505 {
03506    int res = 0;
03507    iks *request = aji_build_node_request(client, collection);
03508 
03509    iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
03510       IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03511       IKS_RULE_DONE);
03512    res = ast_aji_send(client, request);
03513    iks_delete(request);
03514 
03515 }

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

Definition at line 1107 of file res_jabber.c.

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

Referenced by load_module().

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

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

Definition at line 1409 of file res_jabber.c.

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

Referenced by aji_act_hook(), and aji_tls_handshake().

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

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

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

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

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

02585 {
02586    int res = 0;
02587    iks *message_packet = NULL;
02588    char from[AJI_MAX_JIDLEN];
02589    /* the nickname is used only in component mode */
02590    if (nick && client->component) {
02591       snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
02592    } else {
02593       snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
02594    }
02595 
02596    if (client->state != AJI_CONNECTED) {
02597       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
02598       return -1;
02599    }
02600 
02601    message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
02602    if (!message_packet) {
02603       ast_log(LOG_ERROR, "Out of memory.\n");
02604       return -1;
02605    }
02606    iks_insert_attrib(message_packet, "from", from);
02607    res = ast_aji_send(client, message_packet);
02608    iks_delete(message_packet);
02609 
02610    return res;
02611 }

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

References aji_client_destroy(), AJI_MAX_RESJIDLEN, args, 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().

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

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

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

03969 {
03970    int res = 0;
03971    iks *presence = NULL, *x = NULL;
03972    char from[AJI_MAX_JIDLEN];
03973    char roomid[AJI_MAX_JIDLEN];
03974 
03975    presence = iks_make_pres(level, NULL);
03976    x = iks_new("x");
03977 
03978    if (client->component) {
03979       snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
03980       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
03981    } else {
03982       snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
03983       snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
03984    }
03985 
03986    if (!presence || !x || !client) {
03987       ast_log(LOG_ERROR, "Out of memory.\n");
03988       res = -1;
03989       goto safeout;
03990    } else {
03991       iks_insert_attrib(presence, "to", roomid);
03992       iks_insert_attrib(presence, "from", from);
03993       iks_insert_attrib(x, "xmlns", MUC_NS);
03994       iks_insert_node(presence, x);
03995       res = ast_aji_send(client, presence);
03996    }
03997 
03998 safeout:
03999    iks_delete(presence);
04000    iks_delete(x);
04001    return res;
04002 }

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

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

03926 {
03927    int res = 0;
03928    iks *presence = iks_make_pres(level, desc);
03929    iks *cnode = iks_new("c");
03930    iks *priority = iks_new("priority");
03931    char priorityS[10];
03932 
03933    if (presence && cnode && client && priority) {
03934       if (to) {
03935          iks_insert_attrib(presence, "to", to);
03936       }
03937       if (from) {
03938          iks_insert_attrib(presence, "from", from);
03939       }
03940       snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
03941       iks_insert_cdata(priority, priorityS, strlen(priorityS));
03942       iks_insert_node(presence, priority);
03943       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
03944       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
03945       iks_insert_attrib(cnode, "ext", "voice-v1");
03946       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
03947       iks_insert_node(presence, cnode);
03948       res = ast_aji_send(client, presence);
03949    } else {
03950       ast_log(LOG_ERROR, "Out of memory.\n");
03951    }
03952 
03953    iks_delete(cnode);
03954    iks_delete(presence);
03955    iks_delete(priority);
03956 }

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

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

04121 {
04122    struct aji_resource *resource;
04123    struct aji_client *client;
04124 
04125    switch (cmd) {
04126    case CLI_INIT:
04127       e->command = "jabber show buddies";
04128       e->usage =
04129          "Usage: jabber show buddies\n"
04130          "       Shows buddy lists of our clients\n";
04131       return NULL;
04132    case CLI_GENERATE:
04133       return NULL;
04134    }
04135 
04136    ast_cli(a->fd, "Jabber buddy lists\n");
04137    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04138       ast_cli(a->fd, "Client: %s\n", iterator->user);
04139       client = iterator;
04140       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04141          ASTOBJ_RDLOCK(iterator);
04142          ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
04143          if (!iterator->resources)
04144             ast_cli(a->fd, "\t\tResource: None\n");
04145          for (resource = iterator->resources; resource; resource = resource->next) {
04146             ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
04147             if (resource->cap) {
04148                ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
04149                ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
04150                ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
04151             }
04152             ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
04153             ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
04154          }
04155          ASTOBJ_UNLOCK(iterator);
04156       });
04157       iterator = client;
04158    });
04159    return CLI_SUCCESS;
04160 }

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

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

04075 {
04076    char *status;
04077    int count = 0;
04078 
04079    switch (cmd) {
04080    case CLI_INIT:
04081       e->command = "jabber show connections";
04082       e->usage =
04083          "Usage: jabber show connections\n"
04084          "       Shows state of client and component connections\n";
04085       return NULL;
04086    case CLI_GENERATE:
04087       return NULL;
04088    }
04089 
04090    ast_cli(a->fd, "Jabber Users and their status:\n");
04091    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04092       ASTOBJ_RDLOCK(iterator);
04093       count++;
04094       switch (iterator->state) {
04095       case AJI_DISCONNECTED:
04096          status = "Disconnected";
04097          break;
04098       case AJI_CONNECTING:
04099          status = "Connecting";
04100          break;
04101       case AJI_CONNECTED:
04102          status = "Connected";
04103          break;
04104       default:
04105          status = "Unknown";
04106       }
04107       ast_cli(a->fd, "       [%s] %s     - %s\n", iterator->name, iterator->user, status);
04108       ASTOBJ_UNLOCK(iterator);
04109    });
04110    ast_cli(a->fd, "----\n");
04111    ast_cli(a->fd, "   Number of users: %d\n", count);
04112    return CLI_SUCCESS;
04113 }

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

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

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

static int aji_start_tls ( struct aji_client client  )  [static]

Definition at line 1219 of file res_jabber.c.

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

Referenced by aji_act_hook().

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

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

Definition at line 623 of file res_jabber.c.

References aji_find_resource(), args, 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, 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().

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

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

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

04168 {
04169    struct aji_client *client;
04170    struct aji_resource *resource;
04171    const char *name;
04172    struct aji_message *tmp;
04173 
04174    switch (cmd) {
04175    case CLI_INIT:
04176       e->command = "jabber test";
04177       e->usage =
04178          "Usage: jabber test <connection>\n"
04179          "       Sends test message for debugging purposes.  A specific client\n"
04180          "       as configured in jabber.conf must be specified.\n";
04181       return NULL;
04182    case CLI_GENERATE:
04183       return NULL;
04184    }
04185 
04186    if (a->argc != 3) {
04187       return CLI_SHOWUSAGE;
04188    }
04189    name = a->argv[2];
04190 
04191    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
04192       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04193       return CLI_FAILURE;
04194    }
04195 
04196    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
04197    ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
04198    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04199       ASTOBJ_RDLOCK(iterator);
04200       ast_verbose("User: %s\n", iterator->name);
04201       for (resource = iterator->resources; resource; resource = resource->next) {
04202          ast_verbose("Resource: %s\n", resource->resource);
04203          if (resource->cap) {
04204             ast_verbose("   client: %s\n", resource->cap->parent->node);
04205             ast_verbose("   version: %s\n", resource->cap->version);
04206             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
04207          }
04208          ast_verbose("  Priority: %d\n", resource->priority);
04209          ast_verbose("  Status: %d\n", resource->status);
04210          ast_verbose("  Message: %s\n", S_OR(resource->description, ""));
04211       }
04212       ASTOBJ_UNLOCK(iterator);
04213    });
04214    ast_verbose("\nOooh a working message stack!\n");
04215    AST_LIST_LOCK(&client->messages);
04216    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
04217       //ast_verbose("   Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
04218    }
04219    AST_LIST_UNLOCK(&client->messages);
04220    ASTOBJ_UNREF(client, aji_client_destroy);
04221 
04222    return CLI_SUCCESS;
04223 }

static int aji_tls_handshake ( struct aji_client client  )  [static]

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

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

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

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

02622 {
02623    int res = 0;
02624    iks *iq = NULL;
02625    iq = iks_new("iq");
02626 
02627    if (iq && client) {
02628       iks_insert_attrib(iq, "type", "get");
02629       iks_insert_attrib(iq, "to", server);
02630       iks_insert_attrib(iq, "id", client->mid);
02631       ast_aji_increment_mid(client->mid);
02632       ast_aji_send(client, iq);
02633    } else {
02634       ast_log(LOG_ERROR, "Out of memory.\n");
02635    }
02636 
02637    iks_delete(iq);
02638 
02639    return res;
02640 }

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

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

03127 {
03128    if (client) {
03129       ast_verb(4, "JABBER: Disconnecting\n");
03130 #ifdef HAVE_OPENSSL
03131       if (client->stream_flags & SECURE) {
03132          SSL_shutdown(client->ssl_session);
03133          SSL_CTX_free(client->ssl_context);
03134          SSL_free(client->ssl_session);
03135       }
03136 #endif
03137       iks_disconnect(client->p);
03138       iks_parser_delete(client->p);
03139       ASTOBJ_UNREF(client, aji_client_destroy);
03140    }
03141 
03142    return 1;
03143 }

struct aji_client* ast_aji_get_client ( const char *  name  ) 

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

Parameters:
name label or JID
Returns:
aji_client.

Definition at line 4563 of file res_jabber.c.

References ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, 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().

04564 {
04565    struct aji_client *client = NULL;
04566    char *aux = NULL;
04567 
04568    client = ASTOBJ_CONTAINER_FIND(&clients, name);
04569    if (!client && strchr(name, '@')) {
04570       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04571          aux = ast_strdupa(iterator->user);
04572          if (strchr(aux, '/')) {
04573             /* strip resource for comparison */
04574             aux = strsep(&aux, "/");
04575          }
04576          if (!strncasecmp(aux, name, strlen(aux))) {
04577             client = iterator;
04578          }
04579       });
04580    }
04581 
04582    return client;
04583 }

struct aji_client_container* ast_aji_get_clients ( void   ) 

Definition at line 4585 of file res_jabber.c.

References clients.

04586 {
04587    return &clients;
04588 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

02766 {
02767    int i = 0;
02768 
02769    for (i = strlen(mid) - 1; i >= 0; i--) {
02770       if (mid[i] != 'z') {
02771          mid[i] = mid[i] + 1;
02772          i = 0;
02773       } else
02774          mid[i] = 'a';
02775    }
02776 }

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

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

02674 {
02675    int res = 0;
02676    iks *invite, *body, *namespace;
02677 
02678    invite = iks_new("message");
02679    body = iks_new("body");
02680    namespace = iks_new("x");
02681    if (client && invite && body && namespace) {
02682       iks_insert_attrib(invite, "to", user);
02683       iks_insert_attrib(invite, "id", client->mid);
02684       ast_aji_increment_mid(client->mid);
02685       iks_insert_cdata(body, message, 0);
02686       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
02687       iks_insert_attrib(namespace, "jid", room);
02688       iks_insert_node(invite, body);
02689       iks_insert_node(invite, namespace);
02690       res = ast_aji_send(client, invite);
02691    } else {
02692       ast_log(LOG_ERROR, "Out of memory.\n");
02693    }
02694 
02695    iks_delete(body);
02696    iks_delete(namespace);
02697    iks_delete(invite);
02698 
02699    return res;
02700 }

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

References aji_set_group_presence().

Referenced by aji_join_exec().

02650 {
02651    return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
02652 }

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

References aji_set_group_presence().

Referenced by aji_leave_exec().

02662 {
02663    return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
02664 }

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

01436 {
01437    return aji_send_raw(client, iks_string(iks_stack(x), x));
01438 }

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

02558 {
02559    return aji_send_raw_chat(client, 0, NULL, address, message);
02560 }

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

References aji_send_raw_chat().

Referenced by aji_sendgroup_exec().

02571                                                                                                                   {
02572    return aji_send_raw_chat(client, 1, nick, address, message);
02573 }

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

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

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

static int delete_old_messages_all ( struct aji_client client  )  [static]

Definition at line 975 of file res_jabber.c.

References delete_old_messages().

Referenced by aji_recv_loop().

00976 {
00977    return delete_old_messages(client, NULL);
00978 }

static int gtalk_yuck ( iks *  node  )  [static]

Definition at line 569 of file res_jabber.c.

References ast_debug.

Referenced by aji_handle_presence().

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

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

Definition at line 593 of file res_jabber.c.

References ast_sha1_hash().

Referenced by aji_act_hook().

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

static int load_module ( void   )  [static]

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

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

Referenced by load_module().

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

static int reload ( void   )  [static]

Definition at line 4740 of file res_jabber.c.

References aji_reload().

04741 {
04742    aji_reload(1);
04743    return 0;
04744 }

static int unload_module ( void   )  [static]

Definition at line 4675 of file res_jabber.c.

References aji_cli, aji_client_destroy(), AJI_DISCONNECTING, ARRAY_LEN, 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.

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


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

Definition at line 4751 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 376 of file res_jabber.c.

Referenced by load_module(), and unload_module().

char* app_ajijoin = "JabberJoin" [static]

Definition at line 392 of file res_jabber.c.

char* app_ajileave = "JabberLeave" [static]

Definition at line 393 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 389 of file res_jabber.c.

char* app_ajisendgroup = "JabberSendGroup" [static]

Definition at line 390 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 391 of file res_jabber.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4751 of file res_jabber.c.

struct aji_capabilities* capabilities = NULL [static]

Definition at line 396 of file res_jabber.c.

Referenced by aji_find_version(), and ast_request().

struct aji_client_container clients [static]

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

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

Global flags, initialized to default values.

Definition at line 403 of file res_jabber.c.

struct ast_custom_function jabberreceive_function [static]

Initial value:

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

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

Referenced by load_module(), and unload_module().

ast_cond_t message_received_condition [static]

Definition at line 399 of file res_jabber.c.

ast_mutex_t messagelock [static]

Definition at line 400 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 397 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 406 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 Wed Apr 6 11:30:09 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7