res_xmpp.c File Reference

XMPP client and component module. More...

#include "asterisk.h"
#include <ctype.h>
#include <iksemel.h>
#include "asterisk/xmpp.h"
#include "asterisk/module.h"
#include "asterisk/manager.h"
#include "asterisk/app.h"
#include "asterisk/message.h"
#include "asterisk/cli.h"
#include "asterisk/config_options.h"

Include dependency graph for res_xmpp.c:

Go to the source code of this file.

Data Structures

struct  ast_xmpp_client_config
 XMPP Client Configuration. More...
struct  ast_xmpp_global_config
 XMPP Global Configuration. More...
struct  xmpp_config
struct  xmpp_pak_handler
 Defined handlers for different PAK types. More...
struct  xmpp_state_handler
 Defined handlers for XMPP client states. More...

Defines

#define BUDDY_BUCKETS   53
 Number of buckets for buddies (per client).
#define CLIENT_BUCKETS   53
 Number of buckets for client connections.
#define RESOURCE_BUCKETS   53
 Number of buckets for resources (per buddy).
#define STATUS_DISAPPEAR   6
 Status for a disappearing buddy.
#define XMPP_TLS_NS   "urn:ietf:params:xml:ns:xmpp-tls"
 Namespace for TLS support.

Enumerations

enum  {
  XMPP_AUTOPRUNE = (1 << 0), XMPP_AUTOREGISTER = (1 << 1), XMPP_AUTOACCEPT = (1 << 2), XMPP_DEBUG = (1 << 3),
  XMPP_USETLS = (1 << 4), XMPP_USESASL = (1 << 5), XMPP_FORCESSL = (1 << 6), XMPP_KEEPALIVE = (1 << 7),
  XMPP_COMPONENT = (1 << 8), XMPP_SEND_TO_DIALPLAN = (1 << 9), XMPP_DISTRIBUTE_EVENTS = (1 << 10)
}
 Supported general configuration flags. More...
enum  { XMPP_XEP0248 = (1 << 0), XMPP_PUBSUB = (1 << 1), XMPP_PUBSUB_AUTOCREATE = (1 << 2) }
 Supported pubsub configuration flags. More...

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 AO2_GLOBAL_OBJ_STATIC (globals)
int ast_xmpp_chatroom_invite (struct ast_xmpp_client *client, const char *user, const char *room, const char *message)
 Invite a user to an XMPP multi-user chatroom.
int ast_xmpp_chatroom_join (struct ast_xmpp_client *client, const char *room, const char *nickname)
 Join an XMPP multi-user chatroom.
int ast_xmpp_chatroom_leave (struct ast_xmpp_client *client, const char *room, const char *nickname)
 Leave an XMPP multi-user chatroom.
int ast_xmpp_chatroom_send (struct ast_xmpp_client *client, const char *nickname, const char *address, const char *message)
 Send a message to an XMPP multi-user chatroom.
static void * ast_xmpp_client_config_alloc (const char *cat)
 Allocator function for configuration.
static void ast_xmpp_client_config_destructor (void *obj)
 Destructor function for configuration.
int ast_xmpp_client_disconnect (struct ast_xmpp_client *client)
 Disconnect an XMPP client connection.
struct ast_xmpp_clientast_xmpp_client_find (const char *name)
 Find an XMPP client connection using a given name.
void ast_xmpp_client_lock (struct ast_xmpp_client *client)
 Lock an XMPP client connection.
int ast_xmpp_client_send (struct ast_xmpp_client *client, iks *stanza)
 Send an XML stanza out using an established XMPP client connection.
int ast_xmpp_client_send_message (struct ast_xmpp_client *client, const char *user, const char *message)
 Send a message to a given user using an established XMPP client connection.
void ast_xmpp_client_unlock (struct ast_xmpp_client *client)
 Unlock an XMPP client connection.
void ast_xmpp_client_unref (struct ast_xmpp_client *client)
 Release XMPP client connection reference.
void ast_xmpp_increment_mid (char *mid)
 Helper function which increments the message identifier.
static int cached_devstate_cb (void *obj, void *arg, int flags)
static int client_bitfield_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
static int client_buddy_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
static int client_status_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 CONFIG_INFO_STANDARD (cfg_info, globals, xmpp_config_alloc,.files=ACO_FILES(&res_xmpp_conf),.post_apply_config=xmpp_config_post_apply,)
static int delete_old_messages (struct ast_xmpp_client *client, char *from)
static int global_bitfield_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
static int load_module (void)
 Load the module.
static int manager_jabber_send (struct mansession *s, const struct message *m)
static int reload (void)
static int unload_module (void)
static int xmpp_action_hook (void *data, int type, iks *node)
 Action hook for when things occur.
static int xmpp_buddy_cmp (void *obj, void *arg, int flags)
 Comparator function for XMPP buddy.
static void xmpp_buddy_destructor (void *obj)
 Destructor callback function for XMPP buddy.
static int xmpp_buddy_hash (const void *obj, const int flags)
 Hashing function for XMPP buddy.
static char * xmpp_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 * xmpp_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 * xmpp_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 * xmpp_cli_list_pubsub_nodes (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * xmpp_cli_purge_pubsub_nodes (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Method to purge PubSub nodes via CLI.
static struct ast_xmpp_clientxmpp_client_alloc (const char *name)
 Allocator function for ast_xmpp_client.
static int xmpp_client_authenticate (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we need to authenticate.
static int xmpp_client_authenticate_digest (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we need to authenticate using non-SASL.
static int xmpp_client_authenticate_sasl (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we need to authenticate using SASL.
static int xmpp_client_authenticating (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we are authenticating.
static void xmpp_client_change_state (struct ast_xmpp_client *client, int state)
 Internal function which changes the XMPP client state.
static int xmpp_client_config_merge_buddies (void *obj, void *arg, int flags)
static int xmpp_client_config_post_apply (void *obj, void *arg, int flags)
static struct ast_xmpp_buddyxmpp_client_create_buddy (struct ao2_container *container, const char *id)
 Internal function which creates a buddy on a client.
static void xmpp_client_destructor (void *obj)
 Destructor callback function for XMPP client.
static void * xmpp_client_find_or_create (const char *category)
 Look up existing client or create a new one.
static int xmpp_client_receive (struct ast_xmpp_client *client, unsigned int timeout)
 Internal function which receives data from the XMPP client connection.
static int xmpp_client_reconnect (struct ast_xmpp_client *client)
 Internal function used to reconnect an XMPP client to its server.
static int xmpp_client_request_tls (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we need to request TLS support.
static int xmpp_client_requested_tls (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we receive a response to our TLS initiation request.
static int xmpp_client_send_disco_info_request (struct ast_xmpp_client *client, const char *to, const char *from)
 Helper function which sends a discovery information request to a user.
static int xmpp_client_send_message (struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
 Internal function used to send a message to a user or chatroom.
static int xmpp_client_send_raw_message (struct ast_xmpp_client *client, const char *message)
 Internal function which sends a raw message.
static int xmpp_client_service_discovery_get_hook (void *data, ikspak *pak)
 Hook function called when client receives a service discovery get message.
static int xmpp_client_service_discovery_result_hook (void *data, ikspak *pak)
 Hook function called when client receives a service discovery result message.
static int xmpp_client_set_group_presence (struct ast_xmpp_client *client, const char *room, int level, const char *nick)
static void xmpp_client_set_presence (struct ast_xmpp_client *client, const char *to, const char *from, int level, const char *desc)
 Internal function which changes the presence status of an XMPP client.
static int xmpp_client_subscribe_user (void *obj, void *arg, int flags)
 Callback function which subscribes to a user if needed.
static void * xmpp_client_thread (void *data)
 XMPP client connection thread.
static int xmpp_client_unsubscribe_user (struct ast_xmpp_client *client, const char *user)
 Helper function which unsubscribes a user and removes them from the roster.
static int xmpp_component_authenticate (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we should authenticate as a component.
static int xmpp_component_authenticating (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 Internal function called when we authenticated as a component.
static int xmpp_component_register_get_hook (void *data, ikspak *pak)
 Hook function called when the component is queried about registration.
static int xmpp_component_register_set_hook (void *data, ikspak *pak)
 Hook function called when someone registers to the component.
static int xmpp_component_service_discovery_get_hook (void *data, ikspak *pak)
 Hook function called when component receives a service discovery get message.
static int xmpp_component_service_discovery_items_hook (void *data, ikspak *pak)
 Hook function called when we receive a service discovery items request.
static void * xmpp_config_alloc (void)
 Allocator for XMPP configuration.
static int xmpp_config_cmp (void *obj, void *arg, int flags)
 Comparator function for configuration.
static void xmpp_config_destructor (void *obj)
 Destructor for XMPP configuration.
static void * xmpp_config_find (struct ao2_container *tmp_container, const char *category)
 Find function for configuration.
static int xmpp_config_hash (const void *obj, const int flags)
 Hashing function for configuration.
static void xmpp_config_post_apply (void)
static int xmpp_config_prelink (void *newitem)
static int xmpp_connect_hook (void *data, ikspak *pak)
 Hook function called when client finishes authenticating with the server.
static char * xmpp_do_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void xmpp_init_event_distribution (struct ast_xmpp_client *client)
 Initialize collections for event distribution.
static int xmpp_io_recv (struct ast_xmpp_client *client, char *buffer, size_t buf_len, int timeout)
 Internal function which polls on an XMPP client and receives data.
static int xmpp_is_secure (struct ast_xmpp_client *client)
 Helper function which returns whether an XMPP client connection is secure or not.
static int xmpp_join_exec (struct ast_channel *chan, const char *data)
 Application to join a chat room.
static int xmpp_leave_exec (struct ast_channel *chan, const char *data)
 Application to leave a chat room.
static void xmpp_log_hook (void *data, const char *xmpp, size_t size, int incoming)
 Logging hook function.
static void xmpp_message_destroy (struct ast_xmpp_message *message)
 Destroy function for XMPP messages.
static int xmpp_pak_message (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
 Internal function called when a message is received.
static int xmpp_pak_presence (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
 Internal function called when a presence message is received.
static int xmpp_pak_s10n (struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
 Internal function called when a subscription message is received.
static int xmpp_ping_request (struct ast_xmpp_client *client, const char *to, const char *from)
 Helper function which sends a ping request to a server.
static iks * xmpp_pubsub_build_node_config (iks *pubsub, const char *node_type, const char *collection_name)
static iks * xmpp_pubsub_build_node_request (struct ast_xmpp_client *client, const char *collection)
 Build the a node request.
static iks * xmpp_pubsub_build_publish_skeleton (struct ast_xmpp_client *client, const char *node, const char *event_type, unsigned int cachable)
 Build the skeleton of a publish.
static void xmpp_pubsub_create_affiliations (struct ast_xmpp_client *client, const char *node)
 Add Owner affiliations for pubsub node.
static void xmpp_pubsub_create_collection (struct ast_xmpp_client *client, const char *collection_name)
 Create a PubSub collection node.
static void xmpp_pubsub_create_leaf (struct ast_xmpp_client *client, const char *collection_name, const char *leaf_name)
 Create a PubSub leaf node.
static void xmpp_pubsub_create_node (struct ast_xmpp_client *client, const char *node_type, const char *name, const char *collection_name)
 Create a pubsub node.
static void xmpp_pubsub_delete_node (struct ast_xmpp_client *client, const char *node_name)
 Delete a PubSub node.
static int xmpp_pubsub_delete_node_list (void *data, ikspak *pak)
 Delete pubsub item lists.
static void xmpp_pubsub_devstate_cb (void *data, struct stasis_subscription *sub, struct stasis_message *msg)
 Callback function for device state events.
static int xmpp_pubsub_handle_error (void *data, ikspak *pak)
static int xmpp_pubsub_handle_event (void *data, ikspak *pak)
 Callback for handling PubSub events.
static iks * xmpp_pubsub_iq_create (struct ast_xmpp_client *client, const char *type)
 Create an IQ packet.
static void xmpp_pubsub_mwi_cb (void *data, struct stasis_subscription *sub, struct stasis_message *msg)
 Callback function for MWI events.
static void xmpp_pubsub_publish_device_state (struct ast_xmpp_client *client, const char *device, const char *device_state, unsigned int cachable)
 Publish device state to a PubSub node.
static void xmpp_pubsub_publish_mwi (struct ast_xmpp_client *client, const char *mailbox, const char *oldmsgs, const char *newmsgs)
 Publish MWI to a PubSub node.
static void xmpp_pubsub_purge_nodes (struct ast_xmpp_client *client, const char *collection_name)
static int xmpp_pubsub_receive_node_list (void *data, ikspak *pak)
 Receive pubsub item lists.
static void xmpp_pubsub_request_nodes (struct ast_xmpp_client *client, const char *collection)
 Request item list from pubsub.
static void xmpp_pubsub_subscribe (struct ast_xmpp_client *client, const char *node)
 Subscribe to a PubSub node.
static void xmpp_pubsub_unsubscribe (struct ast_xmpp_client *client, const char *node)
 Unsubscribe from a PubSub node.
static int xmpp_resource_cmp (void *obj, void *arg, int flags)
 Comparator function for XMPP resource.
static void xmpp_resource_destructor (void *obj)
 Destructor callback function for XMPP resource.
static int xmpp_resource_hash (const void *obj, const int flags)
 Hashing function for XMPP resource.
static int xmpp_resource_immediate (void *obj, void *arg, int flags)
 Internal astobj2 callback function which returns the first resource, which is the highest priority one.
static int xmpp_resource_is_available (void *obj, void *arg, int flags)
 Callback function which returns when the resource is available.
static int xmpp_roster_hook (void *data, ikspak *pak)
 Hook function called when roster is received from server.
static int xmpp_send_cb (const struct ast_msg *msg, const char *to, const char *from)
static int xmpp_send_exec (struct ast_channel *chan, const char *data)
static int xmpp_send_stream_header (struct ast_xmpp_client *client, const struct ast_xmpp_client_config *cfg, const char *to)
 Helper function which sends an XMPP stream header to the server.
static int xmpp_sendgroup_exec (struct ast_channel *chan, const char *data)
 Application to send a message to a groupchat.
static char * xmpp_show_buddies (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * xmpp_show_clients (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int xmpp_status_exec (struct ast_channel *chan, const char *data)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Asterisk XMPP Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static const char * app_ajijoin = "JabberJoin"
static const char * app_ajileave = "JabberLeave"
static const char * app_ajisend = "JabberSend"
static const char * app_ajisendgroup = "JabberSendGroup"
static const char * app_ajistatus = "JabberStatus"
static struct ast_module_infoast_module_info = &__mod_info
static struct aco_type client_option
struct aco_typeclient_options [] = ACO_TYPES(&client_option)
static int debug
 Global debug status.
static struct aco_type global_option
struct aco_typeglobal_options [] = ACO_TYPES(&global_option)
static struct ast_custom_function jabberreceive_function
static struct ast_custom_function jabberstatus_function
static ast_cond_t message_received_condition
static ast_mutex_t messagelock
static struct ast_msg_tech msg_tech
struct aco_file res_xmpp_conf
static struct ast_cli_entry xmpp_cli []
static struct xmpp_pak_handler xmpp_pak_handlers []
 Defined handlers for different PAK types.
static struct xmpp_state_handler xmpp_state_handlers []
 Defined handlers for XMPP client states.


Detailed Description

XMPP client and component module.

Author:
Joshua Colp <jcolp@digium.com>
Iksemel http://code.google.com/p/iksemel/

A reference module for interfacting Asterisk directly as a client or component with an XMPP/Jabber compliant server.

This module is based upon the original res_jabber as done by Matt O'Gorman.

Definition in file res_xmpp.c.


Define Documentation

#define BUDDY_BUCKETS   53

Number of buckets for buddies (per client).

Definition at line 438 of file res_xmpp.c.

Referenced by ast_xmpp_client_config_alloc(), and xmpp_client_alloc().

#define CLIENT_BUCKETS   53

Number of buckets for client connections.

Definition at line 435 of file res_xmpp.c.

#define RESOURCE_BUCKETS   53

Number of buckets for resources (per buddy).

Definition at line 441 of file res_xmpp.c.

Referenced by xmpp_client_create_buddy().

#define STATUS_DISAPPEAR   6

Status for a disappearing buddy.

Definition at line 447 of file res_xmpp.c.

Referenced by xmpp_pak_presence().

#define XMPP_TLS_NS   "urn:ietf:params:xml:ns:xmpp-tls"

Namespace for TLS support.

Definition at line 444 of file res_xmpp.c.


Enumeration Type Documentation

anonymous enum

Supported general configuration flags.

Enumerator:
XMPP_AUTOPRUNE 
XMPP_AUTOREGISTER 
XMPP_AUTOACCEPT 
XMPP_DEBUG 
XMPP_USETLS 
XMPP_USESASL 
XMPP_FORCESSL 
XMPP_KEEPALIVE 
XMPP_COMPONENT 
XMPP_SEND_TO_DIALPLAN 
XMPP_DISTRIBUTE_EVENTS 

Definition at line 413 of file res_xmpp.c.

00413      {
00414    XMPP_AUTOPRUNE = (1 << 0),
00415    XMPP_AUTOREGISTER = (1 << 1),
00416    XMPP_AUTOACCEPT = (1 << 2),
00417    XMPP_DEBUG = (1 << 3),
00418    XMPP_USETLS = (1 << 4),
00419    XMPP_USESASL = (1 << 5),
00420    XMPP_FORCESSL = (1 << 6),
00421    XMPP_KEEPALIVE = (1 << 7),
00422    XMPP_COMPONENT = (1 << 8),
00423    XMPP_SEND_TO_DIALPLAN = (1 << 9),
00424    XMPP_DISTRIBUTE_EVENTS = (1 << 10),
00425 };

anonymous enum

Supported pubsub configuration flags.

Enumerator:
XMPP_XEP0248 
XMPP_PUBSUB 
XMPP_PUBSUB_AUTOCREATE 

Definition at line 428 of file res_xmpp.c.

00428      {
00429    XMPP_XEP0248 = (1 << 0),
00430    XMPP_PUBSUB = (1 << 1),
00431    XMPP_PUBSUB_AUTOCREATE = (1 << 2),
00432 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4669 of file res_xmpp.c.

static void __unreg_module ( void   )  [static]

Definition at line 4669 of file res_xmpp.c.

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

Definition at line 2010 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, args, ast_xmpp_message::arrived, AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), ast_cond_timedwait, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_EMPTY, 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(), ast_xmpp_message::from, globals, LOG_NOTICE, LOG_WARNING, ast_xmpp_message::message, NULL, parse(), RAII_VAR, timeout, xmpp_config_find(), XMPP_MAX_JIDLEN, and xmpp_message_destroy().

02011 {
02012    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02013    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02014    char *parse = NULL;
02015    int timeout, jidlen, resourcelen, found = 0;
02016    struct timeval start;
02017    long diff = 0;
02018    struct ast_xmpp_message *message;
02019    AST_DECLARE_APP_ARGS(args,
02020               AST_APP_ARG(account);
02021               AST_APP_ARG(jid);
02022               AST_APP_ARG(timeout);
02023       );
02024    AST_DECLARE_APP_ARGS(jid,
02025               AST_APP_ARG(screenname);
02026               AST_APP_ARG(resource);
02027       );
02028 
02029    if (ast_strlen_zero(data)) {
02030       ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
02031       return -1;
02032    }
02033 
02034    parse = ast_strdupa(data);
02035    AST_STANDARD_APP_ARGS(args, parse);
02036 
02037    if (args.argc < 2 || args.argc > 3) {
02038       ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
02039       return -1;
02040    }
02041 
02042    parse = ast_strdupa(args.jid);
02043    AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
02044    if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > XMPP_MAX_JIDLEN) {
02045       ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
02046       return -1;
02047    }
02048 
02049    if (ast_strlen_zero(args.timeout)) {
02050       timeout = 20;
02051    } else {
02052       sscanf(args.timeout, "%d", &timeout);
02053       if (timeout <= 0) {
02054          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
02055          return -1;
02056       }
02057    }
02058 
02059    jidlen = strlen(jid.screenname);
02060    resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
02061 
02062    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.account))) {
02063       ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
02064       return -1;
02065    }
02066 
02067    ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
02068 
02069    start = ast_tvnow();
02070 
02071    if (chan && ast_autoservice_start(chan) < 0) {
02072       ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", ast_channel_name(chan));
02073       return -1;
02074    }
02075 
02076    /* search the messages list, grab the first message that matches with
02077     * the from JID we're expecting, and remove it from the messages list */
02078    while (diff < timeout) {
02079       struct timespec ts = { 0, };
02080       struct timeval wait;
02081       int res = 0;
02082 
02083       wait = ast_tvadd(start, ast_tv(timeout, 0));
02084       ts.tv_sec = wait.tv_sec;
02085       ts.tv_nsec = wait.tv_usec * 1000;
02086 
02087       /* wait up to timeout seconds for an incoming message */
02088       ast_mutex_lock(&messagelock);
02089       if (AST_LIST_EMPTY(&clientcfg->client->messages)) {
02090          res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
02091       }
02092       ast_mutex_unlock(&messagelock);
02093       if (res == ETIMEDOUT) {
02094          ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
02095          break;
02096       }
02097 
02098       AST_LIST_LOCK(&clientcfg->client->messages);
02099       AST_LIST_TRAVERSE_SAFE_BEGIN(&clientcfg->client->messages, message, list) {
02100          if (jid.argc == 1) {
02101             /* no resource provided, compare bare JIDs */
02102             if (strncasecmp(jid.screenname, message->from, jidlen)) {
02103                continue;
02104             }
02105          } else {
02106             /* resource appended, compare bare JIDs and resources */
02107             char *resource = strchr(message->from, '/');
02108             if (!resource || strlen(resource) == 0) {
02109                ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", message->from);
02110                if (strncasecmp(jid.screenname, message->from, jidlen)) {
02111                   continue;
02112                }
02113             } else {
02114                resource ++;
02115                if (strncasecmp(jid.screenname, message->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
02116                   continue;
02117                }
02118             }
02119          }
02120          /* check if the message is not too old */
02121          if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
02122             ast_debug(3, "Found old message from %s, deleting it\n", message->from);
02123             AST_LIST_REMOVE_CURRENT(list);
02124             xmpp_message_destroy(message);
02125             continue;
02126          }
02127          found = 1;
02128          ast_copy_string(buf, message->message, buflen);
02129          AST_LIST_REMOVE_CURRENT(list);
02130          xmpp_message_destroy(message);
02131          break;
02132       }
02133       AST_LIST_TRAVERSE_SAFE_END;
02134       AST_LIST_UNLOCK(&clientcfg->client->messages);
02135       if (found) {
02136          break;
02137       }
02138 
02139       /* check timeout */
02140       diff = ast_tvdiff_ms(ast_tvnow(), start);
02141    }
02142 
02143    if (chan && ast_autoservice_stop(chan) < 0) {
02144       ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", ast_channel_name(chan));
02145    }
02146 
02147    /* return if we timed out */
02148    if (!found) {
02149       ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
02150       return -1;
02151    }
02152 
02153    return 0;
02154 }

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

Definition at line 1723 of file res_xmpp.c.

References ao2_callback, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strlen_zero, globals, LOG_ERROR, LOG_NOTICE, LOG_WARNING, NULL, OBJ_KEY, OBJ_NODATA, RAII_VAR, ast_xmpp_resource::resource, ast_xmpp_buddy::resources, ast_xmpp_resource::status, xmpp_config_find(), xmpp_resource_cmp(), and xmpp_resource_immediate().

01724 {
01725    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01726    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01727    struct ast_xmpp_buddy *buddy;
01728    struct ast_xmpp_resource *resource;
01729    int stat = 7;
01730    AST_DECLARE_APP_ARGS(args,
01731               AST_APP_ARG(sender);
01732               AST_APP_ARG(jid);
01733       );
01734    AST_DECLARE_APP_ARGS(jid,
01735               AST_APP_ARG(screenname);
01736               AST_APP_ARG(resource);
01737       );
01738 
01739    if (ast_strlen_zero(data)) {
01740       ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
01741       return 0;
01742    }
01743    AST_STANDARD_APP_ARGS(args, data);
01744 
01745    if (args.argc != 2) {
01746       ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
01747       return -1;
01748    }
01749 
01750    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
01751    if (jid.argc < 1 || jid.argc > 2) {
01752       ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
01753       return -1;
01754    }
01755 
01756    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
01757       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
01758       return -1;
01759    }
01760 
01761    if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
01762       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
01763       return -1;
01764    }
01765 
01766    if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
01767       resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
01768    }
01769 
01770    ao2_ref(buddy, -1);
01771 
01772    if (resource) {
01773       stat = resource->status;
01774       ao2_ref(resource, -1);
01775    } else {
01776       ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
01777    }
01778 
01779    snprintf(buf, buflen, "%d", stat);
01780 
01781    return 0;
01782 }

static AO2_GLOBAL_OBJ_STATIC ( globals   )  [static]

int ast_xmpp_chatroom_invite ( struct ast_xmpp_client client,
const char *  user,
const char *  room,
const char *  message 
)

Invite a user to an XMPP multi-user chatroom.

Parameters:
client Pointer to the client
user JID of the user
room Name of the chatroom
message Message to send with the invitation
Return values:
0 on success
-1 on failure

Definition at line 944 of file res_xmpp.c.

References ast_xmpp_client_lock(), ast_xmpp_client_send(), ast_xmpp_client_unlock(), ast_xmpp_increment_mid(), ast_xmpp_client::mid, and NULL.

00945 {
00946    int res = 0;
00947    iks *invite, *body = NULL, *namespace = NULL;
00948 
00949    if (!(invite = iks_new("message")) || !(body = iks_new("body")) || !(namespace = iks_new("x"))) {
00950       res = -1;
00951       goto done;
00952    }
00953 
00954    iks_insert_attrib(invite, "to", user);
00955    ast_xmpp_client_lock(client);
00956    iks_insert_attrib(invite, "id", client->mid);
00957    ast_xmpp_increment_mid(client->mid);
00958    ast_xmpp_client_unlock(client);
00959    iks_insert_cdata(body, message, 0);
00960    iks_insert_node(invite, body);
00961    iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
00962    iks_insert_attrib(namespace, "jid", room);
00963    iks_insert_node(invite, namespace);
00964 
00965    res = ast_xmpp_client_send(client, invite);
00966 
00967 done:
00968    iks_delete(namespace);
00969    iks_delete(body);
00970    iks_delete(invite);
00971 
00972    return res;
00973 }

int ast_xmpp_chatroom_join ( struct ast_xmpp_client client,
const char *  room,
const char *  nickname 
)

Join an XMPP multi-user chatroom.

Parameters:
client Pointer to the client
room Name of the chatroom
nickname Nickname to use
Return values:
0 on success
-1 on failure

Definition at line 1011 of file res_xmpp.c.

References xmpp_client_set_group_presence().

Referenced by xmpp_join_exec().

01012 {
01013    return xmpp_client_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nickname);
01014 }

int ast_xmpp_chatroom_leave ( struct ast_xmpp_client client,
const char *  room,
const char *  nickname 
)

Leave an XMPP multi-user chatroom.

Parameters:
client Pointer to the client
room Name of the chatroom
nickname Nickname being used
Return values:
0 on success
-1 on failure

Definition at line 1021 of file res_xmpp.c.

References xmpp_client_set_group_presence().

Referenced by xmpp_leave_exec().

01022 {
01023    return xmpp_client_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nickname);
01024 }

int ast_xmpp_chatroom_send ( struct ast_xmpp_client client,
const char *  nickname,
const char *  address,
const char *  message 
)

Send a message to an XMPP multi-user chatroom.

Parameters:
client Pointer to the client
nickname Nickname to use
address Address of the room
message Message itself
Return values:
0 on success
-1 on failure

Definition at line 1016 of file res_xmpp.c.

References xmpp_client_send_message().

Referenced by xmpp_sendgroup_exec().

01017 {
01018    return xmpp_client_send_message(client, 1, nickname, address, message);
01019 }

static void* ast_xmpp_client_config_alloc ( const char *  cat  )  [static]

Allocator function for configuration.

Definition at line 681 of file res_xmpp.c.

References ao2_alloc, ao2_container_alloc, ao2_ref, ast_string_field_init, ast_string_field_set, ast_xmpp_client_config_destructor(), ast_xmpp_client_config::buddies, BUDDY_BUCKETS, ast_xmpp_client_config::client, name, NULL, xmpp_buddy_cmp(), xmpp_buddy_hash(), and xmpp_client_find_or_create().

00682 {
00683    struct ast_xmpp_client_config *cfg;
00684 
00685    if (!(cfg = ao2_alloc(sizeof(*cfg), ast_xmpp_client_config_destructor))) {
00686       return NULL;
00687    }
00688 
00689    if (ast_string_field_init(cfg, 512)) {
00690       ao2_ref(cfg, -1);
00691       return NULL;
00692    }
00693 
00694    if (!(cfg->client = xmpp_client_find_or_create(cat))) {
00695       ao2_ref(cfg, -1);
00696       return NULL;
00697    }
00698 
00699    if (!(cfg->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
00700       ao2_ref(cfg, -1);
00701       return NULL;
00702    }
00703 
00704    ast_string_field_set(cfg, name, cat);
00705 
00706    return cfg;
00707 }

static void ast_xmpp_client_config_destructor ( void *  obj  )  [static]

Destructor function for configuration.

Definition at line 534 of file res_xmpp.c.

References ao2_cleanup, ast_string_field_free_memory, ast_xmpp_client_config::buddies, and ast_xmpp_client_config::client.

Referenced by ast_xmpp_client_config_alloc().

00535 {
00536    struct ast_xmpp_client_config *cfg = obj;
00537    ast_string_field_free_memory(cfg);
00538    ao2_cleanup(cfg->client);
00539    ao2_cleanup(cfg->buddies);
00540 }

int ast_xmpp_client_disconnect ( struct ast_xmpp_client client  ) 

Disconnect an XMPP client connection.

Parameters:
client Pointer to the client
Return values:
0 on success
-1 on failure

Definition at line 3562 of file res_xmpp.c.

References AST_PTHREADT_NULL, ast_xmpp_client::device_state_sub, ast_xmpp_client::mwi_sub, NULL, ast_xmpp_client::parser, stasis_unsubscribe(), ast_xmpp_client::thread, xmpp_client_change_state(), xmpp_pubsub_unsubscribe(), XMPP_STATE_DISCONNECTED, and XMPP_STATE_DISCONNECTING.

Referenced by xmpp_client_config_post_apply(), xmpp_client_destructor(), and xmpp_client_reconnect().

03563 {
03564    if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) {
03565       xmpp_client_change_state(client, XMPP_STATE_DISCONNECTING);
03566       pthread_join(client->thread, NULL);
03567       client->thread = AST_PTHREADT_NULL;
03568    }
03569 
03570    if (client->mwi_sub) {
03571       client->mwi_sub = stasis_unsubscribe(client->mwi_sub);
03572       xmpp_pubsub_unsubscribe(client, "message_waiting");
03573    }
03574 
03575    if (client->device_state_sub) {
03576       client->device_state_sub = stasis_unsubscribe(client->device_state_sub);
03577       xmpp_pubsub_unsubscribe(client, "device_state");
03578    }
03579 
03580 #ifdef HAVE_OPENSSL
03581    if (client->stream_flags & SECURE) {
03582       SSL_shutdown(client->ssl_session);
03583       SSL_CTX_free(client->ssl_context);
03584       SSL_free(client->ssl_session);
03585    }
03586 
03587    client->stream_flags = 0;
03588 #endif
03589 
03590    if (client->parser) {
03591       iks_disconnect(client->parser);
03592    }
03593 
03594    xmpp_client_change_state(client, XMPP_STATE_DISCONNECTED);
03595 
03596    return 0;
03597 }

struct ast_xmpp_client* ast_xmpp_client_find ( const char *  name  )  [read]

Find an XMPP client connection using a given name.

Parameters:
name Name of the client connection
Return values:
non-NULL on success
NULL on failure
Note:
This will return the client connection with the reference count incremented by one.

Definition at line 882 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_ref, globals, NULL, RAII_VAR, and xmpp_config_find().

Referenced by custom_connection_handler().

00883 {
00884    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00885    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
00886 
00887    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
00888       return NULL;
00889    }
00890 
00891    ao2_ref(clientcfg->client, +1);
00892    return clientcfg->client;
00893 }

void ast_xmpp_client_lock ( struct ast_xmpp_client client  ) 

Lock an XMPP client connection.

Parameters:
client Pointer to the client

Definition at line 900 of file res_xmpp.c.

References ao2_lock.

Referenced by ast_xmpp_chatroom_invite(), xmpp_client_authenticate_digest(), xmpp_client_authenticating(), xmpp_client_send_disco_info_request(), xmpp_component_register_set_hook(), xmpp_pak_message(), xmpp_ping_request(), and xmpp_pubsub_iq_create().

00901 {
00902    ao2_lock(client);
00903 }

int ast_xmpp_client_send ( struct ast_xmpp_client client,
iks *  stanza 
)

int ast_xmpp_client_send_message ( struct ast_xmpp_client client,
const char *  user,
const char *  message 
)

Send a message to a given user using an established XMPP client connection.

Parameters:
client Pointer to the client
user User the message should be sent to
message The message to send
Return values:
0 on success
-1 on failure

Definition at line 939 of file res_xmpp.c.

References NULL, and xmpp_client_send_message().

Referenced by jingle_sendtext(), manager_jabber_send(), xmpp_send_cb(), and xmpp_send_exec().

00940 {
00941    return xmpp_client_send_message(client, 0, NULL, user, message);
00942 }

void ast_xmpp_client_unlock ( struct ast_xmpp_client client  ) 

Unlock an XMPP client connection.

Parameters:
client Pointer to the client

Definition at line 905 of file res_xmpp.c.

References ao2_unlock.

Referenced by ast_xmpp_chatroom_invite(), xmpp_client_authenticate_digest(), xmpp_client_authenticating(), xmpp_client_send_disco_info_request(), xmpp_component_register_set_hook(), xmpp_pak_message(), xmpp_ping_request(), and xmpp_pubsub_iq_create().

00906 {
00907    ao2_unlock(client);
00908 }

void ast_xmpp_client_unref ( struct ast_xmpp_client client  ) 

Release XMPP client connection reference.

Parameters:
client Pointer to the client

Definition at line 895 of file res_xmpp.c.

References ao2_ref.

Referenced by jingle_endpoint_destructor(), and jingle_session_destructor().

00896 {
00897    ao2_ref(client, -1);
00898 }

void ast_xmpp_increment_mid ( char *  mid  ) 

Helper function which increments the message identifier.

Parameters:
mid Pointer to a string containing the message identifier

Definition at line 1026 of file res_xmpp.c.

Referenced by ast_xmpp_chatroom_invite(), jingle_send_session_action(), jingle_send_session_info(), jingle_send_session_terminate(), jingle_send_transport_info(), xmpp_client_authenticate_digest(), xmpp_client_authenticating(), xmpp_client_send_disco_info_request(), xmpp_component_register_set_hook(), xmpp_ping_request(), and xmpp_pubsub_iq_create().

01027 {
01028    int i = 0;
01029 
01030    for (i = strlen(mid) - 1; i >= 0; i--) {
01031       if (mid[i] != 'z') {
01032          mid[i] = mid[i] + 1;
01033          i = 0;
01034       } else {
01035          mid[i] = 'a';
01036       }
01037    }
01038 }

static int cached_devstate_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1582 of file res_xmpp.c.

References ast_xmpp_client::device_state_sub, and xmpp_pubsub_devstate_cb().

01583 {
01584    struct stasis_message *msg = obj;
01585    struct ast_xmpp_client *client = arg;
01586    xmpp_pubsub_devstate_cb(client, client->device_state_sub, msg);
01587    return 0;
01588 }

static int client_bitfield_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
) [static]

Definition at line 4497 of file res_xmpp.c.

References ast_set2_flag, ast_true(), ast_xmpp_client_config::flags, ast_xmpp_client_config::mod_flags, ast_variable::name, ast_variable::value, XMPP_AUTOACCEPT, XMPP_AUTOPRUNE, XMPP_AUTOREGISTER, XMPP_COMPONENT, XMPP_DEBUG, XMPP_DISTRIBUTE_EVENTS, XMPP_FORCESSL, XMPP_KEEPALIVE, XMPP_SEND_TO_DIALPLAN, XMPP_USESASL, and XMPP_USETLS.

Referenced by load_module().

04498 {
04499    struct ast_xmpp_client_config *cfg = obj;
04500 
04501    if (!strcasecmp(var->name, "debug")) {
04502       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_DEBUG);
04503    } else if (!strcasecmp(var->name, "type")) {
04504       ast_set2_flag(&cfg->flags, !strcasecmp(var->value, "component") ? 1 : 0, XMPP_COMPONENT);
04505    } else if (!strcasecmp(var->name, "distribute_events")) {
04506       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_DISTRIBUTE_EVENTS);
04507    } else if (!strcasecmp(var->name, "usetls")) {
04508       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_USETLS);
04509    } else if (!strcasecmp(var->name, "usesasl")) {
04510       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_USESASL);
04511    } else if (!strcasecmp(var->name, "forceoldssl")) {
04512       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_FORCESSL);
04513    } else if (!strcasecmp(var->name, "keepalive")) {
04514       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_KEEPALIVE);
04515    } else if (!strcasecmp(var->name, "autoprune")) {
04516       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_AUTOPRUNE);
04517       ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOPRUNE);
04518    } else if (!strcasecmp(var->name, "autoregister")) {
04519       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_AUTOREGISTER);
04520       ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOREGISTER);
04521    } else if (!strcasecmp(var->name, "auth_policy")) {
04522       ast_set2_flag(&cfg->flags, !strcasecmp(var->value, "accept") ? 1 : 0, XMPP_AUTOACCEPT);
04523       ast_set2_flag(&cfg->mod_flags, 1, XMPP_AUTOACCEPT);
04524    } else if (!strcasecmp(var->name, "sendtodialplan")) {
04525       ast_set2_flag(&cfg->flags, ast_true(var->value), XMPP_SEND_TO_DIALPLAN);
04526    } else {
04527       return -1;
04528    }
04529 
04530    return 0;
04531 }

static int client_buddy_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
) [static]

Definition at line 4562 of file res_xmpp.c.

References ao2_find, ao2_ref, ast_xmpp_client_config::buddies, OBJ_KEY, ast_variable::value, and xmpp_client_create_buddy().

Referenced by load_module().

04563 {
04564    struct ast_xmpp_client_config *cfg = obj;
04565    struct ast_xmpp_buddy *buddy;
04566 
04567    if ((buddy = ao2_find(cfg->buddies, var->value, OBJ_KEY))) {
04568       ao2_ref(buddy, -1);
04569       return -1;
04570    }
04571 
04572    if (!(buddy = xmpp_client_create_buddy(cfg->buddies, var->value))) {
04573       return -1;
04574    }
04575 
04576    ao2_ref(buddy, -1);
04577 
04578    return 0;
04579 }

static int client_status_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
) [static]

Definition at line 4533 of file res_xmpp.c.

References ast_xmpp_client_config::status, and ast_variable::value.

Referenced by load_module().

04534 {
04535    struct ast_xmpp_client_config *cfg = obj;
04536 
04537    if (!strcasecmp(var->value, "unavailable")) {
04538       cfg->status = IKS_SHOW_UNAVAILABLE;
04539    } else if (!strcasecmp(var->value, "available") || !strcasecmp(var->value, "online")) {
04540       cfg->status = IKS_SHOW_AVAILABLE;
04541    } else if (!strcasecmp(var->value, "chat") || !strcasecmp(var->value, "chatty")) {
04542       cfg->status = IKS_SHOW_CHAT;
04543    } else if (!strcasecmp(var->value, "away")) {
04544       cfg->status = IKS_SHOW_AWAY;
04545    } else if (!strcasecmp(var->value, "xa") || !strcasecmp(var->value, "xaway")) {
04546       cfg->status = IKS_SHOW_XA;
04547    } else if (!strcasecmp(var->value, "dnd")) {
04548       cfg->status = IKS_SHOW_DND;
04549    } else if (!strcasecmp(var->value, "invisible")) {
04550 #ifdef IKS_SHOW_INVISIBLE
04551       cfg->status = IKS_SHOW_INVISIBLE;
04552 #else
04553       cfg->status = IKS_SHOW_DND;
04554 #endif
04555    } else {
04556       return -1;
04557    }
04558 
04559    return 0;
04560 }

CONFIG_INFO_STANDARD ( cfg_info  ,
globals  ,
xmpp_config_alloc  ,
files = ACO_FILES(&res_xmpp_conf),
post_apply_config = xmpp_config_post_apply 
)

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

Definition at line 2169 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_xmpp_message::arrived, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_tvdiff_sec(), ast_tvnow(), ast_xmpp_message::from, globals, ast_xmpp_message::list, ast_xmpp_client::messages, ast_xmpp_client::name, NULL, RAII_VAR, xmpp_config_find(), and xmpp_message_destroy().

Referenced by xmpp_pak_message().

02170 {
02171    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02172    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02173    int deleted = 0, isold = 0;
02174    struct ast_xmpp_message *message = NULL;
02175 
02176    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
02177       return 0;
02178    }
02179 
02180    AST_LIST_LOCK(&client->messages);
02181    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, message, list) {
02182       if (isold) {
02183          if (!from || !strncasecmp(from, message->from, strlen(from))) {
02184             AST_LIST_REMOVE_CURRENT(list);
02185             xmpp_message_destroy(message);
02186             deleted++;
02187          }
02188       } else if (ast_tvdiff_sec(ast_tvnow(), message->arrived) >= clientcfg->message_timeout) {
02189          isold = 1;
02190          if (!from || !strncasecmp(from, message->from, strlen(from))) {
02191             AST_LIST_REMOVE_CURRENT(list);
02192             xmpp_message_destroy(message);
02193             deleted++;
02194          }
02195       }
02196    }
02197    AST_LIST_TRAVERSE_SAFE_END;
02198    AST_LIST_UNLOCK(&client->messages);
02199 
02200    return deleted;
02201 }

static int global_bitfield_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
) [static]

Definition at line 4474 of file res_xmpp.c.

References ast_set2_flag, ast_true(), ast_xmpp_global_config::general, global, ast_variable::name, ast_xmpp_global_config::pubsub, ast_variable::value, XMPP_AUTOACCEPT, XMPP_AUTOPRUNE, XMPP_AUTOREGISTER, XMPP_PUBSUB_AUTOCREATE, and XMPP_XEP0248.

Referenced by load_module().

04475 {
04476    struct ast_xmpp_global_config *global = obj;
04477 
04478    if (!strcasecmp(var->name, "debug")) {
04479       debug = ast_true(var->value);
04480    } else if (!strcasecmp(var->name, "autoprune")) {
04481       ast_set2_flag(&global->general, ast_true(var->value), XMPP_AUTOPRUNE);
04482    } else if (!strcasecmp(var->name, "autoregister")) {
04483       ast_set2_flag(&global->general, ast_true(var->value), XMPP_AUTOREGISTER);
04484    } else if (!strcasecmp(var->name, "auth_policy")) {
04485       ast_set2_flag(&global->general, !strcasecmp(var->value, "accept") ? 1 : 0, XMPP_AUTOACCEPT);
04486    } else if (!strcasecmp(var->name, "collection_nodes")) {
04487       ast_set2_flag(&global->pubsub, ast_true(var->value), XMPP_XEP0248);
04488    } else if (!strcasecmp(var->name, "pubsub_autocreate")) {
04489       ast_set2_flag(&global->pubsub, ast_true(var->value), XMPP_PUBSUB_AUTOCREATE);
04490    } else {
04491       return -1;
04492    }
04493 
04494    return 0;
04495 }

static int load_module ( void   )  [static]

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 4591 of file res_xmpp.c.

References ACO_EXACT, aco_info_destroy(), aco_info_init(), aco_option_register, aco_option_register_custom, aco_process_config(), ACO_PROCESS_ERROR, ARRAY_LEN, ast_cli_register_multiple(), ast_cond_init, ast_custom_function_register, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_msg_tech_register(), ast_mutex_init, ast_register_application_xml, client_bitfield_handler(), client_buddy_handler(), client_status_handler(), context, EVENT_FLAG_SYSTEM, FLDSET, global_bitfield_handler(), manager_jabber_send(), NULL, OPT_STRINGFIELD_T, OPT_UINT_T, password, STRFLDSET, xmpp_join_exec(), xmpp_leave_exec(), xmpp_send_exec(), xmpp_sendgroup_exec(), and xmpp_status_exec().

04592 {
04593    if (aco_info_init(&cfg_info)) {
04594       return AST_MODULE_LOAD_DECLINE;
04595    }
04596 
04597    aco_option_register_custom(&cfg_info, "debug", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
04598    aco_option_register_custom(&cfg_info, "autoprune", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
04599    aco_option_register_custom(&cfg_info, "autoregister", ACO_EXACT, global_options, "yes", global_bitfield_handler, 0);
04600    aco_option_register_custom(&cfg_info, "collection_nodes", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
04601    aco_option_register_custom(&cfg_info, "pubsub_autocreate", ACO_EXACT, global_options, "no", global_bitfield_handler, 0);
04602    aco_option_register_custom(&cfg_info, "auth_policy", ACO_EXACT, global_options, "accept", global_bitfield_handler, 0);
04603 
04604    aco_option_register(&cfg_info, "username", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, user));
04605    aco_option_register(&cfg_info, "secret", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, password));
04606    aco_option_register(&cfg_info, "serverhost", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, server));
04607    aco_option_register(&cfg_info, "statusmessage", ACO_EXACT, client_options, "Online and Available", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, statusmsg));
04608    aco_option_register(&cfg_info, "pubsub_node", ACO_EXACT, client_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, pubsubnode));
04609    aco_option_register(&cfg_info, "context", ACO_EXACT, client_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_xmpp_client_config, context));
04610    aco_option_register(&cfg_info, "priority", ACO_EXACT, client_options, "1", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, priority));
04611    aco_option_register(&cfg_info, "port", ACO_EXACT, client_options, "5222", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, port));
04612    aco_option_register(&cfg_info, "timeout", ACO_EXACT, client_options, "5", OPT_UINT_T, 0, FLDSET(struct ast_xmpp_client_config, message_timeout));
04613 
04614    /* Global options that can be overridden per client must not specify a default */
04615    aco_option_register_custom(&cfg_info, "autoprune", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
04616    aco_option_register_custom(&cfg_info, "autoregister", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
04617    aco_option_register_custom(&cfg_info, "auth_policy", ACO_EXACT, client_options, NULL, client_bitfield_handler, 0);
04618 
04619    aco_option_register_custom(&cfg_info, "debug", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
04620    aco_option_register_custom(&cfg_info, "type", ACO_EXACT, client_options, "client", client_bitfield_handler, 0);
04621    aco_option_register_custom(&cfg_info, "distribute_events", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
04622    aco_option_register_custom(&cfg_info, "usetls", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
04623    aco_option_register_custom(&cfg_info, "usesasl", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
04624    aco_option_register_custom(&cfg_info, "forceoldssl", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
04625    aco_option_register_custom(&cfg_info, "keepalive", ACO_EXACT, client_options, "yes", client_bitfield_handler, 0);
04626    aco_option_register_custom(&cfg_info, "sendtodialplan", ACO_EXACT, client_options, "no", client_bitfield_handler, 0);
04627    aco_option_register_custom(&cfg_info, "status", ACO_EXACT, client_options, "available", client_status_handler, 0);
04628    aco_option_register_custom(&cfg_info, "buddy", ACO_EXACT, client_options, NULL, client_buddy_handler, 0);
04629 
04630    if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
04631       aco_info_destroy(&cfg_info);
04632       return AST_MODULE_LOAD_DECLINE;
04633    }
04634 
04635    ast_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send);
04636 
04637    ast_register_application_xml(app_ajisend, xmpp_send_exec);
04638    ast_register_application_xml(app_ajisendgroup, xmpp_sendgroup_exec);
04639    ast_register_application_xml(app_ajistatus, xmpp_status_exec);
04640    ast_register_application_xml(app_ajijoin, xmpp_join_exec);
04641    ast_register_application_xml(app_ajileave, xmpp_leave_exec);
04642 
04643    ast_cli_register_multiple(xmpp_cli, ARRAY_LEN(xmpp_cli));
04644    ast_custom_function_register(&jabberstatus_function);
04645    ast_custom_function_register(&jabberreceive_function);
04646    ast_msg_tech_register(&msg_tech);
04647 
04648    ast_mutex_init(&messagelock);
04649    ast_cond_init(&message_received_condition, NULL);
04650 
04651    return AST_MODULE_LOAD_SUCCESS;
04652 }

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

Definition at line 3895 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_strlen_zero, ast_xmpp_client_send_message(), astman_append(), astman_get_header(), astman_send_ack(), astman_send_error(), globals, NULL, RAII_VAR, and xmpp_config_find().

Referenced by load_module().

03896 {
03897    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
03898    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
03899    const char *id = astman_get_header(m, "ActionID");
03900    const char *jabber = astman_get_header(m, "Jabber");
03901    const char *screenname = astman_get_header(m, "ScreenName");
03902    const char *message = astman_get_header(m, "Message");
03903 
03904    if (ast_strlen_zero(jabber)) {
03905       astman_send_error(s, m, "No transport specified");
03906       return 0;
03907    }
03908    if (ast_strlen_zero(screenname)) {
03909       astman_send_error(s, m, "No ScreenName specified");
03910       return 0;
03911    }
03912    if (ast_strlen_zero(message)) {
03913       astman_send_error(s, m, "No Message specified");
03914       return 0;
03915    }
03916 
03917    astman_send_ack(s, m, "Attempting to send Jabber Message");
03918 
03919    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, jabber))) {
03920       astman_send_error(s, m, "Could not find Sender");
03921       return 0;
03922    }
03923 
03924    if (strchr(screenname, '@') && !ast_xmpp_client_send_message(clientcfg->client, screenname, message)) {
03925       astman_append(s, "Response: Success\r\n");
03926    } else {
03927       astman_append(s, "Response: Error\r\n");
03928    }
03929 
03930    if (!ast_strlen_zero(id)) {
03931       astman_append(s, "ActionID: %s\r\n", id);
03932    }
03933 
03934    astman_append(s, "\r\n");
03935 
03936    return 0;
03937 }

static int reload ( void   )  [static]

Definition at line 4654 of file res_xmpp.c.

References aco_process_config(), ACO_PROCESS_ERROR, and AST_MODULE_LOAD_DECLINE.

04655 {
04656    if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
04657       return AST_MODULE_LOAD_DECLINE;
04658    }
04659 
04660    return 0;
04661 }

static int unload_module ( void   )  [static]

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

Action hook for when things occur.

Definition at line 3492 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ARRAY_LEN, ast_log, ast_test_flag, xmpp_state_handler::component, ast_xmpp_client::filter, globals, handler(), LOG_ERROR, ast_xmpp_client::name, NULL, RAII_VAR, ast_xmpp_client::state, xmpp_pak_handler::type, XMPP_COMPONENT, xmpp_config_find(), XMPP_MAX_ATTRLEN, xmpp_pak_handlers, XMPP_STATE_DISCONNECTING, and xmpp_state_handlers.

Referenced by xmpp_client_config_post_apply().

03493 {
03494    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
03495    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
03496    struct ast_xmpp_client *client = data;
03497    ikspak *pak;
03498    int i;
03499 
03500    if (!node) {
03501       ast_log(LOG_ERROR, "xmpp_action_hook was called without a packet\n");
03502       return IKS_HOOK;
03503    }
03504 
03505    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
03506       return IKS_HOOK;
03507    }
03508 
03509    /* If the client is disconnecting ignore everything */
03510    if (client->state == XMPP_STATE_DISCONNECTING) {
03511       return IKS_HOOK;
03512    }
03513 
03514    pak = iks_packet(node);
03515 
03516    /* work around iksemel's impossibility to recognize node names
03517     * containing a colon. Set the namespace of the corresponding
03518     * node accordingly. */
03519    if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
03520       char *node_ns = NULL;
03521       char attr[XMPP_MAX_ATTRLEN];
03522       char *node_name = iks_name(iks_child(node));
03523       char *aux = strchr(node_name, ':') + 1;
03524       snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
03525       node_ns = iks_find_attrib(iks_child(node), attr);
03526       if (node_ns) {
03527          pak->ns = node_ns;
03528          pak->query = iks_child(node);
03529       }
03530    }
03531 
03532    /* Process through any state handlers */
03533    for (i = 0; i < ARRAY_LEN(xmpp_state_handlers); i++) {
03534       if ((xmpp_state_handlers[i].state == client->state) && (xmpp_state_handlers[i].component == (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) ? 1 : 0))) {
03535          if (xmpp_state_handlers[i].handler(client, clientcfg, type, node)) {
03536             /* If the handler wants us to stop now, do so */
03537             return IKS_HOOK;
03538          }
03539          break;
03540       }
03541    }
03542 
03543    /* Process through any PAK handlers */
03544    for (i = 0; i < ARRAY_LEN(xmpp_pak_handlers); i++) {
03545       if (xmpp_pak_handlers[i].type == pak->type) {
03546          if (xmpp_pak_handlers[i].handler(client, clientcfg, node, pak)) {
03547             /* If the handler wants us to stop now, do so */
03548             return IKS_HOOK;
03549          }
03550          break;
03551       }
03552    }
03553 
03554    /* Send the packet through the filter in case any filters want to process it */
03555    iks_filter_packet(client->filter, pak);
03556 
03557    iks_delete(node);
03558 
03559    return IKS_OK;
03560 }

static int xmpp_buddy_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Comparator function for XMPP buddy.

Definition at line 593 of file res_xmpp.c.

References CMP_MATCH, CMP_STOP, ast_xmpp_buddy::id, and OBJ_KEY.

Referenced by ast_xmpp_client_config_alloc(), and xmpp_client_alloc().

00594 {
00595    struct ast_xmpp_buddy *buddy1 = obj, *buddy2 = arg;
00596    const char *id = arg;
00597 
00598    return !strcmp(buddy1->id, flags & OBJ_KEY ? id : buddy2->id) ? CMP_MATCH | CMP_STOP : 0;
00599 }

static void xmpp_buddy_destructor ( void *  obj  )  [static]

Destructor callback function for XMPP buddy.

Definition at line 863 of file res_xmpp.c.

References ao2_ref, and ast_xmpp_buddy::resources.

Referenced by xmpp_client_create_buddy().

00864 {
00865    struct ast_xmpp_buddy *buddy = obj;
00866 
00867    if (buddy->resources) {
00868       ao2_ref(buddy->resources, -1);
00869    }
00870 }

static int xmpp_buddy_hash ( const void *  obj,
const int  flags 
) [static]

Hashing function for XMPP buddy.

Definition at line 584 of file res_xmpp.c.

References ast_str_hash(), ast_xmpp_buddy::id, and OBJ_KEY.

Referenced by ast_xmpp_client_config_alloc(), and xmpp_client_alloc().

00585 {
00586    const struct ast_xmpp_buddy *buddy = obj;
00587    const char *id = obj;
00588 
00589    return ast_str_hash(flags & OBJ_KEY ? id : buddy->id);
00590 }

static char* xmpp_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 4190 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, globals, name, NULL, RAII_VAR, ast_cli_entry::usage, xmpp_config_find(), and xmpp_pubsub_create_collection().

04191 {
04192    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
04193    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
04194    const char *name, *collection_name;
04195 
04196    switch (cmd) {
04197    case CLI_INIT:
04198       e->command = "xmpp create collection";
04199       e->usage =
04200          "Usage: xmpp create collection <connection> <collection>\n"
04201          "       Creates a PubSub collection node using the account\n"
04202          "       as configured in xmpp.conf.\n";
04203       return NULL;
04204    case CLI_GENERATE:
04205       return NULL;
04206    }
04207 
04208    if (a->argc != 5) {
04209       return CLI_SHOWUSAGE;
04210    }
04211    name = a->argv[3];
04212    collection_name = a->argv[4];
04213 
04214    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
04215       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04216       return CLI_FAILURE;
04217    }
04218 
04219    ast_cli(a->fd, "Creating test PubSub node collection.\n");
04220 
04221    xmpp_pubsub_create_collection(clientcfg->client, collection_name);
04222 
04223    return CLI_SUCCESS;
04224 }

static char* xmpp_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 4230 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, globals, name, NULL, RAII_VAR, ast_cli_entry::usage, xmpp_config_find(), and xmpp_pubsub_create_leaf().

04231 {
04232    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
04233    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
04234    const char *name, *collection_name, *leaf_name;
04235 
04236    switch (cmd) {
04237    case CLI_INIT:
04238       e->command = "xmpp create leaf";
04239       e->usage =
04240          "Usage: xmpp create leaf <connection> <collection> <leaf>\n"
04241          "       Creates a PubSub leaf node using the account\n"
04242          "       as configured in xmpp.conf.\n";
04243       return NULL;
04244    case CLI_GENERATE:
04245       return NULL;
04246    }
04247 
04248    if (a->argc != 6) {
04249       return CLI_SHOWUSAGE;
04250    }
04251    name = a->argv[3];
04252    collection_name = a->argv[4];
04253    leaf_name = a->argv[5];
04254 
04255    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
04256       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04257       return CLI_FAILURE;
04258    }
04259 
04260    ast_cli(a->fd, "Creating test PubSub node collection.\n");
04261 
04262    xmpp_pubsub_create_leaf(clientcfg->client, collection_name, leaf_name);
04263 
04264    return CLI_SUCCESS;
04265 }

static char* xmpp_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 4152 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, globals, name, NULL, RAII_VAR, ast_cli_entry::usage, xmpp_config_find(), and xmpp_pubsub_delete_node().

04154 {
04155    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
04156    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
04157    const char *name;
04158 
04159    switch (cmd) {
04160    case CLI_INIT:
04161       e->command = "xmpp delete node";
04162       e->usage =
04163          "Usage: xmpp delete node <connection> <node>\n"
04164          "       Deletes a node on PubSub server\n"
04165          "       as configured in xmpp.conf.\n";
04166       return NULL;
04167    case CLI_GENERATE:
04168       return NULL;
04169    }
04170 
04171    if (a->argc != 5) {
04172       return CLI_SHOWUSAGE;
04173    }
04174    name = a->argv[3];
04175 
04176    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
04177       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04178       return CLI_FAILURE;
04179    }
04180 
04181    xmpp_pubsub_delete_node(clientcfg->client, a->argv[4]);
04182 
04183    return CLI_SUCCESS;
04184 }

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

Definition at line 4021 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, globals, name, NULL, RAII_VAR, ast_cli_entry::usage, xmpp_config_find(), and xmpp_pubsub_request_nodes().

04023 {
04024    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
04025    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
04026    const char *name = NULL, *collection = NULL;
04027 
04028    switch (cmd) {
04029    case CLI_INIT:
04030       e->command = "xmpp list nodes";
04031       e->usage =
04032          "Usage: xmpp list nodes <connection> [collection]\n"
04033          "       Lists the user's nodes on the respective connection\n"
04034          "       ([connection] as configured in xmpp.conf.)\n";
04035       return NULL;
04036    case CLI_GENERATE:
04037       return NULL;
04038    }
04039 
04040    if (a->argc > 5 || a->argc < 4) {
04041       return CLI_SHOWUSAGE;
04042    } else if (a->argc == 4 || a->argc == 5) {
04043       name = a->argv[3];
04044    }
04045 
04046    if (a->argc == 5) {
04047       collection = a->argv[4];
04048    }
04049 
04050    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
04051       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04052       return CLI_FAILURE;
04053    }
04054 
04055    ast_cli(a->fd, "Listing pubsub nodes.\n");
04056 
04057    xmpp_pubsub_request_nodes(clientcfg->client, collection);
04058 
04059    return CLI_SUCCESS;
04060 }

static char* xmpp_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 4107 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_test_flag, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, globals, name, NULL, RAII_VAR, ast_cli_entry::usage, xmpp_config_find(), xmpp_pubsub_delete_node(), xmpp_pubsub_purge_nodes(), and XMPP_XEP0248.

04109 {
04110    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
04111    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
04112    const char *name;
04113 
04114    switch (cmd) {
04115    case CLI_INIT:
04116       e->command = "xmpp purge nodes";
04117       e->usage =
04118          "Usage: xmpp purge nodes <connection> <node>\n"
04119          "       Purges nodes on PubSub server\n"
04120          "       as configured in xmpp.conf.\n";
04121          return NULL;
04122    case CLI_GENERATE:
04123       return NULL;
04124    }
04125 
04126    if (a->argc != 5) {
04127       return CLI_SHOWUSAGE;
04128    }
04129    name = a->argv[3];
04130 
04131    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, name))) {
04132       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04133       return CLI_FAILURE;
04134    }
04135 
04136    if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
04137       xmpp_pubsub_purge_nodes(clientcfg->client, a->argv[4]);
04138    } else {
04139       xmpp_pubsub_delete_node(clientcfg->client, a->argv[4]);
04140    }
04141 
04142    return CLI_SUCCESS;
04143 }

static struct ast_xmpp_client* xmpp_client_alloc ( const char *  name  )  [static, read]

Allocator function for ast_xmpp_client.

Definition at line 616 of file res_xmpp.c.

References ao2_alloc, ao2_container_alloc, ao2_ref, ast_copy_string(), ast_endpoint_create(), AST_LIST_HEAD_INIT, ast_log, AST_PTHREADT_NULL, ast_string_field_init, ast_string_field_set, ast_xmpp_client::buddies, BUDDY_BUCKETS, ast_xmpp_client::endpoint, LOG_ERROR, ast_xmpp_client::messages, ast_xmpp_client::mid, NULL, ast_xmpp_client::stack, ast_xmpp_client::thread, ast_xmpp_client::timeout, xmpp_buddy_cmp(), xmpp_buddy_hash(), xmpp_client_change_state(), xmpp_client_destructor(), and XMPP_STATE_DISCONNECTED.

Referenced by xmpp_client_find_or_create().

00617 {
00618    struct ast_xmpp_client *client;
00619 
00620    if (!(client = ao2_alloc(sizeof(*client), xmpp_client_destructor))) {
00621       return NULL;
00622    }
00623 
00624    AST_LIST_HEAD_INIT(&client->messages);
00625    client->thread = AST_PTHREADT_NULL;
00626 
00627    client->endpoint = ast_endpoint_create("XMPP", name);
00628    if (!client->endpoint) {
00629       ao2_ref(client, -1);
00630       return NULL;
00631    }
00632 
00633    if (!(client->buddies = ao2_container_alloc(BUDDY_BUCKETS, xmpp_buddy_hash, xmpp_buddy_cmp))) {
00634       ast_log(LOG_ERROR, "Could not initialize buddy container for '%s'\n", name);
00635       ao2_ref(client, -1);
00636       return NULL;
00637    }
00638 
00639    if (ast_string_field_init(client, 512)) {
00640       ast_log(LOG_ERROR, "Could not initialize stringfields for '%s'\n", name);
00641       ao2_ref(client, -1);
00642       return NULL;
00643    }
00644 
00645    if (!(client->stack = iks_stack_new(8192, 8192))) {
00646       ast_log(LOG_ERROR, "Could not create an Iksemel stack for '%s'\n", name);
00647       ao2_ref(client, -1);
00648       return NULL;
00649    }
00650 
00651    ast_string_field_set(client, name, name);
00652 
00653    client->timeout = 50;
00654    xmpp_client_change_state(client, XMPP_STATE_DISCONNECTED);
00655    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
00656 
00657    return client;
00658 }

static int xmpp_client_authenticate ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we need to authenticate.

Definition at line 2798 of file res_xmpp.c.

References ast_test_flag, ast_xmpp_client_config::flags, xmpp_client_authenticate_digest(), xmpp_client_authenticate_sasl(), and XMPP_USESASL.

02799 {
02800    return ast_test_flag(&cfg->flags, XMPP_USESASL) ? xmpp_client_authenticate_sasl(client, cfg, type, node) : xmpp_client_authenticate_digest(client, cfg, type, node);
02801 }

static int xmpp_client_authenticate_digest ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we need to authenticate using non-SASL.

Definition at line 2701 of file res_xmpp.c.

References ast_log, ast_sha1_hash(), ast_xmpp_client_lock(), ast_xmpp_client_send(), ast_xmpp_client_unlock(), ast_xmpp_increment_mid(), buf, ast_xmpp_client::filter, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::mid, ast_xmpp_client::name, NULL, ast_xmpp_client_config::password, xmpp_client_change_state(), xmpp_connect_hook(), and XMPP_STATE_AUTHENTICATING.

Referenced by xmpp_client_authenticate().

02702 {
02703    iks *iq = NULL, *query = NULL;
02704    char buf[41], sidpass[100];
02705 
02706    if (!(iq = iks_new("iq")) || !(query = iks_insert(iq, "query"))) {
02707       ast_log(LOG_ERROR, "Stanzas could not be allocated for authentication on client '%s'\n", client->name);
02708       iks_delete(iq);
02709       return -1;
02710    }
02711 
02712    iks_insert_attrib(iq, "type", "set");
02713    iks_insert_cdata(iks_insert(query, "username"), client->jid->user, 0);
02714    iks_insert_cdata(iks_insert(query, "resource"), client->jid->resource, 0);
02715 
02716    iks_insert_attrib(query, "xmlns", "jabber:iq:auth");
02717    snprintf(sidpass, sizeof(sidpass), "%s%s", iks_find_attrib(node, "id"), cfg->password);
02718    ast_sha1_hash(buf, sidpass);
02719    iks_insert_cdata(iks_insert(query, "digest"), buf, 0);
02720 
02721    ast_xmpp_client_lock(client);
02722    iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
02723    iks_insert_attrib(iq, "id", client->mid);
02724    ast_xmpp_increment_mid(client->mid);
02725    ast_xmpp_client_unlock(client);
02726 
02727    iks_insert_attrib(iq, "to", client->jid->server);
02728 
02729    ast_xmpp_client_send(client, iq);
02730 
02731    iks_delete(iq);
02732 
02733    xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
02734 
02735    return 0;
02736 }

static int xmpp_client_authenticate_sasl ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we need to authenticate using SASL.

Definition at line 2739 of file res_xmpp.c.

References ast_base64encode(), ast_log, ast_strdupa, ast_xmpp_client_send(), base64, ast_xmpp_client::jid, len(), LOG_ERROR, ast_xmpp_client::name, ast_xmpp_client::parser, ast_xmpp_client_config::password, strsep(), xmpp_client_change_state(), xmpp_is_secure(), and XMPP_STATE_AUTHENTICATING.

Referenced by xmpp_client_authenticate().

02740 {
02741    int features, len = strlen(client->jid->user) + strlen(cfg->password) + 3;
02742    iks *auth;
02743    char combined[len];
02744    char base64[(len + 2) * 4 / 3];
02745 
02746    if (strcmp(iks_name(node), "stream:features")) {
02747       /* Ignore anything beside stream features */
02748       return 0;
02749    }
02750 
02751    features = iks_stream_features(node);
02752 
02753    if ((features & IKS_STREAM_SASL_MD5) && !xmpp_is_secure(client)) {
02754       if (iks_start_sasl(client->parser, IKS_SASL_DIGEST_MD5, (char*)client->jid->user, (char*)cfg->password) != IKS_OK) {
02755          ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL DIGEST-MD5 but could not\n", client->name);
02756          return -1;
02757       }
02758 
02759       xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
02760       return 0;
02761    }
02762 
02763    /* Our only other available option is plain so if they don't support it, bail out now */
02764    if (!(features & IKS_STREAM_SASL_PLAIN)) {
02765       ast_log(LOG_ERROR, "Tried to authenticate client '%s' using SASL PLAIN but server does not support it\n", client->name);
02766       return -1;
02767    }
02768 
02769    if (!(auth = iks_new("auth"))) {
02770       ast_log(LOG_ERROR, "Could not allocate memory for SASL PLAIN authentication for client '%s'\n", client->name);
02771       return -1;
02772    }
02773 
02774    iks_insert_attrib(auth, "xmlns", IKS_NS_XMPP_SASL);
02775    iks_insert_attrib(auth, "mechanism", "PLAIN");
02776 
02777    if (strchr(client->jid->user, '/')) {
02778       char *user = ast_strdupa(client->jid->user);
02779 
02780       snprintf(combined, sizeof(combined), "%c%s%c%s", 0, strsep(&user, "/"), 0, cfg->password);
02781    } else {
02782       snprintf(combined, sizeof(combined), "%c%s%c%s", 0, client->jid->user, 0, cfg->password);
02783    }
02784 
02785    ast_base64encode(base64, (const unsigned char *) combined, len - 1, (len + 2) * 4 / 3);
02786    iks_insert_cdata(auth, base64, 0);
02787 
02788    ast_xmpp_client_send(client, auth);
02789 
02790    iks_delete(auth);
02791 
02792    xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
02793 
02794    return 0;
02795 }

static int xmpp_client_authenticating ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we are authenticating.

Definition at line 2804 of file res_xmpp.c.

References ast_log, ast_xmpp_client_lock(), ast_xmpp_client_send(), ast_xmpp_client_unlock(), ast_xmpp_increment_mid(), ast_xmpp_client::filter, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::mid, ast_xmpp_client::name, xmpp_connect_hook(), and xmpp_send_stream_header().

02805 {
02806    int features;
02807 
02808    if (!strcmp(iks_name(node), "success")) {
02809       /* Authentication was a success, yay! */
02810       xmpp_send_stream_header(client, cfg, client->jid->server);
02811 
02812       return 0;
02813    } else if (!strcmp(iks_name(node), "failure")) {
02814       /* Authentication was a bust, disconnect and reconnect later */
02815       return -1;
02816    } else if (strcmp(iks_name(node), "stream:features")) {
02817       /* Ignore any other responses */
02818       return 0;
02819    }
02820 
02821    features = iks_stream_features(node);
02822 
02823    if (features & IKS_STREAM_BIND) {
02824       iks *auth;
02825 
02826       if (!(auth = iks_make_resource_bind(client->jid))) {
02827          ast_log(LOG_ERROR, "Failed to allocate memory for stream bind on client '%s'\n", client->name);
02828          return -1;
02829       }
02830 
02831       ast_xmpp_client_lock(client);
02832       iks_insert_attrib(auth, "id", client->mid);
02833       ast_xmpp_increment_mid(client->mid);
02834       ast_xmpp_client_unlock(client);
02835       ast_xmpp_client_send(client, auth);
02836 
02837       iks_delete(auth);
02838 
02839       iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
02840    }
02841 
02842    if (features & IKS_STREAM_SESSION) {
02843       iks *auth;
02844 
02845       if (!(auth = iks_make_session())) {
02846          ast_log(LOG_ERROR, "Failed to allocate memory for stream session on client '%s'\n", client->name);
02847          return -1;
02848       }
02849 
02850       iks_insert_attrib(auth, "id", "auth");
02851       ast_xmpp_client_lock(client);
02852       ast_xmpp_increment_mid(client->mid);
02853       ast_xmpp_client_unlock(client);
02854       ast_xmpp_client_send(client, auth);
02855 
02856       iks_delete(auth);
02857 
02858       iks_filter_add_rule(client->filter, xmpp_connect_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
02859    }
02860 
02861    return 0;
02862 }

static void xmpp_client_change_state ( struct ast_xmpp_client client,
int  state 
) [static]

static int xmpp_client_config_merge_buddies ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 3818 of file res_xmpp.c.

References ao2_find, ao2_link, ao2_ref, ast_xmpp_buddy::id, and OBJ_KEY.

Referenced by xmpp_client_config_post_apply().

03819 {
03820    struct ast_xmpp_buddy *buddy1 = obj, *buddy2;
03821    struct ao2_container *buddies = arg;
03822 
03823    /* If the buddy does not already exist link it into the client buddies container */
03824    if (!(buddy2 = ao2_find(buddies, buddy1->id, OBJ_KEY))) {
03825       ao2_link(buddies, buddy1);
03826    } else {
03827       ao2_ref(buddy2, -1);
03828    }
03829 
03830    /* All buddies are unlinked from the configuration buddies container, always */
03831    return 1;
03832 }

static int xmpp_client_config_post_apply ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 3834 of file res_xmpp.c.

References ao2_callback, ao2_cleanup, ao2_global_obj_ref, ast_copy_flags, ast_log, ast_pthread_create_background, ast_strlen_zero, ast_test_flag, ast_xmpp_client_disconnect(), ast_xmpp_client::buddies, ast_xmpp_client_config::buddies, ast_xmpp_client_config::client, ast_flags::flags, ast_xmpp_client_config::flags, globals, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client_config::mod_flags, ast_xmpp_client_config::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_xmpp_client::parser, RAII_VAR, ast_xmpp_client::reconnect, ast_xmpp_client::stack, ast_xmpp_client::state, ast_xmpp_client_config::status, ast_xmpp_client_config::statusmsg, ast_xmpp_client::thread, ast_xmpp_client_config::user, xmpp_action_hook(), XMPP_AUTOACCEPT, XMPP_AUTOPRUNE, XMPP_AUTOREGISTER, xmpp_client_config_merge_buddies(), xmpp_client_set_presence(), xmpp_client_subscribe_user(), xmpp_client_thread(), XMPP_COMPONENT, xmpp_log_hook(), and XMPP_STATE_CONNECTED.

Referenced by xmpp_config_post_apply().

03835 {
03836    struct ast_xmpp_client_config *cfg = obj;
03837    RAII_VAR(struct xmpp_config *, gcfg, ao2_global_obj_ref(globals), ao2_cleanup);
03838 
03839    /* Merge global options that have not been modified */
03840    ast_copy_flags(&cfg->flags, &gcfg->global->general, ~(cfg->mod_flags.flags) & (XMPP_AUTOPRUNE | XMPP_AUTOREGISTER | XMPP_AUTOACCEPT));
03841 
03842    /* Merge buddies as need be */
03843    ao2_callback(cfg->buddies, OBJ_MULTIPLE | OBJ_UNLINK, xmpp_client_config_merge_buddies, cfg->client->buddies);
03844 
03845    if (cfg->client->reconnect) {
03846       /* Disconnect the existing session since our role is changing, or we are starting up */
03847       ast_xmpp_client_disconnect(cfg->client);
03848 
03849       if (!(cfg->client->parser = iks_stream_new(ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client", cfg->client,
03850                         xmpp_action_hook))) {
03851          ast_log(LOG_ERROR, "Iksemel stream could not be created for client '%s' - client not active\n", cfg->name);
03852          return -1;
03853       }
03854 
03855       iks_set_log_hook(cfg->client->parser, xmpp_log_hook);
03856 
03857       /* Create a JID based on the given user, if no resource is given use the default */
03858       if (!strchr(cfg->user, '/') && !ast_test_flag(&cfg->flags, XMPP_COMPONENT)) {
03859          char resource[strlen(cfg->user) + strlen("/asterisk-xmpp") + 1];
03860 
03861          snprintf(resource, sizeof(resource), "%s/asterisk-xmpp", cfg->user);
03862          cfg->client->jid = iks_id_new(cfg->client->stack, resource);
03863       } else {
03864          cfg->client->jid = iks_id_new(cfg->client->stack, cfg->user);
03865       }
03866 
03867       if (!cfg->client->jid || ast_strlen_zero(cfg->client->jid->user)) {
03868          ast_log(LOG_ERROR, "Jabber identity '%s' could not be created for client '%s' - client not active\n", cfg->user, cfg->name);
03869          return -1;
03870       }
03871 
03872       ast_pthread_create_background(&cfg->client->thread, NULL, xmpp_client_thread, cfg->client);
03873 
03874       cfg->client->reconnect = 0;
03875    } else if (cfg->client->state == XMPP_STATE_CONNECTED) {
03876       /* If this client is connected update their presence status since it may have changed */
03877       xmpp_client_set_presence(cfg->client, NULL, cfg->client->jid->full, cfg->status, cfg->statusmsg);
03878 
03879       /* Subscribe to the status of any newly added buddies */
03880       if (ast_test_flag(&cfg->flags, XMPP_AUTOREGISTER)) {
03881          ao2_callback(cfg->client->buddies, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_subscribe_user, cfg->client);
03882       }
03883    }
03884 
03885    return 0;
03886 }

static struct ast_xmpp_buddy* xmpp_client_create_buddy ( struct ao2_container container,
const char *  id 
) [static, read]

Internal function which creates a buddy on a client.

Definition at line 2240 of file res_xmpp.c.

References ao2_alloc, ao2_container_alloc, ao2_link, ao2_ref, ast_copy_string(), ast_xmpp_buddy::id, NULL, RESOURCE_BUCKETS, ast_xmpp_buddy::resources, ast_xmpp_buddy::subscribe, xmpp_buddy_destructor(), xmpp_resource_cmp(), and xmpp_resource_hash().

Referenced by client_buddy_handler(), xmpp_pak_s10n(), and xmpp_roster_hook().

02241 {
02242    struct ast_xmpp_buddy *buddy;
02243 
02244    if (!(buddy = ao2_alloc(sizeof(*buddy), xmpp_buddy_destructor))) {
02245       return NULL;
02246    }
02247 
02248    if (!(buddy->resources = ao2_container_alloc(RESOURCE_BUCKETS, xmpp_resource_hash, xmpp_resource_cmp))) {
02249       ao2_ref(buddy, -1);
02250       return NULL;
02251    }
02252 
02253    ast_copy_string(buddy->id, id, sizeof(buddy->id));
02254 
02255    /* Assume we need to subscribe to get their presence until proven otherwise */
02256    buddy->subscribe = 1;
02257 
02258    ao2_link(container, buddy);
02259 
02260    return buddy;
02261 }

static void xmpp_client_destructor ( void *  obj  )  [static]

Destructor callback function for XMPP client.

Definition at line 556 of file res_xmpp.c.

References ao2_cleanup, ast_endpoint_shutdown(), AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, ast_xmpp_client_disconnect(), ast_xmpp_client::buddies, ast_xmpp_client::endpoint, ast_xmpp_client::filter, ast_xmpp_message::list, ast_xmpp_client::messages, NULL, ast_xmpp_client::stack, and xmpp_message_destroy().

Referenced by xmpp_client_alloc().

00557 {
00558    struct ast_xmpp_client *client = obj;
00559    struct ast_xmpp_message *message;
00560 
00561    ast_xmpp_client_disconnect(client);
00562 
00563    ast_endpoint_shutdown(client->endpoint);
00564    ao2_cleanup(client->endpoint);
00565    client->endpoint = NULL;
00566 
00567    if (client->filter) {
00568       iks_filter_delete(client->filter);
00569    }
00570 
00571    if (client->stack) {
00572       iks_stack_delete(client->stack);
00573    }
00574 
00575    ao2_cleanup(client->buddies);
00576 
00577    while ((message = AST_LIST_REMOVE_HEAD(&client->messages, list))) {
00578       xmpp_message_destroy(message);
00579    }
00580    AST_LIST_HEAD_DESTROY(&client->messages);
00581 }

static void* xmpp_client_find_or_create ( const char *  category  )  [static]

Look up existing client or create a new one.

Definition at line 667 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_ref, globals, NULL, RAII_VAR, xmpp_client_alloc(), and xmpp_config_find().

Referenced by ast_xmpp_client_config_alloc().

00668 {
00669    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00670    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
00671 
00672    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, category))) {
00673       return xmpp_client_alloc(category);
00674    }
00675 
00676    ao2_ref(clientcfg->client, +1);
00677    return clientcfg->client;
00678 }

static int xmpp_client_receive ( struct ast_xmpp_client client,
unsigned int  timeout 
) [static]

Internal function which receives data from the XMPP client connection.

Definition at line 3677 of file res_xmpp.c.

References ast_debug, ast_log, buf, c, IKS_NET_EXPIRED, ast_xmpp_client::jid, len(), LOG_WARNING, ast_xmpp_client::name, NET_IO_BUF_SIZE, newbuf(), ast_xmpp_client::parser, xmpp_io_recv(), xmpp_log_hook(), and xmpp_ping_request().

Referenced by xmpp_client_thread().

03678 {
03679    int len, ret, pos = 0, newbufpos = 0;
03680    char buf[NET_IO_BUF_SIZE - 1] = "";
03681    char newbuf[NET_IO_BUF_SIZE - 1] = "";
03682    unsigned char c;
03683 
03684    while (1) {
03685       len = xmpp_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
03686       if (len < 0) return IKS_NET_RWERR;
03687       if (len == 0) return IKS_NET_EXPIRED;
03688       buf[len] = '\0';
03689 
03690       /* our iksemel parser won't work as expected if we feed
03691          it with XML packets that contain multiple whitespace
03692          characters between tags */
03693       while (pos < len) {
03694          c = buf[pos];
03695          /* if we stumble on the ending tag character,
03696             we skip any whitespace that follows it*/
03697          if (c == '>') {
03698             while (isspace(buf[pos+1])) {
03699                pos++;
03700             }
03701          }
03702          newbuf[newbufpos] = c;
03703          newbufpos++;
03704          pos++;
03705       }
03706       pos = 0;
03707       newbufpos = 0;
03708 
03709       /* Log the message here, because iksemel's logHook is
03710          unaccessible */
03711       xmpp_log_hook(client, buf, len, 1);
03712       
03713       if(buf[0] == ' ') {
03714          ast_debug(1, "JABBER: Detected Google Keep Alive. "
03715             "Sending out Ping request for client '%s'\n", client->name);
03716          /* If we just send out the ping here then we will have socket
03717           * read errors because the socket will timeout */
03718          xmpp_ping_request(client, client->jid->server, client->jid->full);
03719       }
03720 
03721       /* let iksemel deal with the string length,
03722          and reset our buffer */
03723       ret = iks_parse(client->parser, newbuf, 0, 0);
03724       memset(newbuf, 0, sizeof(newbuf));
03725 
03726       switch (ret) {
03727       case IKS_NOMEM:
03728          ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
03729          break;
03730       case IKS_BADXML:
03731          ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
03732          break;
03733       case IKS_HOOK:
03734          ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
03735          break;
03736       }
03737       if (ret != IKS_OK) {
03738          return ret;
03739       }
03740       ast_debug(3, "XML parsing successful\n");
03741    }
03742    return IKS_OK;
03743 }

static int xmpp_client_reconnect ( struct ast_xmpp_client client  )  [static]

Internal function used to reconnect an XMPP client to its server.

Definition at line 3600 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_log, ast_test_flag, ast_xmpp_client_disconnect(), ast_xmpp_client::filter, globals, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::name, NULL, ast_xmpp_client::parser, RAII_VAR, S_OR, ast_xmpp_client::timeout, xmpp_client_change_state(), XMPP_COMPONENT, xmpp_config_find(), XMPP_STATE_AUTHENTICATE, XMPP_STATE_REQUEST_TLS, and XMPP_USETLS.

Referenced by xmpp_client_thread().

03601 {
03602    struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
03603    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
03604    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
03605    int res = IKS_NET_NOCONN;
03606 
03607    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
03608       return -1;
03609    }
03610 
03611    ast_xmpp_client_disconnect(client);
03612 
03613    client->timeout = 50;
03614    iks_parser_reset(client->parser);
03615 
03616    if (!client->filter && !(client->filter = iks_filter_new())) {
03617       ast_log(LOG_ERROR, "Could not create IKS filter for client connection '%s'\n", client->name);
03618       return -1;
03619    }
03620 
03621    /* If it's a component connect to user otherwise connect to server */
03622    res = iks_connect_via(client->parser, S_OR(clientcfg->server, client->jid->server), clientcfg->port,
03623                ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) ? clientcfg->user : client->jid->server);
03624 
03625    /* Set socket timeout options */
03626    setsockopt(iks_fd(client->parser), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
03627    
03628    if (res == IKS_NET_NOCONN) {
03629       ast_log(LOG_ERROR, "No XMPP connection available when trying to connect client '%s'\n", client->name);
03630       return -1;
03631    } else if (res == IKS_NET_NODNS) {
03632       ast_log(LOG_ERROR, "No DNS available for XMPP connection when trying to connect client '%s'\n", client->name);
03633       return -1;
03634    }
03635 
03636    /* Depending on the configuration of the client we eiher jump to requesting TLS, or authenticating */
03637    xmpp_client_change_state(client, (ast_test_flag(&clientcfg->flags, XMPP_USETLS) ? XMPP_STATE_REQUEST_TLS : XMPP_STATE_AUTHENTICATE));
03638 
03639    return 0;
03640 }

static int xmpp_client_request_tls ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we need to request TLS support.

Definition at line 2609 of file res_xmpp.c.

References ast_log, LOG_ERROR, ast_xmpp_client::name, ast_xmpp_client::parser, xmpp_client_change_state(), xmpp_is_secure(), XMPP_STATE_AUTHENTICATE, and XMPP_STATE_REQUESTED_TLS.

02610 {
02611    /* If the client connection is already secure we can jump straight to authenticating */
02612    if (xmpp_is_secure(client)) {
02613       xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
02614       return 0;
02615    }
02616 
02617 #ifndef HAVE_OPENSSL
02618    ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL is not available.\n", client->name);
02619    return -1;
02620 #else
02621    if (iks_send_raw(client->parser, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>") == IKS_NET_TLSFAIL) {
02622       ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be started.\n", client->name);
02623       return -1;
02624    }
02625 
02626    client->stream_flags |= TRY_SECURE;
02627 
02628    xmpp_client_change_state(client, XMPP_STATE_REQUESTED_TLS);
02629 
02630    return 0;
02631 #endif
02632 }

static int xmpp_client_requested_tls ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we receive a response to our TLS initiation request.

Definition at line 2635 of file res_xmpp.c.

References ast_debug, ast_log, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::name, ast_xmpp_client::parser, xmpp_client_change_state(), xmpp_send_stream_header(), and XMPP_STATE_AUTHENTICATE.

02636 {
02637 #ifdef HAVE_OPENSSL
02638    int sock;
02639    long ssl_opts;
02640 #endif
02641 
02642    if (!strcmp(iks_name(node), "success")) {
02643       /* TLS is up and working, we can move on to authenticating now */
02644       xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
02645       return 0;
02646    } else if (!strcmp(iks_name(node), "failure")) {
02647       /* TLS negotiation was a failure, close it on down! */
02648       return -1;
02649    } else if (strcmp(iks_name(node), "proceed")) {
02650       /* Ignore any other responses */
02651       return 0;
02652    }
02653 
02654 #ifndef HAVE_OPENSSL
02655    ast_log(LOG_ERROR, "Somehow we managed to try to start TLS negotiation on client '%s' without OpenSSL support, disconnecting\n", client->name);
02656    return -1;
02657 #else
02658    client->ssl_method = SSLv23_method();
02659    if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
02660       goto failure;
02661    }
02662 
02663    ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
02664    SSL_CTX_set_options(client->ssl_context, ssl_opts);
02665 
02666    if (!(client->ssl_session = SSL_new(client->ssl_context))) {
02667       goto failure;
02668    }
02669 
02670    sock = iks_fd(client->parser);
02671    if (!SSL_set_fd(client->ssl_session, sock)) {
02672       goto failure;
02673    }
02674 
02675    if (!SSL_connect(client->ssl_session)) {
02676       goto failure;
02677    }
02678 
02679    client->stream_flags &= (~TRY_SECURE);
02680    client->stream_flags |= SECURE;
02681 
02682    if (xmpp_send_stream_header(client, cfg, client->jid->server) != IKS_OK) {
02683       ast_log(LOG_ERROR, "TLS connection for client '%s' could not be established, failed to send stream header after negotiation\n",
02684          client->name);
02685       return -1;
02686    }
02687 
02688    ast_debug(1, "TLS connection for client '%s' started with server\n", client->name);
02689 
02690    xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
02691 
02692    return 0;
02693 
02694 failure:
02695    ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name);
02696    return -1;
02697 #endif
02698 }

static int xmpp_client_send_disco_info_request ( struct ast_xmpp_client client,
const char *  to,
const char *  from 
) [static]

Helper function which sends a discovery information request to a user.

Definition at line 3229 of file res_xmpp.c.

References ast_xmpp_client_lock(), ast_xmpp_client_send(), ast_xmpp_client_unlock(), ast_xmpp_increment_mid(), and ast_xmpp_client::mid.

Referenced by xmpp_pak_presence().

03230 {
03231    iks *iq, *query;
03232    int res;
03233 
03234    if (!(iq = iks_new("iq")) || !(query = iks_new("query"))) {
03235       iks_delete(iq);
03236       return -1;
03237    }
03238 
03239    iks_insert_attrib(iq, "type", "get");
03240    iks_insert_attrib(iq, "to", to);
03241    iks_insert_attrib(iq, "from", from);
03242    ast_xmpp_client_lock(client);
03243    iks_insert_attrib(iq, "id", client->mid);
03244    ast_xmpp_increment_mid(client->mid);
03245    ast_xmpp_client_unlock(client);
03246    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
03247    iks_insert_node(iq, query);
03248 
03249    res = ast_xmpp_client_send(client, iq);
03250 
03251    iks_delete(query);
03252    iks_delete(iq);
03253 
03254    return res;
03255 }

static int xmpp_client_send_message ( struct ast_xmpp_client client,
int  group,
const char *  nick,
const char *  address,
const char *  message 
) [static]

Internal function used to send a message to a user or chatroom.

Definition at line 911 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_strlen_zero, ast_test_flag, ast_xmpp_client_send(), globals, ast_xmpp_client::jid, ast_xmpp_client::name, NULL, RAII_VAR, XMPP_COMPONENT, xmpp_config_find(), and XMPP_MAX_JIDLEN.

Referenced by ast_xmpp_chatroom_send(), and ast_xmpp_client_send_message().

00912 {
00913    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00914    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
00915    int res = 0;
00916    char from[XMPP_MAX_JIDLEN];
00917    iks *message_packet;
00918 
00919    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
00920        !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
00921       return -1;
00922    }
00923 
00924    if (!ast_strlen_zero(nick) && ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
00925       snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
00926    } else {
00927       snprintf(from, sizeof(from), "%s", client->jid->full);
00928    }
00929 
00930    iks_insert_attrib(message_packet, "from", from);
00931 
00932    res = ast_xmpp_client_send(client, message_packet);
00933 
00934    iks_delete(message_packet);
00935 
00936    return res;
00937 }

static int xmpp_client_send_raw_message ( struct ast_xmpp_client client,
const char *  message 
) [static]

Internal function which sends a raw message.

Definition at line 2564 of file res_xmpp.c.

References len(), ast_xmpp_client::parser, xmpp_is_secure(), and xmpp_log_hook().

Referenced by ast_xmpp_client_send(), xmpp_component_authenticate(), and xmpp_send_stream_header().

02565 {
02566    int ret;
02567 #ifdef HAVE_OPENSSL
02568    int len = strlen(message);
02569 
02570    if (xmpp_is_secure(client)) {
02571       ret = SSL_write(client->ssl_session, message, len);
02572       if (ret) {
02573          /* Log the message here, because iksemel's logHook is
02574             unaccessible */
02575          xmpp_log_hook(client, message, len, 0);
02576          return IKS_OK;
02577       }
02578    }
02579 #endif
02580    /* If needed, data will be sent unencrypted, and logHook will
02581       be called inside iks_send_raw */
02582    ret = iks_send_raw(client->parser, message);
02583    if (ret != IKS_OK) {
02584       return ret;
02585    }
02586 
02587    return IKS_OK;
02588 }

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

Hook function called when client receives a service discovery get message.

Definition at line 2418 of file res_xmpp.c.

References ast_log, ast_xmpp_client_send(), end, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::name, and NULL.

Referenced by xmpp_connect_hook().

02419 {
02420    struct ast_xmpp_client *client = data;
02421    iks *iq, *disco = NULL, *ident = NULL, *google = NULL, *jingle = NULL, *ice = NULL, *rtp = NULL, *audio = NULL, *video = NULL, *query = NULL;
02422 
02423    if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(ident = iks_new("identity")) || !(disco = iks_new("feature")) ||
02424        !(google = iks_new("feature")) || !(jingle = iks_new("feature")) || !(ice = iks_new("feature")) || !(rtp = iks_new("feature")) ||
02425        !(audio = iks_new("feature")) || !(video = iks_new("feature"))) {
02426       ast_log(LOG_ERROR, "Could not allocate memory for responding to service discovery request from '%s' on client '%s'\n",
02427          pak->from->full, client->name);
02428       goto end;
02429    }
02430 
02431    iks_insert_attrib(iq, "from", client->jid->full);
02432 
02433    if (pak->from) {
02434       iks_insert_attrib(iq, "to", pak->from->full);
02435    }
02436 
02437    iks_insert_attrib(iq, "type", "result");
02438    iks_insert_attrib(iq, "id", pak->id);
02439    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02440    iks_insert_attrib(ident, "category", "client");
02441    iks_insert_attrib(ident, "type", "pc");
02442    iks_insert_attrib(ident, "name", "asterisk");
02443    iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
02444 
02445    iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
02446    iks_insert_attrib(jingle, "var", "urn:xmpp:jingle:1");
02447    iks_insert_attrib(ice, "var", "urn:xmpp:jingle:transports:ice-udp:1");
02448    iks_insert_attrib(rtp, "var", "urn:xmpp:jingle:apps:rtp:1");
02449    iks_insert_attrib(audio, "var", "urn:xmpp:jingle:apps:rtp:audio");
02450    iks_insert_attrib(video, "var", "urn:xmpp:jingle:apps:rtp:video");
02451    iks_insert_node(iq, query);
02452    iks_insert_node(query, ident);
02453    iks_insert_node(query, google);
02454    iks_insert_node(query, disco);
02455    iks_insert_node(query, jingle);
02456    iks_insert_node(query, ice);
02457    iks_insert_node(query, rtp);
02458    iks_insert_node(query, audio);
02459    iks_insert_node(query, video);
02460    ast_xmpp_client_send(client, iq);
02461 
02462 end:
02463    iks_delete(query);
02464    iks_delete(video);
02465    iks_delete(audio);
02466    iks_delete(rtp);
02467    iks_delete(ice);
02468    iks_delete(jingle);
02469    iks_delete(google);
02470    iks_delete(ident);
02471    iks_delete(disco);
02472    iks_delete(iq);
02473 
02474    return IKS_FILTER_EAT;
02475 }

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

Hook function called when client receives a service discovery result message.

Definition at line 2478 of file res_xmpp.c.

References ao2_callback, ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_xmpp_client::buddies, ast_xmpp_resource::caps, ast_xmpp_capabilities::jingle, OBJ_KEY, ast_xmpp_resource::resource, ast_xmpp_buddy::resources, and xmpp_resource_cmp().

Referenced by xmpp_component_authenticating(), and xmpp_connect_hook().

02479 {
02480    struct ast_xmpp_client *client = data;
02481    struct ast_xmpp_buddy *buddy;
02482    struct ast_xmpp_resource *resource;
02483 
02484    if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
02485       return IKS_FILTER_EAT;
02486    }
02487 
02488    if (!(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, pak->from->resource))) {
02489       ao2_ref(buddy, -1);
02490       return IKS_FILTER_EAT;
02491    }
02492 
02493    ao2_lock(resource);
02494 
02495    if (iks_find_with_attrib(pak->query, "feature", "var", "urn:xmpp:jingle:1")) {
02496       resource->caps.jingle = 1;
02497    }
02498 
02499    ao2_unlock(resource);
02500 
02501    ao2_ref(resource, -1);
02502    ao2_ref(buddy, -1);
02503 
02504    return IKS_FILTER_EAT;
02505 }

static int xmpp_client_set_group_presence ( struct ast_xmpp_client client,
const char *  room,
int  level,
const char *  nick 
) [static]

Definition at line 975 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_test_flag, ast_xmpp_client_send(), globals, ast_xmpp_client::jid, ast_xmpp_client::name, NULL, RAII_VAR, S_OR, XMPP_COMPONENT, xmpp_config_find(), and XMPP_MAX_JIDLEN.

Referenced by ast_xmpp_chatroom_join(), and ast_xmpp_chatroom_leave().

00976 {
00977    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00978    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
00979    int res = 0;
00980    iks *presence = NULL, *x = NULL;
00981    char from[XMPP_MAX_JIDLEN], roomid[XMPP_MAX_JIDLEN];
00982 
00983    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
00984        !(presence = iks_make_pres(level, NULL)) || !(x = iks_new("x"))) {
00985       res = -1;
00986       goto done;
00987    }
00988 
00989    if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
00990       snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
00991       snprintf(roomid, sizeof(roomid), "%s/%s", room, nick);
00992    } else {
00993       snprintf(from, sizeof(from), "%s", client->jid->full);
00994       snprintf(roomid, sizeof(roomid), "%s/%s", room, S_OR(nick, client->jid->user));
00995    }
00996 
00997    iks_insert_attrib(presence, "to", roomid);
00998    iks_insert_attrib(presence, "from", from);
00999    iks_insert_attrib(x, "xmlns", "http://jabber.org/protocol/muc");
01000    iks_insert_node(presence, x);
01001 
01002    res = ast_xmpp_client_send(client, presence);
01003 
01004 done:
01005    iks_delete(x);
01006    iks_delete(presence);
01007 
01008    return res;
01009 }

static void xmpp_client_set_presence ( struct ast_xmpp_client client,
const char *  to,
const char *  from,
int  level,
const char *  desc 
) [static]

Internal function which changes the presence status of an XMPP client.

Definition at line 2380 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_log, ast_strlen_zero, ast_xmpp_client_send(), globals, LOG_ERROR, ast_xmpp_client::name, NULL, RAII_VAR, and xmpp_config_find().

Referenced by xmpp_client_config_post_apply(), xmpp_connect_hook(), xmpp_pak_presence(), and xmpp_pak_s10n().

02381 {
02382    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02383    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02384    iks *presence = NULL, *cnode = NULL, *priority = NULL;
02385    char priorityS[10];
02386 
02387    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
02388        !(presence = iks_make_pres(level, desc)) || !(cnode = iks_new("c")) || !(priority = iks_new("priority"))) {
02389       ast_log(LOG_ERROR, "Unable to allocate stanzas for setting presence status for client '%s'\n", client->name);
02390       goto done;
02391    }
02392 
02393    if (!ast_strlen_zero(to)) {
02394       iks_insert_attrib(presence, "to", to);
02395    }
02396 
02397    if (!ast_strlen_zero(from)) {
02398       iks_insert_attrib(presence, "from", from);
02399    }
02400 
02401    snprintf(priorityS, sizeof(priorityS), "%d", clientcfg->priority);
02402    iks_insert_cdata(priority, priorityS, strlen(priorityS));
02403    iks_insert_node(presence, priority);
02404    iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
02405    iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
02406    iks_insert_attrib(cnode, "ext", "voice-v1 video-v1 camera-v1");
02407    iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
02408    iks_insert_node(presence, cnode);
02409    ast_xmpp_client_send(client, presence);
02410 
02411 done:
02412    iks_delete(cnode);
02413    iks_delete(presence);
02414    iks_delete(priority);
02415 }

static int xmpp_client_subscribe_user ( void *  obj,
void *  arg,
int  flags 
) [static]

Callback function which subscribes to a user if needed.

Definition at line 2301 of file res_xmpp.c.

References ast_log, ast_xmpp_client_send(), ast_xmpp_buddy::id, LOG_WARNING, ast_xmpp_client::name, and ast_xmpp_buddy::subscribe.

Referenced by xmpp_client_config_post_apply(), and xmpp_roster_hook().

02302 {
02303    struct ast_xmpp_buddy *buddy = obj;
02304    struct ast_xmpp_client *client = arg;
02305 
02306    if (!buddy->subscribe) {
02307       return 0;
02308    }
02309 
02310    if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, buddy->id,
02311                          "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"))) {
02312       ast_log(LOG_WARNING, "Could not send subscription for '%s' on client '%s'\n",
02313          buddy->id, client->name);
02314    }
02315 
02316    buddy->subscribe = 0;
02317 
02318    return 0;
02319 }

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

XMPP client connection thread.

Definition at line 3746 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_debug, ast_log, ast_test_flag, globals, IKS_NET_EXPIRED, ast_xmpp_client::jid, LOG_ERROR, LOG_WARNING, ast_xmpp_client::name, NULL, RAII_VAR, ast_xmpp_client::state, ast_xmpp_client::timeout, xmpp_client_receive(), xmpp_client_reconnect(), xmpp_config_find(), XMPP_KEEPALIVE, xmpp_ping_request(), XMPP_STATE_CONNECTED, and XMPP_STATE_DISCONNECTING.

Referenced by xmpp_client_config_post_apply().

03747 {
03748    struct ast_xmpp_client *client = data;
03749    int res = IKS_NET_RWERR;
03750 
03751    do {
03752       if (client->state == XMPP_STATE_DISCONNECTING) {
03753          ast_debug(1, "JABBER: Disconnecting client '%s'\n", client->name);
03754          break;
03755       }
03756 
03757       if (res == IKS_NET_RWERR || client->timeout == 0) {
03758          ast_debug(3, "Connecting client '%s'\n", client->name);
03759          if ((res = xmpp_client_reconnect(client)) != IKS_OK) {
03760             sleep(4);
03761             res = IKS_NET_RWERR;
03762          }
03763          continue;
03764       }
03765 
03766       res = xmpp_client_receive(client, 1);
03767 
03768       /* Decrease timeout if no data received, and delete
03769        * old messages globally */
03770       if (res == IKS_NET_EXPIRED) {
03771          client->timeout--;
03772       }
03773 
03774       if (res == IKS_HOOK) {
03775          ast_debug(2, "JABBER: Got hook event.\n");
03776       } else if (res == IKS_NET_TLSFAIL) {
03777          ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
03778       } else if (!client->timeout && client->state == XMPP_STATE_CONNECTED) {
03779          RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
03780          RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
03781 
03782          if (cfg && cfg->clients) {
03783             clientcfg = xmpp_config_find(cfg->clients, client->name);
03784          }
03785 
03786          if (clientcfg && ast_test_flag(&clientcfg->flags, XMPP_KEEPALIVE)) {
03787             res = xmpp_ping_request(client, client->jid->server, client->jid->full);
03788          } else {
03789             res = IKS_OK;
03790          }
03791 
03792          if (res == IKS_OK) {
03793             client->timeout = 50;
03794          } else {
03795             ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
03796          }
03797       } else if (res == IKS_NET_RWERR) {
03798          ast_log(LOG_WARNING, "JABBER: socket read error\n");
03799       } else if (res == IKS_NET_NOSOCK) {
03800          ast_log(LOG_WARNING, "JABBER: No Socket\n");
03801       } else if (res == IKS_NET_NOCONN) {
03802          ast_log(LOG_WARNING, "JABBER: No Connection\n");
03803       } else if (res == IKS_NET_NODNS) {
03804          ast_log(LOG_WARNING, "JABBER: No DNS\n");
03805       } else if (res == IKS_NET_NOTSUPP) {
03806          ast_log(LOG_WARNING, "JABBER: Not Supported\n");
03807       } else if (res == IKS_NET_DROPPED) {
03808          ast_log(LOG_WARNING, "JABBER: Dropped?\n");
03809       } else if (res == IKS_NET_UNKNOWN) {
03810          ast_debug(5, "JABBER: Unknown\n");
03811       }
03812 
03813    } while (1);
03814 
03815    return NULL;
03816 }

static int xmpp_client_unsubscribe_user ( struct ast_xmpp_client client,
const char *  user 
) [static]

Helper function which unsubscribes a user and removes them from the roster.

Definition at line 2264 of file res_xmpp.c.

References ast_log, ast_xmpp_client_send(), item, ast_xmpp_client::jid, LOG_WARNING, ast_xmpp_client::name, and NULL.

Referenced by xmpp_roster_hook().

02265 {
02266    iks *iq, *query = NULL, *item = NULL;
02267 
02268    if (ast_xmpp_client_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, user,
02269                          "Goodbye. Your status is no longer required.\n"))) {
02270       return -1;
02271    }
02272 
02273    if (!(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item"))) {
02274       ast_log(LOG_WARNING, "Could not allocate memory for roster removal of '%s' from client '%s'\n",
02275          user, client->name);
02276       goto done;
02277    }
02278 
02279    iks_insert_attrib(iq, "from", client->jid->full);
02280    iks_insert_attrib(iq, "type", "set");
02281    iks_insert_attrib(query, "xmlns", "jabber:iq:roster");
02282    iks_insert_node(iq, query);
02283    iks_insert_attrib(item, "jid", user);
02284    iks_insert_attrib(item, "subscription", "remove");
02285    iks_insert_node(query, item);
02286 
02287    if (ast_xmpp_client_send(client, iq)) {
02288       ast_log(LOG_WARNING, "Could not send roster removal request of '%s' from client '%s'\n",
02289          user, client->name);
02290    }
02291 
02292 done:
02293    iks_delete(item);
02294    iks_delete(query);
02295    iks_delete(iq);
02296 
02297    return 0;
02298 }

static int xmpp_component_authenticate ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we should authenticate as a component.

Definition at line 2865 of file res_xmpp.c.

References ast_log, ast_sha1_hash(), LOG_ERROR, ast_xmpp_client::name, ast_xmpp_client_config::password, xmpp_client_change_state(), xmpp_client_send_raw_message(), and XMPP_STATE_AUTHENTICATING.

02866 {
02867    char secret[160], shasum[320], message[344];
02868    ikspak *pak = iks_packet(node);
02869 
02870    snprintf(secret, sizeof(secret), "%s%s", pak->id, cfg->password);
02871    ast_sha1_hash(shasum, secret);
02872    snprintf(message, sizeof(message), "<handshake>%s</handshake>", shasum);
02873 
02874    if (xmpp_client_send_raw_message(client, message) != IKS_OK) {
02875       ast_log(LOG_ERROR, "Unable to send handshake for component '%s'\n", client->name);
02876       return -1;
02877    }
02878 
02879    xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATING);
02880 
02881    return 0;
02882 }

static int xmpp_component_authenticating ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
int  type,
iks *  node 
) [static]

Internal function called when we authenticated as a component.

Definition at line 3131 of file res_xmpp.c.

References ast_log, ast_xmpp_client::filter, LOG_ERROR, ast_xmpp_client::name, xmpp_client_change_state(), xmpp_client_service_discovery_result_hook(), xmpp_component_register_get_hook(), xmpp_component_register_set_hook(), xmpp_component_service_discovery_get_hook(), xmpp_component_service_discovery_items_hook(), and XMPP_STATE_CONNECTED.

03132 {
03133    if (strcmp(iks_name(node), "handshake")) {
03134       ast_log(LOG_ERROR, "Failed to authenticate component '%s'\n", client->name);
03135       return -1;
03136    }
03137 
03138    iks_filter_add_rule(client->filter, xmpp_component_service_discovery_items_hook, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
03139 
03140    iks_filter_add_rule(client->filter, xmpp_component_service_discovery_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
03141 
03142    /* This uses the client service discovery result hook on purpose, as the code is common between both */
03143    iks_filter_add_rule(client->filter, xmpp_client_service_discovery_result_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
03144 
03145    iks_filter_add_rule(client->filter, xmpp_component_register_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
03146    iks_filter_add_rule(client->filter, xmpp_component_register_set_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
03147 
03148    xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
03149 
03150    return 0;
03151 }

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

Hook function called when the component is queried about registration.

Definition at line 2972 of file res_xmpp.c.

References ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_ref, ast_log, ast_xmpp_client_send(), ast_xmpp_client::buddies, error(), globals, LOG_ERROR, LOG_WARNING, ast_xmpp_client::name, NULL, OBJ_KEY, RAII_VAR, and xmpp_config_find().

Referenced by xmpp_component_authenticating().

02973 {
02974    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02975    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02976    struct ast_xmpp_client *client = data;
02977    iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL, *instructions = NULL;
02978    struct ast_xmpp_buddy *buddy;
02979    char *node;
02980 
02981    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
02982        !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(error = iks_new("error")) || !(notacceptable = iks_new("not-acceptable")) ||
02983        !(instructions = iks_new("instructions"))) {
02984       ast_log(LOG_ERROR, "Failed to allocate stanzas for register get response to '%s' on component '%s'\n",
02985          pak->from->partial, client->name);
02986       goto done;
02987    }
02988 
02989    iks_insert_attrib(iq, "from", clientcfg->user);
02990    iks_insert_attrib(iq, "to", pak->from->full);
02991    iks_insert_attrib(iq, "id", pak->id);
02992    iks_insert_attrib(iq, "type", "result");
02993    iks_insert_attrib(query, "xmlns", "jabber:iq:register");
02994    iks_insert_node(iq, query);
02995 
02996    if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
02997       iks_insert_attrib(error, "code", "406");
02998       iks_insert_attrib(error, "type", "modify");
02999       iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
03000 
03001       iks_insert_node(iq, error);
03002       iks_insert_node(error, notacceptable);
03003 
03004       ast_log(LOG_ERROR, "Received register attempt from '%s' but buddy is not configured on component '%s'\n",
03005          pak->from->partial, client->name);
03006    } else if (!(node = iks_find_attrib(pak->query, "node"))) {
03007       iks_insert_cdata(instructions, "Welcome to Asterisk - the Open Source PBX.\n", 0);
03008       iks_insert_node(query, instructions);
03009       ao2_ref(buddy, -1);
03010    } else {
03011       ast_log(LOG_WARNING, "Received register get to component '%s' using unsupported node '%s' from '%s'\n",
03012          client->name, node, pak->from->partial);
03013       ao2_ref(buddy, -1);
03014       goto done;
03015    }
03016 
03017    if (ast_xmpp_client_send(client, iq)) {
03018       ast_log(LOG_WARNING, "Could not send response to '%s' for received register get on component '%s'\n",
03019          pak->from->partial, client->name);
03020    }
03021 
03022 done:
03023    iks_delete(instructions);
03024    iks_delete(notacceptable);
03025    iks_delete(error);
03026    iks_delete(query);
03027    iks_delete(iq);
03028 
03029    return IKS_FILTER_EAT;
03030 }

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

Hook function called when someone registers to the component.

Definition at line 3033 of file res_xmpp.c.

References ast_log, ast_xmpp_client_lock(), ast_xmpp_client_send(), ast_xmpp_client_unlock(), ast_xmpp_increment_mid(), ast_xmpp_client::jid, LOG_ERROR, LOG_WARNING, ast_xmpp_client::mid, ast_xmpp_client::name, and NULL.

Referenced by xmpp_component_authenticating().

03034 {
03035    struct ast_xmpp_client *client = data;
03036    iks *iq, *presence = NULL, *x = NULL;
03037 
03038    if (!(iq = iks_new("iq")) || !(presence = iks_new("presence")) || !(x = iks_new("x"))) {
03039       ast_log(LOG_ERROR, "Failed to allocate stanzas for register set response to '%s' on component '%s'\n",
03040          pak->from->partial, client->name);
03041       goto done;
03042    }
03043 
03044    iks_insert_attrib(iq, "from", client->jid->full);
03045    iks_insert_attrib(iq, "to", pak->from->full);
03046    iks_insert_attrib(iq, "id", pak->id);
03047    iks_insert_attrib(iq, "type", "result");
03048 
03049    if (ast_xmpp_client_send(client, iq)) {
03050       ast_log(LOG_WARNING, "Could not send response to '%s' for received register set on component '%s'\n",
03051          pak->from->partial, client->name);
03052       goto done;
03053    }
03054 
03055    iks_insert_attrib(presence, "from", client->jid->full);
03056    iks_insert_attrib(presence, "to", pak->from->partial);
03057    ast_xmpp_client_lock(client);
03058    iks_insert_attrib(presence, "id", client->mid);
03059    ast_xmpp_increment_mid(client->mid);
03060    ast_xmpp_client_unlock(client);
03061    iks_insert_attrib(presence, "type", "subscribe");
03062    iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
03063 
03064    iks_insert_node(presence, x);
03065 
03066    if (ast_xmpp_client_send(client, presence)) {
03067       ast_log(LOG_WARNING, "Could not send subscription to '%s' on component '%s'\n",
03068          pak->from->partial, client->name);
03069    }
03070 
03071 done:
03072    iks_delete(x);
03073    iks_delete(presence);
03074    iks_delete(iq);
03075 
03076    return IKS_FILTER_EAT;
03077 }

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

Hook function called when component receives a service discovery get message.

Definition at line 2885 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_debug, ast_log, ast_xmpp_client_send(), commands, globals, item, LOG_ERROR, LOG_WARNING, ast_xmpp_client::name, NULL, RAII_VAR, version, and xmpp_config_find().

Referenced by xmpp_component_authenticating().

02886 {
02887    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02888    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02889    struct ast_xmpp_client *client = data;
02890    iks *iq = NULL, *query = NULL, *identity = NULL, *disco = NULL, *reg = NULL, *commands = NULL, *gateway = NULL;
02891    iks *version = NULL, *vcard = NULL, *search = NULL, *item = NULL;
02892    char *node;
02893 
02894    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
02895        !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(identity = iks_new("identity")) || !(disco = iks_new("feature")) ||
02896        !(reg = iks_new("feature")) || !(commands = iks_new("feature")) || !(gateway = iks_new("feature")) || !(version = iks_new("feature")) ||
02897        !(vcard = iks_new("feature")) || !(search = iks_new("search")) || !(item = iks_new("item"))) {
02898       ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery get response to '%s' on component '%s'\n",
02899          pak->from->partial, client->name);
02900       goto done;
02901    }
02902 
02903    iks_insert_attrib(iq, "from", clientcfg->user);
02904    iks_insert_attrib(iq, "to", pak->from->full);
02905    iks_insert_attrib(iq, "id", pak->id);
02906    iks_insert_attrib(iq, "type", "result");
02907 
02908    if (!(node = iks_find_attrib(pak->query, "node"))) {
02909       iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02910       iks_insert_attrib(identity, "category", "gateway");
02911       iks_insert_attrib(identity, "type", "pstn");
02912       iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
02913       iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
02914       iks_insert_attrib(reg, "var", "jabber:iq:register");
02915       iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
02916       iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
02917       iks_insert_attrib(version, "var", "jabber:iq:version");
02918       iks_insert_attrib(vcard, "var", "vcard-temp");
02919       iks_insert_attrib(search, "var", "jabber:iq:search");
02920 
02921       iks_insert_node(iq, query);
02922       iks_insert_node(query, identity);
02923       iks_insert_node(query, disco);
02924       iks_insert_node(query, reg);
02925       iks_insert_node(query, commands);
02926       iks_insert_node(query, gateway);
02927       iks_insert_node(query, version);
02928       iks_insert_node(query, vcard);
02929       iks_insert_node(query, search);
02930    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
02931       iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
02932       iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
02933       iks_insert_attrib(item, "node", "confirmaccount");
02934       iks_insert_attrib(item, "name", "Confirm account");
02935       iks_insert_attrib(item, "jid", clientcfg->user);
02936 
02937       iks_insert_node(iq, query);
02938       iks_insert_node(query, item);
02939    } else if (!strcasecmp(node, "confirmaccount")) {
02940       iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02941       iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
02942 
02943       iks_insert_node(iq, query);
02944       iks_insert_node(query, commands);
02945    } else {
02946       ast_debug(3, "Unsupported service discovery info request received with node '%s' on component '%s'\n",
02947            node, client->name);
02948       goto done;
02949    }
02950 
02951    if (ast_xmpp_client_send(client, iq)) {
02952       ast_log(LOG_WARNING, "Could not send response to service discovery request on component '%s'\n",
02953          client->name);
02954    }
02955 
02956 done:
02957    iks_delete(search);
02958    iks_delete(vcard);
02959    iks_delete(version);
02960    iks_delete(gateway);
02961    iks_delete(commands);
02962    iks_delete(reg);
02963    iks_delete(disco);
02964    iks_delete(identity);
02965    iks_delete(query);
02966    iks_delete(iq);
02967 
02968    return IKS_FILTER_EAT;
02969 }

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

Hook function called when we receive a service discovery items request.

Definition at line 3080 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_log, ast_xmpp_client_send(), globals, item, LOG_ERROR, LOG_WARNING, ast_xmpp_client::name, NULL, RAII_VAR, and xmpp_config_find().

Referenced by xmpp_component_authenticating().

03081 {
03082    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
03083    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
03084    struct ast_xmpp_client *client = data;
03085    iks *iq = NULL, *query = NULL, *item = NULL, *feature = NULL;
03086    char *node;
03087 
03088    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
03089        !(iq = iks_new("iq")) || !(query = iks_new("query")) || !(item = iks_new("item")) || !(feature = iks_new("feature"))) {
03090       ast_log(LOG_ERROR, "Failed to allocate stanzas for service discovery items response to '%s' on component '%s'\n",
03091          pak->from->partial, client->name);
03092       goto done;
03093    }
03094 
03095    iks_insert_attrib(iq, "from", clientcfg->user);
03096    iks_insert_attrib(iq, "to", pak->from->full);
03097    iks_insert_attrib(iq, "id", pak->id);
03098    iks_insert_attrib(iq, "type", "result");
03099    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03100    iks_insert_node(iq, query);
03101 
03102    if (!(node = iks_find_attrib(pak->query, "node"))) {
03103       iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
03104       iks_insert_attrib(item, "name", "Asterisk Commands");
03105       iks_insert_attrib(item, "jid", clientcfg->user);
03106 
03107       iks_insert_node(query, item);
03108    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
03109       iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
03110    } else {
03111       ast_log(LOG_WARNING, "Received service discovery items request to component '%s' using unsupported node '%s' from '%s'\n",
03112          client->name, node, pak->from->partial);
03113       goto done;
03114    }
03115 
03116    if (ast_xmpp_client_send(client, iq)) {
03117       ast_log(LOG_WARNING, "Could not send response to service discovery items request from '%s' on component '%s'\n",
03118          pak->from->partial, client->name);
03119    }
03120 
03121 done:
03122    iks_delete(feature);
03123    iks_delete(item);
03124    iks_delete(query);
03125    iks_delete(iq);
03126 
03127    return IKS_FILTER_EAT;
03128 }

static void* xmpp_config_alloc ( void   )  [static]

Allocator for XMPP configuration.

Definition at line 734 of file res_xmpp.c.

References ao2_alloc, ao2_container_alloc, ao2_ref, xmpp_config::clients, error(), xmpp_config::global, NULL, xmpp_config_cmp(), xmpp_config_destructor(), and xmpp_config_hash().

00735 {
00736    struct xmpp_config *cfg;
00737 
00738    if (!(cfg = ao2_alloc(sizeof(*cfg), xmpp_config_destructor))) {
00739       return NULL;
00740    }
00741 
00742    if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), NULL))) {
00743       goto error;
00744    }
00745 
00746    if (!(cfg->clients = ao2_container_alloc(1, xmpp_config_hash, xmpp_config_cmp))) {
00747       goto error;
00748    }
00749 
00750    return cfg;
00751 error:
00752    ao2_ref(cfg, -1);
00753    return NULL;
00754 }

static int xmpp_config_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Comparator function for configuration.

Definition at line 726 of file res_xmpp.c.

References CMP_MATCH, CMP_STOP, match(), ast_xmpp_client_config::name, and OBJ_KEY.

Referenced by xmpp_config_alloc().

00727 {
00728    struct ast_xmpp_client_config *one = obj, *two = arg;
00729    const char *match = (flags & OBJ_KEY) ? arg : two->name;
00730    return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
00731 }

static void xmpp_config_destructor ( void *  obj  )  [static]

Destructor for XMPP configuration.

Definition at line 710 of file res_xmpp.c.

References ao2_cleanup, xmpp_config::clients, and xmpp_config::global.

Referenced by xmpp_config_alloc().

00711 {
00712    struct xmpp_config *cfg = obj;
00713    ao2_cleanup(cfg->global);
00714    ao2_cleanup(cfg->clients);
00715 }

static void* xmpp_config_find ( struct ao2_container tmp_container,
const char *  category 
) [static]

static int xmpp_config_hash ( const void *  obj,
const int  flags 
) [static]

Hashing function for configuration.

Definition at line 718 of file res_xmpp.c.

References ast_str_case_hash(), ast_xmpp_client_config::name, name, and OBJ_KEY.

Referenced by xmpp_config_alloc().

00719 {
00720    const struct ast_xmpp_client_config *cfg = obj;
00721    const char *name = (flags & OBJ_KEY) ? obj : cfg->name;
00722    return ast_str_case_hash(name);
00723 }

static void xmpp_config_post_apply ( void   )  [static]

static int xmpp_config_prelink ( void *  newitem  )  [static]

Definition at line 756 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_log, ast_strlen_zero, ast_test_flag, ast_xmpp_client_config::client, ast_xmpp_client_config::flags, globals, LOG_ERROR, ast_xmpp_client_config::name, NULL, ast_xmpp_client_config::password, ast_xmpp_client_config::port, ast_xmpp_client_config::priority, RAII_VAR, ast_xmpp_client::reconnect, ast_xmpp_client_config::server, ast_xmpp_client_config::user, XMPP_COMPONENT, and xmpp_config_find().

00757 {
00758    struct ast_xmpp_client_config *clientcfg = newitem;
00759    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00760    RAII_VAR(struct ast_xmpp_client_config *, oldclientcfg, NULL, ao2_cleanup);
00761 
00762    if (ast_strlen_zero(clientcfg->user)) {
00763       ast_log(LOG_ERROR, "No user specified on client '%s'\n", clientcfg->name);
00764       return -1;
00765    } else if (ast_strlen_zero(clientcfg->password)) {
00766       ast_log(LOG_ERROR, "No password specified on client '%s'\n", clientcfg->name);
00767       return -1;
00768    } else if (ast_strlen_zero(clientcfg->server)) {
00769       ast_log(LOG_ERROR, "No server specified on client '%s'\n", clientcfg->name);
00770       return -1;
00771    }
00772 
00773    /* If this is a new connection force a reconnect */
00774    if (!cfg || !cfg->clients || !(oldclientcfg = xmpp_config_find(cfg->clients, clientcfg->name))) {
00775       clientcfg->client->reconnect = 1;
00776       return 0;
00777    }
00778 
00779    /* If any configuration options are changing that would require reconnecting set the bit so we will do so if possible */
00780    if (strcmp(clientcfg->user, oldclientcfg->user) ||
00781        strcmp(clientcfg->password, oldclientcfg->password) ||
00782        strcmp(clientcfg->server, oldclientcfg->server) ||
00783        (clientcfg->port != oldclientcfg->port) ||
00784        (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT) != ast_test_flag(&oldclientcfg->flags, XMPP_COMPONENT)) ||
00785        (clientcfg->priority != oldclientcfg->priority)) {
00786       clientcfg->client->reconnect = 1;
00787    } else {
00788       clientcfg->client->reconnect = 0;
00789    }
00790 
00791    return 0;
00792 }

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

Hook function called when client finishes authenticating with the server.

Definition at line 2508 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_log, ast_test_flag, ast_xmpp_client_send(), ast_xmpp_client::filter, globals, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::name, NULL, RAII_VAR, ast_xmpp_client::stack, xmpp_client_change_state(), xmpp_client_service_discovery_get_hook(), xmpp_client_service_discovery_result_hook(), xmpp_client_set_presence(), xmpp_config_find(), XMPP_DISTRIBUTE_EVENTS, xmpp_init_event_distribution(), xmpp_roster_hook(), and XMPP_STATE_ROSTER.

Referenced by xmpp_client_authenticate_digest(), and xmpp_client_authenticating().

02509 {
02510    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02511    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02512    struct ast_xmpp_client *client = data;
02513    iks *roster;
02514 
02515    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
02516       return -1;
02517    }
02518 
02519    client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
02520 
02521    if (ast_test_flag(&clientcfg->flags, XMPP_DISTRIBUTE_EVENTS)) {
02522       xmpp_init_event_distribution(client);
02523    }
02524 
02525    if (!(roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER))) {
02526       ast_log(LOG_ERROR, "Unable to allocate memory for roster request for client '%s'\n", client->name);
02527       return -1;
02528    }
02529 
02530    iks_filter_add_rule(client->filter, xmpp_client_service_discovery_get_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02531    iks_filter_add_rule(client->filter, xmpp_client_service_discovery_result_hook, client, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02532 
02533    iks_insert_attrib(roster, "id", "roster");
02534    ast_xmpp_client_send(client, roster);
02535 
02536    iks_filter_remove_hook(client->filter, xmpp_connect_hook);
02537    iks_filter_add_rule(client->filter, xmpp_roster_hook, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
02538 
02539    xmpp_client_set_presence(client, NULL, client->jid->full, clientcfg->status, clientcfg->statusmsg);
02540    xmpp_client_change_state(client, XMPP_STATE_ROSTER);
02541 
02542    return IKS_FILTER_EAT;
02543 }

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

Definition at line 4272 of file res_xmpp.c.

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

04273 {
04274    switch (cmd) {
04275    case CLI_INIT:
04276       e->command = "xmpp set debug {on|off}";
04277       e->usage =
04278          "Usage: xmpp set debug {on|off}\n"
04279          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
04280       return NULL;
04281    case CLI_GENERATE:
04282       return NULL;
04283    }
04284 
04285    if (a->argc != e->args) {
04286       return CLI_SHOWUSAGE;
04287    }
04288 
04289    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
04290       debug = 1;
04291       ast_cli(a->fd, "XMPP Debugging Enabled.\n");
04292       return CLI_SUCCESS;
04293    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
04294       debug = 0;
04295       ast_cli(a->fd, "XMPP Debugging Disabled.\n");
04296       return CLI_SUCCESS;
04297    }
04298    return CLI_SHOWUSAGE; /* defaults to invalid */
04299 }

static void xmpp_init_event_distribution ( struct ast_xmpp_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 1595 of file res_xmpp.c.

References ao2_callback, ao2_cleanup, ao2_global_obj_ref, ast_device_state_cache(), ast_device_state_topic_all(), ast_mwi_topic_all(), cached_devstate_cb(), ast_xmpp_client::device_state_sub, ast_xmpp_client::filter, globals, ast_xmpp_client::mwi_sub, ast_xmpp_client::name, NULL, OBJ_NODATA, RAII_VAR, stasis_cache_dump(), stasis_subscribe(), stasis_subscribe_pool(), stasis_unsubscribe(), xmpp_config_find(), xmpp_pubsub_devstate_cb(), xmpp_pubsub_handle_error(), xmpp_pubsub_handle_event(), xmpp_pubsub_mwi_cb(), xmpp_pubsub_subscribe(), and xmpp_pubsub_unsubscribe().

Referenced by xmpp_connect_hook().

01596 {
01597    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01598    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01599    RAII_VAR(struct ao2_container *, cached, NULL, ao2_cleanup);
01600 
01601    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
01602       return;
01603    }
01604 
01605    xmpp_pubsub_unsubscribe(client, "device_state");
01606    xmpp_pubsub_unsubscribe(client, "message_waiting");
01607 
01608    if (!(client->mwi_sub = stasis_subscribe_pool(ast_mwi_topic_all(), xmpp_pubsub_mwi_cb, client))) {
01609       return;
01610    }
01611 
01612    if (!(client->device_state_sub = stasis_subscribe(ast_device_state_topic_all(), xmpp_pubsub_devstate_cb, client))) {
01613       client->mwi_sub = stasis_unsubscribe(client->mwi_sub);
01614       return;
01615    }
01616 
01617    cached = stasis_cache_dump(ast_device_state_cache(), NULL);
01618    ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, client);
01619 
01620    xmpp_pubsub_subscribe(client, "device_state");
01621    xmpp_pubsub_subscribe(client, "message_waiting");
01622    iks_filter_add_rule(client->filter, xmpp_pubsub_handle_event, client, IKS_RULE_TYPE,
01623              IKS_PAK_MESSAGE, IKS_RULE_FROM, clientcfg->pubsubnode, IKS_RULE_DONE);
01624    iks_filter_add_rule(client->filter, xmpp_pubsub_handle_error, client, IKS_RULE_TYPE,
01625              IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
01626 
01627 }

static int xmpp_io_recv ( struct ast_xmpp_client client,
char *  buffer,
size_t  buf_len,
int  timeout 
) [static]

Internal function which polls on an XMPP client and receives data.

Definition at line 3643 of file res_xmpp.c.

References ast_poll, len(), ast_xmpp_client::parser, and xmpp_is_secure().

Referenced by xmpp_client_receive().

03644 {
03645    struct pollfd pfd = { .events = POLLIN };
03646    int len, res;
03647 
03648 #ifdef HAVE_OPENSSL
03649    if (xmpp_is_secure(client)) {
03650       pfd.fd = SSL_get_fd(client->ssl_session);
03651       if (pfd.fd < 0) {
03652          return -1;
03653       }
03654    } else
03655 #endif /* HAVE_OPENSSL */
03656       pfd.fd = iks_fd(client->parser);
03657 
03658    res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
03659    if (res > 0) {
03660 #ifdef HAVE_OPENSSL
03661       if (xmpp_is_secure(client)) {
03662          len = SSL_read(client->ssl_session, buffer, buf_len);
03663       } else
03664 #endif /* HAVE_OPENSSL */
03665          len = recv(pfd.fd, buffer, buf_len, 0);
03666 
03667       if (len > 0) {
03668          return len;
03669       } else if (len <= 0) {
03670          return -1;
03671       }
03672    }
03673    return res;
03674 }

static int xmpp_is_secure ( struct ast_xmpp_client client  )  [static]

Helper function which returns whether an XMPP client connection is secure or not.

Definition at line 873 of file res_xmpp.c.

Referenced by xmpp_client_authenticate_sasl(), xmpp_client_request_tls(), xmpp_client_send_raw_message(), and xmpp_io_recv().

00874 {
00875 #ifdef HAVE_OPENSSL
00876    return client->stream_flags & SECURE;
00877 #else
00878    return 0;
00879 #endif
00880 }

static int xmpp_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 1796 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, ast_xmpp_chatroom_join(), globals, LOG_ERROR, NULL, RAII_VAR, XMPP_COMPONENT, xmpp_config_find(), and XMPP_MAX_RESJIDLEN.

Referenced by load_module().

01797 {
01798    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01799    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01800    char *s, nick[XMPP_MAX_RESJIDLEN];
01801    AST_DECLARE_APP_ARGS(args,
01802               AST_APP_ARG(sender);
01803               AST_APP_ARG(jid);
01804               AST_APP_ARG(nick);
01805       );
01806 
01807    if (ast_strlen_zero(data)) {
01808       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
01809       return -1;
01810    }
01811    s = ast_strdupa(data);
01812 
01813    AST_STANDARD_APP_ARGS(args, s);
01814    if (args.argc < 2 || args.argc > 3) {
01815       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
01816       return -1;
01817    }
01818 
01819    if (strchr(args.jid, '/')) {
01820       ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
01821       return -1;
01822    }
01823 
01824    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
01825       ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01826       return -1;
01827    }
01828 
01829    if (ast_strlen_zero(args.nick)) {
01830       if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
01831          snprintf(nick, sizeof(nick), "asterisk");
01832       } else {
01833          snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
01834       }
01835    } else {
01836       snprintf(nick, sizeof(nick), "%s", args.nick);
01837    }
01838 
01839    if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
01840       ast_xmpp_chatroom_join(clientcfg->client, args.jid, nick);
01841    } else {
01842       ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
01843    }
01844 
01845    return 0;
01846 }

static int xmpp_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 1855 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, ast_xmpp_chatroom_leave(), globals, LOG_ERROR, NULL, RAII_VAR, XMPP_COMPONENT, xmpp_config_find(), and XMPP_MAX_RESJIDLEN.

Referenced by load_module().

01856 {
01857    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01858    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01859    char *s, nick[XMPP_MAX_RESJIDLEN];
01860    AST_DECLARE_APP_ARGS(args,
01861               AST_APP_ARG(sender);
01862               AST_APP_ARG(jid);
01863               AST_APP_ARG(nick);
01864       );
01865 
01866    if (ast_strlen_zero(data)) {
01867       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
01868       return -1;
01869    }
01870    s = ast_strdupa(data);
01871 
01872    AST_STANDARD_APP_ARGS(args, s);
01873    if (args.argc < 2 || args.argc > 3) {
01874       ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
01875       return -1;
01876    }
01877 
01878    if (strchr(args.jid, '/')) {
01879       ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
01880       return -1;
01881    }
01882 
01883    if (ast_strlen_zero(args.jid) || !strchr(args.jid, '@')) {
01884       ast_log(LOG_ERROR, "No jabber ID specified\n");
01885       return -1;
01886    }
01887 
01888    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
01889       ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01890       return -1;
01891    }
01892 
01893    if (ast_strlen_zero(args.nick)) {
01894       if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
01895          snprintf(nick, sizeof(nick), "asterisk");
01896       } else {
01897          snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
01898       }
01899    } else {
01900       snprintf(nick, sizeof(nick), "%s", args.nick);
01901    }
01902 
01903    ast_xmpp_chatroom_leave(clientcfg->client, args.jid, nick);
01904 
01905    return 0;
01906 }

static void xmpp_log_hook ( void *  data,
const char *  xmpp,
size_t  size,
int  incoming 
) [static]

Logging hook function.

Definition at line 2546 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_test_flag, ast_verbose, globals, ast_xmpp_client::name, NULL, RAII_VAR, xmpp_config_find(), and XMPP_DEBUG.

Referenced by xmpp_client_config_post_apply(), xmpp_client_receive(), and xmpp_client_send_raw_message().

02547 {
02548    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02549    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02550    struct ast_xmpp_client *client = data;
02551 
02552    if (!debug && (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) || !ast_test_flag(&clientcfg->flags, XMPP_DEBUG))) {
02553       return;
02554    }
02555 
02556    if (!incoming) {
02557       ast_verbose("\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->name, xmpp);
02558    } else {
02559       ast_verbose("\n<--- XMPP received from '%s' --->\n%s\n<------------->\n", client->name, xmpp);
02560    }
02561 }

static void xmpp_message_destroy ( struct ast_xmpp_message message  )  [static]

Destroy function for XMPP messages.

Definition at line 543 of file res_xmpp.c.

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

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

00544 {
00545    if (message->from) {
00546       ast_free(message->from);
00547    }
00548    if (message->message) {
00549       ast_free(message->message);
00550    }
00551 
00552    ast_free(message);
00553 }

static int xmpp_pak_message ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
iks *  node,
ikspak *  pak 
) [static]

Internal function called when a message is received.

Definition at line 3154 of file res_xmpp.c.

References ao2_cleanup, ao2_find, ast_xmpp_message::arrived, ast_calloc, ast_cond_broadcast, ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_msg_alloc(), ast_msg_destroy(), ast_msg_queue(), ast_msg_set_body(), ast_msg_set_context(), ast_msg_set_endpoint(), ast_msg_set_from(), ast_msg_set_tech(), ast_msg_set_to(), ast_msg_set_var(), ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_strlen_zero, ast_test_flag, ast_tvnow(), ast_xmpp_client_lock(), ast_xmpp_client_unlock(), ast_xmpp_client::buddies, ast_xmpp_client_config::context, delete_old_messages(), ast_xmpp_client_config::flags, ast_xmpp_message::from, ast_xmpp_buddy::id, ast_xmpp_message::id, ast_xmpp_message::message, ast_xmpp_client::messages, ast_xmpp_client::name, NULL, OBJ_KEY, OBJ_NOLOCK, S_OR, ast_xmpp_client_config::user, and XMPP_SEND_TO_DIALPLAN.

03155 {
03156    struct ast_xmpp_message *message;
03157    char *body;
03158    int deleted = 0;
03159 
03160    ast_debug(3, "XMPP client '%s' received a message\n", client->name);
03161 
03162    if (!(body = iks_find_cdata(pak->x, "body"))) {
03163       /* Message contains no body, ignore it. */
03164       return 0;
03165    }
03166 
03167    if (!(message = ast_calloc(1, sizeof(*message)))) {
03168       return -1;
03169    }
03170 
03171    message->arrived = ast_tvnow();
03172 
03173    message->message = ast_strdup(body);
03174 
03175    ast_copy_string(message->id, S_OR(pak->id, ""), sizeof(message->id));
03176    message->from = !ast_strlen_zero(pak->from->full) ? ast_strdup(pak->from->full) : NULL;
03177 
03178    if (ast_test_flag(&cfg->flags, XMPP_SEND_TO_DIALPLAN)) {
03179       struct ast_msg *msg;
03180       struct ast_xmpp_buddy *buddy;
03181 
03182       if ((msg = ast_msg_alloc())) {
03183          int res;
03184 
03185          ast_xmpp_client_lock(client);
03186 
03187          buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY | OBJ_NOLOCK);
03188 
03189          res = ast_msg_set_to(msg, "xmpp:%s", cfg->user);
03190          res |= ast_msg_set_from(msg, "xmpp:%s", message->from);
03191          res |= ast_msg_set_body(msg, "%s", message->message);
03192          res |= ast_msg_set_context(msg, "%s", cfg->context);
03193          res |= ast_msg_set_tech(msg, "%s", "XMPP");
03194          res |= ast_msg_set_endpoint(msg, "%s", client->name);
03195 
03196          if (buddy) {
03197             res |= ast_msg_set_var(msg, "XMPP_BUDDY", buddy->id);
03198          }
03199 
03200          ao2_cleanup(buddy);
03201 
03202          ast_xmpp_client_unlock(client);
03203 
03204          if (res) {
03205             ast_msg_destroy(msg);
03206          } else {
03207             ast_msg_queue(msg);
03208          }
03209       }
03210    }
03211 
03212    /* remove old messages received from this JID
03213     * and insert received message */
03214    deleted = delete_old_messages(client, pak->from->partial);
03215    ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
03216    AST_LIST_LOCK(&client->messages);
03217    AST_LIST_INSERT_HEAD(&client->messages, message, list);
03218    AST_LIST_UNLOCK(&client->messages);
03219 
03220    /* wake up threads waiting for messages */
03221    ast_mutex_lock(&messagelock);
03222    ast_cond_broadcast(&message_received_condition);
03223    ast_mutex_unlock(&messagelock);
03224 
03225    return 0;
03226 }

static int xmpp_pak_presence ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
iks *  node,
ikspak *  pak 
) [static]

Internal function called when a presence message is received.

Definition at line 3300 of file res_xmpp.c.

References ao2_alloc, ao2_callback, ao2_find, ao2_link_flags, ao2_lock, ao2_ref, ao2_unlink_flags, ao2_unlock, ast_copy_string(), AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_free, ast_log, ast_strdup, ast_strlen_zero, ast_test_flag, ast_xmpp_client::buddies, ast_xmpp_resource::caps, ast_xmpp_resource::description, EVENT_FLAG_USER, ast_xmpp_client_config::flags, ast_xmpp_capabilities::google, ast_xmpp_buddy::id, ast_xmpp_client::jid, LOG_ERROR, LOG_WARNING, manager_event, ast_xmpp_client::name, ast_xmpp_capabilities::node, NULL, OBJ_KEY, OBJ_NOLOCK, ast_xmpp_resource::priority, ast_xmpp_resource::resource, ast_xmpp_buddy::resources, S_OR, ast_xmpp_resource::status, ast_xmpp_client_config::status, status, STATUS_DISAPPEAR, ast_xmpp_client_config::statusmsg, type, ast_xmpp_capabilities::version, xmpp_client_send_disco_info_request(), xmpp_client_set_presence(), XMPP_COMPONENT, xmpp_resource_cmp(), xmpp_resource_destructor(), and xmpp_resource_is_available().

03301 {
03302    struct ast_xmpp_buddy *buddy;
03303    struct ast_xmpp_resource *resource;
03304    char *type = iks_find_attrib(pak->x, "type");
03305    int status = pak->show ? pak->show : STATUS_DISAPPEAR;
03306    enum ast_device_state state = AST_DEVICE_UNAVAILABLE;
03307 
03308    /* If no resource is available this is a general buddy presence update, which we will ignore */
03309    if (!pak->from->resource) {
03310       return 0;
03311    }
03312 
03313    if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY))) {
03314       /* Only output the message if it is not about us */
03315       if (strcmp(client->jid->partial, pak->from->partial)) {
03316          ast_log(LOG_WARNING, "Received presence information about '%s' despite not having them in roster on client '%s'\n",
03317             pak->from->partial, client->name);
03318       }
03319       return 0;
03320    }
03321 
03322    /* If this is a component presence probe request answer immediately with our presence status */
03323    if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) {
03324       xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
03325    }
03326 
03327    ao2_lock(buddy->resources);
03328 
03329    if (!(resource = ao2_callback(buddy->resources, OBJ_NOLOCK, xmpp_resource_cmp, pak->from->resource))) {
03330       /* Only create the new resource if it is not going away - in reality this should not happen */
03331       if (status != STATUS_DISAPPEAR) {
03332          if (!(resource = ao2_alloc(sizeof(*resource), xmpp_resource_destructor))) {
03333             ast_log(LOG_ERROR, "Could not allocate resource object for resource '%s' of buddy '%s' on client '%s'\n",
03334                pak->from->resource, buddy->id, client->name);
03335             ao2_unlock(buddy->resources);
03336             ao2_ref(buddy, -1);
03337             return 0;
03338          }
03339 
03340          ast_copy_string(resource->resource, pak->from->resource, sizeof(resource->resource));
03341       }
03342    } else {
03343       /* We unlink the resource in case the priority changes or in case they are going away */
03344       ao2_unlink_flags(buddy->resources, resource, OBJ_NOLOCK);
03345    }
03346 
03347    /* Only update the resource and add it back in if it is not going away */
03348    if (resource && (status != STATUS_DISAPPEAR)) {
03349       char *node, *ver;
03350 
03351       /* Try to get the XMPP spec node, and fall back to Google if not found */
03352       if (!(node = iks_find_attrib(iks_find(pak->x, "c"), "node"))) {
03353          node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
03354       }
03355 
03356       if (!(ver = iks_find_attrib(iks_find(pak->x, "c"), "ver"))) {
03357          ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
03358       }
03359 
03360       if (resource->description) {
03361          ast_free(resource->description);
03362       }
03363 
03364       if ((node && strcmp(resource->caps.node, node)) || (ver && strcmp(resource->caps.version, ver))) {
03365          /* For interoperability reasons, proceed even if the resource fails to provide node or version */
03366          if (node) {
03367             ast_copy_string(resource->caps.node, node, sizeof(resource->caps.node));
03368          }
03369          if (ver) {
03370             ast_copy_string(resource->caps.version, ver, sizeof(resource->caps.version));
03371          }
03372 
03373          /* Google Talk places the capabilities information directly in presence, so see if it is there */
03374          if (iks_find_with_attrib(pak->x, "c", "node", "http://www.google.com/xmpp/client/caps") ||
03375              iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.google.com/xmpp/client/caps") ||
03376              iks_find_with_attrib(pak->x, "c", "node", "http://www.android.com/gtalk/client/caps") ||
03377              iks_find_with_attrib(pak->x, "caps:c", "node", "http://www.android.com/gtalk/client/caps") ||
03378              iks_find_with_attrib(pak->x, "c", "node", "http://mail.google.com/xmpp/client/caps") ||
03379              iks_find_with_attrib(pak->x, "caps:c", "node", "http://mail.google.com/xmpp/client/caps")) {
03380             resource->caps.google = 1;
03381          }
03382 
03383          /* To discover if the buddy supports Jingle we need to query, so do so */
03384          if (xmpp_client_send_disco_info_request(client, pak->from->full, client->jid->full)) {
03385             ast_log(LOG_WARNING, "Could not send discovery information request to resource '%s' of buddy '%s' on client '%s', capabilities may be incomplete\n", resource->resource, buddy->id, client->name);
03386          }
03387       }
03388 
03389       resource->status = status;
03390       resource->description = ast_strdup(iks_find_cdata(pak->x, "status"));
03391       resource->priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
03392 
03393       ao2_link_flags(buddy->resources, resource, OBJ_NOLOCK);
03394 
03395       manager_event(EVENT_FLAG_USER, "JabberStatus",
03396                "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
03397                "\r\nDescription: %s\r\n",
03398                client->name, pak->from->partial, resource->resource, resource->status,
03399                resource->priority, S_OR(resource->description, ""));
03400 
03401       ao2_ref(resource, -1);
03402    } else {
03403       /* This will get hit by presence coming in for an unknown resource, and also when a resource goes away */
03404       if (resource) {
03405          ao2_ref(resource, -1);
03406       }
03407 
03408       manager_event(EVENT_FLAG_USER, "JabberStatus",
03409                "Account: %s\r\nJID: %s\r\nStatus: %u\r\n",
03410                client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
03411    }
03412 
03413    /* Determine if at least one resource is available for device state purposes */
03414    if ((resource = ao2_callback(buddy->resources, OBJ_NOLOCK, xmpp_resource_is_available, NULL))) {
03415       state = AST_DEVICE_NOT_INUSE;
03416       ao2_ref(resource, -1);
03417    }
03418 
03419    ao2_unlock(buddy->resources);
03420 
03421    ao2_ref(buddy, -1);
03422 
03423    ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "XMPP/%s/%s", client->name, pak->from->partial);
03424 
03425    return 0;
03426 }

static int xmpp_pak_s10n ( struct ast_xmpp_client client,
struct ast_xmpp_client_config cfg,
iks *  node,
ikspak *  pak 
) [static]

Internal function called when a subscription message is received.

Definition at line 3429 of file res_xmpp.c.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log, ast_test_flag, ast_xmpp_client_send(), ast_xmpp_client::buddies, ast_xmpp_client_config::flags, ast_xmpp_client::jid, LOG_ERROR, LOG_WARNING, ast_xmpp_client::name, NULL, OBJ_KEY, OBJ_NOLOCK, ast_xmpp_client_config::status, status, ast_xmpp_client_config::statusmsg, XMPP_AUTOREGISTER, xmpp_client_create_buddy(), xmpp_client_set_presence(), and XMPP_COMPONENT.

03430 {
03431    struct ast_xmpp_buddy *buddy;
03432 
03433    switch (pak->subtype) {
03434    case IKS_TYPE_SUBSCRIBE:
03435       if (ast_test_flag(&cfg->flags, XMPP_AUTOREGISTER)) {
03436          iks *presence, *status = NULL;
03437 
03438          if ((presence = iks_new("presence")) && (status = iks_new("status"))) {
03439             iks_insert_attrib(presence, "type", "subscribed");
03440             iks_insert_attrib(presence, "to", pak->from->full);
03441             iks_insert_attrib(presence, "from", client->jid->full);
03442 
03443             if (pak->id) {
03444                iks_insert_attrib(presence, "id", pak->id);
03445             }
03446 
03447             iks_insert_cdata(status, "Asterisk has approved your subscription", 0);
03448             iks_insert_node(presence, status);
03449 
03450             if (ast_xmpp_client_send(client, presence)) {
03451                ast_log(LOG_ERROR, "Could not send subscription acceptance to '%s' from client '%s'\n",
03452                   pak->from->partial, client->name);
03453             }
03454          } else {
03455             ast_log(LOG_ERROR, "Could not allocate presence stanzas for accepting subscription from '%s' to client '%s'\n",
03456                pak->from->partial, client->name);
03457          }
03458 
03459          iks_delete(status);
03460          iks_delete(presence);
03461       }
03462 
03463       if (ast_test_flag(&cfg->flags, XMPP_COMPONENT)) {
03464          xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
03465       }
03466       /* This purposely flows through so we have the subscriber amongst our buddies */
03467    case IKS_TYPE_SUBSCRIBED:
03468       ao2_lock(client->buddies);
03469 
03470       if (!(buddy = ao2_find(client->buddies, pak->from->partial, OBJ_KEY | OBJ_NOLOCK))) {
03471          buddy = xmpp_client_create_buddy(client->buddies, pak->from->partial);
03472       }
03473 
03474       if (!buddy) {
03475          ast_log(LOG_WARNING, "Could not find or create buddy '%s' on client '%s'\n",
03476             pak->from->partial, client->name);
03477       } else {
03478          ao2_ref(buddy, -1);
03479       }
03480 
03481       ao2_unlock(client->buddies);
03482 
03483       break;
03484    default:
03485       break;
03486    }
03487 
03488    return 0;
03489 }

static int xmpp_ping_request ( struct ast_xmpp_client client,
const char *  to,
const char *  from 
) [static]

Helper function which sends a ping request to a server.

Definition at line 3266 of file res_xmpp.c.

References ast_debug, ast_xmpp_client_lock(), ast_xmpp_client_send(), ast_xmpp_client_unlock(), ast_xmpp_increment_mid(), ast_xmpp_client::mid, and ast_xmpp_client::name.

Referenced by xmpp_client_receive(), and xmpp_client_thread().

03267 {
03268    iks *iq, *ping;
03269    int res;
03270    
03271    ast_debug(2, "JABBER: Sending Keep-Alive Ping for client '%s'\n", client->name);
03272 
03273    if (!(iq = iks_new("iq")) || !(ping = iks_new("ping"))) {
03274       iks_delete(iq);
03275       return -1;
03276    }
03277    
03278    iks_insert_attrib(iq, "type", "get");
03279    iks_insert_attrib(iq, "to", to);
03280    iks_insert_attrib(iq, "from", from);
03281    
03282    ast_xmpp_client_lock(client);
03283    iks_insert_attrib(iq, "id", client->mid);
03284    ast_xmpp_increment_mid(client->mid);
03285    ast_xmpp_client_unlock(client);
03286    
03287    iks_insert_attrib(ping, "xmlns", "urn:xmpp:ping");
03288    iks_insert_node(iq, ping);
03289    
03290    res = ast_xmpp_client_send(client, iq);
03291    
03292    iks_delete(ping);
03293    iks_delete(iq);
03294 
03295 
03296    return res;
03297 }

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

Definition at line 1115 of file res_xmpp.c.

Referenced by xmpp_pubsub_create_node().

01116 {
01117    iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
01118       *field_deliver_payload, *field_persist_items, *field_access_model,
01119       *field_pubsub_collection;
01120    configure = iks_insert(pubsub, "configure");
01121    x = iks_insert(configure, "x");
01122    iks_insert_attrib(x, "xmlns", "jabber:x:data");
01123    iks_insert_attrib(x, "type", "submit");
01124    field_owner = iks_insert(x, "field");
01125    iks_insert_attrib(field_owner, "var", "FORM_TYPE");
01126    iks_insert_attrib(field_owner, "type", "hidden");
01127    iks_insert_cdata(iks_insert(field_owner, "value"),
01128           "http://jabber.org/protocol/pubsub#owner", 39);
01129    if (node_type) {
01130       field_node_type = iks_insert(x, "field");
01131       iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
01132       iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
01133    }
01134    field_node_config = iks_insert(x, "field");
01135    iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
01136    iks_insert_attrib(field_node_config, "type", "hidden");
01137    iks_insert_cdata(iks_insert(field_node_config, "value"),
01138           "http://jabber.org/protocol/pubsub#node_config", 45);
01139    field_deliver_payload = iks_insert(x, "field");
01140    iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
01141    iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
01142    field_persist_items = iks_insert(x, "field");
01143    iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
01144    iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
01145    field_access_model = iks_insert(x, "field");
01146    iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
01147    iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
01148    if (node_type && !strcasecmp(node_type, "leaf")) {
01149       field_pubsub_collection = iks_insert(x, "field");
01150       iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
01151       iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
01152              strlen(collection_name));
01153    }
01154    return configure;
01155 }

static iks* xmpp_pubsub_build_node_request ( struct ast_xmpp_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 3945 of file res_xmpp.c.

References NULL, request(), and xmpp_pubsub_iq_create().

Referenced by xmpp_pubsub_purge_nodes(), and xmpp_pubsub_request_nodes().

03946 {
03947    iks *request = xmpp_pubsub_iq_create(client, "get"), *query;
03948 
03949    if (!request) {
03950       return NULL;
03951    }
03952 
03953    query = iks_insert(request, "query");
03954    iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03955 
03956    if (collection) {
03957       iks_insert_attrib(query, "node", collection);
03958    }
03959 
03960    return request;
03961 }

static iks* xmpp_pubsub_build_publish_skeleton ( struct ast_xmpp_client client,
const char *  node,
const char *  event_type,
unsigned int  cachable 
) [static]

Build the skeleton of a publish.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
node Name of the node that will be published to
event_type 
Returns:
iks *

Definition at line 1078 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, AST_DEVSTATE_NOT_CACHABLE, ast_test_flag, globals, item, NULL, publish, RAII_VAR, request(), xmpp_pubsub_iq_create(), and XMPP_XEP0248.

Referenced by xmpp_pubsub_publish_device_state(), and xmpp_pubsub_publish_mwi().

01080 {
01081    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01082    iks *request, *pubsub, *publish, *item;
01083 
01084    if (!cfg || !cfg->global || !(request = xmpp_pubsub_iq_create(client, "set"))) {
01085       return NULL;
01086    }
01087 
01088    pubsub = iks_insert(request, "pubsub");
01089    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
01090    publish = iks_insert(pubsub, "publish");
01091    iks_insert_attrib(publish, "node", ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248) ? node : event_type);
01092    item = iks_insert(publish, "item");
01093    iks_insert_attrib(item, "id", node);
01094 
01095    if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
01096       iks *options, *x, *field_form_type, *field_persist;
01097 
01098       options = iks_insert(pubsub, "publish-options");
01099       x = iks_insert(options, "x");
01100       iks_insert_attrib(x, "xmlns", "jabber:x:data");
01101       iks_insert_attrib(x, "type", "submit");
01102       field_form_type = iks_insert(x, "field");
01103       iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
01104       iks_insert_attrib(field_form_type, "type", "hidden");
01105       iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
01106       field_persist = iks_insert(x, "field");
01107       iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
01108       iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
01109    }
01110 
01111    return item;
01112 
01113 }

static void xmpp_pubsub_create_affiliations ( struct ast_xmpp_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 1163 of file res_xmpp.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_log, ast_xmpp_client_send(), ast_xmpp_client::buddies, ast_xmpp_buddy::id, LOG_ERROR, ast_xmpp_client::name, and xmpp_pubsub_iq_create().

Referenced by xmpp_pubsub_create_node().

01164 {
01165    iks *modify_affiliates = xmpp_pubsub_iq_create(client, "set");
01166    iks *pubsub, *affiliations, *affiliate;
01167    struct ao2_iterator i;
01168    struct ast_xmpp_buddy *buddy;
01169 
01170    if (!modify_affiliates) {
01171       ast_log(LOG_ERROR, "Could not create IQ for creating affiliations on client '%s'\n", client->name);
01172       return;
01173    }
01174 
01175    pubsub = iks_insert(modify_affiliates, "pubsub");
01176    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
01177    affiliations = iks_insert(pubsub, "affiliations");
01178    iks_insert_attrib(affiliations, "node", node);
01179 
01180    i = ao2_iterator_init(client->buddies, 0);
01181    while ((buddy = ao2_iterator_next(&i))) {
01182       affiliate = iks_insert(affiliations, "affiliation");
01183       iks_insert_attrib(affiliate, "jid", buddy->id);
01184       iks_insert_attrib(affiliate, "affiliation", "owner");
01185       ao2_ref(buddy, -1);
01186    }
01187    ao2_iterator_destroy(&i);
01188 
01189    ast_xmpp_client_send(client, modify_affiliates);
01190    iks_delete(modify_affiliates);
01191 }

static void xmpp_pubsub_create_collection ( struct ast_xmpp_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 1249 of file res_xmpp.c.

References NULL, and xmpp_pubsub_create_node().

Referenced by xmpp_cli_create_collection(), and xmpp_pubsub_handle_error().

01250 {
01251    xmpp_pubsub_create_node(client, "collection", collection_name, NULL);
01252 }

static void xmpp_pubsub_create_leaf ( struct ast_xmpp_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
collection_name 
leaf_name The name to use for this collection
Returns:
void.

Definition at line 1262 of file res_xmpp.c.

References xmpp_pubsub_create_node().

Referenced by xmpp_cli_create_leafnode(), and xmpp_pubsub_handle_error().

01264 {
01265    xmpp_pubsub_create_node(client, "leaf", leaf_name, collection_name);
01266 }

static void xmpp_pubsub_create_node ( struct ast_xmpp_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
collection_name 
Returns:
void

Definition at line 1201 of file res_xmpp.c.

References ast_xmpp_client_send(), xmpp_pubsub_build_node_config(), xmpp_pubsub_create_affiliations(), and xmpp_pubsub_iq_create().

Referenced by xmpp_pubsub_create_collection(), xmpp_pubsub_create_leaf(), xmpp_pubsub_handle_error(), and xmpp_pubsub_publish_device_state().

01203 {
01204    iks *node, *pubsub, *create;
01205 
01206    if (!(node = xmpp_pubsub_iq_create(client, "set"))) {
01207       return;
01208    }
01209 
01210    pubsub = iks_insert(node, "pubsub");
01211    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
01212    create = iks_insert(pubsub, "create");
01213    iks_insert_attrib(create, "node", name);
01214    xmpp_pubsub_build_node_config(pubsub, node_type, collection_name);
01215    ast_xmpp_client_send(client, node);
01216    xmpp_pubsub_create_affiliations(client, name);
01217    iks_delete(node);
01218 }

static void xmpp_pubsub_delete_node ( struct ast_xmpp_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 1226 of file res_xmpp.c.

References ast_xmpp_client_send(), request(), and xmpp_pubsub_iq_create().

Referenced by xmpp_cli_delete_pubsub_node(), xmpp_cli_purge_pubsub_nodes(), and xmpp_pubsub_delete_node_list().

01227 {
01228    iks *request, *pubsub, *delete;
01229 
01230    if (!(request = xmpp_pubsub_iq_create(client, "set"))) {
01231       return;
01232    }
01233 
01234    pubsub = iks_insert(request, "pubsub");
01235    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
01236    delete = iks_insert(pubsub, "delete");
01237    iks_insert_attrib(delete, "node", node_name);
01238    ast_xmpp_client_send(client, request);
01239 
01240    iks_delete(request);
01241 }

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

Delete pubsub item lists.

Parameters:
data pointer to ast_xmpp_client structure
pak response from pubsub diso::items query
Returns:
IKS_FILTER_EAT

Definition at line 4068 of file res_xmpp.c.

References ast_log, item, ast_xmpp_client::jid, LOG_WARNING, NULL, and xmpp_pubsub_delete_node().

Referenced by xmpp_pubsub_purge_nodes().

04069 {
04070    struct ast_xmpp_client *client = data;
04071    iks *item = NULL;
04072 
04073    if (iks_has_children(pak->query)) {
04074       item = iks_first_tag(pak->query);
04075       ast_log(LOG_WARNING, "Connection: %s  Node name: %s\n", client->jid->partial,
04076          iks_find_attrib(item, "node"));
04077       while ((item = iks_next_tag(item))) {
04078          xmpp_pubsub_delete_node(client, iks_find_attrib(item, "node"));
04079       }
04080    }
04081 
04082    if (item) {
04083       iks_delete(item);
04084    }
04085 
04086    return IKS_FILTER_EAT;
04087 }

static void xmpp_pubsub_devstate_cb ( void *  data,
struct stasis_subscription sub,
struct stasis_message msg 
) [static]

Callback function for device state events.

Parameters:
ast_event 
data void pointer to ast_client structure
Returns:
void

Definition at line 1371 of file res_xmpp.c.

References ast_device_state_message_type(), ast_devstate_str(), ast_eid_cmp(), ast_eid_default, ast_device_state_message::cachable, ast_device_state_message::device, ast_device_state_message::eid, stasis_message_data(), stasis_message_type(), stasis_subscription_is_subscribed(), ast_device_state_message::state, and xmpp_pubsub_publish_device_state().

Referenced by cached_devstate_cb(), and xmpp_init_event_distribution().

01372 {
01373    struct ast_xmpp_client *client = data;
01374    struct ast_device_state_message *dev_state;
01375 
01376    if (!stasis_subscription_is_subscribed(sub) || ast_device_state_message_type() != stasis_message_type(msg)) {
01377       return;
01378    }
01379 
01380    dev_state = stasis_message_data(msg);
01381    if (!dev_state->eid || ast_eid_cmp(&ast_eid_default, dev_state->eid)) {
01382       /* If the event is aggregate or didn't originate from this server, don't send it out. */
01383       return;
01384    }
01385 
01386    xmpp_pubsub_publish_device_state(client, dev_state->device, ast_devstate_str(dev_state->state), dev_state->cachable);
01387 }

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

Definition at line 1514 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_debug, ast_log, ast_test_flag, ast_xmpp_client_send(), error(), globals, LOG_ERROR, NULL, RAII_VAR, request(), xmpp_pubsub_create_collection(), xmpp_pubsub_create_leaf(), xmpp_pubsub_create_node(), xmpp_pubsub_iq_create(), and XMPP_XEP0248.

Referenced by xmpp_init_event_distribution().

01515 {
01516    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01517    char *node_name, *error;
01518    int error_num;
01519    iks *orig_request, *orig_pubsub = iks_find(pak->x, "pubsub");
01520    struct ast_xmpp_client *client = data;
01521 
01522    if (!cfg || !cfg->global) {
01523       ast_log(LOG_ERROR, "No global configuration available\n");
01524       return IKS_FILTER_EAT;
01525    }
01526 
01527    if (!orig_pubsub) {
01528       ast_debug(1, "Error isn't a PubSub error, why are we here?\n");
01529       return IKS_FILTER_EAT;
01530    }
01531 
01532    orig_request = iks_child(orig_pubsub);
01533    error = iks_find_attrib(iks_find(pak->x, "error"), "code");
01534    node_name = iks_find_attrib(orig_request, "node");
01535 
01536    if (!sscanf(error, "%30d", &error_num)) {
01537       return IKS_FILTER_EAT;
01538    }
01539 
01540    if (error_num > 399 && error_num < 500 && error_num != 404) {
01541       ast_log(LOG_ERROR,
01542          "Error performing operation on PubSub node %s, %s.\n", node_name, error);
01543       return IKS_FILTER_EAT;
01544    } else if (error_num > 499 && error_num < 600) {
01545       ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
01546       return IKS_FILTER_EAT;
01547    }
01548 
01549    if (!strcasecmp(iks_name(orig_request), "publish")) {
01550       iks *request;
01551 
01552       if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
01553          if (iks_find(iks_find(orig_request, "item"), "state")) {
01554             xmpp_pubsub_create_leaf(client, "device_state", node_name);
01555          } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
01556             xmpp_pubsub_create_leaf(client, "message_waiting", node_name);
01557          }
01558       } else {
01559          xmpp_pubsub_create_node(client, NULL, node_name, NULL);
01560       }
01561 
01562       if ((request = xmpp_pubsub_iq_create(client, "set"))) {
01563          iks_insert_node(request, orig_pubsub);
01564          ast_xmpp_client_send(client, request);
01565          iks_delete(request);
01566       } else {
01567          ast_log(LOG_ERROR, "PubSub publish could not create IQ\n");
01568       }
01569 
01570       return IKS_FILTER_EAT;
01571    } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
01572       if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
01573          xmpp_pubsub_create_collection(client, node_name);
01574       } else {
01575          xmpp_pubsub_create_node(client, NULL, node_name, NULL);
01576       }
01577    }
01578 
01579    return IKS_FILTER_EAT;
01580 }

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

Callback for handling PubSub events.

Parameters:
data void pointer to ast_xmpp_client structure
pak A pak
Returns:
IKS_FILTER_EAT

Definition at line 1468 of file res_xmpp.c.

References ast_debug, AST_DEVSTATE_CACHABLE, AST_DEVSTATE_NOT_CACHABLE, ast_devstate_val(), ast_eid_cmp(), ast_eid_default, ast_log, ast_publish_device_state_full(), ast_publish_mwi_state_full(), ast_str_to_eid(), item, LOG_ERROR, mailbox, NULL, and strsep().

Referenced by xmpp_init_event_distribution().

01469 {
01470    char *item_id, *device_state, *mailbox, *cachable_str;
01471    int oldmsgs, newmsgs;
01472    iks *item, *item_content;
01473    struct ast_eid pubsub_eid;
01474    unsigned int cachable = AST_DEVSTATE_CACHABLE;
01475    item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
01476    if (!item) {
01477       ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
01478       return IKS_FILTER_EAT;
01479    }
01480    item_id = iks_find_attrib(item, "id");
01481    item_content = iks_child(item);
01482    ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
01483    if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
01484       ast_debug(1, "Returning here, eid of incoming event matches ours!\n");
01485       return IKS_FILTER_EAT;
01486    }
01487    if (!strcasecmp(iks_name(item_content), "state")) {
01488       if ((cachable_str = iks_find_attrib(item_content, "cachable"))) {
01489          sscanf(cachable_str, "%30u", &cachable);
01490       }
01491       device_state = iks_find_cdata(item, "state");
01492       ast_publish_device_state_full(item_id,
01493                   ast_devstate_val(device_state),
01494                   cachable == AST_DEVSTATE_CACHABLE ? AST_DEVSTATE_CACHABLE : AST_DEVSTATE_NOT_CACHABLE,
01495                   &pubsub_eid);
01496       return IKS_FILTER_EAT;
01497    } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
01498       mailbox = strsep(&item_id, "@");
01499       sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
01500       sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
01501 
01502       ast_publish_mwi_state_full(mailbox, item_id, newmsgs, oldmsgs, NULL, &pubsub_eid);
01503 
01504       return IKS_FILTER_EAT;
01505    } else {
01506       ast_debug(1, "Don't know how to handle PubSub event of type %s\n",
01507            iks_name(item_content));
01508       return IKS_FILTER_EAT;
01509    }
01510 
01511    return IKS_FILTER_EAT;
01512 }

static iks* xmpp_pubsub_iq_create ( struct ast_xmpp_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 1046 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_strlen_zero, ast_xmpp_client_lock(), ast_xmpp_client_unlock(), ast_xmpp_increment_mid(), globals, ast_xmpp_client::jid, ast_xmpp_client::mid, ast_xmpp_client::name, NULL, RAII_VAR, request(), and xmpp_config_find().

Referenced by xmpp_pubsub_build_node_request(), xmpp_pubsub_build_publish_skeleton(), xmpp_pubsub_create_affiliations(), xmpp_pubsub_create_node(), xmpp_pubsub_delete_node(), xmpp_pubsub_handle_error(), xmpp_pubsub_subscribe(), and xmpp_pubsub_unsubscribe().

01047 {
01048    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01049    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01050    iks *request;
01051 
01052    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
01053        !(request = iks_new("iq"))) {
01054       return NULL;
01055    }
01056 
01057    if (!ast_strlen_zero(clientcfg->pubsubnode)) {
01058       iks_insert_attrib(request, "to", clientcfg->pubsubnode);
01059    }
01060 
01061    iks_insert_attrib(request, "from", client->jid->full);
01062    iks_insert_attrib(request, "type", type);
01063    ast_xmpp_client_lock(client);
01064    ast_xmpp_increment_mid(client->mid);
01065    iks_insert_attrib(request, "id", client->mid);
01066    ast_xmpp_client_unlock(client);
01067 
01068    return request;
01069 }

static void xmpp_pubsub_mwi_cb ( void *  data,
struct stasis_subscription sub,
struct stasis_message msg 
) [static]

Callback function for MWI events.

Parameters:
ast_event 
data void pointer to ast_client structure
Returns:
void

Definition at line 1343 of file res_xmpp.c.

References ast_eid_cmp(), ast_eid_default, ast_mwi_state_type(), ast_mwi_state::eid, ast_mwi_state::new_msgs, ast_mwi_state::old_msgs, stasis_message_data(), stasis_message_type(), stasis_subscription_is_subscribed(), ast_mwi_state::uniqueid, and xmpp_pubsub_publish_mwi().

Referenced by xmpp_init_event_distribution().

01344 {
01345    struct ast_xmpp_client *client = data;
01346    char oldmsgs[10], newmsgs[10];
01347    struct ast_mwi_state *mwi_state;
01348 
01349    if (!stasis_subscription_is_subscribed(sub) || ast_mwi_state_type() != stasis_message_type(msg)) {
01350       return;
01351    }
01352 
01353    mwi_state = stasis_message_data(msg);
01354 
01355    if (ast_eid_cmp(&ast_eid_default, &mwi_state->eid)) {
01356       /* If the event didn't originate from this server, don't send it back out. */
01357       return;
01358    }
01359 
01360    snprintf(oldmsgs, sizeof(oldmsgs), "%d", mwi_state->old_msgs);
01361    snprintf(newmsgs, sizeof(newmsgs), "%d", mwi_state->new_msgs);
01362    xmpp_pubsub_publish_mwi(client, mwi_state->uniqueid, oldmsgs, newmsgs);
01363 }

static void xmpp_pubsub_publish_device_state ( struct ast_xmpp_client client,
const char *  device,
const char *  device_state,
unsigned int  cachable 
) [static]

Publish device state to a PubSub node.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
device the name of the device whose state to publish
device_state the state to publish
Returns:
void

Definition at line 1307 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_eid_default, ast_eid_to_str(), ast_test_flag, ast_xmpp_client_send(), globals, NULL, RAII_VAR, request(), XMPP_PUBSUB_AUTOCREATE, xmpp_pubsub_build_publish_skeleton(), xmpp_pubsub_create_node(), and XMPP_XEP0248.

Referenced by xmpp_pubsub_devstate_cb().

01309 {
01310    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01311    iks *request, *state;
01312    char eid_str[20], cachable_str[2];
01313 
01314    if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state", cachable))) {
01315       return;
01316    }
01317 
01318    if (ast_test_flag(&cfg->global->pubsub, XMPP_PUBSUB_AUTOCREATE)) {
01319       if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
01320          xmpp_pubsub_create_node(client, "leaf", device, "device_state");
01321       } else {
01322          xmpp_pubsub_create_node(client, NULL, device, NULL);
01323       }
01324    }
01325 
01326    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
01327    state = iks_insert(request, "state");
01328    iks_insert_attrib(state, "xmlns", "http://asterisk.org");
01329    iks_insert_attrib(state, "eid", eid_str);
01330    snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
01331    iks_insert_attrib(state, "cachable", cachable_str);
01332    iks_insert_cdata(state, device_state, strlen(device_state));
01333    ast_xmpp_client_send(client, iks_root(request));
01334    iks_delete(request);
01335 }

static void xmpp_pubsub_publish_mwi ( struct ast_xmpp_client client,
const char *  mailbox,
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
mailbox The mailbox identifier
oldmsgs Old messages
newmsgs New Messages
Returns:
void

Definition at line 1276 of file res_xmpp.c.

References AST_DEVSTATE_CACHABLE, ast_eid_default, ast_eid_to_str(), ast_xmpp_client_send(), request(), and xmpp_pubsub_build_publish_skeleton().

Referenced by xmpp_pubsub_mwi_cb().

01278 {
01279    char eid_str[20];
01280    iks *mailbox_node, *request;
01281 
01282    request = xmpp_pubsub_build_publish_skeleton(client, mailbox, "message_waiting",
01283       AST_DEVSTATE_CACHABLE);
01284    if (!request) {
01285       return;
01286    }
01287 
01288    ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
01289    mailbox_node = iks_insert(request, "mailbox");
01290    iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
01291    iks_insert_attrib(mailbox_node, "eid", eid_str);
01292    iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
01293    iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
01294 
01295    ast_xmpp_client_send(client, iks_root(request));
01296 
01297    iks_delete(request);
01298 }

static void xmpp_pubsub_purge_nodes ( struct ast_xmpp_client client,
const char *  collection_name 
) [static]

Definition at line 4089 of file res_xmpp.c.

References ast_xmpp_client_send(), ast_xmpp_client::filter, ast_xmpp_client::mid, request(), xmpp_pubsub_build_node_request(), and xmpp_pubsub_delete_node_list().

Referenced by xmpp_cli_purge_pubsub_nodes().

04090 {
04091    iks *request = xmpp_pubsub_build_node_request(client, collection_name);
04092    ast_xmpp_client_send(client, request);
04093    iks_filter_add_rule(client->filter, xmpp_pubsub_delete_node_list, client, IKS_RULE_TYPE,
04094              IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
04095              IKS_RULE_DONE);
04096    ast_xmpp_client_send(client, request);
04097    iks_delete(request);
04098 }

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

Receive pubsub item lists.

Parameters:
data pointer to ast_xmpp_client structure
pak response from pubsub diso::items query
Returns:
IKS_FILTER_EAT

Definition at line 3969 of file res_xmpp.c.

References ast_verbose, item, ast_xmpp_client::jid, ast_xmpp_client::name, and NULL.

Referenced by xmpp_pubsub_request_nodes().

03970 {
03971    struct ast_xmpp_client *client = data;
03972    iks *item = NULL;
03973 
03974    if (iks_has_children(pak->query)) {
03975       item = iks_first_tag(pak->query);
03976       ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
03977              iks_find_attrib(item, "node"));
03978       while ((item = iks_next_tag(item))) {
03979          ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
03980       }
03981    }
03982 
03983    if (item) {
03984       iks_delete(item);
03985    }
03986 
03987 
03988    return IKS_FILTER_EAT;
03989 }

static void xmpp_pubsub_request_nodes ( struct ast_xmpp_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 3997 of file res_xmpp.c.

References ast_log, ast_xmpp_client_send(), ast_xmpp_client::filter, LOG_ERROR, ast_xmpp_client::mid, ast_xmpp_client::name, request(), xmpp_pubsub_build_node_request(), and xmpp_pubsub_receive_node_list().

Referenced by xmpp_cli_list_pubsub_nodes().

03998 {
03999    iks *request = xmpp_pubsub_build_node_request(client, collection);
04000 
04001    if (!request) {
04002       ast_log(LOG_ERROR, "Could not request pubsub nodes on client '%s' - IQ could not be created\n", client->name);
04003       return;
04004    }
04005 
04006    iks_filter_add_rule(client->filter, xmpp_pubsub_receive_node_list, client, IKS_RULE_TYPE,
04007              IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
04008              IKS_RULE_DONE);
04009    ast_xmpp_client_send(client, request);
04010    iks_delete(request);
04011 
04012 }

static void xmpp_pubsub_subscribe ( struct ast_xmpp_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 1421 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_log, ast_test_flag, ast_xmpp_client_send(), globals, ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::name, RAII_VAR, request(), subscribe, xmpp_pubsub_iq_create(), and XMPP_XEP0248.

Referenced by xmpp_init_event_distribution().

01422 {
01423    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01424    iks *request = xmpp_pubsub_iq_create(client, "set");
01425    iks *pubsub, *subscribe;
01426 
01427    if (!cfg || !cfg->global || !request) {
01428       ast_log(LOG_ERROR, "Could not create IQ when creating pubsub subscription on client '%s'\n", client->name);
01429       return;
01430    }
01431 
01432    pubsub = iks_insert(request, "pubsub");
01433    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
01434    subscribe = iks_insert(pubsub, "subscribe");
01435    iks_insert_attrib(subscribe, "jid", client->jid->partial);
01436    iks_insert_attrib(subscribe, "node", node);
01437    if (ast_test_flag(&cfg->global->pubsub, XMPP_XEP0248)) {
01438       iks *options, *x, *sub_options, *sub_type, *sub_depth, *sub_expire;
01439       options = iks_insert(pubsub, "options");
01440       x = iks_insert(options, "x");
01441       iks_insert_attrib(x, "xmlns", "jabber:x:data");
01442       iks_insert_attrib(x, "type", "submit");
01443       sub_options = iks_insert(x, "field");
01444       iks_insert_attrib(sub_options, "var", "FORM_TYPE");
01445       iks_insert_attrib(sub_options, "type", "hidden");
01446       iks_insert_cdata(iks_insert(sub_options, "value"),
01447              "http://jabber.org/protocol/pubsub#subscribe_options", 51);
01448       sub_type = iks_insert(x, "field");
01449       iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
01450       iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
01451       sub_depth = iks_insert(x, "field");
01452       iks_insert_attrib(sub_depth, "var", "pubsub#subscription_depth");
01453       iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
01454       sub_expire = iks_insert(x, "field");
01455       iks_insert_attrib(sub_expire, "var", "pubsub#expire");
01456       iks_insert_cdata(iks_insert(sub_expire, "value"), "presence", 8);
01457    }
01458    ast_xmpp_client_send(client, request);
01459    iks_delete(request);
01460 }

static void xmpp_pubsub_unsubscribe ( struct ast_xmpp_client client,
const char *  node 
) [static]

Unsubscribe from 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 unsubscribe from
Returns:
void

Definition at line 1395 of file res_xmpp.c.

References ast_log, ast_xmpp_client_send(), ast_xmpp_client::jid, LOG_ERROR, ast_xmpp_client::name, request(), unsubscribe(), and xmpp_pubsub_iq_create().

Referenced by ast_xmpp_client_disconnect(), and xmpp_init_event_distribution().

01396 {
01397    iks *request = xmpp_pubsub_iq_create(client, "set");
01398    iks *pubsub, *unsubscribe;
01399 
01400    if (!request) {
01401       ast_log(LOG_ERROR, "Could not create IQ when creating pubsub unsubscription on client '%s'\n", client->name);
01402       return;
01403    }
01404 
01405    pubsub = iks_insert(request, "pubsub");
01406    iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
01407    unsubscribe = iks_insert(pubsub, "unsubscribe");
01408    iks_insert_attrib(unsubscribe, "jid", client->jid->partial);
01409    iks_insert_attrib(unsubscribe, "node", node);
01410 
01411    ast_xmpp_client_send(client, request);
01412    iks_delete(request);
01413 }

static int xmpp_resource_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Comparator function for XMPP resource.

Definition at line 854 of file res_xmpp.c.

References CMP_MATCH, CMP_STOP, and ast_xmpp_resource::resource.

Referenced by acf_jabberstatus_read(), xmpp_client_create_buddy(), xmpp_client_service_discovery_result_hook(), xmpp_pak_presence(), and xmpp_status_exec().

00855 {
00856    struct ast_xmpp_resource *resource1 = obj;
00857    const char *resource = arg;
00858 
00859    return !strcmp(resource1->resource, resource) ? CMP_MATCH | CMP_STOP : 0;
00860 }

static void xmpp_resource_destructor ( void *  obj  )  [static]

Destructor callback function for XMPP resource.

Definition at line 836 of file res_xmpp.c.

References ast_free, ast_xmpp_resource::description, and ast_xmpp_resource::resource.

Referenced by xmpp_pak_presence().

00837 {
00838    struct ast_xmpp_resource *resource = obj;
00839 
00840    if (resource->description) {
00841       ast_free(resource->description);
00842    }
00843 }

static int xmpp_resource_hash ( const void *  obj,
const int  flags 
) [static]

Hashing function for XMPP resource.

Definition at line 846 of file res_xmpp.c.

References OBJ_KEY, ast_xmpp_resource::priority, and ast_xmpp_resource::resource.

Referenced by xmpp_client_create_buddy().

00847 {
00848    const struct ast_xmpp_resource *resource = obj;
00849 
00850    return flags & OBJ_KEY ? -1 : resource->priority;
00851 }

static int xmpp_resource_immediate ( void *  obj,
void *  arg,
int  flags 
) [static]

Internal astobj2 callback function which returns the first resource, which is the highest priority one.

Definition at line 1630 of file res_xmpp.c.

References CMP_MATCH, and CMP_STOP.

Referenced by acf_jabberstatus_read(), and xmpp_status_exec().

01631 {
01632    return CMP_MATCH | CMP_STOP;
01633 }

static int xmpp_resource_is_available ( void *  obj,
void *  arg,
int  flags 
) [static]

Callback function which returns when the resource is available.

Definition at line 3258 of file res_xmpp.c.

References CMP_MATCH, CMP_STOP, ast_xmpp_resource::resource, and ast_xmpp_resource::status.

Referenced by xmpp_pak_presence().

03259 {
03260    struct ast_xmpp_resource *resource = obj;
03261 
03262    return (resource->status == IKS_SHOW_AVAILABLE) ? CMP_MATCH | CMP_STOP : 0;
03263 }

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

Hook function called when roster is received from server.

Definition at line 2322 of file res_xmpp.c.

References ao2_callback, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_ref, ast_log, ast_test_flag, ast_xmpp_client::buddies, globals, item, LOG_ERROR, ast_xmpp_client::name, NULL, OBJ_KEY, OBJ_MULTIPLE, OBJ_NODATA, RAII_VAR, ast_xmpp_buddy::subscribe, XMPP_AUTOPRUNE, XMPP_AUTOREGISTER, xmpp_client_change_state(), xmpp_client_create_buddy(), xmpp_client_subscribe_user(), xmpp_client_unsubscribe_user(), xmpp_config_find(), and XMPP_STATE_CONNECTED.

Referenced by xmpp_connect_hook().

02323 {
02324    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02325    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02326    struct ast_xmpp_client *client = data;
02327    iks *item;
02328 
02329    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name))) {
02330       return IKS_FILTER_EAT;
02331    }
02332 
02333    for (item = iks_child(pak->query); item; item = iks_next(item)) {
02334       struct ast_xmpp_buddy *buddy;
02335 
02336       if (iks_strcmp(iks_name(item), "item")) {
02337          continue;
02338       }
02339 
02340       if (!(buddy = ao2_find(client->buddies, iks_find_attrib(item, "jid"), OBJ_KEY))) {
02341          if (ast_test_flag(&clientcfg->flags, XMPP_AUTOPRUNE)) {
02342             /* The buddy has not been specified in the configuration file, we no longer
02343              * want them on our buddy list or to receive their presence. */
02344             if (xmpp_client_unsubscribe_user(client, iks_find_attrib(item, "jid"))) {
02345                ast_log(LOG_ERROR, "Could not unsubscribe user '%s' on client '%s'\n",
02346                   iks_find_attrib(item, "jid"), client->name);
02347             }
02348             continue;
02349          }
02350 
02351          if (!(buddy = xmpp_client_create_buddy(client->buddies, iks_find_attrib(item, "jid")))) {
02352             ast_log(LOG_ERROR, "Could not allocate buddy '%s' on client '%s'\n", iks_find_attrib(item, "jid"),
02353                client->name);
02354             continue;
02355          }
02356       }
02357 
02358       /* Determine if we need to subscribe to their presence or not */
02359       if (!iks_strcmp(iks_find_attrib(item, "subscription"), "none") ||
02360           !iks_strcmp(iks_find_attrib(item, "subscription"), "from")) {
02361          buddy->subscribe = 1;
02362       } else {
02363          buddy->subscribe = 0;
02364       }
02365 
02366       ao2_ref(buddy, -1);
02367    }
02368 
02369    /* If autoregister is enabled we need to go through every buddy that we need to subscribe to and do so */
02370    if (ast_test_flag(&clientcfg->flags, XMPP_AUTOREGISTER)) {
02371       ao2_callback(client->buddies, OBJ_NODATA | OBJ_MULTIPLE, xmpp_client_subscribe_user, client);
02372    }
02373 
02374    xmpp_client_change_state(client, XMPP_STATE_CONNECTED);
02375 
02376    return IKS_FILTER_EAT;
02377 }

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

Definition at line 2203 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ast_debug, ast_log, ast_msg_get_body(), ast_strdupa, ast_strlen_zero, ast_xmpp_client_send_message(), globals, LOG_ERROR, LOG_WARNING, NULL, RAII_VAR, strsep(), and xmpp_config_find().

02204 {
02205    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
02206    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
02207    char *sender, *dest;
02208    int res;
02209 
02210    sender = ast_strdupa(from);
02211    strsep(&sender, ":");
02212    dest = ast_strdupa(to);
02213    strsep(&dest, ":");
02214 
02215    if (ast_strlen_zero(sender)) {
02216       ast_log(LOG_ERROR, "MESSAGE(from) of '%s' invalid for XMPP\n", from);
02217       return -1;
02218    }
02219 
02220    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, sender))) {
02221       ast_log(LOG_WARNING, "Could not finder account to send from as '%s'\n", sender);
02222       return -1;
02223    }
02224 
02225    ast_debug(1, "Sending message to '%s' from '%s'\n", dest, clientcfg->name);
02226 
02227    if ((res = ast_xmpp_client_send_message(clientcfg->client, dest, ast_msg_get_body(msg))) != IKS_OK) {
02228       ast_log(LOG_WARNING, "Failed to send XMPP message (%d).\n", res);
02229    }
02230 
02231    return res == IKS_OK ? 0 : -1;
02232 }

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

Definition at line 1916 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_xmpp_client_send_message(), globals, LOG_WARNING, NULL, RAII_VAR, and xmpp_config_find().

Referenced by load_module().

01917 {
01918    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01919    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01920    char *s;
01921    AST_DECLARE_APP_ARGS(args,
01922               AST_APP_ARG(sender);
01923               AST_APP_ARG(recipient);
01924               AST_APP_ARG(message);
01925       );
01926 
01927    if (ast_strlen_zero(data)) {
01928       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01929       return -1;
01930    }
01931    s = ast_strdupa(data);
01932 
01933    AST_STANDARD_APP_ARGS(args, s);
01934 
01935    if ((args.argc < 3) || ast_strlen_zero(args.message) || !strchr(args.recipient, '@')) {
01936       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01937       return -1;
01938    }
01939 
01940    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
01941       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
01942       return -1;
01943    }
01944 
01945    ast_xmpp_client_send_message(clientcfg->client, args.recipient, args.message);
01946 
01947    return 0;
01948 }

static int xmpp_send_stream_header ( struct ast_xmpp_client client,
const struct ast_xmpp_client_config cfg,
const char *  to 
) [static]

Helper function which sends an XMPP stream header to the server.

Definition at line 2591 of file res_xmpp.c.

References ast_test_flag, ast_xmpp_client_config::flags, xmpp_client_send_raw_message(), and XMPP_COMPONENT.

Referenced by xmpp_client_authenticating(), and xmpp_client_requested_tls().

02592 {
02593    char *namespace = ast_test_flag(&cfg->flags, XMPP_COMPONENT) ? "jabber:component:accept" : "jabber:client";
02594    char msg[91 + strlen(namespace) + 6 + strlen(to) + 16 + 1];
02595 
02596    snprintf(msg, sizeof(msg), "<?xml version='1.0'?>"
02597        "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
02598        "%s' to='%s' version='1.0'>", namespace, to);
02599 
02600    return xmpp_client_send_raw_message(client, msg);
02601 }

static int xmpp_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 1957 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, ast_xmpp_chatroom_send(), globals, LOG_ERROR, NULL, RAII_VAR, XMPP_COMPONENT, xmpp_config_find(), and XMPP_MAX_RESJIDLEN.

Referenced by load_module().

01958 {
01959    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01960    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01961    char *s, nick[XMPP_MAX_RESJIDLEN];
01962    AST_DECLARE_APP_ARGS(args,
01963               AST_APP_ARG(sender);
01964               AST_APP_ARG(groupchat);
01965               AST_APP_ARG(message);
01966               AST_APP_ARG(nick);
01967       );
01968 
01969    if (ast_strlen_zero(data)) {
01970       ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01971       return -1;
01972    }
01973    s = ast_strdupa(data);
01974 
01975    AST_STANDARD_APP_ARGS(args, s);
01976    if ((args.argc < 3) || (args.argc > 4) || ast_strlen_zero(args.message) || !strchr(args.groupchat, '@')) {
01977       ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01978       return -1;
01979    }
01980 
01981    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
01982       ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01983       return -1;
01984    }
01985 
01986    if (ast_strlen_zero(args.nick) || args.argc == 3) {
01987       if (ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
01988          snprintf(nick, sizeof(nick), "asterisk");
01989       } else {
01990          snprintf(nick, sizeof(nick), "%s", clientcfg->client->jid->user);
01991       }
01992    } else {
01993       snprintf(nick, sizeof(nick), "%s", args.nick);
01994    }
01995 
01996    ast_xmpp_chatroom_send(clientcfg->client, nick, args.groupchat, args.message);
01997 
01998    return 0;
01999 }

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

Definition at line 4382 of file res_xmpp.c.

References ao2_cleanup, ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), ast_xmpp_client::buddies, ast_xmpp_resource::caps, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_xmpp_client_config::client, ast_cli_entry::command, ast_cli_args::fd, globals, ast_xmpp_capabilities::google, ast_xmpp_buddy::id, ast_xmpp_capabilities::jingle, ast_xmpp_client_config::name, ast_xmpp_capabilities::node, NULL, RAII_VAR, ast_xmpp_resource::resource, ast_xmpp_buddy::resources, ast_cli_entry::usage, and ast_xmpp_capabilities::version.

04383 {
04384    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
04385    struct ao2_iterator i;
04386    struct ast_xmpp_client_config *clientcfg;
04387 
04388    switch (cmd) {
04389    case CLI_INIT:
04390       e->command = "xmpp show buddies";
04391       e->usage =
04392          "Usage: xmpp show buddies\n"
04393          "       Shows buddy lists of our clients\n";
04394       return NULL;
04395    case CLI_GENERATE:
04396       return NULL;
04397    }
04398 
04399    if (!cfg || !cfg->clients) {
04400       return NULL;
04401    }
04402 
04403    ast_cli(a->fd, "XMPP buddy lists\n");
04404 
04405    i = ao2_iterator_init(cfg->clients, 0);
04406    while ((clientcfg = ao2_iterator_next(&i))) {
04407       struct ao2_iterator bud;
04408       struct ast_xmpp_buddy *buddy;
04409 
04410       ast_cli(a->fd, "Client: %s\n", clientcfg->name);
04411 
04412       bud = ao2_iterator_init(clientcfg->client->buddies, 0);
04413       while ((buddy = ao2_iterator_next(&bud))) {
04414          struct ao2_iterator res;
04415          struct ast_xmpp_resource *resource;
04416 
04417          ast_cli(a->fd, "\tBuddy:\t%s\n", buddy->id);
04418 
04419          res = ao2_iterator_init(buddy->resources, 0);
04420          while ((resource = ao2_iterator_next(&res))) {
04421             ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
04422             ast_cli(a->fd, "\t\t\tnode: %s\n", resource->caps.node);
04423             ast_cli(a->fd, "\t\t\tversion: %s\n", resource->caps.version);
04424             ast_cli(a->fd, "\t\t\tGoogle Talk capable: %s\n", resource->caps.google ? "yes" : "no");
04425             ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->caps.jingle ? "yes" : "no");
04426 
04427             ao2_ref(resource, -1);
04428          }
04429          ao2_iterator_destroy(&res);
04430 
04431          ao2_ref(buddy, -1);
04432       }
04433       ao2_iterator_destroy(&bud);
04434 
04435       ao2_ref(clientcfg, -1);
04436    }
04437    ao2_iterator_destroy(&i);
04438 
04439    return CLI_SUCCESS;
04440 }

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

Definition at line 4306 of file res_xmpp.c.

References ao2_cleanup, ao2_container_count(), ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_xmpp_client_config::client, ast_cli_entry::command, ast_cli_args::fd, globals, ast_xmpp_client_config::name, NULL, RAII_VAR, ast_xmpp_client::state, ast_cli_entry::usage, ast_xmpp_client_config::user, XMPP_STATE_AUTHENTICATE, XMPP_STATE_AUTHENTICATING, XMPP_STATE_CONNECTED, XMPP_STATE_CONNECTING, XMPP_STATE_DISCONNECTED, XMPP_STATE_DISCONNECTING, XMPP_STATE_REQUEST_TLS, XMPP_STATE_REQUESTED_TLS, and XMPP_STATE_ROSTER.

04307 {
04308    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
04309    struct ao2_iterator i;
04310    struct ast_xmpp_client_config *clientcfg;
04311 
04312    switch (cmd) {
04313    case CLI_INIT:
04314       e->command = "xmpp show connections";
04315       e->usage =
04316          "Usage: xmpp show connections\n"
04317          "       Shows state of client and component connections\n";
04318       return NULL;
04319    case CLI_GENERATE:
04320       return NULL;
04321    }
04322 
04323    if (!cfg || !cfg->clients) {
04324       return NULL;
04325    }
04326 
04327    ast_cli(a->fd, "Jabber Users and their status:\n");
04328 
04329    i = ao2_iterator_init(cfg->clients, 0);
04330    while ((clientcfg = ao2_iterator_next(&i))) {
04331       char *state;
04332 
04333       switch (clientcfg->client->state) {
04334       case XMPP_STATE_DISCONNECTING:
04335          state = "Disconnecting";
04336          break;
04337       case XMPP_STATE_DISCONNECTED:
04338          state = "Disconnected";
04339          break;
04340       case XMPP_STATE_CONNECTING:
04341          state = "Connecting";
04342          break;
04343       case XMPP_STATE_REQUEST_TLS:
04344          state = "Waiting to request TLS";
04345          break;
04346       case XMPP_STATE_REQUESTED_TLS:
04347          state = "Requested TLS";
04348          break;
04349       case XMPP_STATE_AUTHENTICATE:
04350          state = "Waiting to authenticate";
04351          break;
04352       case XMPP_STATE_AUTHENTICATING:
04353          state = "Authenticating";
04354          break;
04355       case XMPP_STATE_ROSTER:
04356          state = "Retrieving roster";
04357          break;
04358       case XMPP_STATE_CONNECTED:
04359          state = "Connected";
04360          break;
04361       default:
04362          state = "Unknown";
04363       }
04364 
04365       ast_cli(a->fd, "       [%s] %s     - %s\n", clientcfg->name, clientcfg->user, state);
04366 
04367       ao2_ref(clientcfg, -1);
04368    }
04369    ao2_iterator_destroy(&i);
04370 
04371    ast_cli(a->fd, "----\n");
04372    ast_cli(a->fd, "   Number of clients: %d\n", ao2_container_count(cfg->clients));
04373 
04374    return CLI_SUCCESS;
04375 }

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

Definition at line 1644 of file res_xmpp.c.

References ao2_callback, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, globals, LOG_ERROR, LOG_NOTICE, LOG_WARNING, NULL, OBJ_KEY, OBJ_NODATA, pbx_builtin_setvar_helper(), RAII_VAR, ast_xmpp_resource::resource, ast_xmpp_buddy::resources, ast_xmpp_resource::status, status, xmpp_config_find(), xmpp_resource_cmp(), and xmpp_resource_immediate().

Referenced by load_module().

01645 {
01646    RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01647    RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
01648    struct ast_xmpp_buddy *buddy;
01649    struct ast_xmpp_resource *resource;
01650    char *s = NULL, status[2];
01651    int stat = 7;
01652    static int deprecation_warning = 0;
01653    AST_DECLARE_APP_ARGS(args,
01654               AST_APP_ARG(sender);
01655               AST_APP_ARG(jid);
01656               AST_APP_ARG(variable);
01657       );
01658    AST_DECLARE_APP_ARGS(jid,
01659               AST_APP_ARG(screenname);
01660               AST_APP_ARG(resource);
01661       );
01662 
01663    if (deprecation_warning++ % 10 == 0) {
01664       ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
01665    }
01666 
01667    if (ast_strlen_zero(data)) {
01668       ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
01669       return 0;
01670    }
01671    s = ast_strdupa(data);
01672    AST_STANDARD_APP_ARGS(args, s);
01673 
01674    if (args.argc != 3) {
01675       ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
01676       return -1;
01677    }
01678 
01679    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
01680    if (jid.argc < 1 || jid.argc > 2) {
01681       ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
01682       return -1;
01683    }
01684 
01685    if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, args.sender))) {
01686       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
01687       return -1;
01688    }
01689 
01690    if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
01691       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
01692       return -1;
01693    }
01694 
01695    if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
01696       resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
01697    }
01698 
01699    ao2_ref(buddy, -1);
01700 
01701    if (resource) {
01702       stat = resource->status;
01703       ao2_ref(resource, -1);
01704    } else {
01705       ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
01706    }
01707 
01708    snprintf(status, sizeof(status), "%d", stat);
01709    pbx_builtin_setvar_helper(chan, args.variable, status);
01710 
01711    return 0;
01712 }


Variable Documentation

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

Definition at line 4669 of file res_xmpp.c.

const char* app_ajijoin = "JabberJoin" [static]

Definition at line 525 of file res_xmpp.c.

const char* app_ajileave = "JabberLeave" [static]

Definition at line 526 of file res_xmpp.c.

const char* app_ajisend = "JabberSend" [static]

Definition at line 522 of file res_xmpp.c.

const char* app_ajisendgroup = "JabberSendGroup" [static]

Definition at line 523 of file res_xmpp.c.

const char* app_ajistatus = "JabberStatus" [static]

Definition at line 524 of file res_xmpp.c.

Definition at line 4669 of file res_xmpp.c.

struct aco_type client_option [static]

Definition at line 811 of file res_xmpp.c.

struct aco_type* client_options[] = ACO_TYPES(&client_option)

Definition at line 822 of file res_xmpp.c.

int debug [static]

struct aco_type global_option [static]

Definition at line 801 of file res_xmpp.c.

struct aco_type* global_options[] = ACO_TYPES(&global_option)

Definition at line 809 of file res_xmpp.c.

Initial value:

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

Definition at line 2156 of file res_xmpp.c.

Initial value:

 {
   .name = "JABBER_STATUS",
   .read