2006-05-22 21:12:30 +00:00
/*
* Asterisk - - An open source telephony toolkit .
*
2010-06-15 17:06:23 +00:00
* Copyright ( C ) 1999 - 2010 , Digium , Inc .
2006-05-22 21:12:30 +00:00
*
* Matt O ' Gorman < mogorman @ digium . com >
*
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
* This program is free software , distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
/*! \file
2008-08-06 13:34:08 +00:00
* \ brief A resource for interfacing Asterisk directly as a client
* or a component to a XMPP / Jabber compliant server .
*
* References :
* - http : //www.xmpp.org - The XMPP standards foundation
2007-05-07 18:25:56 +00:00
*
2012-09-21 17:14:59 +00:00
* Iksemel http : //code.google.com/p/iksemel/
2007-06-07 10:06:32 +00:00
*
* \ todo If you unload this module , chan_gtalk / jingle will be dead . How do we handle that ?
2008-08-06 13:34:08 +00:00
* \ todo Dialplan applications need RETURN variable , like JABBERSENDSTATUS
2007-06-07 10:06:32 +00:00
*
2006-05-22 21:12:30 +00:00
*/
2012-10-14 21:44:27 +00:00
/*! \li \ref res_jabber.c uses the configuration file \ref jabber.conf
* \ addtogroup configuration_file Configuration Files
*/
/*!
* \ page jabber . conf jabber . conf
* \ verbinclude jabber . conf . sample
*/
2006-05-22 21:12:30 +00:00
/*** MODULEINFO
2012-07-07 17:06:51 +00:00
< defaultenabled > no < / defaultenabled >
2006-05-22 21:12:30 +00:00
< depend > iksemel < / depend >
2011-07-05 22:11:40 +00:00
< use type = " external " > openssl < / use >
2012-09-10 19:49:30 +00:00
< support_level > deprecated < / support_level >
< replacement > res_xmpp < / replacement >
2006-05-22 21:12:30 +00:00
* * */
2009-12-07 17:59:46 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
# include <ctype.h>
# include <iksemel.h>
# include "asterisk/channel.h"
# include "asterisk/jabber.h"
# include "asterisk/file.h"
# include "asterisk/config.h"
# include "asterisk/callerid.h"
# include "asterisk/lock.h"
# include "asterisk/cli.h"
# include "asterisk/app.h"
# include "asterisk/pbx.h"
# include "asterisk/md5.h"
# include "asterisk/acl.h"
# include "asterisk/utils.h"
# include "asterisk/module.h"
# include "asterisk/astobj.h"
# include "asterisk/astdb.h"
# include "asterisk/manager.h"
2010-06-15 17:06:23 +00:00
# include "asterisk/devicestate.h"
2011-06-01 21:31:40 +00:00
# include "asterisk/message.h"
2009-12-07 17:59:46 +00:00
2009-09-25 10:54:42 +00:00
/*** DOCUMENTATION
2013-01-16 15:33:05 +00:00
< application name = " JabberSend " language = " en_US " module = " res_jabber " >
2009-09-25 10:54:42 +00:00
< synopsis >
Sends an XMPP message to a buddy .
< / synopsis >
< syntax >
< parameter name = " account " required = " true " >
< para > The local named account to listen on ( specified in
jabber . conf ) < / para >
< / parameter >
< parameter name = " jid " required = " true " >
< para > Jabber ID of the buddy to send the message to . It can be a
bare JID ( username @ domain ) or a full JID ( username @ domain / resource ) . < / para >
< / parameter >
< parameter name = " message " required = " true " >
< para > The message to send . < / para >
< / parameter >
< / syntax >
< description >
< para > Sends the content of < replaceable > message < / replaceable > as text message
from the given < replaceable > account < / replaceable > to the buddy identified by
< replaceable > jid < / replaceable > < / para >
< para > Example : JabberSend ( asterisk , bob @ domain . com , Hello world ) sends " Hello world "
to < replaceable > bob @ domain . com < / replaceable > as an XMPP message from the account
< replaceable > asterisk < / replaceable > , configured in jabber . conf . < / para >
< / description >
< see - also >
2013-01-16 17:46:15 +00:00
< ref type = " function " module = " res_jabber " > JABBER_STATUS < / ref >
< ref type = " function " module = " res_jabber " > JABBER_RECEIVE < / ref >
2009-09-25 10:54:42 +00:00
< / see - also >
< / application >
2013-01-16 15:33:05 +00:00
< function name = " JABBER_RECEIVE " language = " en_US " module = " res_jabber " >
2009-09-25 10:54:42 +00:00
< synopsis >
Reads XMPP messages .
< / synopsis >
< syntax >
< parameter name = " account " required = " true " >
< para > The local named account to listen on ( specified in
jabber . conf ) < / para >
< / parameter >
< parameter name = " jid " required = " true " >
< para > Jabber ID of the buddy to receive message from . It can be a
bare JID ( username @ domain ) or a full JID ( username @ domain / resource ) . < / para >
< / parameter >
< parameter name = " timeout " >
< para > In seconds , defaults to < literal > 20 < / literal > . < / para >
< / parameter >
< / syntax >
< description >
< para > Receives a text message on the given < replaceable > account < / replaceable >
from the buddy identified by < replaceable > jid < / replaceable > and returns the contents . < / para >
< para > Example : $ { JABBER_RECEIVE ( asterisk , bob @ domain . com ) } returns an XMPP message
sent from < replaceable > bob @ domain . com < / replaceable > ( or nothing in case of a time out ) , to
the < replaceable > asterisk < / replaceable > XMPP account configured in jabber . conf . < / para >
< / description >
< see - also >
2013-01-16 17:46:15 +00:00
< ref type = " function " module = " res_jabber " > JABBER_STATUS < / ref >
< ref type = " application " module = " res_jabber " > JabberSend < / ref >
2009-09-25 10:54:42 +00:00
< / see - also >
< / function >
2013-01-16 15:33:05 +00:00
< function name = " JABBER_STATUS " language = " en_US " module = " res_jabber " >
2009-09-25 10:54:42 +00:00
< synopsis >
Retrieves a buddy ' s status .
< / synopsis >
< syntax >
< parameter name = " account " required = " true " >
< para > The local named account to listen on ( specified in
jabber . conf ) < / para >
< / parameter >
< parameter name = " jid " required = " true " >
< para > Jabber ID of the buddy to receive message from . It can be a
bare JID ( username @ domain ) or a full JID ( username @ domain / resource ) . < / para >
< / parameter >
< / syntax >
< description >
< para > Retrieves the numeric status associated with the buddy identified
by < replaceable > jid < / replaceable > .
If the buddy does not exist in the buddylist , returns 7. < / para >
< para > Status will be 1 - 7. < / para >
< para > 1 = Online , 2 = Chatty , 3 = Away , 4 = XAway , 5 = DND , 6 = Offline < / para >
< para > If not in roster variable will be set to 7. < / para >
< para > Example : $ { JABBER_STATUS ( asterisk , bob @ domain . com ) } returns 1 if
< replaceable > bob @ domain . com < / replaceable > is online . < replaceable > asterisk < / replaceable > is
the associated XMPP account configured in jabber . conf . < / para >
< / description >
< see - also >
2013-01-16 17:46:15 +00:00
< ref type = " function " module = " res_jabber " > JABBER_RECEIVE < / ref >
< ref type = " application " module = " res_jabber " > JabberSend < / ref >
2009-09-25 10:54:42 +00:00
< / see - also >
< / function >
2013-01-16 15:33:05 +00:00
< application name = " JabberSendGroup " language = " en_US " module = " res_jabber " >
2009-02-04 21:26:15 +00:00
< synopsis >
2009-12-07 17:59:46 +00:00
Send a Jabber Message to a specified chat room
2009-02-04 21:26:15 +00:00
< / synopsis >
< syntax >
< parameter name = " Jabber " required = " true " >
< para > Client or transport Asterisk uses to connect to Jabber . < / para >
< / parameter >
2009-12-07 17:59:46 +00:00
< parameter name = " RoomJID " required = " true " >
< para > XMPP / Jabber JID ( Name ) of chat room . < / para >
2009-02-04 21:26:15 +00:00
< / parameter >
< parameter name = " Message " required = " true " >
2009-12-07 17:59:46 +00:00
< para > Message to be sent to the chat room . < / para >
< / parameter >
< parameter name = " Nickname " required = " false " >
< para > The nickname Asterisk uses in the chat room . < / para >
2009-02-04 21:26:15 +00:00
< / parameter >
< / syntax >
< description >
2009-12-07 17:59:46 +00:00
< para > Allows user to send a message to a chat room via XMPP . < / para >
< note > < para > To be able to send messages to a chat room , a user must have previously joined it . Use the < replaceable > JabberJoin < / replaceable > function to do so . < / para > < / note >
2009-02-04 21:26:15 +00:00
< / description >
< / application >
2013-01-16 15:33:05 +00:00
< application name = " JabberJoin " language = " en_US " module = " res_jabber " >
2009-02-04 21:26:15 +00:00
< synopsis >
2010-03-02 19:02:56 +00:00
Join a chat room
2009-02-04 21:26:15 +00:00
< / synopsis >
< syntax >
< parameter name = " Jabber " required = " true " >
2009-12-07 17:59:46 +00:00
< para > Client or transport Asterisk uses to connect to Jabber . < / para >
2009-02-04 21:26:15 +00:00
< / parameter >
2009-12-07 17:59:46 +00:00
< parameter name = " RoomJID " required = " true " >
< para > XMPP / Jabber JID ( Name ) of chat room . < / para >
2009-02-04 21:26:15 +00:00
< / parameter >
2009-12-07 17:59:46 +00:00
< parameter name = " Nickname " required = " false " >
< para > The nickname Asterisk will use in the chat room . < / para >
< note > < para > If a different nickname is supplied to an already joined room , the old nick will be changed to the new one . < / para > < / note >
2009-02-04 21:26:15 +00:00
< / parameter >
< / syntax >
< description >
2009-12-07 17:59:46 +00:00
< para > Allows Asterisk to join a chat room . < / para >
2009-02-04 21:26:15 +00:00
< / description >
< / application >
2013-01-16 15:33:05 +00:00
< application name = " JabberLeave " language = " en_US " module = " res_jabber " >
2009-12-07 17:59:46 +00:00
< synopsis >
2010-03-02 19:02:56 +00:00
Leave a chat room
2009-12-07 17:59:46 +00:00
< / synopsis >
< syntax >
< parameter name = " Jabber " required = " true " >
< para > Client or transport Asterisk uses to connect to Jabber . < / para >
< / parameter >
< parameter name = " RoomJID " required = " true " >
< para > XMPP / Jabber JID ( Name ) of chat room . < / para >
< / parameter >
< parameter name = " Nickname " required = " false " >
< para > The nickname Asterisk uses in the chat room . < / para >
< / parameter >
< / syntax >
< description >
< para > Allows Asterisk to leave a chat room . < / para >
< / description >
< / application >
2013-01-16 15:33:05 +00:00
< application name = " JabberStatus " language = " en_US " module = " res_jabber " >
2009-02-04 21:26:15 +00:00
< synopsis >
2009-02-13 20:26:49 +00:00
Retrieve the status of a jabber list member
2009-02-04 21:26:15 +00:00
< / synopsis >
< syntax >
2009-12-07 17:59:46 +00:00
< parameter name = " Jabber " required = " true " >
< para > Client or transport Asterisk users to connect to Jabber . < / para >
2009-02-04 21:26:15 +00:00
< / parameter >
2009-12-07 17:59:46 +00:00
< parameter name = " JID " required = " true " >
2009-02-04 21:26:15 +00:00
< para > XMPP / Jabber JID ( Name ) of recipient . < / para >
< / parameter >
2009-12-07 17:59:46 +00:00
< parameter name = " Variable " required = " true " >
< para > Variable to store the status of requested user . < / para >
2009-02-04 21:26:15 +00:00
< / parameter >
< / syntax >
< description >
2009-12-07 17:59:46 +00:00
< para > This application is deprecated . Please use the JABBER_STATUS ( ) function instead . < / para >
2009-02-04 21:26:15 +00:00
< para > Retrieves the numeric status associated with the specified buddy < replaceable > JID < / replaceable > .
2009-12-07 17:59:46 +00:00
The return value in the < replaceable > Variable < / replaceable > will be one of the following . < / para >
2009-02-04 21:26:15 +00:00
< enumlist >
< enum name = " 1 " >
< para > Online . < / para >
< / enum >
< enum name = " 2 " >
< para > Chatty . < / para >
< / enum >
< enum name = " 3 " >
< para > Away . < / para >
< / enum >
< enum name = " 4 " >
< para > Extended Away . < / para >
< / enum >
< enum name = " 5 " >
< para > Do Not Disturb . < / para >
< / enum >
< enum name = " 6 " >
< para > Offline . < / para >
< / enum >
< enum name = " 7 " >
< para > Not In Roster . < / para >
< / enum >
< / enumlist >
< / description >
2013-01-16 17:46:15 +00:00
< / application >
2013-01-16 15:33:05 +00:00
< manager name = " JabberSend " language = " en_US " module = " res_jabber " >
2009-06-01 16:09:42 +00:00
< synopsis >
Sends a message to a Jabber Client .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Jabber " required = " true " >
< para > Client or transport Asterisk uses to connect to JABBER . < / para >
< / parameter >
< parameter name = " JID " required = " true " >
< para > XMPP / Jabber JID ( Name ) of recipient . < / para >
< / parameter >
< parameter name = " Message " required = " true " >
< para > Message to be sent to the buddy . < / para >
< / parameter >
< / syntax >
< description >
< para > Sends a message to a Jabber Client . < / para >
< / description >
< / manager >
2009-02-04 21:26:15 +00:00
* * */
2010-06-15 17:06:23 +00:00
/*!\todo This should really be renamed to xmpp.conf. For backwards compatibility, we
* need to read both files */
2006-05-22 21:12:30 +00:00
# define JABBER_CONFIG "jabber.conf"
2006-08-07 21:15:28 +00:00
/*-- Forward declarations */
2009-09-25 10:54:42 +00:00
static void aji_message_destroy ( struct aji_message * obj ) ;
2007-11-01 22:10:33 +00:00
static int aji_is_secure ( struct aji_client * client ) ;
2008-06-27 07:28:17 +00:00
# ifdef HAVE_OPENSSL
2007-11-01 22:10:33 +00:00
static int aji_start_tls ( struct aji_client * client ) ;
static int aji_tls_handshake ( struct aji_client * client ) ;
2008-06-27 07:28:17 +00:00
# endif
2007-11-01 22:10:33 +00:00
static int aji_io_recv ( struct aji_client * client , char * buffer , size_t buf_len , int timeout ) ;
static int aji_recv ( struct aji_client * client , int timeout ) ;
static int aji_send_header ( struct aji_client * client , const char * to ) ;
static int aji_send_raw ( struct aji_client * client , const char * xmlstr ) ;
2006-05-22 21:12:30 +00:00
static void aji_log_hook ( void * data , const char * xmpp , size_t size , int is_incoming ) ;
2007-11-01 22:10:33 +00:00
static int aji_start_sasl ( struct aji_client * client , enum ikssasltype type , char * username , char * pass ) ;
2006-05-22 21:12:30 +00:00
static int aji_act_hook ( void * data , int type , iks * node ) ;
static void aji_handle_iq ( struct aji_client * client , iks * node ) ;
2006-06-07 22:43:20 +00:00
static void aji_handle_message ( struct aji_client * client , ikspak * pak ) ;
2006-05-22 21:12:30 +00:00
static void aji_handle_presence ( struct aji_client * client , ikspak * pak ) ;
static void aji_handle_subscribe ( struct aji_client * client , ikspak * pak ) ;
2009-12-07 17:59:46 +00:00
static int aji_send_raw_chat ( struct aji_client * client , int groupchat , const char * nick , const char * address , const char * message ) ;
2006-05-22 21:12:30 +00:00
static void * aji_recv_loop ( void * data ) ;
2007-06-07 08:45:19 +00:00
static int aji_initialize ( struct aji_client * client ) ;
2006-05-22 21:12:30 +00:00
static int aji_client_connect ( void * data , ikspak * pak ) ;
2006-09-21 23:55:13 +00:00
static void aji_set_presence ( struct aji_client * client , char * to , char * from , int level , char * desc ) ;
2009-12-07 17:59:46 +00:00
static int aji_set_group_presence ( struct aji_client * client , char * room , int level , char * nick , char * desc ) ;
2008-02-08 21:26:32 +00:00
static char * aji_do_set_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a ) ;
2007-09-18 22:43:45 +00:00
static char * aji_do_reload ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a ) ;
static char * aji_show_clients ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a ) ;
2007-09-25 16:34:49 +00:00
static char * aji_show_buddies ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a ) ;
2006-05-22 21:12:30 +00:00
static int aji_create_client ( char * label , struct ast_variable * var , int debug ) ;
static int aji_create_buddy ( char * label , struct aji_client * client ) ;
2007-08-16 21:09:46 +00:00
static int aji_reload ( int reload ) ;
static int aji_load_config ( int reload ) ;
2006-05-22 21:12:30 +00:00
static void aji_pruneregister ( struct aji_client * client ) ;
static int aji_filter_roster ( void * data , ikspak * pak ) ;
static int aji_get_roster ( struct aji_client * client ) ;
static int aji_client_info_handler ( void * data , ikspak * pak ) ;
static int aji_dinfo_handler ( void * data , ikspak * pak ) ;
static int aji_ditems_handler ( void * data , ikspak * pak ) ;
static int aji_register_query_handler ( void * data , ikspak * pak ) ;
static int aji_register_approve_handler ( void * data , ikspak * pak ) ;
static int aji_reconnect ( struct aji_client * client ) ;
2010-06-15 17:06:23 +00:00
static char * aji_cli_create_collection ( struct ast_cli_entry * e , int cmd ,
struct ast_cli_args * a ) ;
static char * aji_cli_list_pubsub_nodes ( struct ast_cli_entry * e , int cmd ,
struct ast_cli_args * a ) ;
static char * aji_cli_delete_pubsub_node ( struct ast_cli_entry * e , int cmd , struct
ast_cli_args * a ) ;
static char * aji_cli_purge_pubsub_nodes ( struct ast_cli_entry * e , int cmd , struct
ast_cli_args * a ) ;
2006-05-22 21:12:30 +00:00
static iks * jabber_make_auth ( iksid * id , const char * pass , const char * sid ) ;
2010-06-15 17:06:23 +00:00
static int aji_receive_node_list ( void * data , ikspak * pak ) ;
static void aji_init_event_distribution ( struct aji_client * client ) ;
static iks * aji_create_pubsub_node ( struct aji_client * client , const char * node_type ,
const char * name , const char * collection_name ) ;
static iks * aji_build_node_config ( iks * pubsub , const char * node_type ,
const char * collection_name ) ;
static void aji_create_pubsub_collection ( struct aji_client * client ,
const char * collection_name ) ;
static void aji_create_pubsub_leaf ( struct aji_client * client , const char * collection_name ,
const char * leaf_name ) ;
static char * aji_cli_create_leafnode ( struct ast_cli_entry * e , int cmd ,
struct ast_cli_args * a ) ;
static void aji_create_affiliations ( struct aji_client * client , const char * node ) ;
static iks * aji_pubsub_iq_create ( struct aji_client * client , const char * type ) ;
static void aji_publish_device_state ( struct aji_client * client , const char * device ,
2013-01-02 18:11:59 +00:00
const char * device_state , unsigned int cachable ) ;
2010-06-15 17:06:23 +00:00
static int aji_handle_pubsub_error ( void * data , ikspak * pak ) ;
static int aji_handle_pubsub_event ( void * data , ikspak * pak ) ;
static void aji_pubsub_subscribe ( struct aji_client * client , const char * node ) ;
static void aji_delete_pubsub_node ( struct aji_client * client , const char * node_name ) ;
static iks * aji_build_node_request ( struct aji_client * client , const char * collection ) ;
static int aji_delete_node_list ( void * data , ikspak * pak ) ;
static void aji_pubsub_purge_nodes ( struct aji_client * client ,
const char * collection_name ) ;
static void aji_publish_mwi ( struct aji_client * client , const char * mailbox ,
2013-12-19 16:52:43 +00:00
const char * oldmsgs , const char * newmsgs ) ;
Multiple revisions 399887,400138,400178,400180-400181
........
r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line
Minor performance bump by not allocate manager variable struct if we don't need it
........
r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines
Stasis performance improvements
This patch addresses several performance problems that were found in
the initial performance testing of Asterisk 12.
The Stasis dispatch object was allocated as an AO2 object, even though
it has a very confined lifecycle. This was replaced with a straight
ast_malloc().
The Stasis message router was spending an inordinate amount of time
searching hash tables. In this case, most of our routers had 6 or
fewer routes in them to begin with. This was replaced with an array
that's searched linearly for the route.
We more heavily rely on AO2 objects in Asterisk 12, and the memset()
in ao2_ref() actually became noticeable on the profile. This was
#ifdef'ed to only run when AO2_DEBUG was enabled.
After being misled by an erroneous comment in taskprocessor.c during
profiling, the wrong comment was removed.
Review: https://reviewboard.asterisk.org/r/2873/
........
r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines
Taskprocessor optimization; switch Stasis to use taskprocessors
This patch optimizes taskprocessor to use a semaphore for signaling,
which the OS can do a better job at managing contention and waiting
that we can with a mutex and condition.
The taskprocessor execution was also slightly optimized to reduce the
number of locks taken.
The only observable difference in the taskprocessor implementation is
that when the final reference to the taskprocessor goes away, it will
execute all tasks to completion instead of discarding the unexecuted
tasks.
For systems where unnamed semaphores are not supported, a really
simple semaphore implementation is provided. (Which gives identical
performance as the original taskprocessor implementation).
The way we ended up implementing Stasis caused the threadpool to be a
burden instead of a boost to performance. This was switched to just
use taskprocessors directly for subscriptions.
Review: https://reviewboard.asterisk.org/r/2881/
........
r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines
Optimize how Stasis forwards are dispatched
This patch optimizes how forwards are dispatched in Stasis.
Originally, forwards were dispatched as subscriptions that are invoked
on the publishing thread. This did not account for the vast number of
forwards we would end up having in the system, and the amount of work it
would take to walk though the forward subscriptions.
This patch modifies Stasis so that rather than walking the tree of
forwards on every dispatch, when forwards and subscriptions are changed,
the subscriber list for every topic in the tree is changed.
This has a couple of benefits. First, this reduces the workload of
dispatching messages. It also reduces contention when dispatching to
different topics that happen to forward to the same aggregation topic
(as happens with all of the channel, bridge and endpoint topics).
Since forwards are no longer subscriptions, the bulk of this patch is
simply changing stasis_subscription objects to stasis_forward objects
(which, admittedly, I should have done in the first place.)
Since this required me to yet again put in a growing array, I finally
abstracted that out into a set of ast_vector macros in
asterisk/vector.h.
Review: https://reviewboard.asterisk.org/r/2883/
........
r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines
Remove dispatch object allocation from Stasis publishing
While looking for areas for performance improvement, I realized that an
unused feature in Stasis was negatively impacting performance.
When a message is sent to a subscriber, a dispatch object is allocated
for the dispatch, containing the topic the message was published to, the
subscriber the message is being sent to, and the message itself.
The topic is actually unused by any subscriber in Asterisk today. And
the subscriber is associated with the taskprocessor the message is being
dispatched to.
First, this patch removes the unused topic parameter from Stasis
subscription callbacks.
Second, this patch introduces the concept of taskprocessor local data,
data that may be set on a taskprocessor and provided along with the data
pointer when a task is pushed using the ast_taskprocessor_push_local()
call. This allows the task to have both data specific to that
taskprocessor, in addition to data specific to that invocation.
With those two changes, the dispatch object can be removed completely,
and the message is simply refcounted and sent directly to the
taskprocessor.
Review: https://reviewboard.asterisk.org/r/2884/
........
Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
static void aji_devstate_cb ( void * data , struct stasis_subscription * sub , struct stasis_message * msg ) ;
static void aji_mwi_cb ( void * data , struct stasis_subscription * sub , struct stasis_message * msg ) ;
2010-06-15 17:06:23 +00:00
static iks * aji_build_publish_skeleton ( struct aji_client * client , const char * node ,
2013-01-02 18:11:59 +00:00
const char * event_type , unsigned int cachable ) ;
2006-10-03 00:07:45 +00:00
/* No transports in this version */
/*
static int aji_create_transport ( char * label , struct aji_client * client ) ;
static int aji_register_transport ( void * data , ikspak * pak ) ;
static int aji_register_transport2 ( void * data , ikspak * pak ) ;
*/
2006-05-22 21:12:30 +00:00
2011-06-01 21:31:40 +00:00
static int msg_send_cb ( const struct ast_msg * msg , const char * to , const char * from ) ;
static const struct ast_msg_tech msg_tech = {
. name = " xmpp " ,
. msg_send = msg_send_cb ,
} ;
2006-05-22 21:12:30 +00:00
static struct ast_cli_entry aji_cli [ ] = {
2008-11-12 06:46:04 +00:00
AST_CLI_DEFINE ( aji_do_set_debug , " Enable/Disable Jabber debug " ) ,
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( aji_do_reload , " Reload Jabber configuration " ) ,
AST_CLI_DEFINE ( aji_show_clients , " Show state of clients and components " ) ,
AST_CLI_DEFINE ( aji_show_buddies , " Show buddy lists of our clients " ) ,
2010-06-15 17:06:23 +00:00
AST_CLI_DEFINE ( aji_cli_create_collection , " Creates a PubSub node collection. " ) ,
AST_CLI_DEFINE ( aji_cli_list_pubsub_nodes , " Lists PubSub nodes " ) ,
AST_CLI_DEFINE ( aji_cli_create_leafnode , " Creates a PubSub leaf node " ) ,
AST_CLI_DEFINE ( aji_cli_delete_pubsub_node , " Deletes a PubSub node " ) ,
AST_CLI_DEFINE ( aji_cli_purge_pubsub_nodes , " Purges PubSub nodes " ) ,
2006-09-18 19:54:18 +00:00
} ;
2006-05-22 21:12:30 +00:00
2006-08-07 21:15:28 +00:00
static char * app_ajisend = " JabberSend " ;
2009-12-07 17:59:46 +00:00
static char * app_ajisendgroup = " JabberSendGroup " ;
2006-08-07 21:15:28 +00:00
static char * app_ajistatus = " JabberStatus " ;
2009-12-07 17:59:46 +00:00
static char * app_ajijoin = " JabberJoin " ;
static char * app_ajileave = " JabberLeave " ;
2006-05-22 21:12:30 +00:00
2009-06-15 17:34:30 +00:00
static struct aji_client_container clients ;
static struct aji_capabilities * capabilities = NULL ;
2013-03-16 15:45:58 +00:00
static struct stasis_subscription * mwi_sub = NULL ;
2013-04-16 15:33:59 +00:00
static struct stasis_subscription * device_state_sub = NULL ;
2009-09-25 10:54:42 +00:00
static ast_cond_t message_received_condition ;
static ast_mutex_t messagelock ;
2006-05-22 21:12:30 +00:00
2006-08-07 21:15:28 +00:00
/*! \brief Global flags, initialized to default values */
2009-12-16 20:25:27 +00:00
static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT } ;
2006-05-22 21:12:30 +00:00
2010-06-15 17:06:23 +00:00
/*! \brief PubSub flags, initialized to default values */
2010-11-26 18:31:48 +00:00
static struct ast_flags pubsubflags = { 0 } ;
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief Deletes the aji_client data structure .
2007-06-07 21:22:25 +00:00
* \ param obj aji_client The structure we will delete .
2006-05-22 21:12:30 +00:00
* \ return void .
*/
2011-11-23 17:16:33 +00:00
void ast_aji_client_destroy ( struct aji_client * obj )
2006-05-22 21:12:30 +00:00
{
2006-06-07 22:43:20 +00:00
struct aji_message * tmp ;
2011-11-23 17:16:33 +00:00
ASTOBJ_CONTAINER_DESTROYALL ( & obj - > buddies , ast_aji_buddy_destroy ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_DESTROY ( & obj - > buddies ) ;
2006-06-09 16:08:33 +00:00
iks_filter_delete ( obj - > f ) ;
iks_parser_delete ( obj - > p ) ;
iks_stack_delete ( obj - > stack ) ;
2006-06-09 18:37:26 +00:00
AST_LIST_LOCK ( & obj - > messages ) ;
while ( ( tmp = AST_LIST_REMOVE_HEAD ( & obj - > messages , list ) ) ) {
2009-09-25 10:54:42 +00:00
aji_message_destroy ( tmp ) ;
2006-06-07 22:43:20 +00:00
}
2006-06-09 18:37:26 +00:00
AST_LIST_HEAD_DESTROY ( & obj - > messages ) ;
2007-06-06 21:20:11 +00:00
ast_free ( obj ) ;
2006-05-22 21:12:30 +00:00
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief Deletes the aji_buddy data structure .
2007-06-07 21:22:25 +00:00
* \ param obj aji_buddy The structure we will delete .
2006-05-22 21:12:30 +00:00
* \ return void .
*/
2011-11-23 17:16:33 +00:00
void ast_aji_buddy_destroy ( struct aji_buddy * obj )
2006-05-22 21:12:30 +00:00
{
struct aji_resource * tmp ;
while ( ( tmp = obj - > resources ) ) {
obj - > resources = obj - > resources - > next ;
2007-06-06 21:20:11 +00:00
ast_free ( tmp - > description ) ;
ast_free ( tmp ) ;
2006-05-22 21:12:30 +00:00
}
2007-06-06 21:20:11 +00:00
ast_free ( obj ) ;
2006-05-22 21:12:30 +00:00
}
2007-05-04 20:06:02 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
* \ brief Deletes the aji_message data structure .
* \ param obj aji_message The structure we will delete .
* \ return void .
*/
static void aji_message_destroy ( struct aji_message * obj )
{
if ( obj - > from ) {
ast_free ( obj - > from ) ;
}
if ( obj - > message ) {
ast_free ( obj - > message ) ;
}
ast_free ( obj ) ;
}
/*!
* \ internal
2007-05-04 20:06:02 +00:00
* \ brief Find version in XML stream and populate our capabilities list
2009-09-25 10:54:42 +00:00
* \ param node the node attribute in the caps element we ' ll look for or add to
2007-05-04 20:06:02 +00:00
* our list
2009-09-25 10:54:42 +00:00
* \ param version the version attribute in the caps element we ' ll look for or
2007-05-04 20:06:02 +00:00
* add to our list
2007-06-07 21:22:25 +00:00
* \ param pak struct The XML stanza we ' re processing
2007-05-04 20:06:02 +00:00
* \ return a pointer to the added or found aji_version structure
2009-09-25 10:54:42 +00:00
*/
2006-05-22 21:12:30 +00:00
static struct aji_version * aji_find_version ( char * node , char * version , ikspak * pak )
{
struct aji_capabilities * list = NULL ;
struct aji_version * res = NULL ;
list = capabilities ;
2010-06-15 17:06:23 +00:00
if ( ! node ) {
2006-05-22 21:12:30 +00:00
node = pak - > from - > full ;
2010-06-15 17:06:23 +00:00
}
if ( ! version ) {
2006-05-22 21:12:30 +00:00
version = " none supplied. " ;
2010-06-15 17:06:23 +00:00
}
while ( list ) {
2009-09-25 10:54:42 +00:00
if ( ! strcasecmp ( list - > node , node ) ) {
2006-05-22 21:12:30 +00:00
res = list - > versions ;
while ( res ) {
2010-06-15 17:06:23 +00:00
if ( ! strcasecmp ( res - > version , version ) ) {
return res ;
}
res = res - > next ;
2006-05-22 21:12:30 +00:00
}
2009-09-25 10:54:42 +00:00
/* Specified version not found. Let's add it to
2007-05-04 20:06:02 +00:00
this node in our capabilities list */
2009-09-25 10:54:42 +00:00
if ( ! res ) {
2007-06-06 21:20:11 +00:00
res = ast_malloc ( sizeof ( * res ) ) ;
2009-09-25 10:54:42 +00:00
if ( ! res ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
return NULL ;
}
res - > jingle = 0 ;
res - > parent = list ;
ast_copy_string ( res - > version , version , sizeof ( res - > version ) ) ;
res - > next = list - > versions ;
list - > versions = res ;
return res ;
}
}
list = list - > next ;
}
2007-05-04 20:06:02 +00:00
/* Specified node not found. Let's add it our capabilities list */
2009-09-25 10:54:42 +00:00
if ( ! list ) {
2007-06-06 21:20:11 +00:00
list = ast_malloc ( sizeof ( * list ) ) ;
2009-09-25 10:54:42 +00:00
if ( ! list ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
return NULL ;
}
2007-06-06 21:20:11 +00:00
res = ast_malloc ( sizeof ( * res ) ) ;
2009-09-25 10:54:42 +00:00
if ( ! res ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
2007-10-31 21:23:42 +00:00
ast_free ( list ) ;
2006-05-22 21:12:30 +00:00
return NULL ;
}
ast_copy_string ( list - > node , node , sizeof ( list - > node ) ) ;
ast_copy_string ( res - > version , version , sizeof ( res - > version ) ) ;
res - > jingle = 0 ;
res - > parent = list ;
2007-05-04 20:06:02 +00:00
res - > next = NULL ;
2006-05-22 21:12:30 +00:00
list - > versions = res ;
list - > next = capabilities ;
capabilities = list ;
}
return res ;
}
2009-09-25 10:54:42 +00:00
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief Find the aji_resource we want
* \ param buddy aji_buddy A buddy
2010-06-15 17:06:23 +00:00
* \ param name
2007-06-07 21:22:25 +00:00
* \ return aji_resource object
*/
2006-10-03 00:07:45 +00:00
static struct aji_resource * aji_find_resource ( struct aji_buddy * buddy , char * name )
2006-05-22 21:12:30 +00:00
{
struct aji_resource * res = NULL ;
2010-06-15 17:06:23 +00:00
if ( ! buddy | | ! name ) {
2006-05-22 21:12:30 +00:00
return res ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
res = buddy - > resources ;
while ( res ) {
2006-10-03 00:07:45 +00:00
if ( ! strcasecmp ( res - > resource , name ) ) {
2006-05-22 21:12:30 +00:00
break ;
}
res = res - > next ;
}
return res ;
}
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief Jabber GTalk function
* \ param node iks
* \ return 1 on success , 0 on failure .
*/
2006-05-22 21:12:30 +00:00
static int gtalk_yuck ( iks * node )
{
2010-06-15 17:06:23 +00:00
if ( iks_find_with_attrib ( node , " c " , " node " , " http://www.google.com/xmpp/client/caps " ) ) {
2010-10-05 22:01:52 +00:00
ast_debug ( 1 , " Found resource with Googletalk voice capabilities \n " ) ;
return 1 ;
} else if ( iks_find_with_attrib ( node , " caps:c " , " ext " , " pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1 " ) ) {
ast_debug ( 1 , " Found resource with Gmail voice/video chat capabilities \n " ) ;
return 1 ;
} else if ( iks_find_with_attrib ( node , " caps:c " , " ext " , " pmuc-v1 sms-v1 video-v1 voice-v1 " ) ) {
ast_debug ( 1 , " Found resource with Gmail voice/video chat capabilities (no camera) \n " ) ;
2006-05-22 21:12:30 +00:00
return 1 ;
2010-06-15 17:06:23 +00:00
}
2010-10-05 22:01:52 +00:00
2006-05-22 21:12:30 +00:00
return 0 ;
}
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief Setup the authentication struct
* \ param id iksid
* \ param pass password
* \ param sid
* \ return x iks
*/
2006-05-22 21:12:30 +00:00
static iks * jabber_make_auth ( iksid * id , const char * pass , const char * sid )
{
iks * x , * y ;
x = iks_new ( " iq " ) ;
iks_insert_attrib ( x , " type " , " set " ) ;
y = iks_insert ( x , " query " ) ;
iks_insert_attrib ( y , " xmlns " , IKS_NS_AUTH ) ;
iks_insert_cdata ( iks_insert ( y , " username " ) , id - > user , 0 ) ;
iks_insert_cdata ( iks_insert ( y , " resource " ) , id - > resource , 0 ) ;
if ( sid ) {
char buf [ 41 ] ;
char sidpass [ 100 ] ;
snprintf ( sidpass , sizeof ( sidpass ) , " %s%s " , sid , pass ) ;
ast_sha1_hash ( buf , sidpass ) ;
iks_insert_cdata ( iks_insert ( y , " digest " ) , buf , 0 ) ;
} else {
iks_insert_cdata ( iks_insert ( y , " password " ) , pass , 0 ) ;
}
return x ;
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief Dial plan function status ( ) . puts the status of watched user
2009-09-25 10:54:42 +00:00
* into a channel variable .
2007-06-07 21:22:25 +00:00
* \ param chan ast_channel
* \ param data
2009-09-25 10:54:42 +00:00
* \ retval 0 success
* \ retval - 1 error
2006-05-22 21:12:30 +00:00
*/
2009-05-21 21:13:09 +00:00
static int aji_status_exec ( struct ast_channel * chan , const char * data )
2006-05-22 21:12:30 +00:00
{
struct aji_client * client = NULL ;
2006-07-05 20:28:54 +00:00
struct aji_buddy * buddy = NULL ;
2006-05-22 21:12:30 +00:00
struct aji_resource * r = NULL ;
2007-10-04 16:56:00 +00:00
char * s = NULL ;
2006-07-05 20:28:54 +00:00
int stat = 7 ;
2006-05-22 21:12:30 +00:00
char status [ 2 ] ;
2007-10-04 16:56:00 +00:00
static int deprecation_warning = 0 ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( sender ) ;
AST_APP_ARG ( jid ) ;
AST_APP_ARG ( variable ) ;
) ;
AST_DECLARE_APP_ARGS ( jid ,
AST_APP_ARG ( screenname ) ;
AST_APP_ARG ( resource ) ;
) ;
2010-06-15 17:06:23 +00:00
if ( deprecation_warning + + % 10 = = 0 ) {
2007-10-04 16:56:00 +00:00
ast_log ( LOG_WARNING , " JabberStatus is deprecated. Please use the JABBER_STATUS dialplan function in the future. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2007-02-20 07:48:12 +00:00
if ( ! data ) {
2008-08-19 15:58:39 +00:00
ast_log ( LOG_ERROR , " Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname> \n " ) ;
2007-02-20 07:48:12 +00:00
return 0 ;
}
2007-02-20 16:56:58 +00:00
s = ast_strdupa ( data ) ;
2007-10-04 16:56:00 +00:00
AST_STANDARD_APP_ARGS ( args , s ) ;
if ( args . argc ! = 3 ) {
ast_log ( LOG_ERROR , " JabberStatus() requires 3 arguments. \n " ) ;
return - 1 ;
2006-05-22 21:12:30 +00:00
}
2007-10-04 16:56:00 +00:00
AST_NONSTANDARD_APP_ARGS ( jid , args . jid , ' / ' ) ;
2009-09-25 10:54:42 +00:00
if ( jid . argc < 1 | | jid . argc > 2 ) {
ast_log ( LOG_WARNING , " Wrong JID %s, exiting \n " , args . jid ) ;
return - 1 ;
}
2007-10-04 16:56:00 +00:00
if ( ! ( client = ast_aji_get_client ( args . sender ) ) ) {
ast_log ( LOG_WARNING , " Could not find sender connection: '%s' \n " , args . sender ) ;
return - 1 ;
2006-06-04 16:56:16 +00:00
}
2007-10-04 16:56:00 +00:00
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , jid . screenname ) ;
if ( ! buddy ) {
ast_log ( LOG_WARNING , " Could not find buddy in list: '%s' \n " , jid . screenname ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return - 1 ;
}
2007-10-04 16:56:00 +00:00
r = aji_find_resource ( buddy , jid . resource ) ;
2010-06-15 17:06:23 +00:00
if ( ! r & & buddy - > resources ) {
2007-10-04 16:56:00 +00:00
r = buddy - > resources ;
2010-06-15 17:06:23 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
if ( ! r ) {
2007-10-04 16:56:00 +00:00
ast_log ( LOG_NOTICE , " Resource '%s' of buddy '%s' was not found \n " , jid . resource , jid . screenname ) ;
2010-06-15 17:06:23 +00:00
} else {
2007-10-04 16:56:00 +00:00
stat = r - > status ;
2010-06-15 17:06:23 +00:00
}
2007-10-04 16:56:00 +00:00
snprintf ( status , sizeof ( status ) , " %d " , stat ) ;
pbx_builtin_setvar_helper ( chan , args . variable , status ) ;
return 0 ;
}
2009-09-25 10:54:42 +00:00
/*!
* \ internal
* \ brief Dial plan funtcion to retrieve the status of a buddy .
* \ param channel The associated ast_channel , if there is one
* \ param data The account , buddy JID , and optional timeout
* timeout .
* \ retval 0 success
* \ retval - 1 failure
*/
2007-10-04 16:56:00 +00:00
static int acf_jabberstatus_read ( struct ast_channel * chan , const char * name , char * data , char * buf , size_t buflen )
{
struct aji_client * client = NULL ;
struct aji_buddy * buddy = NULL ;
struct aji_resource * r = NULL ;
int stat = 7 ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( sender ) ;
AST_APP_ARG ( jid ) ;
) ;
AST_DECLARE_APP_ARGS ( jid ,
AST_APP_ARG ( screenname ) ;
AST_APP_ARG ( resource ) ;
) ;
if ( ! data ) {
2008-08-06 13:34:08 +00:00
ast_log ( LOG_ERROR , " Usage: JABBER_STATUS(<sender>,<jid>[/<resource>]) \n " ) ;
2007-10-04 16:56:00 +00:00
return 0 ;
}
AST_STANDARD_APP_ARGS ( args , data ) ;
if ( args . argc ! = 2 ) {
2008-08-06 13:34:08 +00:00
ast_log ( LOG_ERROR , " JABBER_STATUS requires 2 arguments: sender and jid. \n " ) ;
2006-06-01 08:22:44 +00:00
return - 1 ;
}
2007-10-04 16:56:00 +00:00
AST_NONSTANDARD_APP_ARGS ( jid , args . jid , ' / ' ) ;
2009-09-25 10:54:42 +00:00
if ( jid . argc < 1 | | jid . argc > 2 ) {
ast_log ( LOG_WARNING , " Wrong JID %s, exiting \n " , args . jid ) ;
return - 1 ;
}
2007-10-04 16:56:00 +00:00
if ( ! ( client = ast_aji_get_client ( args . sender ) ) ) {
ast_log ( LOG_WARNING , " Could not find sender connection: '%s' \n " , args . sender ) ;
return - 1 ;
}
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , jid . screenname ) ;
2006-07-05 20:28:54 +00:00
if ( ! buddy ) {
2007-10-04 16:56:00 +00:00
ast_log ( LOG_WARNING , " Could not find buddy in list: '%s' \n " , jid . screenname ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return - 1 ;
}
2007-10-04 16:56:00 +00:00
r = aji_find_resource ( buddy , jid . resource ) ;
2010-06-15 17:06:23 +00:00
if ( ! r & & buddy - > resources ) {
2006-07-05 20:28:54 +00:00
r = buddy - > resources ;
2010-06-15 17:06:23 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
if ( ! r ) {
2007-10-04 16:56:00 +00:00
ast_log ( LOG_NOTICE , " Resource %s of buddy %s was not found. \n " , jid . resource , jid . screenname ) ;
2010-06-15 17:06:23 +00:00
} else {
2007-03-05 03:39:32 +00:00
stat = r - > status ;
2010-06-15 17:06:23 +00:00
}
2007-10-04 16:56:00 +00:00
snprintf ( buf , buflen , " %d " , stat ) ;
2006-05-22 21:12:30 +00:00
return 0 ;
}
2007-10-04 16:56:00 +00:00
static struct ast_custom_function jabberstatus_function = {
. name = " JABBER_STATUS " ,
. read = acf_jabberstatus_read ,
} ;
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
* \ brief Dial plan function to receive a message .
* \ param channel The associated ast_channel , if there is one
* \ param data The account , JID , and optional timeout
* timeout .
* \ retval 0 success
* \ retval - 1 failure
*/
static int acf_jabberreceive_read ( struct ast_channel * chan , const char * name , char * data , char * buf , size_t buflen )
{
2013-01-02 15:39:42 +00:00
char * parse = NULL ;
2009-09-25 10:54:42 +00:00
int timeout ;
int jidlen , resourcelen ;
struct timeval start ;
long diff = 0 ;
struct aji_client * client = NULL ;
int found = 0 ;
struct aji_message * tmp = NULL ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( account ) ;
AST_APP_ARG ( jid ) ;
AST_APP_ARG ( timeout ) ;
) ;
AST_DECLARE_APP_ARGS ( jid ,
AST_APP_ARG ( screenname ) ;
AST_APP_ARG ( resource ) ;
) ;
if ( ast_strlen_zero ( data ) ) {
ast_log ( LOG_WARNING , " %s requires arguments (account,jid[,timeout]) \n " , name ) ;
return - 1 ;
}
parse = ast_strdupa ( data ) ;
AST_STANDARD_APP_ARGS ( args , parse ) ;
if ( args . argc < 2 | | args . argc > 3 ) {
2010-06-15 17:06:23 +00:00
ast_log ( LOG_WARNING , " %s requires arguments (account,jid[,timeout]) \n " , name ) ;
2009-09-25 10:54:42 +00:00
return - 1 ;
}
parse = ast_strdupa ( args . jid ) ;
AST_NONSTANDARD_APP_ARGS ( jid , parse , ' / ' ) ;
if ( jid . argc < 1 | | jid . argc > 2 | | strlen ( args . jid ) > AJI_MAX_JIDLEN ) {
ast_log ( LOG_WARNING , " Invalid JID : %s \n " , parse ) ;
return - 1 ;
}
if ( ast_strlen_zero ( args . timeout ) ) {
timeout = 20 ;
} else {
sscanf ( args . timeout , " %d " , & timeout ) ;
if ( timeout < = 0 ) {
ast_log ( LOG_WARNING , " Invalid timeout specified: '%s' \n " , args . timeout ) ;
return - 1 ;
}
}
jidlen = strlen ( jid . screenname ) ;
resourcelen = ast_strlen_zero ( jid . resource ) ? 0 : strlen ( jid . resource ) ;
2011-11-23 17:16:33 +00:00
client = ast_aji_get_client ( args . account ) ;
if ( ! client ) {
ast_log ( LOG_WARNING , " Could not find client %s, exiting \n " , args . account ) ;
return - 1 ;
}
2009-09-25 10:54:42 +00:00
ast_debug ( 3 , " Waiting for an XMPP message from %s \n " , args . jid ) ;
start = ast_tvnow ( ) ;
2014-03-27 19:21:44 +00:00
if ( chan & & ast_autoservice_start ( chan ) < 0 ) {
2012-01-09 22:15:50 +00:00
ast_log ( LOG_WARNING , " Cannot start autoservice for channel %s \n " , ast_channel_name ( chan ) ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2009-09-25 10:54:42 +00:00
return - 1 ;
}
/* search the messages list, grab the first message that matches with
* the from JID we ' re expecting , and remove it from the messages list */
while ( diff < timeout ) {
struct timespec ts = { 0 , } ;
struct timeval wait ;
int res ;
2010-06-15 17:06:23 +00:00
wait = ast_tvadd ( start , ast_tv ( timeout , 0 ) ) ;
2009-09-25 10:54:42 +00:00
ts . tv_sec = wait . tv_sec ;
ts . tv_nsec = wait . tv_usec * 1000 ;
/* wait up to timeout seconds for an incoming message */
ast_mutex_lock ( & messagelock ) ;
res = ast_cond_timedwait ( & message_received_condition , & messagelock , & ts ) ;
ast_mutex_unlock ( & messagelock ) ;
if ( res = = ETIMEDOUT ) {
ast_debug ( 3 , " No message received from %s in %d seconds \n " , args . jid , timeout ) ;
break ;
2010-06-15 17:06:23 +00:00
}
2009-09-25 10:54:42 +00:00
AST_LIST_LOCK ( & client - > messages ) ;
AST_LIST_TRAVERSE_SAFE_BEGIN ( & client - > messages , tmp , list ) {
if ( jid . argc = = 1 ) {
/* no resource provided, compare bare JIDs */
if ( strncasecmp ( jid . screenname , tmp - > from , jidlen ) ) {
continue ;
}
} else {
/* resource appended, compare bare JIDs and resources */
char * resource = strchr ( tmp - > from , ' / ' ) ;
if ( ! resource | | strlen ( resource ) = = 0 ) {
ast_log ( LOG_WARNING , " Remote JID has no resource : %s \n " , tmp - > from ) ;
if ( strncasecmp ( jid . screenname , tmp - > from , jidlen ) ) {
continue ;
}
} else {
resource + + ;
if ( strncasecmp ( jid . screenname , tmp - > from , jidlen ) | | strncmp ( jid . resource , resource , resourcelen ) ) {
continue ;
}
}
}
/* check if the message is not too old */
if ( ast_tvdiff_sec ( ast_tvnow ( ) , tmp - > arrived ) > = client - > message_timeout ) {
ast_debug ( 3 , " Found old message from %s, deleting it \n " , tmp - > from ) ;
AST_LIST_REMOVE_CURRENT ( list ) ;
aji_message_destroy ( tmp ) ;
continue ;
}
found = 1 ;
2013-01-02 15:39:42 +00:00
ast_copy_string ( buf , tmp - > message , buflen ) ;
2009-09-25 10:54:42 +00:00
AST_LIST_REMOVE_CURRENT ( list ) ;
aji_message_destroy ( tmp ) ;
break ;
}
AST_LIST_TRAVERSE_SAFE_END ;
AST_LIST_UNLOCK ( & client - > messages ) ;
if ( found ) {
break ;
}
/* check timeout */
diff = ast_tvdiff_ms ( ast_tvnow ( ) , start ) ;
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2014-03-27 19:21:44 +00:00
if ( chan & & ast_autoservice_stop ( chan ) < 0 ) {
2012-01-09 22:15:50 +00:00
ast_log ( LOG_WARNING , " Cannot stop autoservice for channel %s \n " , ast_channel_name ( chan ) ) ;
2009-09-25 10:54:42 +00:00
}
/* return if we timed out */
if ( ! found ) {
ast_log ( LOG_NOTICE , " Timed out : no message received from %s \n " , args . jid ) ;
return - 1 ;
}
return 0 ;
}
static struct ast_custom_function jabberreceive_function = {
. name = " JABBER_RECEIVE " ,
. read = acf_jabberreceive_read ,
} ;
/*!
* \ internal
* \ brief Delete old messages from a given JID
* Messages stored during more than client - > message_timeout are deleted
* \ param client Asterisk ' s XMPP client
* \ param from the JID we received messages from
* \ retval the number of deleted messages
* \ retval - 1 failure
*/
static int delete_old_messages ( struct aji_client * client , char * from )
{
int deleted = 0 ;
int isold = 0 ;
struct aji_message * tmp = NULL ;
if ( ! client ) {
ast_log ( LOG_ERROR , " Cannot find our XMPP client \n " ) ;
return - 1 ;
}
/* remove old messages */
AST_LIST_LOCK ( & client - > messages ) ;
if ( AST_LIST_EMPTY ( & client - > messages ) ) {
AST_LIST_UNLOCK ( & client - > messages ) ;
return 0 ;
}
AST_LIST_TRAVERSE_SAFE_BEGIN ( & client - > messages , tmp , list ) {
if ( isold ) {
if ( ! from | | ! strncasecmp ( from , tmp - > from , strlen ( from ) ) ) {
AST_LIST_REMOVE_CURRENT ( list ) ;
aji_message_destroy ( tmp ) ;
deleted + + ;
}
} else if ( ast_tvdiff_sec ( ast_tvnow ( ) , tmp - > arrived ) > = client - > message_timeout ) {
isold = 1 ;
if ( ! from | | ! strncasecmp ( from , tmp - > from , strlen ( from ) ) ) {
AST_LIST_REMOVE_CURRENT ( list ) ;
aji_message_destroy ( tmp ) ;
deleted + + ;
}
}
}
AST_LIST_TRAVERSE_SAFE_END ;
AST_LIST_UNLOCK ( & client - > messages ) ;
return deleted ;
}
/*!
* \ internal
* \ brief Delete old messages
* Messages stored during more than client - > message_timeout are deleted
* \ param client Asterisk ' s XMPP client
* \ retval the number of deleted messages
* \ retval - 1 failure
*/
static int delete_old_messages_all ( struct aji_client * client )
{
return delete_old_messages ( client , NULL ) ;
}
2009-12-07 17:59:46 +00:00
/*!
* \ brief Application to join a chat room
* \ param chan ast_channel
* \ param data Data is sender | jid | nickname .
* \ retval 0 success
* \ retval - 1 error
*/
static int aji_join_exec ( struct ast_channel * chan , const char * data )
{
struct aji_client * client = NULL ;
char * s ;
char nick [ AJI_MAX_RESJIDLEN ] ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( sender ) ;
AST_APP_ARG ( jid ) ;
AST_APP_ARG ( nick ) ;
) ;
if ( ! data ) {
ast_log ( LOG_ERROR , " %s requires arguments (sender,jid[,nickname]) \n " , app_ajijoin ) ;
return - 1 ;
}
s = ast_strdupa ( data ) ;
AST_STANDARD_APP_ARGS ( args , s ) ;
if ( args . argc < 2 | | args . argc > 3 ) {
ast_log ( LOG_ERROR , " %s requires arguments (sender,jid[,nickname]) \n " , app_ajijoin ) ;
return - 1 ;
}
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
if ( strchr ( args . jid , ' / ' ) ) {
ast_log ( LOG_ERROR , " Invalid room name : resource must not be appended \n " ) ;
2009-12-07 17:59:46 +00:00
return - 1 ;
}
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
if ( ! ( client = ast_aji_get_client ( args . sender ) ) ) {
ast_log ( LOG_ERROR , " Could not find sender connection: '%s' \n " , args . sender ) ;
2009-12-07 17:59:46 +00:00
return - 1 ;
2010-06-15 17:06:23 +00:00
}
2009-12-07 17:59:46 +00:00
if ( ! ast_strlen_zero ( args . nick ) ) {
snprintf ( nick , AJI_MAX_RESJIDLEN , " %s " , args . nick ) ;
} else {
if ( client - > component ) {
2010-06-15 17:06:23 +00:00
sprintf ( nick , " asterisk " ) ;
2009-12-07 17:59:46 +00:00
} else {
snprintf ( nick , AJI_MAX_RESJIDLEN , " %s " , client - > jid - > user ) ;
}
}
if ( ! ast_strlen_zero ( args . jid ) & & strchr ( args . jid , ' @ ' ) ) {
ast_aji_join_chat ( client , args . jid , nick ) ;
} else {
ast_log ( LOG_ERROR , " Problem with specified jid of '%s' \n " , args . jid ) ;
}
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2009-12-07 17:59:46 +00:00
return 0 ;
}
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
/*!
* \ brief Application to leave a chat room
* \ param chan ast_channel
* \ param data Data is sender | jid | nickname .
* \ retval 0 success
* \ retval - 1 error
*/
static int aji_leave_exec ( struct ast_channel * chan , const char * data )
{
struct aji_client * client = NULL ;
char * s ;
char nick [ AJI_MAX_RESJIDLEN ] ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( sender ) ;
AST_APP_ARG ( jid ) ;
AST_APP_ARG ( nick ) ;
) ;
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( ! data ) {
ast_log ( LOG_ERROR , " %s requires arguments (sender,jid[,nickname]) \n " , app_ajileave ) ;
return - 1 ;
}
s = ast_strdupa ( data ) ;
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
AST_STANDARD_APP_ARGS ( args , s ) ;
if ( args . argc < 2 | | args . argc > 3 ) {
ast_log ( LOG_ERROR , " %s requires arguments (sender,jid[,nickname]) \n " , app_ajileave ) ;
return - 1 ;
}
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
if ( strchr ( args . jid , ' / ' ) ) {
ast_log ( LOG_ERROR , " Invalid room name, resource must not be appended \n " ) ;
2009-12-07 17:59:46 +00:00
return - 1 ;
}
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
if ( ! ( client = ast_aji_get_client ( args . sender ) ) ) {
ast_log ( LOG_ERROR , " Could not find sender connection: '%s' \n " , args . sender ) ;
2009-12-07 17:59:46 +00:00
return - 1 ;
2010-06-15 17:06:23 +00:00
}
2011-11-23 17:16:33 +00:00
2009-12-07 17:59:46 +00:00
if ( ! ast_strlen_zero ( args . nick ) ) {
snprintf ( nick , AJI_MAX_RESJIDLEN , " %s " , args . nick ) ;
} else {
if ( client - > component ) {
sprintf ( nick , " asterisk " ) ;
} else {
snprintf ( nick , AJI_MAX_RESJIDLEN , " %s " , client - > jid - > user ) ;
}
}
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( ! ast_strlen_zero ( args . jid ) & & strchr ( args . jid , ' @ ' ) ) {
ast_aji_leave_chat ( client , args . jid , nick ) ;
2010-06-15 17:06:23 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2009-12-07 17:59:46 +00:00
return 0 ;
}
2009-09-25 10:54:42 +00:00
/*!
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief Dial plan function to send a message .
2007-06-07 21:22:25 +00:00
* \ param chan ast_channel
2009-09-25 10:54:42 +00:00
* \ param data Data is account , jid , message .
* \ retval 0 success
* \ retval - 1 failure
2006-05-22 21:12:30 +00:00
*/
2009-05-21 21:13:09 +00:00
static int aji_send_exec ( struct ast_channel * chan , const char * data )
2006-05-22 21:12:30 +00:00
{
struct aji_client * client = NULL ;
2007-10-04 16:56:00 +00:00
char * s ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( sender ) ;
AST_APP_ARG ( recipient ) ;
AST_APP_ARG ( message ) ;
) ;
2006-08-07 21:15:28 +00:00
if ( ! data ) {
2009-09-25 10:54:42 +00:00
ast_log ( LOG_WARNING , " %s requires arguments (account,jid,message) \n " , app_ajisend ) ;
return - 1 ;
2006-08-07 21:15:28 +00:00
}
2007-02-20 16:56:58 +00:00
s = ast_strdupa ( data ) ;
2007-10-04 16:56:00 +00:00
AST_STANDARD_APP_ARGS ( args , s ) ;
if ( args . argc < 3 ) {
2009-09-25 10:54:42 +00:00
ast_log ( LOG_WARNING , " %s requires arguments (account,jid,message) \n " , app_ajisend ) ;
2007-10-04 16:56:00 +00:00
return - 1 ;
2006-08-07 21:15:28 +00:00
}
2007-10-04 16:56:00 +00:00
if ( ! ( client = ast_aji_get_client ( args . sender ) ) ) {
ast_log ( LOG_WARNING , " Could not find sender connection: '%s' \n " , args . sender ) ;
2006-05-22 21:12:30 +00:00
return - 1 ;
}
2009-09-25 10:54:42 +00:00
if ( strchr ( args . recipient , ' @ ' ) & & ! ast_strlen_zero ( args . message ) ) {
2007-11-06 18:44:19 +00:00
ast_aji_send_chat ( client , args . recipient , args . message ) ;
2009-09-25 10:54:42 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return 0 ;
}
2011-06-01 21:31:40 +00:00
static int msg_send_cb ( const struct ast_msg * msg , const char * to , const char * from )
{
struct aji_client * client ;
char * sender ;
char * dest ;
int res ;
sender = ast_strdupa ( from ) ;
strsep ( & sender , " : " ) ;
dest = ast_strdupa ( to ) ;
strsep ( & dest , " : " ) ;
if ( ast_strlen_zero ( sender ) ) {
ast_log ( LOG_ERROR , " MESSAGE(from) of '%s' invalid for xmpp \n " , from ) ;
return - 1 ;
}
if ( ! ( client = ast_aji_get_client ( sender ) ) ) {
ast_log ( LOG_WARNING , " Could not finder account to send from as '%s' \n " , sender ) ;
return - 1 ;
}
ast_debug ( 1 , " Sending message to '%s' from '%s' \n " , dest , client - > name ) ;
res = ast_aji_send_chat ( client , dest , ast_msg_get_body ( msg ) ) ;
if ( res ! = IKS_OK ) {
ast_log ( LOG_WARNING , " Failed to send xmpp message (%d). \n " , res ) ;
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2011-06-01 21:31:40 +00:00
return res = = IKS_OK ? 0 : - 1 ;
}
2009-12-07 17:59:46 +00:00
/*!
* \ brief Application to send a message to a groupchat .
* \ param chan ast_channel
* \ param data Data is sender | groupchat | message .
* \ retval 0 success
* \ retval - 1 error
*/
static int aji_sendgroup_exec ( struct ast_channel * chan , const char * data )
{
struct aji_client * client = NULL ;
char * s ;
char nick [ AJI_MAX_RESJIDLEN ] ;
int res = 0 ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( sender ) ;
AST_APP_ARG ( groupchat ) ;
AST_APP_ARG ( message ) ;
AST_APP_ARG ( nick ) ;
) ;
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( ! data ) {
ast_log ( LOG_ERROR , " %s requires arguments (sender,groupchatid,message[,nickname]) \n " , app_ajisendgroup ) ;
return - 1 ;
}
s = ast_strdupa ( data ) ;
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
AST_STANDARD_APP_ARGS ( args , s ) ;
if ( args . argc < 3 | | args . argc > 4 ) {
ast_log ( LOG_ERROR , " %s requires arguments (sender,groupchatid,message[,nickname]) \n " , app_ajisendgroup ) ;
return - 1 ;
}
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( ! ( client = ast_aji_get_client ( args . sender ) ) ) {
ast_log ( LOG_ERROR , " Could not find sender connection: '%s' \n " , args . sender ) ;
return - 1 ;
}
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( ast_strlen_zero ( args . nick ) | | args . argc = = 3 ) {
if ( client - > component ) {
sprintf ( nick , " asterisk " ) ;
} else {
snprintf ( nick , AJI_MAX_RESJIDLEN , " %s " , client - > jid - > user ) ;
}
} else {
snprintf ( nick , AJI_MAX_RESJIDLEN , " %s " , args . nick ) ;
}
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( strchr ( args . groupchat , ' @ ' ) & & ! ast_strlen_zero ( args . message ) ) {
res = ast_aji_send_groupchat ( client , nick , args . groupchat , args . message ) ;
}
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2009-12-07 17:59:46 +00:00
if ( res ! = IKS_OK ) {
return - 1 ;
}
return 0 ;
}
2009-09-25 10:54:42 +00:00
/*!
* \ internal
2007-11-01 22:10:33 +00:00
* \ brief Tests whether the connection is secured or not
* \ return 0 if the connection is not secured
*/
static int aji_is_secure ( struct aji_client * client )
{
# ifdef HAVE_OPENSSL
return client - > stream_flags & SECURE ;
# else
return 0 ;
# endif
}
2008-06-27 07:28:17 +00:00
# ifdef HAVE_OPENSSL
2007-11-01 22:10:33 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-11-01 22:10:33 +00:00
* \ brief Starts the TLS procedure
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ return IKS_OK on success , an error code if sending failed , IKS_NET_TLSFAIL
* if OpenSSL is not installed
*/
static int aji_start_tls ( struct aji_client * client )
{
int ret ;
2008-06-27 07:28:17 +00:00
2007-11-01 22:10:33 +00:00
/* This is sent not encrypted */
2010-06-15 17:06:23 +00:00
if ( ( ret = iks_send_raw ( client - > p , " <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> " ) ) ) {
2007-11-01 22:10:33 +00:00
return ret ;
2010-06-15 17:06:23 +00:00
}
2007-11-01 22:10:33 +00:00
2008-06-27 07:28:17 +00:00
client - > stream_flags | = TRY_SECURE ;
2007-11-01 22:10:33 +00:00
return IKS_OK ;
}
2010-06-15 17:06:23 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-11-01 22:10:33 +00:00
* \ brief TLS handshake , OpenSSL initialization
* \ param client the configured XMPP client we use to connect to a XMPP server
2010-06-15 17:06:23 +00:00
* \ return IKS_OK on success , IKS_NET_TLSFAIL on failure
2007-11-01 22:10:33 +00:00
*/
static int aji_tls_handshake ( struct aji_client * client )
{
int sock ;
2010-06-15 17:06:23 +00:00
ast_debug ( 1 , " Starting TLS handshake \n " ) ;
2007-11-01 22:10:33 +00:00
/* Choose an SSL/TLS protocol version, create SSL_CTX */
client - > ssl_method = SSLv3_method ( ) ;
2010-11-18 18:08:43 +00:00
if ( ! ( client - > ssl_context = SSL_CTX_new ( ( SSL_METHOD * ) client - > ssl_method ) ) ) {
2007-11-01 22:10:33 +00:00
return IKS_NET_TLSFAIL ;
2010-06-15 17:06:23 +00:00
}
2007-11-01 22:10:33 +00:00
/* Create new SSL session */
2010-06-15 17:06:23 +00:00
if ( ! ( client - > ssl_session = SSL_new ( client - > ssl_context ) ) ) {
2007-11-01 22:10:33 +00:00
return IKS_NET_TLSFAIL ;
2010-06-15 17:06:23 +00:00
}
2007-11-01 22:10:33 +00:00
/* Enforce TLS on our XMPP connection */
sock = iks_fd ( client - > p ) ;
2012-04-17 18:57:40 +00:00
if ( ! SSL_set_fd ( client - > ssl_session , sock ) ) {
2007-11-01 22:10:33 +00:00
return IKS_NET_TLSFAIL ;
2010-06-15 17:06:23 +00:00
}
2007-11-01 22:10:33 +00:00
/* Perform SSL handshake */
2012-04-17 18:57:40 +00:00
if ( ! SSL_connect ( client - > ssl_session ) ) {
2007-11-01 22:10:33 +00:00
return IKS_NET_TLSFAIL ;
2010-06-15 17:06:23 +00:00
}
2007-11-01 22:10:33 +00:00
client - > stream_flags & = ( ~ TRY_SECURE ) ;
client - > stream_flags | = SECURE ;
/* Sent over the established TLS connection */
2012-04-17 18:57:40 +00:00
if ( aji_send_header ( client , client - > jid - > server ) ! = IKS_OK ) {
2007-11-01 22:10:33 +00:00
return IKS_NET_TLSFAIL ;
2010-06-15 17:06:23 +00:00
}
2007-11-01 22:10:33 +00:00
2010-06-15 17:06:23 +00:00
ast_debug ( 1 , " TLS started with server \n " ) ;
2007-11-01 22:10:33 +00:00
return IKS_OK ;
}
2008-06-27 07:28:17 +00:00
# endif /* HAVE_OPENSSL */
2007-11-01 22:10:33 +00:00
2010-06-15 17:06:23 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-11-01 22:10:33 +00:00
* \ brief Secured or unsecured IO socket receiving function
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param buffer the reception buffer
* \ param buf_len the size of the buffer
* \ param timeout the select timer
2009-09-25 10:54:42 +00:00
* \ retval the number of read bytes
* \ retval 0 timeout expiration
* \ retval - 1 error
2007-11-01 22:10:33 +00:00
*/
static int aji_io_recv ( struct aji_client * client , char * buffer , size_t buf_len , int timeout )
{
2010-09-02 05:02:54 +00:00
struct pollfd pfd = { . events = POLLIN } ;
2007-11-01 22:10:33 +00:00
int len , res ;
# ifdef HAVE_OPENSSL
if ( aji_is_secure ( client ) ) {
2010-09-02 05:02:54 +00:00
pfd . fd = SSL_get_fd ( client - > ssl_session ) ;
if ( pfd . fd < 0 ) {
2010-06-15 17:06:23 +00:00
return - 1 ;
}
2007-11-01 22:10:33 +00:00
} else
# endif /* HAVE_OPENSSL */
2010-09-02 05:02:54 +00:00
pfd . fd = iks_fd ( client - > p ) ;
2007-11-01 22:10:33 +00:00
2010-09-02 05:02:54 +00:00
res = ast_poll ( & pfd , 1 , timeout > 0 ? timeout * 1000 : - 1 ) ;
2007-11-01 22:10:33 +00:00
if ( res > 0 ) {
# ifdef HAVE_OPENSSL
if ( aji_is_secure ( client ) ) {
len = SSL_read ( client - > ssl_session , buffer , buf_len ) ;
} else
# endif /* HAVE_OPENSSL */
2010-09-02 05:02:54 +00:00
len = recv ( pfd . fd , buffer , buf_len , 0 ) ;
2007-11-01 22:10:33 +00:00
if ( len > 0 ) {
return len ;
} else if ( len < = 0 ) {
return - 1 ;
}
}
return res ;
}
2010-06-15 17:06:23 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-11-01 22:10:33 +00:00
* \ brief Tries to receive data from the Jabber server
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param timeout the timeout value
* This function receives ( encrypted or unencrypted ) data from the XMPP server ,
* and passes it to the parser .
2009-09-25 10:54:42 +00:00
* \ retval IKS_OK success
* \ retval IKS_NET_RWERR IO error
* \ retval IKS_NET_NOCONN no connection available
* \ retval IKS_NET_EXPIRED timeout expiration
2007-11-01 22:10:33 +00:00
*/
static int aji_recv ( struct aji_client * client , int timeout )
{
int len , ret ;
2009-05-30 20:11:33 +00:00
char buf [ NET_IO_BUF_SIZE - 1 ] ;
char newbuf [ NET_IO_BUF_SIZE - 1 ] ;
2008-05-23 10:33:21 +00:00
int pos = 0 ;
int newbufpos = 0 ;
unsigned char c ;
2007-11-01 22:10:33 +00:00
memset ( buf , 0 , sizeof ( buf ) ) ;
2008-05-23 10:33:21 +00:00
memset ( newbuf , 0 , sizeof ( newbuf ) ) ;
2007-11-01 22:10:33 +00:00
while ( 1 ) {
2009-05-30 20:11:33 +00:00
len = aji_io_recv ( client , buf , NET_IO_BUF_SIZE - 2 , timeout ) ;
2007-11-01 22:10:33 +00:00
if ( len < 0 ) return IKS_NET_RWERR ;
if ( len = = 0 ) return IKS_NET_EXPIRED ;
buf [ len ] = ' \0 ' ;
2008-05-23 10:33:21 +00:00
/* our iksemel parser won't work as expected if we feed
2010-06-15 17:06:23 +00:00
it with XML packets that contain multiple whitespace
2008-05-23 10:33:21 +00:00
characters between tags */
while ( pos < len ) {
c = buf [ pos ] ;
/* if we stumble on the ending tag character,
we skip any whitespace that follows it */
if ( c = = ' > ' ) {
while ( isspace ( buf [ pos + 1 ] ) ) {
pos + + ;
}
}
newbuf [ newbufpos ] = c ;
newbufpos + + ;
pos + + ;
}
pos = 0 ;
newbufpos = 0 ;
2010-06-15 17:06:23 +00:00
/* Log the message here, because iksemel's logHook is
2007-11-01 22:10:33 +00:00
unaccessible */
aji_log_hook ( client , buf , len , 1 ) ;
2008-05-23 10:33:21 +00:00
2010-06-15 17:06:23 +00:00
/* let iksemel deal with the string length,
2008-05-23 10:33:21 +00:00
and reset our buffer */
ret = iks_parse ( client - > p , newbuf , 0 , 0 ) ;
memset ( newbuf , 0 , sizeof ( newbuf ) ) ;
2009-05-30 20:11:33 +00:00
switch ( ret ) {
case IKS_NOMEM :
ast_log ( LOG_WARNING , " Parsing failure: Out of memory. \n " ) ;
break ;
case IKS_BADXML :
ast_log ( LOG_WARNING , " Parsing failure: Invalid XML. \n " ) ;
break ;
case IKS_HOOK :
ast_log ( LOG_WARNING , " Parsing failure: Hook returned an error. \n " ) ;
break ;
}
2007-11-01 22:10:33 +00:00
if ( ret ! = IKS_OK ) {
return ret ;
}
2010-06-15 17:06:23 +00:00
ast_debug ( 3 , " XML parsing successful \n " ) ;
2007-11-01 22:10:33 +00:00
}
return IKS_OK ;
}
2010-06-15 17:06:23 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-11-01 22:10:33 +00:00
* \ brief Sends XMPP header to the server
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param to the target XMPP server
* \ return IKS_OK on success , any other value on failure
*/
static int aji_send_header ( struct aji_client * client , const char * to )
{
char * msg ;
int len , err ;
len = 91 + strlen ( client - > name_space ) + 6 + strlen ( to ) + 16 + 1 ;
msg = iks_malloc ( len ) ;
if ( ! msg )
return IKS_NOMEM ;
sprintf ( msg , " <?xml version='1.0'?> "
" <stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns=' "
" %s' to='%s' version='1.0'> " , client - > name_space , to ) ;
err = aji_send_raw ( client , msg ) ;
iks_free ( msg ) ;
if ( err ! = IKS_OK )
return err ;
return IKS_OK ;
}
2010-06-15 17:06:23 +00:00
/*!
2007-11-01 22:10:33 +00:00
* \ brief Wraps raw sending
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param x the XMPP packet to send
* \ return IKS_OK on success , any other value on failure
*/
2007-11-06 18:44:19 +00:00
int ast_aji_send ( struct aji_client * client , iks * x )
2007-11-01 22:10:33 +00:00
{
return aji_send_raw ( client , iks_string ( iks_stack ( x ) , x ) ) ;
}
2010-06-15 17:06:23 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-11-01 22:10:33 +00:00
* \ brief Sends an XML string over an XMPP connection
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param xmlstr the XML string to send
2010-06-15 17:06:23 +00:00
* The XML data is sent whether the connection is secured or not . In the
2007-11-01 22:10:33 +00:00
* latter case , we just call iks_send_raw ( ) .
* \ return IKS_OK on success , any other value on failure
*/
static int aji_send_raw ( struct aji_client * client , const char * xmlstr )
{
int ret ;
# ifdef HAVE_OPENSSL
int len = strlen ( xmlstr ) ;
if ( aji_is_secure ( client ) ) {
ret = SSL_write ( client - > ssl_session , xmlstr , len ) ;
if ( ret ) {
2010-06-15 17:06:23 +00:00
/* Log the message here, because iksemel's logHook is
2007-11-01 22:10:33 +00:00
unaccessible */
aji_log_hook ( client , xmlstr , len , 0 ) ;
return IKS_OK ;
}
}
# endif
2010-06-15 17:06:23 +00:00
/* If needed, data will be sent unencrypted, and logHook will
2007-11-01 22:10:33 +00:00
be called inside iks_send_raw */
2011-10-04 14:22:11 +00:00
ret = iks_send_raw ( client - > p , xmlstr ) ;
2010-06-15 17:06:23 +00:00
if ( ret ! = IKS_OK ) {
return ret ;
}
2007-11-01 22:10:33 +00:00
return IKS_OK ;
}
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief the debug loop .
2007-06-07 21:22:25 +00:00
* \ param data void
* \ param xmpp xml data as string
* \ param size size of string
* \ param is_incoming direction of packet 1 for inbound 0 for outbound .
2006-05-22 21:12:30 +00:00
*/
static void aji_log_hook ( void * data , const char * xmpp , size_t size , int is_incoming )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2007-04-09 18:13:30 +00:00
2006-09-19 23:57:04 +00:00
if ( client - > debug ) {
2010-06-15 17:06:23 +00:00
if ( is_incoming ) {
2006-05-22 21:12:30 +00:00
ast_verbose ( " \n JABBER: %s INCOMING: %s \n " , client - > name , xmpp ) ;
2010-06-15 17:06:23 +00:00
} else {
2009-09-25 10:54:42 +00:00
if ( strlen ( xmpp ) = = 1 ) {
if ( option_debug > 2 & & xmpp [ 0 ] = = ' ' ) {
2008-08-06 13:34:08 +00:00
ast_verbose ( " \n JABBER: Keep alive packet \n " ) ;
}
2010-06-15 17:06:23 +00:00
} else {
2006-09-19 23:57:04 +00:00
ast_verbose ( " \n JABBER: %s OUTGOING: %s \n " , client - > name , xmpp ) ;
2010-06-15 17:06:23 +00:00
}
2006-09-19 23:57:04 +00:00
}
2006-05-22 21:12:30 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
}
2007-06-26 16:39:22 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-26 16:39:22 +00:00
* \ brief A wrapper function for iks_start_sasl
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-26 16:39:22 +00:00
* \ param type the SASL authentication type . Supported types are PLAIN and MD5
* \ param username
2007-09-05 16:31:39 +00:00
* \ param pass password .
*
2007-06-26 16:39:22 +00:00
* \ return IKS_OK on success , IKSNET_NOTSUPP on failure .
*/
2007-11-01 22:10:33 +00:00
static int aji_start_sasl ( struct aji_client * client , enum ikssasltype type , char * username , char * pass )
2007-06-26 16:39:22 +00:00
{
iks * x = NULL ;
2007-06-28 19:30:39 +00:00
int len ;
char * s ;
char * base64 ;
2007-06-26 16:39:22 +00:00
2008-01-04 17:19:25 +00:00
/* trigger SASL DIGEST-MD5 only over an unsecured connection.
iks_start_sasl is an iksemel API function and relies on GnuTLS ,
whereas we use OpenSSL */
if ( ( type & IKS_STREAM_SASL_MD5 ) & & ! aji_is_secure ( client ) )
return iks_start_sasl ( client - > p , IKS_SASL_DIGEST_MD5 , username , pass ) ;
if ( ! ( type & IKS_STREAM_SASL_PLAIN ) ) {
ast_log ( LOG_ERROR , " Server does not support SASL PLAIN authentication \n " ) ;
return IKS_NET_NOTSUPP ;
}
2007-06-26 16:39:22 +00:00
x = iks_new ( " auth " ) ;
if ( ! x ) {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
return IKS_NET_NOTSUPP ;
}
iks_insert_attrib ( x , " xmlns " , IKS_NS_XMPP_SASL ) ;
2007-06-28 19:30:39 +00:00
len = strlen ( username ) + strlen ( pass ) + 3 ;
2012-07-31 20:21:43 +00:00
s = ast_alloca ( len ) ;
base64 = ast_alloca ( ( len + 2 ) * 4 / 3 ) ;
2007-06-26 16:39:22 +00:00
iks_insert_attrib ( x , " mechanism " , " PLAIN " ) ;
2007-10-04 16:56:00 +00:00
snprintf ( s , len , " %c%s%c%s " , 0 , username , 0 , pass ) ;
2008-01-04 17:19:25 +00:00
/* exclude the NULL training byte from the base64 encoding operation
as some XMPP servers will refuse it .
The format for authentication is [ authzid ] \ 0 authcid \ 0 password
not [ authzid ] \ 0 authcid \ 0 password \ 0 */
ast_base64encode ( base64 , ( const unsigned char * ) s , len - 1 , ( len + 2 ) * 4 / 3 ) ;
2007-06-26 16:39:22 +00:00
iks_insert_cdata ( x , base64 , 0 ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , x ) ;
2007-06-26 16:39:22 +00:00
iks_delete ( x ) ;
return IKS_OK ;
}
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief The action hook parses the inbound packets , constantly running .
2007-06-07 09:21:29 +00:00
* \ param data aji client structure
* \ param type type of packet
* \ param node the actual packet .
2006-05-22 21:12:30 +00:00
* \ return IKS_OK or IKS_HOOK .
*/
static int aji_act_hook ( void * data , int type , iks * node )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
ikspak * pak = NULL ;
iks * auth = NULL ;
2007-06-26 16:39:22 +00:00
int features = 0 ;
2006-05-22 21:12:30 +00:00
2009-09-25 10:54:42 +00:00
if ( ! node ) {
2006-08-08 17:07:41 +00:00
ast_log ( LOG_ERROR , " aji_act_hook was called with out a packet \n " ) ; /* most likely cause type is IKS_NODE_ERROR lost connection */
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-08-08 17:07:41 +00:00
return IKS_HOOK ;
}
2007-06-07 09:21:29 +00:00
if ( client - > state = = AJI_DISCONNECTING ) {
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2007-06-07 09:21:29 +00:00
return IKS_HOOK ;
}
2006-05-22 21:12:30 +00:00
pak = iks_packet ( node ) ;
2010-10-05 22:01:52 +00:00
/* work around iksemel's impossibility to recognize node names
* containing a semicolon . Set the namespace of the corresponding
* node accordingly . */
if ( iks_has_children ( node ) & & strchr ( iks_name ( iks_child ( node ) ) , ' : ' ) ) {
char * node_ns = NULL ;
char attr [ AJI_MAX_ATTRLEN ] ;
char * node_name = iks_name ( iks_child ( node ) ) ;
char * aux = strchr ( node_name , ' : ' ) + 1 ;
snprintf ( attr , strlen ( " xmlns: " ) + ( strlen ( node_name ) - strlen ( aux ) ) , " xmlns:%s " , node_name ) ;
node_ns = iks_find_attrib ( iks_child ( node ) , attr ) ;
if ( node_ns ) {
pak - > ns = node_ns ;
pak - > query = iks_child ( node ) ;
}
}
2006-09-21 23:55:13 +00:00
if ( ! client - > component ) { /*client */
2006-05-22 21:12:30 +00:00
switch ( type ) {
case IKS_NODE_START :
2007-11-01 22:10:33 +00:00
if ( client - > usetls & & ! aji_is_secure ( client ) ) {
2008-06-27 07:28:17 +00:00
# ifndef HAVE_OPENSSL
2011-08-02 20:54:19 +00:00
ast_log ( LOG_ERROR , " TLS connection cannot be established. Please install OpenSSL and its development libraries on this system, or disable the TLS option in your configuration file \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2008-06-27 07:28:17 +00:00
return IKS_HOOK ;
# else
2007-11-01 22:10:33 +00:00
if ( aji_start_tls ( client ) = = IKS_NET_TLSFAIL ) {
2008-06-27 07:28:17 +00:00
ast_log ( LOG_ERROR , " Could not start TLS \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
return IKS_HOOK ;
2007-11-01 22:10:33 +00:00
}
2006-05-22 21:12:30 +00:00
break ;
2012-04-17 18:57:40 +00:00
# endif
2006-05-22 21:12:30 +00:00
}
if ( ! client - > usesasl ) {
iks_filter_add_rule ( client - > f , aji_client_connect , client , IKS_RULE_TYPE , IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_RESULT , IKS_RULE_ID , client - > mid , IKS_RULE_DONE ) ;
auth = jabber_make_auth ( client - > jid , client - > password , iks_find_attrib ( node , " id " ) ) ;
if ( auth ) {
iks_insert_attrib ( auth , " id " , client - > mid ) ;
iks_insert_attrib ( auth , " to " , client - > jid - > server ) ;
ast_aji_increment_mid ( client - > mid ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , auth ) ;
2006-05-22 21:12:30 +00:00
iks_delete ( auth ) ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
}
break ;
case IKS_NODE_NORMAL :
2008-06-27 07:28:17 +00:00
# ifdef HAVE_OPENSSL
2007-11-01 22:10:33 +00:00
if ( client - > stream_flags & TRY_SECURE ) {
if ( ! strcmp ( " proceed " , iks_name ( node ) ) ) {
return aji_tls_handshake ( client ) ;
}
}
2008-06-27 07:28:17 +00:00
# endif
2007-06-26 16:39:22 +00:00
if ( ! strcmp ( " stream:features " , iks_name ( node ) ) ) {
features = iks_stream_features ( node ) ;
if ( client - > usesasl ) {
2010-06-15 17:06:23 +00:00
if ( client - > usetls & & ! aji_is_secure ( client ) ) {
2007-06-26 16:39:22 +00:00
break ;
2010-06-15 17:06:23 +00:00
}
2007-06-26 16:39:22 +00:00
if ( client - > authorized ) {
if ( features & IKS_STREAM_BIND ) {
2007-11-01 22:10:33 +00:00
iks_filter_add_rule ( client - > f , aji_client_connect , client , IKS_RULE_TYPE , IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_RESULT , IKS_RULE_DONE ) ;
2007-06-26 16:39:22 +00:00
auth = iks_make_resource_bind ( client - > jid ) ;
if ( auth ) {
iks_insert_attrib ( auth , " id " , client - > mid ) ;
ast_aji_increment_mid ( client - > mid ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , auth ) ;
2007-06-26 16:39:22 +00:00
iks_delete ( auth ) ;
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2007-06-04 15:53:15 +00:00
break ;
}
2007-06-26 16:39:22 +00:00
}
if ( features & IKS_STREAM_SESSION ) {
iks_filter_add_rule ( client - > f , aji_client_connect , client , IKS_RULE_TYPE , IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_RESULT , IKS_RULE_ID , " auth " , IKS_RULE_DONE ) ;
auth = iks_make_session ( ) ;
if ( auth ) {
iks_insert_attrib ( auth , " id " , " auth " ) ;
ast_aji_increment_mid ( client - > mid ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , auth ) ;
2007-06-26 16:39:22 +00:00
iks_delete ( auth ) ;
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2006-05-22 21:12:30 +00:00
}
}
2007-06-26 16:39:22 +00:00
} else {
int ret ;
if ( ! client - > jid - > user ) {
ast_log ( LOG_ERROR , " Malformed Jabber ID : %s (domain missing?) \n " , client - > jid - > full ) ;
break ;
}
2008-01-04 17:19:25 +00:00
2007-11-01 22:10:33 +00:00
ret = aji_start_sasl ( client , features , client - > jid - > user , client - > password ) ;
2007-06-26 16:39:22 +00:00
if ( ret ! = IKS_OK ) {
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2007-06-26 16:39:22 +00:00
return IKS_HOOK ;
}
break ;
2006-05-22 21:12:30 +00:00
}
}
2007-06-26 16:39:22 +00:00
} else if ( ! strcmp ( " failure " , iks_name ( node ) ) ) {
ast_log ( LOG_ERROR , " JABBER: encryption failure. possible bad password. \n " ) ;
} else if ( ! strcmp ( " success " , iks_name ( node ) ) ) {
client - > authorized = 1 ;
2007-11-01 22:10:33 +00:00
aji_send_header ( client , client - > jid - > server ) ;
2006-05-22 21:12:30 +00:00
}
2007-06-26 16:39:22 +00:00
break ;
2010-06-15 17:06:23 +00:00
case IKS_NODE_ERROR :
ast_log ( LOG_ERROR , " JABBER: Node Error \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return IKS_HOOK ;
break ;
case IKS_NODE_STOP :
ast_log ( LOG_WARNING , " JABBER: Disconnected \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return IKS_HOOK ;
break ;
2006-05-22 21:12:30 +00:00
}
2006-09-21 23:55:13 +00:00
} else if ( client - > state ! = AJI_CONNECTED & & client - > component ) {
2006-05-22 21:12:30 +00:00
switch ( type ) {
2006-08-07 21:15:28 +00:00
case IKS_NODE_START :
if ( client - > state = = AJI_DISCONNECTED ) {
2006-05-22 21:12:30 +00:00
char secret [ 160 ] , shasum [ 320 ] , * handshake ;
2006-08-07 21:15:28 +00:00
sprintf ( secret , " %s%s " , pak - > id , client - > password ) ;
ast_sha1_hash ( shasum , secret ) ;
2012-08-21 21:01:11 +00:00
if ( ast_asprintf ( & handshake , " <handshake>%s</handshake> " , shasum ) > = 0 ) {
2007-11-01 22:10:33 +00:00
aji_send_raw ( client , handshake ) ;
2007-06-06 21:20:11 +00:00
ast_free ( handshake ) ;
2006-06-06 18:51:37 +00:00
}
2006-09-19 23:57:04 +00:00
client - > state = AJI_CONNECTING ;
2009-09-25 10:54:42 +00:00
if ( aji_recv ( client , 1 ) = = 2 ) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
2006-09-19 23:57:04 +00:00
client - > state = AJI_CONNECTED ;
2006-09-20 00:39:44 +00:00
else
2007-10-04 16:56:00 +00:00
ast_log ( LOG_WARNING , " Jabber didn't seem to handshake, failed to authenticate. \n " ) ;
2006-09-19 23:57:04 +00:00
break ;
2006-05-22 21:12:30 +00:00
}
2006-08-07 21:15:28 +00:00
break ;
2006-05-22 21:12:30 +00:00
2006-08-07 21:15:28 +00:00
case IKS_NODE_NORMAL :
break ;
2006-05-22 21:12:30 +00:00
2006-08-07 21:15:28 +00:00
case IKS_NODE_ERROR :
ast_log ( LOG_ERROR , " JABBER: Node Error \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-08-07 21:15:28 +00:00
return IKS_HOOK ;
case IKS_NODE_STOP :
ast_log ( LOG_WARNING , " JABBER: Disconnected \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-08-07 21:15:28 +00:00
return IKS_HOOK ;
2006-05-22 21:12:30 +00:00
}
}
switch ( pak - > type ) {
case IKS_PAK_NONE :
2007-10-04 16:56:00 +00:00
ast_debug ( 1 , " JABBER: I don't know what to do with paktype NONE. \n " ) ;
2006-05-22 21:12:30 +00:00
break ;
case IKS_PAK_MESSAGE :
2006-06-07 22:43:20 +00:00
aji_handle_message ( client , pak ) ;
2007-10-04 16:56:00 +00:00
ast_debug ( 1 , " JABBER: Handling paktype MESSAGE. \n " ) ;
2006-05-22 21:12:30 +00:00
break ;
case IKS_PAK_PRESENCE :
aji_handle_presence ( client , pak ) ;
2007-10-04 16:56:00 +00:00
ast_debug ( 1 , " JABBER: Handling paktype PRESENCE \n " ) ;
2006-05-22 21:12:30 +00:00
break ;
case IKS_PAK_S10N :
aji_handle_subscribe ( client , pak ) ;
2007-10-04 16:56:00 +00:00
ast_debug ( 1 , " JABBER: Handling paktype S10N \n " ) ;
2006-05-22 21:12:30 +00:00
break ;
case IKS_PAK_IQ :
2007-10-04 16:56:00 +00:00
ast_debug ( 1 , " JABBER: Handling paktype IQ \n " ) ;
2006-05-22 21:12:30 +00:00
aji_handle_iq ( client , node ) ;
break ;
default :
2014-05-09 22:49:26 +00:00
ast_debug ( 1 , " JABBER: I don't know anything about paktype '%u' \n " , pak - > type ) ;
2006-05-22 21:12:30 +00:00
break ;
}
2010-06-15 17:06:23 +00:00
2006-05-22 21:12:30 +00:00
iks_filter_packet ( client - > f , pak ) ;
if ( node )
iks_delete ( node ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_OK ;
}
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2008-08-06 13:34:08 +00:00
* \ brief Unknown
2007-06-07 21:22:25 +00:00
* \ param data void
* \ param pak ikspak
* \ return IKS_FILTER_EAT .
*/
2006-05-22 21:12:30 +00:00
static int aji_register_approve_handler ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2006-10-03 00:07:45 +00:00
iks * iq = NULL , * presence = NULL , * x = NULL ;
2006-05-22 21:12:30 +00:00
iq = iks_new ( " iq " ) ;
2006-09-21 23:55:13 +00:00
presence = iks_new ( " presence " ) ;
x = iks_new ( " x " ) ;
2006-10-03 00:07:45 +00:00
if ( client & & iq & & presence & & x ) {
2006-05-22 21:12:30 +00:00
if ( ! iks_find ( pak - > query , " remove " ) ) {
iks_insert_attrib ( iq , " from " , client - > jid - > full ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-09-21 23:55:13 +00:00
iks_insert_attrib ( presence , " from " , client - > jid - > full ) ;
iks_insert_attrib ( presence , " to " , pak - > from - > partial ) ;
iks_insert_attrib ( presence , " id " , client - > mid ) ;
2006-05-22 21:12:30 +00:00
ast_aji_increment_mid ( client - > mid ) ;
2006-09-21 23:55:13 +00:00
iks_insert_attrib ( presence , " type " , " subscribe " ) ;
iks_insert_attrib ( x , " xmlns " , " vcard-temp:x:update " ) ;
iks_insert_node ( presence , x ) ;
2010-06-15 17:06:23 +00:00
ast_aji_send ( client , presence ) ;
2006-05-22 21:12:30 +00:00
}
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2006-09-21 23:55:13 +00:00
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( presence ) ;
iks_delete ( x ) ;
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2008-08-06 13:34:08 +00:00
* \ brief register handler for incoming querys ( IQ ' s )
2007-06-07 21:22:25 +00:00
* \ param data incoming aji_client request
* \ param pak ikspak
* \ return IKS_FILTER_EAT .
*/
2006-05-22 21:12:30 +00:00
static int aji_register_query_handler ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2010-06-15 17:06:23 +00:00
struct aji_buddy * buddy = NULL ;
2008-08-06 13:34:08 +00:00
iks * iq = NULL , * query = NULL ;
2006-05-22 21:12:30 +00:00
client = ( struct aji_client * ) data ;
2006-10-03 00:07:45 +00:00
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , pak - > from - > partial ) ;
if ( ! buddy ) {
2008-08-06 13:34:08 +00:00
iks * error = NULL , * notacceptable = NULL ;
2006-11-03 18:10:44 +00:00
2008-08-06 13:34:08 +00:00
ast_log ( LOG_ERROR , " Someone.... %s tried to register but they aren't allowed \n " , pak - > from - > partial ) ;
2006-10-03 00:07:45 +00:00
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
error = iks_new ( " error " ) ;
notacceptable = iks_new ( " not-acceptable " ) ;
2009-09-25 10:54:42 +00:00
if ( iq & & query & & error & & notacceptable ) {
2006-10-03 00:07:45 +00:00
iks_insert_attrib ( iq , " type " , " error " ) ;
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( query , " xmlns " , " jabber:iq:register " ) ;
iks_insert_attrib ( error , " code " , " 406 " ) ;
iks_insert_attrib ( error , " type " , " modify " ) ;
iks_insert_attrib ( notacceptable , " xmlns " , " urn:ietf:params:xml:ns:xmpp-stanzas " ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( iq , error ) ;
iks_insert_node ( error , notacceptable ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-10-03 00:07:45 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( error ) ;
iks_delete ( notacceptable ) ;
2012-04-17 18:57:40 +00:00
} else if ( ! iks_find_attrib ( pak - > query , " node " ) ) {
2008-08-06 13:34:08 +00:00
iks * instructions = NULL ;
2006-08-07 21:15:28 +00:00
char * explain = " Welcome to Asterisk - the Open Source PBX. \n " ;
2006-05-22 21:12:30 +00:00
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
instructions = iks_new ( " instructions " ) ;
if ( iq & & query & & instructions & & client ) {
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( query , " xmlns " , " jabber:iq:register " ) ;
iks_insert_cdata ( instructions , explain , 0 ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , instructions ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-05-22 21:12:30 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( instructions ) ;
2006-05-22 21:12:30 +00:00
}
2008-08-06 13:34:08 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief Handles stuff
* \ param data void
2010-06-15 17:06:23 +00:00
* \ param pak ikspak
2007-06-07 21:22:25 +00:00
* \ return IKS_FILTER_EAT .
*/
2006-05-22 21:12:30 +00:00
static int aji_ditems_handler ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
char * node = NULL ;
if ( ! ( node = iks_find_attrib ( pak - > query , " node " ) ) ) {
iks * iq = NULL , * query = NULL , * item = NULL ;
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
item = iks_new ( " item " ) ;
if ( iq & & query & & item ) {
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#items " ) ;
iks_insert_attrib ( item , " node " , " http://jabber.org/protocol/commands " ) ;
iks_insert_attrib ( item , " name " , " Million Dollar Asterisk Commands " ) ;
iks_insert_attrib ( item , " jid " , client - > user ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , item ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-05-22 21:12:30 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( item ) ;
2006-05-22 21:12:30 +00:00
} else if ( ! strcasecmp ( node , " http://jabber.org/protocol/commands " ) ) {
iks * iq , * query , * confirm ;
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
confirm = iks_new ( " item " ) ;
if ( iq & & query & & confirm & & client ) {
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#items " ) ;
iks_insert_attrib ( query , " node " , " http://jabber.org/protocol/commands " ) ;
iks_insert_attrib ( confirm , " node " , " confirmaccount " ) ;
iks_insert_attrib ( confirm , " name " , " Confirm AIM account " ) ;
iks_insert_attrib ( confirm , " jid " , " blog.astjab.org " ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , confirm ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-05-22 21:12:30 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( confirm ) ;
2006-05-22 21:12:30 +00:00
} else if ( ! strcasecmp ( node , " confirmaccount " ) ) {
iks * iq = NULL , * query = NULL , * feature = NULL ;
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
feature = iks_new ( " feature " ) ;
if ( iq & & query & & feature & & client ) {
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#items " ) ;
iks_insert_attrib ( feature , " var " , " http://jabber.org/protocol/commands " ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , feature ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-05-22 21:12:30 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( feature ) ;
2006-05-22 21:12:30 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
2009-09-25 10:54:42 +00:00
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief Handle add extra info
* \ param data void
* \ param pak ikspak
* \ return IKS_FILTER_EAT
*/
2006-05-22 21:12:30 +00:00
static int aji_client_info_handler ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
struct aji_resource * resource = NULL ;
2006-08-07 21:15:28 +00:00
struct aji_buddy * buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , pak - > from - > partial ) ;
2006-05-22 21:12:30 +00:00
2012-10-04 02:16:43 +00:00
if ( ! buddy ) {
ast_log ( LOG_NOTICE , " JABBER: Received client info from unknown buddy: %s. \n " , pak - > from - > full ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
return IKS_FILTER_EAT ;
}
2006-05-22 21:12:30 +00:00
resource = aji_find_resource ( buddy , pak - > from - > resource ) ;
if ( pak - > subtype = = IKS_TYPE_RESULT ) {
2006-06-07 22:43:20 +00:00
if ( ! resource ) {
2008-08-06 13:34:08 +00:00
ast_log ( LOG_NOTICE , " JABBER: Received client info from %s when not requested. \n " , pak - > from - > full ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-06-07 22:43:20 +00:00
return IKS_FILTER_EAT ;
}
2006-05-22 21:12:30 +00:00
if ( iks_find_with_attrib ( pak - > query , " feature " , " var " , " http://www.google.com/xmpp/protocol/voice/v1 " ) ) {
resource - > cap - > jingle = 1 ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
resource - > cap - > jingle = 0 ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
} else if ( pak - > subtype = = IKS_TYPE_GET ) {
iks * iq , * disco , * ident , * google , * query ;
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
ident = iks_new ( " identity " ) ;
disco = iks_new ( " feature " ) ;
google = iks_new ( " feature " ) ;
if ( iq & & ident & & disco & & google ) {
iks_insert_attrib ( iq , " from " , client - > jid - > full ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
2006-06-07 22:43:20 +00:00
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#info " ) ;
2006-05-22 21:12:30 +00:00
iks_insert_attrib ( ident , " category " , " client " ) ;
iks_insert_attrib ( ident , " type " , " pc " ) ;
iks_insert_attrib ( ident , " name " , " asterisk " ) ;
iks_insert_attrib ( disco , " var " , " http://jabber.org/protocol/disco#info " ) ;
iks_insert_attrib ( google , " var " , " http://www.google.com/xmpp/protocol/voice/v1 " ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , ident ) ;
iks_insert_node ( query , google ) ;
2006-06-06 19:18:44 +00:00
iks_insert_node ( query , disco ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of Memory. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( ident ) ;
iks_delete ( google ) ;
iks_delete ( disco ) ;
2006-05-22 21:12:30 +00:00
} else if ( pak - > subtype = = IKS_TYPE_ERROR ) {
ast_log ( LOG_NOTICE , " User %s does not support discovery. \n " , pak - > from - > full ) ;
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
2009-09-25 10:54:42 +00:00
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief Handler of the return info packet
* \ param data aji_client
* \ param pak ikspak
* \ return IKS_FILTER_EAT
*/
2006-05-22 21:12:30 +00:00
static int aji_dinfo_handler ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2006-10-03 22:36:51 +00:00
char * node = NULL ;
struct aji_resource * resource = NULL ;
struct aji_buddy * buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , pak - > from - > partial ) ;
2012-10-04 02:16:43 +00:00
if ( ! buddy ) {
ast_log ( LOG_NOTICE , " JABBER: Received client info from unknown buddy: %s. \n " , pak - > from - > full ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
return IKS_FILTER_EAT ;
}
2006-10-03 22:36:51 +00:00
if ( pak - > subtype = = IKS_TYPE_ERROR ) {
2009-07-27 16:33:50 +00:00
ast_log ( LOG_WARNING , " Received error from a client, turn on jabber debug! \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-09-19 23:57:04 +00:00
return IKS_FILTER_EAT ;
}
2011-11-23 17:16:33 +00:00
resource = aji_find_resource ( buddy , pak - > from - > resource ) ;
2006-10-03 22:36:51 +00:00
if ( pak - > subtype = = IKS_TYPE_RESULT ) {
if ( ! resource ) {
2010-06-15 17:06:23 +00:00
ast_log ( LOG_NOTICE , " JABBER: Received client info from %s when not requested. \n " , pak - > from - > full ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-10-03 22:36:51 +00:00
return IKS_FILTER_EAT ;
}
if ( iks_find_with_attrib ( pak - > query , " feature " , " var " , " http://www.google.com/xmpp/protocol/voice/v1 " ) ) {
resource - > cap - > jingle = 1 ;
2010-06-15 17:06:23 +00:00
} else {
2006-10-03 22:36:51 +00:00
resource - > cap - > jingle = 0 ;
2010-06-15 17:06:23 +00:00
}
2006-10-03 22:36:51 +00:00
} else if ( pak - > subtype = = IKS_TYPE_GET & & ! ( node = iks_find_attrib ( pak - > query , " node " ) ) ) {
2006-08-07 21:15:28 +00:00
iks * iq , * query , * identity , * disco , * reg , * commands , * gateway , * version , * vcard , * search ;
2006-05-22 21:12:30 +00:00
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
identity = iks_new ( " identity " ) ;
disco = iks_new ( " feature " ) ;
reg = iks_new ( " feature " ) ;
commands = iks_new ( " feature " ) ;
gateway = iks_new ( " feature " ) ;
version = iks_new ( " feature " ) ;
vcard = iks_new ( " feature " ) ;
search = iks_new ( " feature " ) ;
if ( iq & & query & & identity & & disco & & reg & & commands & & gateway & & version & & vcard & & search & & client ) {
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#info " ) ;
iks_insert_attrib ( identity , " category " , " gateway " ) ;
iks_insert_attrib ( identity , " type " , " pstn " ) ;
iks_insert_attrib ( identity , " name " , " Asterisk The Open Source PBX " ) ;
iks_insert_attrib ( disco , " var " , " http://jabber.org/protocol/disco " ) ;
iks_insert_attrib ( reg , " var " , " jabber:iq:register " ) ;
iks_insert_attrib ( commands , " var " , " http://jabber.org/protocol/commands " ) ;
iks_insert_attrib ( gateway , " var " , " jabber:iq:gateway " ) ;
iks_insert_attrib ( version , " var " , " jabber:iq:version " ) ;
iks_insert_attrib ( vcard , " var " , " vcard-temp " ) ;
iks_insert_attrib ( search , " var " , " jabber:iq:search " ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , identity ) ;
iks_insert_node ( query , disco ) ;
iks_insert_node ( query , reg ) ;
iks_insert_node ( query , commands ) ;
iks_insert_node ( query , gateway ) ;
iks_insert_node ( query , version ) ;
iks_insert_node ( query , vcard ) ;
iks_insert_node ( query , search ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-05-22 21:12:30 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( identity ) ;
iks_delete ( disco ) ;
iks_delete ( reg ) ;
iks_delete ( commands ) ;
iks_delete ( gateway ) ;
iks_delete ( version ) ;
iks_delete ( vcard ) ;
iks_delete ( search ) ;
2006-10-03 22:36:51 +00:00
} else if ( pak - > subtype = = IKS_TYPE_GET & & ! strcasecmp ( node , " http://jabber.org/protocol/commands " ) ) {
2006-08-07 21:15:28 +00:00
iks * iq , * query , * confirm ;
2006-05-22 21:12:30 +00:00
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
confirm = iks_new ( " item " ) ;
if ( iq & & query & & confirm & & client ) {
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#items " ) ;
iks_insert_attrib ( query , " node " , " http://jabber.org/protocol/commands " ) ;
iks_insert_attrib ( confirm , " node " , " confirmaccount " ) ;
iks_insert_attrib ( confirm , " name " , " Confirm AIM account " ) ;
iks_insert_attrib ( confirm , " jid " , client - > user ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , confirm ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-05-22 21:12:30 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( confirm ) ;
2006-05-22 21:12:30 +00:00
2006-10-03 22:36:51 +00:00
} else if ( pak - > subtype = = IKS_TYPE_GET & & ! strcasecmp ( node , " confirmaccount " ) ) {
2006-08-07 21:15:28 +00:00
iks * iq , * query , * feature ;
2006-05-22 21:12:30 +00:00
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
feature = iks_new ( " feature " ) ;
2006-08-07 21:15:28 +00:00
2006-05-22 21:12:30 +00:00
if ( iq & & query & & feature & & client ) {
iks_insert_attrib ( iq , " from " , client - > user ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
iks_insert_attrib ( iq , " id " , pak - > id ) ;
iks_insert_attrib ( iq , " type " , " result " ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#info " ) ;
iks_insert_attrib ( feature , " var " , " http://jabber.org/protocol/commands " ) ;
iks_insert_node ( iq , query ) ;
iks_insert_node ( query , feature ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2006-05-22 21:12:30 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( feature ) ;
2006-05-22 21:12:30 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
* \ brief Handles \ verbatim < iq > \ endverbatim stanzas .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2009-09-25 10:54:42 +00:00
* \ param node iks
2006-05-22 21:12:30 +00:00
* \ return void .
*/
static void aji_handle_iq ( struct aji_client * client , iks * node )
{
2006-08-08 17:07:41 +00:00
/*Nothing to see here */
2006-05-22 21:12:30 +00:00
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
* \ brief Handles \ verbatim < message > \ endverbatim stanzas .
* Adds the incoming message to the client ' s message list .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ param pak ikspak the node
2006-05-22 21:12:30 +00:00
*/
2006-06-07 22:43:20 +00:00
static void aji_handle_message ( struct aji_client * client , ikspak * pak )
{
2009-09-25 10:54:42 +00:00
struct aji_message * insert ;
int deleted = 0 ;
2011-06-01 21:31:40 +00:00
struct ast_msg * msg ;
2009-09-25 10:54:42 +00:00
ast_debug ( 3 , " client %s received a message \n " , client - > name ) ;
if ( ! ( insert = ast_calloc ( 1 , sizeof ( * insert ) ) ) ) {
2006-06-18 21:45:48 +00:00
return ;
2009-09-25 10:54:42 +00:00
}
insert - > arrived = ast_tvnow ( ) ;
/* wake up threads waiting for messages */
ast_mutex_lock ( & messagelock ) ;
ast_cond_broadcast ( & message_received_condition ) ;
ast_mutex_unlock ( & messagelock ) ;
if ( iks_find_cdata ( pak - > x , " body " ) ) {
2006-06-27 14:07:24 +00:00
insert - > message = ast_strdup ( iks_find_cdata ( pak - > x , " body " ) ) ;
2009-09-25 10:54:42 +00:00
}
if ( pak - > id ) {
ast_copy_string ( insert - > id , pak - > id , sizeof ( insert - > id ) ) ;
}
if ( pak - > from ) {
/* insert will furtherly be added to message list */
2006-10-23 17:08:53 +00:00
insert - > from = ast_strdup ( pak - > from - > full ) ;
2009-09-25 10:54:42 +00:00
if ( ! insert - > from ) {
2012-05-18 14:43:44 +00:00
ast_free ( insert ) ;
2009-09-25 10:54:42 +00:00
ast_log ( LOG_ERROR , " Memory allocation failure \n " ) ;
return ;
2006-06-07 22:43:20 +00:00
}
2009-09-25 10:54:42 +00:00
ast_debug ( 3 , " message comes from %s \n " , insert - > from ) ;
2006-06-07 22:43:20 +00:00
}
2009-09-25 10:54:42 +00:00
2011-06-07 19:17:31 +00:00
if ( client - > send_to_dialplan ) {
if ( ( msg = ast_msg_alloc ( ) ) ) {
int res ;
2011-06-01 21:31:40 +00:00
2011-06-07 19:17:31 +00:00
res = ast_msg_set_to ( msg , " xmpp:%s " , client - > user ) ;
res | = ast_msg_set_from ( msg , " xmpp:%s " , insert - > from ) ;
res | = ast_msg_set_body ( msg , " %s " , insert - > message ) ;
res | = ast_msg_set_context ( msg , " %s " , client - > context ) ;
2011-06-01 21:31:40 +00:00
2011-06-07 19:17:31 +00:00
if ( res ) {
ast_msg_destroy ( msg ) ;
} else {
ast_msg_queue ( msg ) ;
}
2011-06-01 21:31:40 +00:00
2011-06-07 19:17:31 +00:00
msg = NULL ;
}
2011-06-01 21:31:40 +00:00
}
2009-09-25 10:54:42 +00:00
/* remove old messages received from this JID
* and insert received message */
deleted = delete_old_messages ( client , pak - > from - > partial ) ;
ast_debug ( 3 , " Deleted %d messages for client %s from JID %s \n " , deleted , client - > name , pak - > from - > partial ) ;
AST_LIST_LOCK ( & client - > messages ) ;
2006-06-18 21:45:48 +00:00
AST_LIST_INSERT_HEAD ( & client - > messages , insert , list ) ;
2006-06-09 16:08:33 +00:00
AST_LIST_UNLOCK ( & client - > messages ) ;
2006-06-07 22:43:20 +00:00
}
2009-09-25 10:54:42 +00:00
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
* \ brief handles \ verbatim < presence > \ endverbatim stanzas .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ param pak ikspak
2009-09-25 10:54:42 +00:00
*/
2006-05-22 21:12:30 +00:00
static void aji_handle_presence ( struct aji_client * client , ikspak * pak )
{
int status , priority ;
2006-08-07 21:15:28 +00:00
struct aji_buddy * buddy ;
2006-05-22 21:12:30 +00:00
struct aji_resource * tmp = NULL , * last = NULL , * found = NULL ;
2006-10-03 00:07:45 +00:00
char * ver , * node , * descrip , * type ;
2009-09-25 10:54:42 +00:00
if ( client - > state ! = AJI_CONNECTED )
2006-08-07 21:15:28 +00:00
aji_create_buddy ( pak - > from - > partial , client ) ;
2006-05-22 21:12:30 +00:00
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , pak - > from - > partial ) ;
2007-10-07 16:18:49 +00:00
if ( ! buddy & & pak - > from - > partial ) {
/* allow our jid to be used to log in with another resource */
if ( ! strcmp ( ( const char * ) pak - > from - > partial , ( const char * ) client - > jid - > partial ) )
aji_create_buddy ( pak - > from - > partial , client ) ;
else
ast_log ( LOG_NOTICE , " Got presence packet from %s, someone not in our roster!!!! \n " , pak - > from - > partial ) ;
2006-05-22 21:12:30 +00:00
return ;
}
2006-10-03 00:07:45 +00:00
type = iks_find_attrib ( pak - > x , " type " ) ;
2009-09-25 10:54:42 +00:00
if ( client - > component & & type & & ! strcasecmp ( " probe " , type ) ) {
2007-10-07 16:28:25 +00:00
aji_set_presence ( client , pak - > from - > full , iks_find_attrib ( pak - > x , " to " ) , client - > status , client - > statusmessage ) ;
2006-09-21 23:55:13 +00:00
ast_verbose ( " what i was looking for \n " ) ;
}
2006-06-06 18:51:37 +00:00
ASTOBJ_WRLOCK ( buddy ) ;
2006-05-22 21:12:30 +00:00
status = ( pak - > show ) ? pak - > show : 6 ;
priority = atoi ( ( iks_find_cdata ( pak - > x , " priority " ) ) ? iks_find_cdata ( pak - > x , " priority " ) : " 0 " ) ;
tmp = buddy - > resources ;
2010-06-15 17:06:23 +00:00
descrip = ast_strdup ( iks_find_cdata ( pak - > x , " status " ) ) ;
2006-05-22 21:12:30 +00:00
2007-10-07 15:54:48 +00:00
while ( tmp & & pak - > from - > resource ) {
2006-05-22 21:12:30 +00:00
if ( ! strcasecmp ( tmp - > resource , pak - > from - > resource ) ) {
tmp - > status = status ;
2010-06-15 17:06:23 +00:00
if ( tmp - > description ) {
ast_free ( tmp - > description ) ;
}
2006-06-06 19:51:26 +00:00
tmp - > description = descrip ;
2006-05-22 21:12:30 +00:00
found = tmp ;
if ( status = = 6 ) { /* Sign off Destroy resource */
if ( last & & found - > next ) {
last - > next = found - > next ;
} else if ( ! last ) {
2010-06-15 17:06:23 +00:00
if ( found - > next ) {
2006-05-22 21:12:30 +00:00
buddy - > resources = found - > next ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
buddy - > resources = NULL ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
} else if ( ! found - > next ) {
2010-06-15 17:06:23 +00:00
if ( last ) {
2006-05-22 21:12:30 +00:00
last - > next = NULL ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
buddy - > resources = NULL ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
}
2007-06-06 21:20:11 +00:00
ast_free ( found ) ;
2006-05-22 21:12:30 +00:00
found = NULL ;
break ;
}
2007-08-16 09:45:22 +00:00
/* resource list is sorted by descending priority */
2006-05-22 21:12:30 +00:00
if ( tmp - > priority ! = priority ) {
found - > priority = priority ;
2010-06-15 17:06:23 +00:00
if ( ! last & & ! found - > next ) {
2007-08-16 09:45:22 +00:00
/* resource was found to be unique,
leave loop */
2006-05-22 21:12:30 +00:00
break ;
2010-06-15 17:06:23 +00:00
}
2007-08-16 09:45:22 +00:00
/* search for resource in our list
and take it out for the moment */
2010-06-15 17:06:23 +00:00
if ( last ) {
2006-05-22 21:12:30 +00:00
last - > next = found - > next ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
buddy - > resources = found - > next ;
2010-06-15 17:06:23 +00:00
}
2007-08-16 09:45:22 +00:00
2006-05-22 21:12:30 +00:00
last = NULL ;
tmp = buddy - > resources ;
2010-06-15 17:06:23 +00:00
if ( ! buddy - > resources ) {
2006-05-22 21:12:30 +00:00
buddy - > resources = found ;
2010-06-15 17:06:23 +00:00
}
2007-08-16 09:45:22 +00:00
/* priority processing */
2006-05-22 21:12:30 +00:00
while ( tmp ) {
2010-06-15 17:06:23 +00:00
/* insert resource back according to
2007-08-16 09:45:22 +00:00
its priority value */
2006-05-22 21:12:30 +00:00
if ( found - > priority > tmp - > priority ) {
2010-06-15 17:06:23 +00:00
if ( last ) {
2007-08-16 09:45:22 +00:00
/* insert within list */
2006-05-22 21:12:30 +00:00
last - > next = found ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
found - > next = tmp ;
2010-06-15 17:06:23 +00:00
if ( ! last ) {
2007-08-16 09:45:22 +00:00
/* insert on top */
2006-05-22 21:12:30 +00:00
buddy - > resources = found ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
break ;
}
if ( ! tmp - > next ) {
2007-08-16 09:45:22 +00:00
/* insert at the end of the list */
2006-05-22 21:12:30 +00:00
tmp - > next = found ;
2007-08-16 09:45:22 +00:00
found - > next = NULL ;
2006-05-22 21:12:30 +00:00
break ;
}
last = tmp ;
tmp = tmp - > next ;
}
}
break ;
}
last = tmp ;
tmp = tmp - > next ;
}
2007-08-16 09:45:22 +00:00
/* resource not found in our list, create it */
2007-10-07 15:54:48 +00:00
if ( ! found & & status ! = 6 & & pak - > from - > resource ) {
2007-06-06 21:20:11 +00:00
found = ast_calloc ( 1 , sizeof ( * found ) ) ;
2006-08-07 21:15:28 +00:00
2006-05-22 21:12:30 +00:00
if ( ! found ) {
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNLOCK ( buddy ) ;
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
2006-05-22 21:12:30 +00:00
return ;
}
ast_copy_string ( found - > resource , pak - > from - > resource , sizeof ( found - > resource ) ) ;
found - > status = status ;
2006-06-06 19:51:26 +00:00
found - > description = descrip ;
2006-05-22 21:12:30 +00:00
found - > priority = priority ;
found - > next = NULL ;
last = NULL ;
tmp = buddy - > resources ;
while ( tmp ) {
if ( found - > priority > tmp - > priority ) {
2010-06-15 17:06:23 +00:00
if ( last ) {
2006-05-22 21:12:30 +00:00
last - > next = found ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
found - > next = tmp ;
2010-06-15 17:06:23 +00:00
if ( ! last ) {
2006-05-22 21:12:30 +00:00
buddy - > resources = found ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
break ;
}
if ( ! tmp - > next ) {
tmp - > next = found ;
break ;
}
last = tmp ;
tmp = tmp - > next ;
}
2010-06-15 17:06:23 +00:00
if ( ! tmp ) {
2006-05-22 21:12:30 +00:00
buddy - > resources = found ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
}
2010-06-15 17:06:23 +00:00
2006-06-06 18:51:37 +00:00
ASTOBJ_UNLOCK ( buddy ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
2006-05-22 21:12:30 +00:00
node = iks_find_attrib ( iks_find ( pak - > x , " c " ) , " node " ) ;
ver = iks_find_attrib ( iks_find ( pak - > x , " c " ) , " ver " ) ;
2007-08-16 09:45:22 +00:00
/* handle gmail client's special caps:c tag */
if ( ! node & & ! ver ) {
node = iks_find_attrib ( iks_find ( pak - > x , " caps:c " ) , " node " ) ;
ver = iks_find_attrib ( iks_find ( pak - > x , " caps:c " ) , " ver " ) ;
}
2007-10-07 15:54:48 +00:00
/* retrieve capabilites of the new resource */
2009-09-25 10:54:42 +00:00
if ( status ! = 6 & & found & & ! found - > cap ) {
2006-05-22 21:12:30 +00:00
found - > cap = aji_find_version ( node , ver , pak ) ;
2010-06-15 17:06:23 +00:00
if ( gtalk_yuck ( pak - > x ) ) { /* gtalk should do discover */
2006-05-22 21:12:30 +00:00
found - > cap - > jingle = 1 ;
2006-10-03 15:53:07 +00:00
}
2010-10-05 22:01:52 +00:00
if ( found - > cap - > jingle ) {
2010-06-15 17:06:23 +00:00
ast_debug ( 1 , " Special case for google till they support discover. \n " ) ;
} else {
2006-05-22 21:12:30 +00:00
iks * iq , * query ;
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
2010-06-15 17:06:23 +00:00
if ( query & & iq ) {
2006-05-22 21:12:30 +00:00
iks_insert_attrib ( iq , " type " , " get " ) ;
iks_insert_attrib ( iq , " to " , pak - > from - > full ) ;
2010-06-15 17:06:23 +00:00
iks_insert_attrib ( iq , " from " , client - > jid - > full ) ;
2006-05-22 21:12:30 +00:00
iks_insert_attrib ( iq , " id " , client - > mid ) ;
ast_aji_increment_mid ( client - > mid ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#info " ) ;
iks_insert_node ( iq , query ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2008-02-29 14:15:03 +00:00
iks_delete ( query ) ;
iks_delete ( iq ) ;
2006-05-22 21:12:30 +00:00
}
}
2007-10-07 15:56:22 +00:00
switch ( pak - > subtype ) {
case IKS_TYPE_AVAILABLE :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: I am available ^_* %u \n " , pak - > subtype ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_TYPE_UNAVAILABLE :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: I am unavailable ^_* %u \n " , pak - > subtype ) ;
2007-10-07 15:56:22 +00:00
break ;
default :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: Ohh sexy and the wrong type: %u \n " , pak - > subtype ) ;
2006-05-22 21:12:30 +00:00
}
2007-10-07 15:56:22 +00:00
switch ( pak - > show ) {
case IKS_SHOW_UNAVAILABLE :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: type: %u subtype %u \n " , pak - > subtype , pak - > show ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_SHOW_AVAILABLE :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: type is available \n " ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_SHOW_CHAT :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: type: %u subtype %u \n " , pak - > subtype , pak - > show ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_SHOW_AWAY :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: type is away \n " ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_SHOW_XA :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: type: %u subtype %u \n " , pak - > subtype , pak - > show ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_SHOW_DND :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: type: %u subtype %u \n " , pak - > subtype , pak - > show ) ;
2007-10-07 15:56:22 +00:00
break ;
default :
2014-05-09 22:49:26 +00:00
ast_debug ( 3 , " JABBER: Kinky! how did that happen %u \n " , pak - > show ) ;
2007-10-07 15:56:22 +00:00
}
2010-02-18 16:34:08 +00:00
2010-06-15 17:06:23 +00:00
if ( found ) {
manager_event ( EVENT_FLAG_USER , " JabberStatus " ,
2010-02-18 16:34:08 +00:00
" Account: %s \r \n JID: %s \r \n Resource: %s \r \n Status: %d \r \n Priority: %d "
" \r \n Description: %s \r \n " ,
client - > name , pak - > from - > partial , found - > resource , found - > status ,
2011-03-18 16:24:19 +00:00
found - > priority , S_OR ( found - > description , " " ) ) ;
2010-06-15 17:06:23 +00:00
} else {
manager_event ( EVENT_FLAG_USER , " JabberStatus " ,
2014-05-09 22:49:26 +00:00
" Account: %s \r \n JID: %s \r \n Status: %u \r \n " ,
2010-06-15 17:06:23 +00:00
client - > name , pak - > from - > partial , pak - > show ? pak - > show : IKS_SHOW_UNAVAILABLE ) ;
}
2007-10-07 15:56:22 +00:00
}
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief handles subscription requests .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ param pak ikspak iksemel packet .
2006-05-22 21:12:30 +00:00
* \ return void .
*/
static void aji_handle_subscribe ( struct aji_client * client , ikspak * pak )
{
2008-02-29 13:12:34 +00:00
iks * presence = NULL , * status = NULL ;
struct aji_buddy * buddy = NULL ;
2010-06-15 17:06:23 +00:00
switch ( pak - > subtype ) {
2008-02-29 13:12:34 +00:00
case IKS_TYPE_SUBSCRIBE :
2009-12-16 20:25:27 +00:00
if ( ast_test_flag ( & client - > flags , AJI_AUTOACCEPT ) ) {
presence = iks_new ( " presence " ) ;
status = iks_new ( " status " ) ;
if ( presence & & status ) {
iks_insert_attrib ( presence , " type " , " subscribed " ) ;
iks_insert_attrib ( presence , " to " , pak - > from - > full ) ;
iks_insert_attrib ( presence , " from " , client - > jid - > full ) ;
if ( pak - > id )
iks_insert_attrib ( presence , " id " , pak - > id ) ;
iks_insert_cdata ( status , " Asterisk has approved subscription " , 0 ) ;
iks_insert_node ( presence , status ) ;
ast_aji_send ( client , presence ) ;
2010-06-15 17:06:23 +00:00
} else {
2009-12-16 20:25:27 +00:00
ast_log ( LOG_ERROR , " Unable to allocate nodes \n " ) ;
2010-06-15 17:06:23 +00:00
}
2008-02-29 14:15:03 +00:00
2009-12-16 20:25:27 +00:00
iks_delete ( presence ) ;
iks_delete ( status ) ;
}
2008-02-29 14:15:03 +00:00
2007-10-04 16:56:00 +00:00
if ( client - > component )
2007-10-07 16:28:25 +00:00
aji_set_presence ( client , pak - > from - > full , iks_find_attrib ( pak - > x , " to " ) , client - > status , client - > statusmessage ) ;
2007-10-04 16:56:00 +00:00
case IKS_TYPE_SUBSCRIBED :
2008-02-29 13:12:34 +00:00
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , pak - > from - > partial ) ;
if ( ! buddy & & pak - > from - > partial ) {
aji_create_buddy ( pak - > from - > partial , client ) ;
2011-11-23 17:16:33 +00:00
} else if ( buddy ) {
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
2008-02-29 13:12:34 +00:00
}
default :
2014-05-28 22:54:12 +00:00
ast_debug ( 3 , " JABBER: This is a subcription of type %i \n " , pak - > subtype ) ;
2006-05-22 21:12:30 +00:00
}
2007-10-04 16:56:00 +00:00
}
2006-05-22 21:12:30 +00:00
/*!
* \ brief sends messages .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ param address
* \ param message
2009-09-25 10:54:42 +00:00
* \ retval IKS_OK success
* \ retval - 1 failure
2006-05-22 21:12:30 +00:00
*/
2007-11-06 18:44:19 +00:00
int ast_aji_send_chat ( struct aji_client * client , const char * address , const char * message )
2009-12-07 17:59:46 +00:00
{
return aji_send_raw_chat ( client , 0 , NULL , address , message ) ;
}
/*!
* \ brief sends message to a groupchat
* Prior to sending messages to a groupchat , one must be connected to it .
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param nick the nickname we use in the chatroom
* \ param address the user the messages must be sent to
* \ param message the message to send
* \ return IKS_OK on success , any other value on failure
*/
int ast_aji_send_groupchat ( struct aji_client * client , const char * nick , const char * address , const char * message ) {
return aji_send_raw_chat ( client , 1 , nick , address , message ) ;
}
/*!
* \ brief sends messages .
* \ param client the configured XMPP client we use to connect to a XMPP server
2010-06-08 14:38:18 +00:00
* \ param groupchat
2009-12-07 17:59:46 +00:00
* \ param nick the nickname we use in chatrooms
* \ param address
* \ param message
* \ return IKS_OK on success , any other value on failure
*/
static int aji_send_raw_chat ( struct aji_client * client , int groupchat , const char * nick , const char * address , const char * message )
2006-05-22 21:12:30 +00:00
{
int res = 0 ;
iks * message_packet = NULL ;
2009-12-07 17:59:46 +00:00
char from [ AJI_MAX_JIDLEN ] ;
/* the nickname is used only in component mode */
if ( nick & & client - > component ) {
snprintf ( from , AJI_MAX_JIDLEN , " %s@%s/%s " , nick , client - > jid - > full , nick ) ;
} else {
snprintf ( from , AJI_MAX_JIDLEN , " %s " , client - > jid - > full ) ;
}
2010-06-15 17:06:23 +00:00
2009-09-25 10:54:42 +00:00
if ( client - > state ! = AJI_CONNECTED ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_WARNING , " JABBER: Not connected can't send \n " ) ;
2009-09-25 10:54:42 +00:00
return - 1 ;
2010-06-15 17:06:23 +00:00
}
2009-12-07 17:59:46 +00:00
message_packet = iks_make_msg ( groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT , address , message ) ;
2009-09-25 10:54:42 +00:00
if ( ! message_packet ) {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
return - 1 ;
}
2009-12-07 17:59:46 +00:00
iks_insert_attrib ( message_packet , " from " , from ) ;
2009-09-25 10:54:42 +00:00
res = ast_aji_send ( client , message_packet ) ;
iks_delete ( message_packet ) ;
2010-06-15 17:06:23 +00:00
2009-09-25 10:54:42 +00:00
return res ;
2006-05-22 21:12:30 +00:00
}
/*!
* \ brief create a chatroom .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ param room name of room
* \ param server name of server
* \ param topic topic for the room .
2006-05-22 21:12:30 +00:00
* \ return 0.
*/
int ast_aji_create_chat ( struct aji_client * client , char * room , char * server , char * topic )
{
int res = 0 ;
iks * iq = NULL ;
iq = iks_new ( " iq " ) ;
2008-02-29 14:50:40 +00:00
2006-05-22 21:12:30 +00:00
if ( iq & & client ) {
iks_insert_attrib ( iq , " type " , " get " ) ;
iks_insert_attrib ( iq , " to " , server ) ;
iks_insert_attrib ( iq , " id " , client - > mid ) ;
ast_aji_increment_mid ( client - > mid ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , iq ) ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2008-02-29 14:50:40 +00:00
iks_delete ( iq ) ;
2006-05-22 21:12:30 +00:00
return res ;
}
/*!
* \ brief join a chatroom .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ param room room to join
2009-12-07 17:59:46 +00:00
* \ param nick the nickname to use in this room
* \ return IKS_OK on success , any other value on failure .
2006-05-22 21:12:30 +00:00
*/
2009-12-07 17:59:46 +00:00
int ast_aji_join_chat ( struct aji_client * client , char * room , char * nick )
2006-05-22 21:12:30 +00:00
{
2009-12-07 17:59:46 +00:00
return aji_set_group_presence ( client , room , IKS_SHOW_AVAILABLE , nick , NULL ) ;
2006-05-22 21:12:30 +00:00
}
2009-12-07 17:59:46 +00:00
/*!
* \ brief leave a chatroom .
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param room room to leave
* \ param nick the nickname used in this room
* \ return IKS_OK on success , any other value on failure .
*/
int ast_aji_leave_chat ( struct aji_client * client , char * room , char * nick )
{
return aji_set_group_presence ( client , room , IKS_SHOW_UNAVAILABLE , nick , NULL ) ;
}
2006-05-22 21:12:30 +00:00
/*!
* \ brief invite to a chatroom .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2010-06-15 17:06:23 +00:00
* \ param user
2007-06-07 21:22:25 +00:00
* \ param room
* \ param message
2006-05-22 21:12:30 +00:00
* \ return res .
*/
int ast_aji_invite_chat ( struct aji_client * client , char * user , char * room , char * message )
{
int res = 0 ;
2006-08-07 21:15:28 +00:00
iks * invite , * body , * namespace ;
2006-05-22 21:12:30 +00:00
invite = iks_new ( " message " ) ;
body = iks_new ( " body " ) ;
namespace = iks_new ( " x " ) ;
if ( client & & invite & & body & & namespace ) {
iks_insert_attrib ( invite , " to " , user ) ;
iks_insert_attrib ( invite , " id " , client - > mid ) ;
ast_aji_increment_mid ( client - > mid ) ;
2006-09-21 23:55:13 +00:00
iks_insert_cdata ( body , message , 0 ) ;
2006-05-22 21:12:30 +00:00
iks_insert_attrib ( namespace , " xmlns " , " jabber:x:conference " ) ;
iks_insert_attrib ( namespace , " jid " , room ) ;
iks_insert_node ( invite , body ) ;
iks_insert_node ( invite , namespace ) ;
2007-11-06 18:44:19 +00:00
res = ast_aji_send ( client , invite ) ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2008-02-29 14:15:03 +00:00
iks_delete ( body ) ;
iks_delete ( namespace ) ;
iks_delete ( invite ) ;
2010-06-15 17:06:23 +00:00
2006-05-22 21:12:30 +00:00
return res ;
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief receive message loop .
2007-06-07 21:22:25 +00:00
* \ param data void
2006-05-22 21:12:30 +00:00
* \ return void .
*/
static void * aji_recv_loop ( void * data )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2006-05-23 20:25:23 +00:00
int res = IKS_HOOK ;
2007-11-01 22:10:33 +00:00
2010-06-15 17:06:23 +00:00
while ( res ! = IKS_OK ) {
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: Connecting. \n " ) ;
2007-11-01 22:10:33 +00:00
res = aji_reconnect ( client ) ;
sleep ( 4 ) ;
}
2006-05-23 20:25:23 +00:00
do {
2007-11-01 22:10:33 +00:00
if ( res = = IKS_NET_RWERR | | client - > timeout = = 0 ) {
2010-06-15 17:06:23 +00:00
while ( res ! = IKS_OK ) {
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: reconnecting. \n " ) ;
2006-05-23 20:25:23 +00:00
res = aji_reconnect ( client ) ;
2006-05-23 21:18:07 +00:00
sleep ( 4 ) ;
2006-05-23 20:25:23 +00:00
}
}
2006-06-07 22:43:20 +00:00
2007-11-01 22:10:33 +00:00
res = aji_recv ( client , 1 ) ;
2010-06-15 17:06:23 +00:00
2007-06-07 09:21:29 +00:00
if ( client - > state = = AJI_DISCONNECTING ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 2 , " Ending our Jabber client's thread due to a disconnect \n " ) ;
2007-06-07 09:21:29 +00:00
pthread_exit ( NULL ) ;
}
2007-11-01 22:10:33 +00:00
2009-09-25 10:54:42 +00:00
/* Decrease timeout if no data received, and delete
* old messages globally */
if ( res = = IKS_NET_EXPIRED ) {
2007-11-01 22:10:33 +00:00
client - > timeout - - ;
2009-09-25 10:54:42 +00:00
delete_old_messages_all ( client ) ;
}
if ( res = = IKS_HOOK ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_WARNING , " JABBER: Got hook event. \n " ) ;
2009-09-25 10:54:42 +00:00
} else if ( res = = IKS_NET_TLSFAIL ) {
2008-08-06 13:34:08 +00:00
ast_log ( LOG_ERROR , " JABBER: Failure in TLS. \n " ) ;
2009-09-25 10:54:42 +00:00
} else if ( client - > timeout = = 0 & & client - > state = = AJI_CONNECTED ) {
2008-04-17 13:46:17 +00:00
res = client - > keepalive ? aji_send_raw ( client , " " ) : IKS_OK ;
2009-09-25 10:54:42 +00:00
if ( res = = IKS_OK ) {
2006-09-19 23:57:04 +00:00
client - > timeout = 50 ;
2009-09-25 10:54:42 +00:00
} else {
2006-09-19 23:57:04 +00:00
ast_log ( LOG_WARNING , " JABBER: Network Timeout \n " ) ;
2009-09-25 10:54:42 +00:00
}
} else if ( res = = IKS_NET_RWERR ) {
2006-05-23 20:25:23 +00:00
ast_log ( LOG_WARNING , " JABBER: socket read error \n " ) ;
2009-09-25 10:54:42 +00:00
}
2006-05-23 21:18:07 +00:00
} while ( client ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return 0 ;
}
/*!
* \ brief increments the mid field for messages and other events .
2007-06-07 21:22:25 +00:00
* \ param mid char .
2006-05-22 21:12:30 +00:00
* \ return void .
*/
void ast_aji_increment_mid ( char * mid )
{
int i = 0 ;
2006-08-07 21:15:28 +00:00
2006-05-22 21:12:30 +00:00
for ( i = strlen ( mid ) - 1 ; i > = 0 ; i - - ) {
if ( mid [ i ] ! = ' z ' ) {
mid [ i ] = mid [ i ] + 1 ;
i = 0 ;
} else
mid [ i ] = ' a ' ;
}
}
2007-10-04 16:56:00 +00:00
#if 0
2006-05-22 21:12:30 +00:00
/*!
* \ brief attempts to register to a transport .
* \ param aji_client struct , and xml packet .
* \ return IKS_FILTER_EAT .
*/
2006-10-03 00:07:45 +00:00
/*allows for registering to transport , was too sketch and is out for now. */
2007-10-04 16:56:00 +00:00
static int aji_register_transport ( void * data , ikspak * pak )
2006-05-22 21:12:30 +00:00
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
int res = 0 ;
struct aji_buddy * buddy = NULL ;
2006-08-07 21:15:28 +00:00
iks * send = iks_make_iq ( IKS_TYPE_GET , " jabber:iq:register " ) ;
2006-05-22 21:12:30 +00:00
if ( client & & send ) {
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
if ( iterator - > btype = = AJI_TRANS ) {
buddy = iterator ;
}
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
iks_filter_remove_hook ( client - > f , aji_register_transport ) ;
iks_filter_add_rule ( client - > f , aji_register_transport2 , client , IKS_RULE_TYPE , IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_RESULT , IKS_RULE_NS , IKS_NS_REGISTER , IKS_RULE_DONE ) ;
iks_insert_attrib ( send , " to " , buddy - > host ) ;
iks_insert_attrib ( send , " id " , client - > mid ) ;
ast_aji_increment_mid ( client - > mid ) ;
iks_insert_attrib ( send , " from " , client - > user ) ;
2007-11-06 18:44:19 +00:00
res = ast_aji_send ( client , send ) ;
2006-08-07 21:15:28 +00:00
} else
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2006-08-07 21:15:28 +00:00
2006-05-22 21:12:30 +00:00
if ( send )
iks_delete ( send ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
/*!
* \ brief attempts to register to a transport step 2.
* \ param aji_client struct , and xml packet .
* \ return IKS_FILTER_EAT .
*/
2006-10-03 00:07:45 +00:00
/* more of the same blob of code, too wonky for now*/
2007-10-04 16:56:00 +00:00
static int aji_register_transport2 ( void * data , ikspak * pak )
2006-05-22 21:12:30 +00:00
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
int res = 0 ;
struct aji_buddy * buddy = NULL ;
2006-08-07 21:15:28 +00:00
iks * regiq = iks_new ( " iq " ) ;
iks * regquery = iks_new ( " query " ) ;
iks * reguser = iks_new ( " username " ) ;
iks * regpass = iks_new ( " password " ) ;
2006-05-22 21:12:30 +00:00
if ( client & & regquery & & reguser & & regpass & & regiq ) {
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
if ( iterator - > btype = = AJI_TRANS )
buddy = iterator ; ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
iks_filter_remove_hook ( client - > f , aji_register_transport2 ) ;
iks_insert_attrib ( regiq , " to " , buddy - > host ) ;
iks_insert_attrib ( regiq , " type " , " set " ) ;
iks_insert_attrib ( regiq , " id " , client - > mid ) ;
ast_aji_increment_mid ( client - > mid ) ;
iks_insert_attrib ( regiq , " from " , client - > user ) ;
iks_insert_attrib ( regquery , " xmlns " , " jabber:iq:register " ) ;
2006-09-21 23:55:13 +00:00
iks_insert_cdata ( reguser , buddy - > user , 0 ) ;
iks_insert_cdata ( regpass , buddy - > pass , 0 ) ;
2006-05-22 21:12:30 +00:00
iks_insert_node ( regiq , regquery ) ;
iks_insert_node ( regquery , reguser ) ;
iks_insert_node ( regquery , regpass ) ;
2007-11-06 18:44:19 +00:00
res = ast_aji_send ( client , regiq ) ;
2006-08-07 21:15:28 +00:00
} else
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
if ( regiq )
iks_delete ( regiq ) ;
if ( regquery )
iks_delete ( regquery ) ;
if ( reguser )
iks_delete ( reguser ) ;
if ( regpass )
iks_delete ( regpass ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
2007-10-04 16:56:00 +00:00
# endif
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief goes through roster and prunes users not needed in list , or adds them accordingly .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2006-05-22 21:12:30 +00:00
* \ return void .
2008-08-06 13:34:08 +00:00
* \ note The messages here should be configurable .
2006-05-22 21:12:30 +00:00
*/
static void aji_pruneregister ( struct aji_client * client )
{
2006-08-07 21:15:28 +00:00
iks * removeiq = iks_new ( " iq " ) ;
iks * removequery = iks_new ( " query " ) ;
iks * removeitem = iks_new ( " item " ) ;
iks * send = iks_make_iq ( IKS_TYPE_GET , " http://jabber.org/protocol/disco#items " ) ;
2008-06-24 17:28:39 +00:00
if ( ! client | | ! removeiq | | ! removequery | | ! removeitem | | ! send ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2008-06-24 17:28:39 +00:00
goto safeout ;
}
iks_insert_node ( removeiq , removequery ) ;
iks_insert_node ( removequery , removeitem ) ;
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
/* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
* be called at the same time */
2008-09-09 22:08:56 +00:00
if ( ast_test_flag ( & iterator - > flags , AJI_AUTOPRUNE ) ) { /* If autoprune is set on jabber.conf */
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , iks_make_s10n ( IKS_TYPE_UNSUBSCRIBE , iterator - > name ,
2008-08-06 13:34:08 +00:00
" GoodBye. Your status is no longer needed by Asterisk the Open Source PBX "
2008-06-24 17:28:39 +00:00
" so I am no longer subscribing to your presence. \n " ) ) ;
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , iks_make_s10n ( IKS_TYPE_UNSUBSCRIBED , iterator - > name ,
2008-08-06 13:34:08 +00:00
" GoodBye. You are no longer in the Asterisk config file so I am removing "
2008-06-24 17:28:39 +00:00
" your access to my presence. \n " ) ) ;
2010-06-15 17:06:23 +00:00
iks_insert_attrib ( removeiq , " from " , client - > jid - > full ) ;
iks_insert_attrib ( removeiq , " type " , " set " ) ;
2008-06-24 17:28:39 +00:00
iks_insert_attrib ( removequery , " xmlns " , " jabber:iq:roster " ) ;
iks_insert_attrib ( removeitem , " jid " , iterator - > name ) ;
iks_insert_attrib ( removeitem , " subscription " , " remove " ) ;
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , removeiq ) ;
2008-06-24 17:28:39 +00:00
} else if ( ast_test_flag ( & iterator - > flags , AJI_AUTOREGISTER ) ) {
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , iks_make_s10n ( IKS_TYPE_SUBSCRIBE , iterator - > name ,
2008-08-06 13:34:08 +00:00
" Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence \n " ) ) ;
2008-06-24 17:28:39 +00:00
ast_clear_flag ( & iterator - > flags , AJI_AUTOREGISTER ) ;
}
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
2008-02-29 14:15:03 +00:00
2008-06-24 17:28:39 +00:00
safeout :
2008-02-29 14:15:03 +00:00
iks_delete ( removeiq ) ;
iks_delete ( removequery ) ;
iks_delete ( removeitem ) ;
iks_delete ( send ) ;
2010-06-15 17:06:23 +00:00
2011-11-23 17:16:33 +00:00
ASTOBJ_CONTAINER_PRUNE_MARKED ( & client - > buddies , ast_aji_buddy_destroy ) ;
2006-05-22 21:12:30 +00:00
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief filters the roster packet we get back from server .
2007-06-07 21:22:25 +00:00
* \ param data void
* \ param pak ikspak iksemel packet .
2006-05-22 21:12:30 +00:00
* \ return IKS_FILTER_EAT .
*/
static int aji_filter_roster ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
int flag = 0 ;
iks * x = NULL ;
struct aji_buddy * buddy ;
2010-06-15 17:06:23 +00:00
2006-06-06 18:51:37 +00:00
client - > state = AJI_CONNECTED ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
x = iks_child ( pak - > query ) ;
flag = 0 ;
while ( x ) {
if ( ! iks_strcmp ( iks_name ( x ) , " item " ) ) {
2006-10-03 00:07:45 +00:00
if ( ! strcasecmp ( iterator - > name , iks_find_attrib ( x , " jid " ) ) ) {
flag = 1 ;
2008-02-12 14:08:58 +00:00
ast_clear_flag ( & iterator - > flags , AJI_AUTOPRUNE | AJI_AUTOREGISTER ) ;
2006-05-22 21:12:30 +00:00
}
}
x = iks_next ( x ) ;
}
2010-06-15 17:06:23 +00:00
if ( ! flag ) {
2008-02-12 14:08:58 +00:00
ast_copy_flags ( & iterator - > flags , & client - > flags , AJI_AUTOREGISTER ) ;
2010-06-15 17:06:23 +00:00
}
2008-02-29 14:15:03 +00:00
iks_delete ( x ) ;
2010-06-15 17:06:23 +00:00
2006-05-22 21:12:30 +00:00
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
x = iks_child ( pak - > query ) ;
while ( x ) {
flag = 0 ;
if ( iks_strcmp ( iks_name ( x ) , " item " ) = = 0 ) {
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
2006-10-03 00:07:45 +00:00
if ( ! strcasecmp ( iterator - > name , iks_find_attrib ( x , " jid " ) ) )
2006-05-22 21:12:30 +00:00
flag = 1 ;
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
2008-06-24 17:50:22 +00:00
if ( flag ) {
/* found buddy, don't create a new one */
x = iks_next ( x ) ;
continue ;
}
2010-06-15 17:06:23 +00:00
2008-06-24 17:50:22 +00:00
buddy = ast_calloc ( 1 , sizeof ( * buddy ) ) ;
if ( ! buddy ) {
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2008-06-24 17:50:22 +00:00
return 0 ;
}
ASTOBJ_INIT ( buddy ) ;
ASTOBJ_WRLOCK ( buddy ) ;
ast_copy_string ( buddy - > name , iks_find_attrib ( x , " jid " ) , sizeof ( buddy - > name ) ) ;
ast_clear_flag ( & buddy - > flags , AST_FLAGS_ALL ) ;
2009-09-25 10:54:42 +00:00
if ( ast_test_flag ( & client - > flags , AJI_AUTOPRUNE ) ) {
2008-06-24 17:50:22 +00:00
ast_set_flag ( & buddy - > flags , AJI_AUTOPRUNE ) ;
ASTOBJ_MARK ( buddy ) ;
2011-08-26 16:38:37 +00:00
} else if ( ast_test_flag ( & client - > flags , AJI_AUTOREGISTER ) ) {
if ( ! iks_strcmp ( iks_find_attrib ( x , " subscription " ) , " none " ) | | ! iks_strcmp ( iks_find_attrib ( x , " subscription " ) , " from " ) ) {
/* subscribe to buddy's presence only
if we really need to */
ast_set_flag ( & buddy - > flags , AJI_AUTOREGISTER ) ;
}
2008-06-24 17:50:22 +00:00
}
ASTOBJ_UNLOCK ( buddy ) ;
if ( buddy ) {
ASTOBJ_CONTAINER_LINK ( & client - > buddies , buddy ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
2006-05-22 21:12:30 +00:00
}
}
x = iks_next ( x ) ;
}
2008-02-29 14:15:03 +00:00
iks_delete ( x ) ;
2006-05-22 21:12:30 +00:00
aji_pruneregister ( client ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return IKS_FILTER_EAT ;
}
2008-08-06 13:34:08 +00:00
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief reconnect to jabber server
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ return res .
*/
2006-05-22 21:12:30 +00:00
static int aji_reconnect ( struct aji_client * client )
{
int res = 0 ;
2010-06-15 17:06:23 +00:00
if ( client - > state ) {
2006-05-22 21:12:30 +00:00
client - > state = AJI_DISCONNECTED ;
2010-06-15 17:06:23 +00:00
}
client - > timeout = 50 ;
if ( client - > p ) {
2006-05-22 21:12:30 +00:00
iks_parser_reset ( client - > p ) ;
2010-06-15 17:06:23 +00:00
}
if ( client - > authorized ) {
2006-05-22 21:12:30 +00:00
client - > authorized = 0 ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
2007-06-07 08:45:19 +00:00
res = aji_initialize ( client ) ;
2006-09-21 23:55:13 +00:00
2006-05-22 21:12:30 +00:00
return res ;
}
2008-08-06 13:34:08 +00:00
2007-06-07 21:22:25 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-06-07 21:22:25 +00:00
* \ brief Get the roster of jabber users
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ return 1.
*/
2006-05-22 21:12:30 +00:00
static int aji_get_roster ( struct aji_client * client )
{
iks * roster = NULL ;
roster = iks_make_iq ( IKS_TYPE_GET , IKS_NS_ROSTER ) ;
2008-02-29 14:15:03 +00:00
2009-09-25 10:54:42 +00:00
if ( roster ) {
2006-05-22 21:12:30 +00:00
iks_insert_attrib ( roster , " id " , " roster " ) ;
2007-10-07 16:28:25 +00:00
aji_set_presence ( client , NULL , client - > jid - > full , client - > status , client - > statusmessage ) ;
2007-11-06 18:44:19 +00:00
ast_aji_send ( client , roster ) ;
2006-05-22 21:12:30 +00:00
}
2008-02-29 14:15:03 +00:00
iks_delete ( roster ) ;
2010-06-15 17:06:23 +00:00
2006-05-22 21:12:30 +00:00
return 1 ;
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief connects as a client to jabber server .
2007-06-07 21:22:25 +00:00
* \ param data void
* \ param pak ikspak iksemel packet
2006-05-22 21:12:30 +00:00
* \ return res .
*/
static int aji_client_connect ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2010-10-05 20:24:37 +00:00
int res = IKS_FILTER_PASS ;
2006-08-07 21:15:28 +00:00
2006-05-22 21:12:30 +00:00
if ( client ) {
if ( client - > state = = AJI_DISCONNECTED ) {
iks_filter_add_rule ( client - > f , aji_filter_roster , client , IKS_RULE_TYPE , IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_RESULT , IKS_RULE_ID , " roster " , IKS_RULE_DONE ) ;
2006-06-06 18:51:37 +00:00
client - > state = AJI_CONNECTING ;
2006-05-22 21:12:30 +00:00
client - > jid = ( iks_find_cdata ( pak - > query , " jid " ) ) ? iks_id_new ( client - > stack , iks_find_cdata ( pak - > query , " jid " ) ) : client - > jid ;
2010-06-15 17:06:23 +00:00
if ( ! client - > component ) { /*client*/
2006-05-22 21:12:30 +00:00
aji_get_roster ( client ) ;
2010-06-15 17:06:23 +00:00
}
2010-10-05 20:24:37 +00:00
if ( client - > distribute_events ) {
aji_init_event_distribution ( client ) ;
}
iks_filter_remove_hook ( client - > f , aji_client_connect ) ;
/* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */
res = IKS_FILTER_EAT ;
2006-05-22 21:12:30 +00:00
}
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
return res ;
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief prepares client for connect .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2006-05-22 21:12:30 +00:00
* \ return 1.
*/
2007-06-07 08:45:19 +00:00
static int aji_initialize ( struct aji_client * client )
2006-05-22 21:12:30 +00:00
{
2008-01-02 11:34:26 +00:00
int connected = IKS_NET_NOCONN ;
2008-06-27 07:28:17 +00:00
2010-06-15 17:06:23 +00:00
# ifdef HAVE_OPENSSL
2008-01-02 11:34:26 +00:00
/* reset stream flags */
client - > stream_flags = 0 ;
2008-06-27 07:28:17 +00:00
# endif
2007-06-07 08:45:19 +00:00
/* If it's a component, connect to user, otherwise, connect to server */
2008-01-02 11:34:26 +00:00
connected = iks_connect_via ( client - > p , S_OR ( client - > serverhost , client - > jid - > server ) , client - > port , client - > component ? client - > user : client - > jid - > server ) ;
2006-05-22 21:12:30 +00:00
if ( connected = = IKS_NET_NOCONN ) {
ast_log ( LOG_ERROR , " JABBER ERROR: No Connection \n " ) ;
2006-05-23 20:25:23 +00:00
return IKS_HOOK ;
2010-06-15 17:06:23 +00:00
} else if ( connected = = IKS_NET_NODNS ) {
ast_log ( LOG_ERROR , " JABBER ERROR: No DNS %s for client to %s \n " , client - > name ,
S_OR ( client - > serverhost , client - > jid - > server ) ) ;
2006-05-23 20:25:23 +00:00
return IKS_HOOK ;
2007-11-01 22:10:33 +00:00
}
2006-09-19 23:57:04 +00:00
return IKS_OK ;
2006-05-22 21:12:30 +00:00
}
/*!
* \ brief disconnect from jabber server .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2006-05-22 21:12:30 +00:00
* \ return 1.
*/
int ast_aji_disconnect ( struct aji_client * client )
{
if ( client ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 4 , " JABBER: Disconnecting \n " ) ;
2007-11-01 22:10:33 +00:00
# ifdef HAVE_OPENSSL
if ( client - > stream_flags & SECURE ) {
SSL_shutdown ( client - > ssl_session ) ;
SSL_CTX_free ( client - > ssl_context ) ;
SSL_free ( client - > ssl_session ) ;
}
# endif
2006-05-22 21:12:30 +00:00
iks_disconnect ( client - > p ) ;
iks_parser_delete ( client - > p ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
}
return 1 ;
}
2010-06-15 17:06:23 +00:00
/*!
* \ brief Callback function for MWI events
* \ param ast_event
* \ param data void pointer to ast_client structure
* \ return void
*/
Multiple revisions 399887,400138,400178,400180-400181
........
r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line
Minor performance bump by not allocate manager variable struct if we don't need it
........
r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines
Stasis performance improvements
This patch addresses several performance problems that were found in
the initial performance testing of Asterisk 12.
The Stasis dispatch object was allocated as an AO2 object, even though
it has a very confined lifecycle. This was replaced with a straight
ast_malloc().
The Stasis message router was spending an inordinate amount of time
searching hash tables. In this case, most of our routers had 6 or
fewer routes in them to begin with. This was replaced with an array
that's searched linearly for the route.
We more heavily rely on AO2 objects in Asterisk 12, and the memset()
in ao2_ref() actually became noticeable on the profile. This was
#ifdef'ed to only run when AO2_DEBUG was enabled.
After being misled by an erroneous comment in taskprocessor.c during
profiling, the wrong comment was removed.
Review: https://reviewboard.asterisk.org/r/2873/
........
r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines
Taskprocessor optimization; switch Stasis to use taskprocessors
This patch optimizes taskprocessor to use a semaphore for signaling,
which the OS can do a better job at managing contention and waiting
that we can with a mutex and condition.
The taskprocessor execution was also slightly optimized to reduce the
number of locks taken.
The only observable difference in the taskprocessor implementation is
that when the final reference to the taskprocessor goes away, it will
execute all tasks to completion instead of discarding the unexecuted
tasks.
For systems where unnamed semaphores are not supported, a really
simple semaphore implementation is provided. (Which gives identical
performance as the original taskprocessor implementation).
The way we ended up implementing Stasis caused the threadpool to be a
burden instead of a boost to performance. This was switched to just
use taskprocessors directly for subscriptions.
Review: https://reviewboard.asterisk.org/r/2881/
........
r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines
Optimize how Stasis forwards are dispatched
This patch optimizes how forwards are dispatched in Stasis.
Originally, forwards were dispatched as subscriptions that are invoked
on the publishing thread. This did not account for the vast number of
forwards we would end up having in the system, and the amount of work it
would take to walk though the forward subscriptions.
This patch modifies Stasis so that rather than walking the tree of
forwards on every dispatch, when forwards and subscriptions are changed,
the subscriber list for every topic in the tree is changed.
This has a couple of benefits. First, this reduces the workload of
dispatching messages. It also reduces contention when dispatching to
different topics that happen to forward to the same aggregation topic
(as happens with all of the channel, bridge and endpoint topics).
Since forwards are no longer subscriptions, the bulk of this patch is
simply changing stasis_subscription objects to stasis_forward objects
(which, admittedly, I should have done in the first place.)
Since this required me to yet again put in a growing array, I finally
abstracted that out into a set of ast_vector macros in
asterisk/vector.h.
Review: https://reviewboard.asterisk.org/r/2883/
........
r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines
Remove dispatch object allocation from Stasis publishing
While looking for areas for performance improvement, I realized that an
unused feature in Stasis was negatively impacting performance.
When a message is sent to a subscriber, a dispatch object is allocated
for the dispatch, containing the topic the message was published to, the
subscriber the message is being sent to, and the message itself.
The topic is actually unused by any subscriber in Asterisk today. And
the subscriber is associated with the taskprocessor the message is being
dispatched to.
First, this patch removes the unused topic parameter from Stasis
subscription callbacks.
Second, this patch introduces the concept of taskprocessor local data,
data that may be set on a taskprocessor and provided along with the data
pointer when a task is pushed using the ast_taskprocessor_push_local()
call. This allows the task to have both data specific to that
taskprocessor, in addition to data specific to that invocation.
With those two changes, the dispatch object can be removed completely,
and the message is simply refcounted and sent directly to the
taskprocessor.
Review: https://reviewboard.asterisk.org/r/2884/
........
Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
static void aji_mwi_cb ( void * data , struct stasis_subscription * sub , struct stasis_message * msg )
2010-06-15 17:06:23 +00:00
{
char oldmsgs [ 10 ] ;
char newmsgs [ 10 ] ;
2013-03-16 15:45:58 +00:00
struct aji_client * client = data ;
2013-05-24 20:44:07 +00:00
struct ast_mwi_state * mwi_state ;
2013-03-16 15:45:58 +00:00
2013-05-24 20:44:07 +00:00
if ( ! stasis_subscription_is_subscribed ( sub ) | | ast_mwi_state_type ( ) ! = stasis_message_type ( msg ) ) {
2013-03-16 15:45:58 +00:00
return ;
}
mwi_state = stasis_message_data ( msg ) ;
if ( ast_eid_cmp ( & ast_eid_default , & mwi_state - > eid ) ) {
2010-06-15 17:06:23 +00:00
/* If the event didn't originate from this server, don't send it back out. */
return ;
}
2013-12-19 16:52:43 +00:00
snprintf ( oldmsgs , sizeof ( oldmsgs ) , " %d " , mwi_state - > old_msgs ) ;
snprintf ( newmsgs , sizeof ( newmsgs ) , " %d " , mwi_state - > new_msgs ) ;
aji_publish_mwi ( client , mwi_state - > uniqueid , oldmsgs , newmsgs ) ;
2010-06-15 17:06:23 +00:00
}
/*!
* \ brief Callback function for device state events
* \ param ast_event
* \ param data void pointer to ast_client structure
* \ return void
*/
Multiple revisions 399887,400138,400178,400180-400181
........
r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line
Minor performance bump by not allocate manager variable struct if we don't need it
........
r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines
Stasis performance improvements
This patch addresses several performance problems that were found in
the initial performance testing of Asterisk 12.
The Stasis dispatch object was allocated as an AO2 object, even though
it has a very confined lifecycle. This was replaced with a straight
ast_malloc().
The Stasis message router was spending an inordinate amount of time
searching hash tables. In this case, most of our routers had 6 or
fewer routes in them to begin with. This was replaced with an array
that's searched linearly for the route.
We more heavily rely on AO2 objects in Asterisk 12, and the memset()
in ao2_ref() actually became noticeable on the profile. This was
#ifdef'ed to only run when AO2_DEBUG was enabled.
After being misled by an erroneous comment in taskprocessor.c during
profiling, the wrong comment was removed.
Review: https://reviewboard.asterisk.org/r/2873/
........
r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines
Taskprocessor optimization; switch Stasis to use taskprocessors
This patch optimizes taskprocessor to use a semaphore for signaling,
which the OS can do a better job at managing contention and waiting
that we can with a mutex and condition.
The taskprocessor execution was also slightly optimized to reduce the
number of locks taken.
The only observable difference in the taskprocessor implementation is
that when the final reference to the taskprocessor goes away, it will
execute all tasks to completion instead of discarding the unexecuted
tasks.
For systems where unnamed semaphores are not supported, a really
simple semaphore implementation is provided. (Which gives identical
performance as the original taskprocessor implementation).
The way we ended up implementing Stasis caused the threadpool to be a
burden instead of a boost to performance. This was switched to just
use taskprocessors directly for subscriptions.
Review: https://reviewboard.asterisk.org/r/2881/
........
r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines
Optimize how Stasis forwards are dispatched
This patch optimizes how forwards are dispatched in Stasis.
Originally, forwards were dispatched as subscriptions that are invoked
on the publishing thread. This did not account for the vast number of
forwards we would end up having in the system, and the amount of work it
would take to walk though the forward subscriptions.
This patch modifies Stasis so that rather than walking the tree of
forwards on every dispatch, when forwards and subscriptions are changed,
the subscriber list for every topic in the tree is changed.
This has a couple of benefits. First, this reduces the workload of
dispatching messages. It also reduces contention when dispatching to
different topics that happen to forward to the same aggregation topic
(as happens with all of the channel, bridge and endpoint topics).
Since forwards are no longer subscriptions, the bulk of this patch is
simply changing stasis_subscription objects to stasis_forward objects
(which, admittedly, I should have done in the first place.)
Since this required me to yet again put in a growing array, I finally
abstracted that out into a set of ast_vector macros in
asterisk/vector.h.
Review: https://reviewboard.asterisk.org/r/2883/
........
r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines
Remove dispatch object allocation from Stasis publishing
While looking for areas for performance improvement, I realized that an
unused feature in Stasis was negatively impacting performance.
When a message is sent to a subscriber, a dispatch object is allocated
for the dispatch, containing the topic the message was published to, the
subscriber the message is being sent to, and the message itself.
The topic is actually unused by any subscriber in Asterisk today. And
the subscriber is associated with the taskprocessor the message is being
dispatched to.
First, this patch removes the unused topic parameter from Stasis
subscription callbacks.
Second, this patch introduces the concept of taskprocessor local data,
data that may be set on a taskprocessor and provided along with the data
pointer when a task is pushed using the ast_taskprocessor_push_local()
call. This allows the task to have both data specific to that
taskprocessor, in addition to data specific to that invocation.
With those two changes, the dispatch object can be removed completely,
and the message is simply refcounted and sent directly to the
taskprocessor.
Review: https://reviewboard.asterisk.org/r/2884/
........
Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
static void aji_devstate_cb ( void * data , struct stasis_subscription * sub , struct stasis_message * msg )
2010-06-15 17:06:23 +00:00
{
2013-04-16 15:33:59 +00:00
struct aji_client * client = data ;
struct ast_device_state_message * dev_state ;
if ( ! stasis_subscription_is_subscribed ( sub ) | | ast_device_state_message_type ( ) ! = stasis_message_type ( msg ) ) {
2010-06-15 17:06:23 +00:00
return ;
}
2013-04-16 15:33:59 +00:00
dev_state = stasis_message_data ( msg ) ;
if ( ! dev_state - > eid | | ast_eid_cmp ( & ast_eid_default , dev_state - > eid ) ) {
/* If the event is aggregate or didn't originate from this server, don't send it out. */
return ;
}
aji_publish_device_state ( client , dev_state - > device , ast_devstate_str ( dev_state - > state ) , dev_state - > cachable ) ;
}
static int cached_devstate_cb ( void * obj , void * arg , int flags )
{
struct stasis_message * msg = obj ;
struct aji_client * client = arg ;
Multiple revisions 399887,400138,400178,400180-400181
........
r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line
Minor performance bump by not allocate manager variable struct if we don't need it
........
r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines
Stasis performance improvements
This patch addresses several performance problems that were found in
the initial performance testing of Asterisk 12.
The Stasis dispatch object was allocated as an AO2 object, even though
it has a very confined lifecycle. This was replaced with a straight
ast_malloc().
The Stasis message router was spending an inordinate amount of time
searching hash tables. In this case, most of our routers had 6 or
fewer routes in them to begin with. This was replaced with an array
that's searched linearly for the route.
We more heavily rely on AO2 objects in Asterisk 12, and the memset()
in ao2_ref() actually became noticeable on the profile. This was
#ifdef'ed to only run when AO2_DEBUG was enabled.
After being misled by an erroneous comment in taskprocessor.c during
profiling, the wrong comment was removed.
Review: https://reviewboard.asterisk.org/r/2873/
........
r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines
Taskprocessor optimization; switch Stasis to use taskprocessors
This patch optimizes taskprocessor to use a semaphore for signaling,
which the OS can do a better job at managing contention and waiting
that we can with a mutex and condition.
The taskprocessor execution was also slightly optimized to reduce the
number of locks taken.
The only observable difference in the taskprocessor implementation is
that when the final reference to the taskprocessor goes away, it will
execute all tasks to completion instead of discarding the unexecuted
tasks.
For systems where unnamed semaphores are not supported, a really
simple semaphore implementation is provided. (Which gives identical
performance as the original taskprocessor implementation).
The way we ended up implementing Stasis caused the threadpool to be a
burden instead of a boost to performance. This was switched to just
use taskprocessors directly for subscriptions.
Review: https://reviewboard.asterisk.org/r/2881/
........
r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines
Optimize how Stasis forwards are dispatched
This patch optimizes how forwards are dispatched in Stasis.
Originally, forwards were dispatched as subscriptions that are invoked
on the publishing thread. This did not account for the vast number of
forwards we would end up having in the system, and the amount of work it
would take to walk though the forward subscriptions.
This patch modifies Stasis so that rather than walking the tree of
forwards on every dispatch, when forwards and subscriptions are changed,
the subscriber list for every topic in the tree is changed.
This has a couple of benefits. First, this reduces the workload of
dispatching messages. It also reduces contention when dispatching to
different topics that happen to forward to the same aggregation topic
(as happens with all of the channel, bridge and endpoint topics).
Since forwards are no longer subscriptions, the bulk of this patch is
simply changing stasis_subscription objects to stasis_forward objects
(which, admittedly, I should have done in the first place.)
Since this required me to yet again put in a growing array, I finally
abstracted that out into a set of ast_vector macros in
asterisk/vector.h.
Review: https://reviewboard.asterisk.org/r/2883/
........
r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines
Remove dispatch object allocation from Stasis publishing
While looking for areas for performance improvement, I realized that an
unused feature in Stasis was negatively impacting performance.
When a message is sent to a subscriber, a dispatch object is allocated
for the dispatch, containing the topic the message was published to, the
subscriber the message is being sent to, and the message itself.
The topic is actually unused by any subscriber in Asterisk today. And
the subscriber is associated with the taskprocessor the message is being
dispatched to.
First, this patch removes the unused topic parameter from Stasis
subscription callbacks.
Second, this patch introduces the concept of taskprocessor local data,
data that may be set on a taskprocessor and provided along with the data
pointer when a task is pushed using the ast_taskprocessor_push_local()
call. This allows the task to have both data specific to that
taskprocessor, in addition to data specific to that invocation.
With those two changes, the dispatch object can be removed completely,
and the message is simply refcounted and sent directly to the
taskprocessor.
Review: https://reviewboard.asterisk.org/r/2884/
........
Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
aji_devstate_cb ( client , device_state_sub , msg ) ;
2013-04-16 15:33:59 +00:00
return 0 ;
2010-06-15 17:06:23 +00:00
}
/*!
* \ brief Initialize collections for event distribution
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ return void
*/
static void aji_init_event_distribution ( struct aji_client * client )
{
if ( ! mwi_sub ) {
2013-05-24 20:44:07 +00:00
mwi_sub = stasis_subscribe ( ast_mwi_topic_all ( ) , aji_mwi_cb , client ) ;
2010-06-15 17:06:23 +00:00
}
if ( ! device_state_sub ) {
2013-04-16 15:33:59 +00:00
RAII_VAR ( struct ao2_container * , cached , NULL , ao2_cleanup ) ;
device_state_sub = stasis_subscribe ( ast_device_state_topic_all ( ) ,
aji_devstate_cb , client ) ;
2013-08-01 13:49:34 +00:00
cached = stasis_cache_dump ( ast_device_state_cache ( ) , NULL ) ;
2013-04-16 15:33:59 +00:00
ao2_callback ( cached , OBJ_NODATA , cached_devstate_cb , client ) ;
2010-06-15 17:06:23 +00:00
}
aji_pubsub_subscribe ( client , " device_state " ) ;
aji_pubsub_subscribe ( client , " message_waiting " ) ;
iks_filter_add_rule ( client - > f , aji_handle_pubsub_event , client , IKS_RULE_TYPE ,
IKS_PAK_MESSAGE , IKS_RULE_FROM , client - > pubsub_node , IKS_RULE_DONE ) ;
iks_filter_add_rule ( client - > f , aji_handle_pubsub_error , client , IKS_RULE_TYPE ,
IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_ERROR , IKS_RULE_DONE ) ;
}
/*!
* \ brief Callback for handling PubSub events
* \ param data void pointer to aji_client structure
2012-09-21 17:14:59 +00:00
* \ param pak A pak
2010-06-15 17:06:23 +00:00
* \ return IKS_FILTER_EAT
*/
static int aji_handle_pubsub_event ( void * data , ikspak * pak )
{
2013-09-06 21:23:02 +00:00
char * item_id , * device_state , * mailbox , * cachable_str ;
2010-06-15 17:06:23 +00:00
int oldmsgs , newmsgs ;
iks * item , * item_content ;
struct ast_eid pubsub_eid ;
2013-01-02 18:11:59 +00:00
unsigned int cachable = AST_DEVSTATE_CACHABLE ;
2010-06-15 17:06:23 +00:00
item = iks_find ( iks_find ( iks_find ( pak - > x , " event " ) , " items " ) , " item " ) ;
if ( ! item ) {
ast_log ( LOG_ERROR , " Could not parse incoming PubSub event \n " ) ;
return IKS_FILTER_EAT ;
}
item_id = iks_find_attrib ( item , " id " ) ;
item_content = iks_child ( item ) ;
ast_str_to_eid ( & pubsub_eid , iks_find_attrib ( item_content , " eid " ) ) ;
if ( ! ast_eid_cmp ( & ast_eid_default , & pubsub_eid ) ) {
2011-02-04 16:55:39 +00:00
ast_debug ( 1 , " Returning here, eid of incoming event matches ours! \n " ) ;
2010-06-15 17:06:23 +00:00
return IKS_FILTER_EAT ;
}
if ( ! strcasecmp ( iks_name ( item_content ) , " state " ) ) {
2013-04-16 23:44:18 +00:00
if ( ( cachable_str = iks_find_attrib ( item_content , " cachable " ) ) ) {
2014-05-09 22:49:26 +00:00
sscanf ( cachable_str , " %30u " , & cachable ) ;
2013-01-02 18:11:59 +00:00
}
2013-04-16 23:44:18 +00:00
device_state = iks_find_cdata ( item , " state " ) ;
2013-04-16 15:33:59 +00:00
ast_publish_device_state_full ( item_id ,
ast_devstate_val ( device_state ) ,
cachable = = AST_DEVSTATE_CACHABLE ? AST_DEVSTATE_CACHABLE : AST_DEVSTATE_NOT_CACHABLE ,
& pubsub_eid ) ;
return IKS_FILTER_EAT ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( iks_name ( item_content ) , " mailbox " ) ) {
2013-09-06 21:23:02 +00:00
mailbox = strsep ( & item_id , " @ " ) ;
2010-06-15 17:06:23 +00:00
sscanf ( iks_find_cdata ( item_content , " OLDMSGS " ) , " %10d " , & oldmsgs ) ;
sscanf ( iks_find_cdata ( item_content , " NEWMSGS " ) , " %10d " , & newmsgs ) ;
2013-03-16 15:45:58 +00:00
2013-09-06 21:23:02 +00:00
ast_publish_mwi_state_full ( mailbox , item_id , newmsgs , oldmsgs , NULL , & pubsub_eid ) ;
2013-03-16 15:45:58 +00:00
return IKS_FILTER_EAT ;
2010-06-15 17:06:23 +00:00
} else {
2011-02-04 16:55:39 +00:00
ast_debug ( 1 , " Don't know how to handle PubSub event of type %s \n " ,
2010-06-15 17:06:23 +00:00
iks_name ( item_content ) ) ;
return IKS_FILTER_EAT ;
}
2013-01-02 18:11:59 +00:00
2010-06-15 17:06:23 +00:00
return IKS_FILTER_EAT ;
}
/*!
* \ brief Add Owner affiliations for pubsub node
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param node the name of the node to which to add affiliations
* \ return void
*/
static void aji_create_affiliations ( struct aji_client * client , const char * node )
{
iks * modify_affiliates = aji_pubsub_iq_create ( client , " set " ) ;
iks * pubsub , * affiliations , * affiliate ;
pubsub = iks_insert ( modify_affiliates , " pubsub " ) ;
iks_insert_attrib ( pubsub , " xmlns " , " http://jabber.org/protocol/pubsub#owner " ) ;
affiliations = iks_insert ( pubsub , " affiliations " ) ;
iks_insert_attrib ( affiliations , " node " , node ) ;
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
affiliate = iks_insert ( affiliations , " affiliation " ) ;
iks_insert_attrib ( affiliate , " jid " , iterator - > name ) ;
iks_insert_attrib ( affiliate , " affiliation " , " owner " ) ;
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , modify_affiliates ) ;
2010-06-15 17:06:23 +00:00
iks_delete ( modify_affiliates ) ;
}
/*!
* \ brief Subscribe to a PubSub node
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param node the name of the node to which to subscribe
* \ return void
*/
static void aji_pubsub_subscribe ( struct aji_client * client , const char * node )
{
iks * request = aji_pubsub_iq_create ( client , " set " ) ;
iks * pubsub , * subscribe ;
pubsub = iks_insert ( request , " pubsub " ) ;
iks_insert_attrib ( pubsub , " xmlns " , " http://jabber.org/protocol/pubsub " ) ;
subscribe = iks_insert ( pubsub , " subscribe " ) ;
iks_insert_attrib ( subscribe , " jid " , client - > jid - > partial ) ;
iks_insert_attrib ( subscribe , " node " , node ) ;
if ( ast_test_flag ( & globalflags , AJI_XEP0248 ) ) {
iks * options , * x , * sub_options , * sub_type , * sub_depth ;
options = iks_insert ( pubsub , " options " ) ;
x = iks_insert ( options , " x " ) ;
iks_insert_attrib ( x , " xmlns " , " jabber:x:data " ) ;
iks_insert_attrib ( x , " type " , " submit " ) ;
sub_options = iks_insert ( x , " field " ) ;
iks_insert_attrib ( sub_options , " var " , " FORM_TYPE " ) ;
iks_insert_attrib ( sub_options , " type " , " hidden " ) ;
iks_insert_cdata ( iks_insert ( sub_options , " value " ) ,
" http://jabber.org/protocol/pubsub#subscribe_options " , 51 ) ;
sub_type = iks_insert ( x , " field " ) ;
iks_insert_attrib ( sub_type , " var " , " pubsub#subscription_type " ) ;
iks_insert_cdata ( iks_insert ( sub_type , " value " ) , " items " , 5 ) ;
sub_depth = iks_insert ( x , " field " ) ;
iks_insert_attrib ( sub_type , " var " , " pubsub#subscription_depth " ) ;
iks_insert_cdata ( iks_insert ( sub_depth , " value " ) , " all " , 3 ) ;
}
ast_aji_send ( client , request ) ;
iks_delete ( request ) ;
}
/*!
* \ brief Build the skeleton of a publish
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param node Name of the node that will be published to
* \ param event_type
* \ return iks *
*/
static iks * aji_build_publish_skeleton ( struct aji_client * client , const char * node ,
2013-01-02 18:11:59 +00:00
const char * event_type , unsigned int cachable )
2010-06-15 17:06:23 +00:00
{
iks * request = aji_pubsub_iq_create ( client , " set " ) ;
iks * pubsub , * publish , * item ;
pubsub = iks_insert ( request , " pubsub " ) ;
iks_insert_attrib ( pubsub , " xmlns " , " http://jabber.org/protocol/pubsub " ) ;
publish = iks_insert ( pubsub , " publish " ) ;
if ( ast_test_flag ( & globalflags , AJI_XEP0248 ) ) {
iks_insert_attrib ( publish , " node " , node ) ;
} else {
iks_insert_attrib ( publish , " node " , event_type ) ;
}
item = iks_insert ( publish , " item " ) ;
iks_insert_attrib ( item , " id " , node ) ;
2013-01-02 18:11:59 +00:00
if ( cachable = = AST_DEVSTATE_NOT_CACHABLE ) {
iks * options , * x , * field_form_type , * field_persist ;
options = iks_insert ( pubsub , " publish-options " ) ;
x = iks_insert ( options , " x " ) ;
iks_insert_attrib ( x , " xmlns " , " jabber:x:data " ) ;
iks_insert_attrib ( x , " type " , " submit " ) ;
field_form_type = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_form_type , " var " , " FORM_TYPE " ) ;
iks_insert_attrib ( field_form_type , " type " , " hidden " ) ;
iks_insert_cdata ( iks_insert ( field_form_type , " value " ) , " http://jabber.org/protocol/pubsub#publish-options " , 0 ) ;
field_persist = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_persist , " var " , " pubsub#persist_items " ) ;
iks_insert_cdata ( iks_insert ( field_persist , " value " ) , " 0 " , 1 ) ;
}
return item ;
2010-06-15 17:06:23 +00:00
}
/*!
* \ brief Publish device state to a PubSub node
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param device the name of the device whose state to publish
* \ param device_state the state to publish
* \ return void
*/
static void aji_publish_device_state ( struct aji_client * client , const char * device ,
2013-01-02 18:11:59 +00:00
const char * device_state , unsigned int cachable )
2010-06-15 17:06:23 +00:00
{
2013-01-02 18:11:59 +00:00
iks * request = aji_build_publish_skeleton ( client , device , " device_state " , cachable ) ;
2010-06-15 17:06:23 +00:00
iks * state ;
2013-01-02 18:11:59 +00:00
char eid_str [ 20 ] , cachable_str [ 2 ] ;
2010-06-15 17:06:23 +00:00
if ( ast_test_flag ( & pubsubflags , AJI_PUBSUB_AUTOCREATE ) ) {
if ( ast_test_flag ( & pubsubflags , AJI_XEP0248 ) ) {
aji_create_pubsub_node ( client , " leaf " , device , " device_state " ) ;
} else {
aji_create_pubsub_node ( client , NULL , device , NULL ) ;
}
}
ast_eid_to_str ( eid_str , sizeof ( eid_str ) , & ast_eid_default ) ;
state = iks_insert ( request , " state " ) ;
iks_insert_attrib ( state , " xmlns " , " http://asterisk.org " ) ;
iks_insert_attrib ( state , " eid " , eid_str ) ;
2013-01-02 18:11:59 +00:00
snprintf ( cachable_str , sizeof ( cachable_str ) , " %u " , cachable ) ;
iks_insert_attrib ( state , " cachable " , cachable_str ) ;
2010-06-15 17:06:23 +00:00
iks_insert_cdata ( state , device_state , strlen ( device_state ) ) ;
ast_aji_send ( client , iks_root ( request ) ) ;
iks_delete ( request ) ;
}
/*!
* \ brief Publish MWI to a PubSub node
* \ param client the configured XMPP client we use to connect to a XMPP server
2013-12-19 16:52:43 +00:00
* \ param mailbox The mailbox identifier
2012-09-21 17:14:59 +00:00
* \ param oldmsgs Old messages
* \ param newmsgs New messages
2010-06-15 17:06:23 +00:00
* \ return void
*/
static void aji_publish_mwi ( struct aji_client * client , const char * mailbox ,
2013-12-19 16:52:43 +00:00
const char * oldmsgs , const char * newmsgs )
2010-06-15 17:06:23 +00:00
{
char eid_str [ 20 ] ;
2010-06-15 18:16:04 +00:00
iks * mailbox_node , * request ;
2013-12-19 16:52:43 +00:00
request = aji_build_publish_skeleton ( client , mailbox , " message_waiting " , 1 ) ;
2010-06-15 17:06:23 +00:00
ast_eid_to_str ( eid_str , sizeof ( eid_str ) , & ast_eid_default ) ;
mailbox_node = iks_insert ( request , " mailbox " ) ;
iks_insert_attrib ( mailbox_node , " xmlns " , " http://asterisk.org " ) ;
iks_insert_attrib ( mailbox_node , " eid " , eid_str ) ;
iks_insert_cdata ( iks_insert ( mailbox_node , " NEWMSGS " ) , newmsgs , strlen ( newmsgs ) ) ;
iks_insert_cdata ( iks_insert ( mailbox_node , " OLDMSGS " ) , oldmsgs , strlen ( oldmsgs ) ) ;
ast_aji_send ( client , iks_root ( request ) ) ;
iks_delete ( request ) ;
}
/*!
* \ brief Create an IQ packet
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param type the type of IQ packet to create
* \ return iks *
*/
static iks * aji_pubsub_iq_create ( struct aji_client * client , const char * type )
{
iks * request = iks_new ( " iq " ) ;
iks_insert_attrib ( request , " to " , client - > pubsub_node ) ;
iks_insert_attrib ( request , " from " , client - > jid - > full ) ;
iks_insert_attrib ( request , " type " , type ) ;
ast_aji_increment_mid ( client - > mid ) ;
iks_insert_attrib ( request , " id " , client - > mid ) ;
return request ;
}
static int aji_handle_pubsub_error ( void * data , ikspak * pak )
{
char * node_name ;
char * error ;
int error_num ;
iks * orig_request ;
iks * orig_pubsub = iks_find ( pak - > x , " pubsub " ) ;
2011-10-27 14:24:01 +00:00
struct aji_client * client ;
2010-06-15 17:06:23 +00:00
if ( ! orig_pubsub ) {
2013-10-17 15:41:22 +00:00
ast_debug ( 1 , " Error isn't a PubSub error, why are we here? \n " ) ;
2010-06-15 17:06:23 +00:00
return IKS_FILTER_EAT ;
}
orig_request = iks_child ( orig_pubsub ) ;
error = iks_find_attrib ( iks_find ( pak - > x , " error " ) , " code " ) ;
node_name = iks_find_attrib ( orig_request , " node " ) ;
if ( ! sscanf ( error , " %30d " , & error_num ) ) {
return IKS_FILTER_EAT ;
}
if ( error_num > 399 & & error_num < 500 & & error_num ! = 404 ) {
ast_log ( LOG_ERROR ,
" Error performing operation on PubSub node %s, %s. \n " , node_name , error ) ;
return IKS_FILTER_EAT ;
} else if ( error_num > 499 & & error_num < 600 ) {
ast_log ( LOG_ERROR , " PubSub Server error, %s \n " , error ) ;
return IKS_FILTER_EAT ;
}
2011-10-27 14:24:01 +00:00
client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2010-06-15 17:06:23 +00:00
if ( ! strcasecmp ( iks_name ( orig_request ) , " publish " ) ) {
2010-06-15 18:16:04 +00:00
iks * request ;
2010-06-15 17:06:23 +00:00
if ( ast_test_flag ( & pubsubflags , AJI_XEP0248 ) ) {
if ( iks_find ( iks_find ( orig_request , " item " ) , " state " ) ) {
aji_create_pubsub_leaf ( client , " device_state " , node_name ) ;
} else if ( iks_find ( iks_find ( orig_request , " item " ) , " mailbox " ) ) {
aji_create_pubsub_leaf ( client , " message_waiting " , node_name ) ;
}
} else {
aji_create_pubsub_node ( client , NULL , node_name , NULL ) ;
}
2010-06-15 18:16:04 +00:00
request = aji_pubsub_iq_create ( client , " set " ) ;
2010-06-15 17:06:23 +00:00
iks_insert_node ( request , orig_pubsub ) ;
ast_aji_send ( client , request ) ;
iks_delete ( request ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return IKS_FILTER_EAT ;
} else if ( ! strcasecmp ( iks_name ( orig_request ) , " subscribe " ) ) {
if ( ast_test_flag ( & pubsubflags , AJI_XEP0248 ) ) {
aji_create_pubsub_collection ( client , node_name ) ;
} else {
aji_create_pubsub_node ( client , NULL , node_name , NULL ) ;
}
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return IKS_FILTER_EAT ;
}
/*!
* \ brief Request item list from pubsub
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param collection name of the collection for request
* \ return void
*/
static void aji_request_pubsub_nodes ( struct aji_client * client , const char * collection )
{
iks * request = aji_build_node_request ( client , collection ) ;
iks_filter_add_rule ( client - > f , aji_receive_node_list , client , IKS_RULE_TYPE ,
IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_RESULT , IKS_RULE_ID , client - > mid ,
IKS_RULE_DONE ) ;
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , request ) ;
2010-06-15 17:06:23 +00:00
iks_delete ( request ) ;
}
/*!
* \ brief Build the a node request
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param collection name of the collection for request
* \ return iks *
*/
static iks * aji_build_node_request ( struct aji_client * client , const char * collection )
{
iks * request = aji_pubsub_iq_create ( client , " get " ) ;
iks * query ;
query = iks_insert ( request , " query " ) ;
iks_insert_attrib ( query , " xmlns " , " http://jabber.org/protocol/disco#items " ) ;
if ( collection ) {
iks_insert_attrib ( query , " node " , collection ) ;
}
return request ;
}
/*!
* \ brief Receive pubsub item lists
* \ param data pointer to aji_client structure
* \ param pak response from pubsub diso # items query
* \ return IKS_FILTER_EAT
*/
static int aji_receive_node_list ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2010-07-16 05:59:11 +00:00
iks * item = NULL ;
2010-06-15 17:06:23 +00:00
if ( iks_has_children ( pak - > query ) ) {
item = iks_first_tag ( pak - > query ) ;
2010-11-26 18:31:48 +00:00
ast_verbose ( " Connection %s: %s \n Node name: %s \n " , client - > name , client - > jid - > partial ,
2010-06-15 17:06:23 +00:00
iks_find_attrib ( item , " node " ) ) ;
while ( ( item = iks_next_tag ( item ) ) ) {
ast_verbose ( " Node name: %s \n " , iks_find_attrib ( item , " node " ) ) ;
}
}
2010-07-16 05:59:11 +00:00
if ( item ) {
iks_delete ( item ) ;
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return IKS_FILTER_EAT ;
}
/*!
* \ brief Method to expose PubSub node list via CLI .
* \ param e pointer to ast_cli_entry structure
* \ param cmd
* \ param a pointer to ast_cli_args structure
* \ return char *
*/
static char * aji_cli_list_pubsub_nodes ( struct ast_cli_entry * e , int cmd , struct
ast_cli_args * a )
{
struct aji_client * client ;
2010-11-26 18:31:48 +00:00
const char * name = NULL ;
2010-06-15 17:06:23 +00:00
const char * collection = NULL ;
switch ( cmd ) {
case CLI_INIT :
e - > command = " jabber list nodes " ;
e - > usage =
2010-11-26 18:31:48 +00:00
" Usage: jabber list nodes <connection> [collection] \n "
" Lists the user's nodes on the respective connection \n "
" ([connection] as configured in jabber.conf.) \n " ;
2010-06-15 17:06:23 +00:00
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a - > argc > 5 | | a - > argc < 4 ) {
return CLI_SHOWUSAGE ;
} else if ( a - > argc = = 4 | | a - > argc = = 5 ) {
name = a - > argv [ 3 ] ;
}
if ( a - > argc = = 5 ) {
collection = a - > argv [ 4 ] ;
}
2011-11-23 17:16:33 +00:00
if ( ! ( client = ASTOBJ_CONTAINER_FIND ( & clients , name ) ) ) {
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " Unable to find client '%s'! \n " , name ) ;
return CLI_FAILURE ;
}
ast_cli ( a - > fd , " Listing pubsub nodes. \n " ) ;
aji_request_pubsub_nodes ( client , collection ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return CLI_SUCCESS ;
}
/*!
* \ brief Method to purge PubSub nodes via CLI .
* \ param e pointer to ast_cli_entry structure
* \ param cmd
* \ param a pointer to ast_cli_args structure
* \ return char *
*/
static char * aji_cli_purge_pubsub_nodes ( struct ast_cli_entry * e , int cmd , struct
ast_cli_args * a )
{
struct aji_client * client ;
2010-11-26 18:31:48 +00:00
const char * name ;
2010-06-15 17:06:23 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " jabber purge nodes " ;
e - > usage =
2010-11-26 18:31:48 +00:00
" Usage: jabber purge nodes <connection> <node> \n "
2010-06-15 17:06:23 +00:00
" Purges nodes on PubSub server \n "
" as configured in jabber.conf. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2010-11-26 18:31:48 +00:00
if ( a - > argc ! = 5 ) {
2010-06-15 17:06:23 +00:00
return CLI_SHOWUSAGE ;
}
2010-11-26 18:31:48 +00:00
name = a - > argv [ 3 ] ;
2010-06-15 17:06:23 +00:00
if ( ! ( client = ASTOBJ_CONTAINER_FIND ( & clients , name ) ) ) {
ast_cli ( a - > fd , " Unable to find client '%s'! \n " , name ) ;
return CLI_FAILURE ;
}
if ( ast_test_flag ( & pubsubflags , AJI_XEP0248 ) ) {
aji_pubsub_purge_nodes ( client , a - > argv [ 4 ] ) ;
} else {
aji_delete_pubsub_node ( client , a - > argv [ 4 ] ) ;
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return CLI_SUCCESS ;
}
static void aji_pubsub_purge_nodes ( struct aji_client * client , const char * collection_name )
{
iks * request = aji_build_node_request ( client , collection_name ) ;
ast_aji_send ( client , request ) ;
iks_filter_add_rule ( client - > f , aji_delete_node_list , client , IKS_RULE_TYPE ,
IKS_PAK_IQ , IKS_RULE_SUBTYPE , IKS_TYPE_RESULT , IKS_RULE_ID , client - > mid ,
IKS_RULE_DONE ) ;
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , request ) ;
2010-06-15 17:06:23 +00:00
iks_delete ( request ) ;
}
/*!
* \ brief Delete pubsub item lists
* \ param data pointer to aji_client structure
* \ param pak response from pubsub diso # items query
* \ return IKS_FILTER_EAT
*/
static int aji_delete_node_list ( void * data , ikspak * pak )
{
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2010-07-16 06:04:22 +00:00
iks * item = NULL ;
2010-06-15 17:06:23 +00:00
if ( iks_has_children ( pak - > query ) ) {
item = iks_first_tag ( pak - > query ) ;
ast_log ( LOG_WARNING , " Connection: %s Node name: %s \n " , client - > jid - > partial ,
iks_find_attrib ( item , " node " ) ) ;
while ( ( item = iks_next_tag ( item ) ) ) {
aji_delete_pubsub_node ( client , iks_find_attrib ( item , " node " ) ) ;
}
}
2010-07-16 06:04:22 +00:00
if ( item ) {
iks_delete ( item ) ;
}
2010-06-15 17:06:23 +00:00
return IKS_FILTER_EAT ;
}
/*!
* \ brief Method to expose PubSub node deletion via CLI .
* \ param e pointer to ast_cli_entry structure
* \ param cmd
* \ param a pointer to ast_cli_args structure
* \ return char *
*/
static char * aji_cli_delete_pubsub_node ( struct ast_cli_entry * e , int cmd , struct
ast_cli_args * a )
{
struct aji_client * client ;
2010-11-26 18:31:48 +00:00
const char * name ;
2010-06-15 17:06:23 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " jabber delete node " ;
e - > usage =
2010-11-26 18:31:48 +00:00
" Usage: jabber delete node <connection> <node> \n "
2010-06-15 17:06:23 +00:00
" Deletes a node on PubSub server \n "
" as configured in jabber.conf. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2010-11-26 18:31:48 +00:00
if ( a - > argc ! = 5 ) {
2010-06-15 17:06:23 +00:00
return CLI_SHOWUSAGE ;
}
2010-11-26 18:31:48 +00:00
name = a - > argv [ 3 ] ;
2010-06-15 17:06:23 +00:00
if ( ! ( client = ASTOBJ_CONTAINER_FIND ( & clients , name ) ) ) {
ast_cli ( a - > fd , " Unable to find client '%s'! \n " , name ) ;
return CLI_FAILURE ;
}
aji_delete_pubsub_node ( client , a - > argv [ 4 ] ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return CLI_SUCCESS ;
}
/*!
* \ brief Delete a PubSub node
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param node_name the name of the node to delete
* return void
*/
static void aji_delete_pubsub_node ( struct aji_client * client , const char * node_name )
{
iks * request = aji_pubsub_iq_create ( client , " set " ) ;
iks * pubsub , * delete ;
pubsub = iks_insert ( request , " pubsub " ) ;
iks_insert_attrib ( pubsub , " xmlns " , " http://jabber.org/protocol/pubsub#owner " ) ;
delete = iks_insert ( pubsub , " delete " ) ;
iks_insert_attrib ( delete , " node " , node_name ) ;
ast_aji_send ( client , request ) ;
}
/*!
* \ brief Create a PubSub collection node .
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param collection_name The name to use for this collection
* \ return void .
*/
static void aji_create_pubsub_collection ( struct aji_client * client , const char
* collection_name )
{
aji_create_pubsub_node ( client , " collection " , collection_name , NULL ) ;
}
/*!
* \ brief Create a PubSub leaf node .
* \ param client the configured XMPP client we use to connect to a XMPP server
2012-09-21 17:14:59 +00:00
* \ param collection_name The name to use for this collection
2010-06-15 17:06:23 +00:00
* \ param leaf_name The name to use for this collection
* \ return void .
*/
static void aji_create_pubsub_leaf ( struct aji_client * client , const char * collection_name ,
const char * leaf_name )
{
aji_create_pubsub_node ( client , " leaf " , leaf_name , collection_name ) ;
}
/*!
* \ brief Create a pubsub node
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param node_type the type of node to create
* \ param name the name of the node to create
2012-09-21 17:14:59 +00:00
* \ param collection_name The name to use for this collection
2010-06-15 17:06:23 +00:00
* \ return iks *
*/
static iks * aji_create_pubsub_node ( struct aji_client * client , const char * node_type , const
char * name , const char * collection_name )
{
iks * node = aji_pubsub_iq_create ( client , " set " ) ;
2011-05-05 22:44:52 +00:00
iks * pubsub , * create ;
2010-06-15 17:06:23 +00:00
pubsub = iks_insert ( node , " pubsub " ) ;
iks_insert_attrib ( pubsub , " xmlns " , " http://jabber.org/protocol/pubsub " ) ;
create = iks_insert ( pubsub , " create " ) ;
iks_insert_attrib ( create , " node " , name ) ;
2011-05-05 22:44:52 +00:00
aji_build_node_config ( pubsub , node_type , collection_name ) ;
ast_aji_send ( client , node ) ;
2010-06-15 17:06:23 +00:00
aji_create_affiliations ( client , name ) ;
iks_delete ( node ) ;
return 0 ;
}
static iks * aji_build_node_config ( iks * pubsub , const char * node_type , const char * collection_name )
{
iks * configure , * x , * field_owner , * field_node_type , * field_node_config ,
* field_deliver_payload , * field_persist_items , * field_access_model ,
* field_pubsub_collection ;
configure = iks_insert ( pubsub , " configure " ) ;
x = iks_insert ( configure , " x " ) ;
iks_insert_attrib ( x , " xmlns " , " jabber:x:data " ) ;
iks_insert_attrib ( x , " type " , " submit " ) ;
field_owner = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_owner , " var " , " FORM_TYPE " ) ;
iks_insert_attrib ( field_owner , " type " , " hidden " ) ;
iks_insert_cdata ( iks_insert ( field_owner , " value " ) ,
" http://jabber.org/protocol/pubsub#owner " , 39 ) ;
if ( node_type ) {
field_node_type = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_node_type , " var " , " pubsub#node_type " ) ;
iks_insert_cdata ( iks_insert ( field_node_type , " value " ) , node_type , strlen ( node_type ) ) ;
}
field_node_config = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_node_config , " var " , " FORM_TYPE " ) ;
iks_insert_attrib ( field_node_config , " type " , " hidden " ) ;
iks_insert_cdata ( iks_insert ( field_node_config , " value " ) ,
" http://jabber.org/protocol/pubsub#node_config " , 45 ) ;
field_deliver_payload = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_deliver_payload , " var " , " pubsub#deliver_payloads " ) ;
iks_insert_cdata ( iks_insert ( field_deliver_payload , " value " ) , " 1 " , 1 ) ;
field_persist_items = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_persist_items , " var " , " pubsub#persist_items " ) ;
iks_insert_cdata ( iks_insert ( field_persist_items , " value " ) , " 1 " , 1 ) ;
field_access_model = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_access_model , " var " , " pubsub#access_model " ) ;
iks_insert_cdata ( iks_insert ( field_access_model , " value " ) , " whitelist " , 9 ) ;
if ( node_type & & ! strcasecmp ( node_type , " leaf " ) ) {
field_pubsub_collection = iks_insert ( x , " field " ) ;
iks_insert_attrib ( field_pubsub_collection , " var " , " pubsub#collection " ) ;
iks_insert_cdata ( iks_insert ( field_pubsub_collection , " value " ) , collection_name ,
strlen ( collection_name ) ) ;
}
return configure ;
}
/*!
* \ brief Method to expose PubSub collection node creation via CLI .
* \ return char * .
*/
static char * aji_cli_create_collection ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
struct aji_client * client ;
2010-11-26 18:31:48 +00:00
const char * name ;
const char * collection_name ;
2010-06-15 17:06:23 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " jabber create collection " ;
e - > usage =
2010-11-26 18:31:48 +00:00
" Usage: jabber create collection <connection> <collection> \n "
2010-06-15 17:06:23 +00:00
" Creates a PubSub collection node using the account \n "
" as configured in jabber.conf. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2010-11-26 18:31:48 +00:00
if ( a - > argc ! = 5 ) {
2010-06-15 17:06:23 +00:00
return CLI_SHOWUSAGE ;
}
2010-11-26 18:31:48 +00:00
name = a - > argv [ 3 ] ;
collection_name = a - > argv [ 4 ] ;
2010-06-15 17:06:23 +00:00
2010-11-26 18:31:48 +00:00
if ( ! ( client = ASTOBJ_CONTAINER_FIND ( & clients , name ) ) ) {
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " Unable to find client '%s'! \n " , name ) ;
return CLI_FAILURE ;
}
ast_cli ( a - > fd , " Creating test PubSub node collection. \n " ) ;
aji_create_pubsub_collection ( client , collection_name ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return CLI_SUCCESS ;
}
/*!
* \ brief Method to expose PubSub leaf node creation via CLI .
* \ return char * .
*/
static char * aji_cli_create_leafnode ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
struct aji_client * client ;
2010-11-26 18:31:48 +00:00
const char * name ;
const char * collection_name ;
const char * leaf_name ;
2010-06-15 17:06:23 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " jabber create leaf " ;
e - > usage =
2010-11-26 18:31:48 +00:00
" Usage: jabber create leaf <connection> <collection> <leaf> \n "
2010-06-15 17:06:23 +00:00
" Creates a PubSub leaf node using the account \n "
" as configured in jabber.conf. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2010-11-26 18:31:48 +00:00
if ( a - > argc ! = 6 ) {
2010-06-15 17:06:23 +00:00
return CLI_SHOWUSAGE ;
}
2010-11-26 18:31:48 +00:00
name = a - > argv [ 3 ] ;
collection_name = a - > argv [ 4 ] ;
leaf_name = a - > argv [ 5 ] ;
2010-06-15 17:06:23 +00:00
if ( ! ( client = ASTOBJ_CONTAINER_FIND ( & clients , name ) ) ) {
ast_cli ( a - > fd , " Unable to find client '%s'! \n " , name ) ;
return CLI_FAILURE ;
}
ast_cli ( a - > fd , " Creating test PubSub node collection. \n " ) ;
aji_create_pubsub_leaf ( client , collection_name , leaf_name ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2010-06-15 17:06:23 +00:00
return CLI_SUCCESS ;
}
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief set presence of client .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ param to user send it to
* \ param from user it came from
* \ param level
* \ param desc
2006-05-22 21:12:30 +00:00
* \ return void .
*/
2006-09-21 23:55:13 +00:00
static void aji_set_presence ( struct aji_client * client , char * to , char * from , int level , char * desc )
2006-05-22 21:12:30 +00:00
{
2006-08-07 21:15:28 +00:00
iks * presence = iks_make_pres ( level , desc ) ;
iks * cnode = iks_new ( " c " ) ;
iks * priority = iks_new ( " priority " ) ;
2007-10-07 16:28:25 +00:00
char priorityS [ 10 ] ;
2006-08-07 21:15:28 +00:00
2007-10-07 16:28:25 +00:00
if ( presence & & cnode & & client & & priority ) {
2010-06-15 17:06:23 +00:00
if ( to ) {
2006-09-21 23:55:13 +00:00
iks_insert_attrib ( presence , " to " , to ) ;
2010-06-15 17:06:23 +00:00
}
if ( from ) {
2006-09-21 23:55:13 +00:00
iks_insert_attrib ( presence , " from " , from ) ;
2010-06-15 17:06:23 +00:00
}
2007-10-07 16:28:25 +00:00
snprintf ( priorityS , sizeof ( priorityS ) , " %d " , client - > priority ) ;
iks_insert_cdata ( priority , priorityS , strlen ( priorityS ) ) ;
iks_insert_node ( presence , priority ) ;
2006-05-22 21:12:30 +00:00
iks_insert_attrib ( cnode , " node " , " http://www.asterisk.org/xmpp/client/caps " ) ;
iks_insert_attrib ( cnode , " ver " , " asterisk-xmpp " ) ;
iks_insert_attrib ( cnode , " ext " , " voice-v1 " ) ;
iks_insert_attrib ( cnode , " xmlns " , " http://jabber.org/protocol/caps " ) ;
iks_insert_node ( presence , cnode ) ;
2011-05-05 22:44:52 +00:00
ast_aji_send ( client , presence ) ;
2010-06-15 17:06:23 +00:00
} else {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
2010-06-15 17:06:23 +00:00
}
2008-02-29 14:15:03 +00:00
iks_delete ( cnode ) ;
iks_delete ( presence ) ;
iks_delete ( priority ) ;
2006-05-22 21:12:30 +00:00
}
2009-12-07 17:59:46 +00:00
/*
* \ brief set the presence of the client in a groupchat context .
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ param room the groupchat identifier in the from roomname @ service
* \ param from user it came from
* \ param level the type of action , i . e . join or leave the chatroom
* \ param nick the nickname to use in the chatroom
* \ param desc a text that details the action to be taken
* \ return res .
*/
static int aji_set_group_presence ( struct aji_client * client , char * room , int level , char * nick , char * desc )
{
int res = 0 ;
iks * presence = NULL , * x = NULL ;
char from [ AJI_MAX_JIDLEN ] ;
char roomid [ AJI_MAX_JIDLEN ] ;
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
presence = iks_make_pres ( level , NULL ) ;
x = iks_new ( " x " ) ;
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( client - > component ) {
snprintf ( from , AJI_MAX_JIDLEN , " %s@%s/%s " , nick , client - > jid - > full , nick ) ;
snprintf ( roomid , AJI_MAX_JIDLEN , " %s/%s " , room , nick ) ;
} else {
snprintf ( from , AJI_MAX_JIDLEN , " %s " , client - > jid - > full ) ;
snprintf ( roomid , AJI_MAX_JIDLEN , " %s/%s " , room , nick ? nick : client - > jid - > user ) ;
}
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
if ( ! presence | | ! x | | ! client ) {
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
res = - 1 ;
goto safeout ;
2010-06-15 17:06:23 +00:00
} else {
2009-12-07 17:59:46 +00:00
iks_insert_attrib ( presence , " to " , roomid ) ;
iks_insert_attrib ( presence , " from " , from ) ;
iks_insert_attrib ( x , " xmlns " , MUC_NS ) ;
iks_insert_node ( presence , x ) ;
res = ast_aji_send ( client , presence ) ;
}
2010-06-15 17:06:23 +00:00
2009-12-07 17:59:46 +00:00
safeout :
iks_delete ( presence ) ;
iks_delete ( x ) ;
return res ;
}
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2008-02-08 21:26:32 +00:00
* \ brief Turn on / off console debugging .
2007-09-18 22:43:45 +00:00
* \ return CLI_SUCCESS .
2006-05-22 21:12:30 +00:00
*/
2008-02-08 21:26:32 +00:00
static char * aji_do_set_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-05-22 21:12:30 +00:00
{
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e - > command = " jabber set debug {on|off} " ;
2007-09-18 22:43:45 +00:00
e - > usage =
2008-02-08 21:26:32 +00:00
" Usage: jabber set debug {on|off} \n "
2008-08-06 13:34:08 +00:00
" Enables/disables dumping of XMPP/Jabber packets for debugging purposes. \n " ;
2007-09-18 22:43:45 +00:00
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2010-06-15 17:06:23 +00:00
if ( a - > argc ! = e - > args ) {
2008-02-08 21:26:32 +00:00
return CLI_SHOWUSAGE ;
2010-06-15 17:06:23 +00:00
}
2008-02-08 21:26:32 +00:00
if ( ! strncasecmp ( a - > argv [ e - > args - 1 ] , " on " , 2 ) ) {
ASTOBJ_CONTAINER_TRAVERSE ( & clients , 1 , {
2010-06-15 17:06:23 +00:00
ASTOBJ_RDLOCK ( iterator ) ;
2008-02-08 21:26:32 +00:00
iterator - > debug = 1 ;
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
ast_cli ( a - > fd , " Jabber Debugging Enabled. \n " ) ;
return CLI_SUCCESS ;
} else if ( ! strncasecmp ( a - > argv [ e - > args - 1 ] , " off " , 3 ) ) {
ASTOBJ_CONTAINER_TRAVERSE ( & clients , 1 , {
2010-06-15 17:06:23 +00:00
ASTOBJ_RDLOCK ( iterator ) ;
2008-02-08 21:26:32 +00:00
iterator - > debug = 0 ;
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
ast_cli ( a - > fd , " Jabber Debugging Disabled. \n " ) ;
return CLI_SUCCESS ;
}
return CLI_SHOWUSAGE ; /* defaults to invalid */
2006-05-22 21:12:30 +00:00
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2008-02-08 21:26:32 +00:00
* \ brief Reload jabber module .
2007-09-18 22:43:45 +00:00
* \ return CLI_SUCCESS .
2006-05-22 21:12:30 +00:00
*/
2008-02-08 21:26:32 +00:00
static char * aji_do_reload ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-05-22 21:12:30 +00:00
{
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e - > command = " jabber reload " ;
2007-09-18 22:43:45 +00:00
e - > usage =
2008-02-08 21:26:32 +00:00
" Usage: jabber reload \n "
" Reloads the Jabber module. \n " ;
2007-09-18 22:43:45 +00:00
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
aji_reload ( 1 ) ;
ast_cli ( a - > fd , " Jabber Reloaded. \n " ) ;
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2006-05-22 21:12:30 +00:00
}
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-09-18 22:43:45 +00:00
* \ brief Show client status .
* \ return CLI_SUCCESS .
2006-05-22 21:12:30 +00:00
*/
2007-09-18 22:43:45 +00:00
static char * aji_show_clients ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-05-22 21:12:30 +00:00
{
2006-08-07 21:15:28 +00:00
char * status ;
int count = 0 ;
2010-06-15 17:06:23 +00:00
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
2010-11-26 18:31:48 +00:00
e - > command = " jabber show connections " ;
2007-09-18 22:43:45 +00:00
e - > usage =
2010-11-26 18:31:48 +00:00
" Usage: jabber show connections \n "
" Shows state of client and component connections \n " ;
2007-09-18 22:43:45 +00:00
return NULL ;
case CLI_GENERATE :
return NULL ;
}
ast_cli ( a - > fd , " Jabber Users and their status: \n " ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_TRAVERSE ( & clients , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
2006-08-07 21:15:28 +00:00
count + + ;
2006-05-22 21:12:30 +00:00
switch ( iterator - > state ) {
case AJI_DISCONNECTED :
status = " Disconnected " ;
break ;
case AJI_CONNECTING :
status = " Connecting " ;
break ;
case AJI_CONNECTED :
status = " Connected " ;
break ;
default :
status = " Unknown " ;
}
2010-11-26 18:31:48 +00:00
ast_cli ( a - > fd , " [%s] %s - %s \n " , iterator - > name , iterator - > user , status ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " ---- \n " ) ;
ast_cli ( a - > fd , " Number of users: %d \n " , count ) ;
return CLI_SUCCESS ;
2006-05-22 21:12:30 +00:00
}
2007-09-25 16:34:49 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2007-09-25 16:34:49 +00:00
* \ brief Show buddy lists
* \ return CLI_SUCCESS .
*/
static char * aji_show_buddies ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
struct aji_resource * resource ;
struct aji_client * client ;
switch ( cmd ) {
case CLI_INIT :
e - > command = " jabber show buddies " ;
e - > usage =
" Usage: jabber show buddies \n "
" Shows buddy lists of our clients \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
ast_cli ( a - > fd , " Jabber buddy lists \n " ) ;
ASTOBJ_CONTAINER_TRAVERSE ( & clients , 1 , {
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " Client: %s \n " , iterator - > user ) ;
2007-09-25 16:34:49 +00:00
client = iterator ;
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " \t Buddy: \t %s \n " , iterator - > name ) ;
2007-09-25 16:34:49 +00:00
if ( ! iterator - > resources )
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " \t \t Resource: None \n " ) ;
2007-09-25 16:34:49 +00:00
for ( resource = iterator - > resources ; resource ; resource = resource - > next ) {
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " \t \t Resource: %s \n " , resource - > resource ) ;
2009-09-25 10:54:42 +00:00
if ( resource - > cap ) {
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " \t \t \t node: %s \n " , resource - > cap - > parent - > node ) ;
ast_cli ( a - > fd , " \t \t \t version: %s \n " , resource - > cap - > version ) ;
ast_cli ( a - > fd , " \t \t \t Jingle capable: %s \n " , resource - > cap - > jingle ? " yes " : " no " ) ;
2007-09-25 16:34:49 +00:00
}
2010-06-15 17:06:23 +00:00
ast_cli ( a - > fd , " \t \t Status: %d \n " , resource - > status ) ;
ast_cli ( a - > fd , " \t \t Priority: %d \n " , resource - > priority ) ;
2007-09-25 16:34:49 +00:00
}
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
iterator = client ;
} ) ;
return CLI_SUCCESS ;
}
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief creates aji_client structure .
2007-06-07 21:22:25 +00:00
* \ param label
* \ param var ast_variable
2010-06-15 17:06:23 +00:00
* \ param debug
2006-05-22 21:12:30 +00:00
* \ return 0.
*/
static int aji_create_client ( char * label , struct ast_variable * var , int debug )
{
char * resource ;
struct aji_client * client = NULL ;
int flag = 0 ;
2006-08-07 21:15:28 +00:00
2010-06-15 17:06:23 +00:00
client = ASTOBJ_CONTAINER_FIND ( & clients , label ) ;
2006-08-07 21:15:28 +00:00
if ( ! client ) {
2006-05-22 21:12:30 +00:00
flag = 1 ;
2007-06-06 21:20:11 +00:00
client = ast_calloc ( 1 , sizeof ( * client ) ) ;
2006-08-07 21:15:28 +00:00
if ( ! client ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
return 0 ;
}
2006-08-07 21:15:28 +00:00
ASTOBJ_INIT ( client ) ;
ASTOBJ_WRLOCK ( client ) ;
ASTOBJ_CONTAINER_INIT ( & client - > buddies ) ;
2006-05-22 21:12:30 +00:00
} else {
ASTOBJ_WRLOCK ( client ) ;
ASTOBJ_UNMARK ( client ) ;
}
ASTOBJ_CONTAINER_MARKALL ( & client - > buddies ) ;
ast_copy_string ( client - > name , label , sizeof ( client - > name ) ) ;
ast_copy_string ( client - > mid , " aaaaa " , sizeof ( client - > mid ) ) ;
2011-06-01 21:31:40 +00:00
ast_copy_string ( client - > context , " default " , sizeof ( client - > context ) ) ;
2006-05-22 21:12:30 +00:00
2007-06-07 09:57:52 +00:00
/* Set default values for the client object */
2006-05-22 21:12:30 +00:00
client - > debug = debug ;
2008-02-12 14:08:58 +00:00
ast_copy_flags ( & client - > flags , & globalflags , AST_FLAGS_ALL ) ;
2006-05-22 21:12:30 +00:00
client - > port = 5222 ;
client - > usetls = 1 ;
2006-06-07 22:43:20 +00:00
client - > usesasl = 1 ;
2006-05-22 21:12:30 +00:00
client - > forcessl = 0 ;
client - > keepalive = 1 ;
2006-09-19 23:57:04 +00:00
client - > timeout = 50 ;
2009-09-25 10:54:42 +00:00
client - > message_timeout = 5 ;
2010-06-15 17:06:23 +00:00
client - > distribute_events = 0 ;
2006-06-09 16:08:33 +00:00
AST_LIST_HEAD_INIT ( & client - > messages ) ;
2006-09-21 23:55:13 +00:00
client - > component = 0 ;
2006-06-01 07:49:47 +00:00
ast_copy_string ( client - > statusmessage , " Online and Available " , sizeof ( client - > statusmessage ) ) ;
2007-10-07 16:28:25 +00:00
client - > priority = 0 ;
client - > status = IKS_SHOW_AVAILABLE ;
2011-06-01 21:31:40 +00:00
client - > send_to_dialplan = 0 ;
2006-06-01 07:49:47 +00:00
2006-08-07 21:15:28 +00:00
if ( flag ) {
client - > authorized = 0 ;
client - > state = AJI_DISCONNECTED ;
}
2006-05-22 21:12:30 +00:00
while ( var ) {
2010-06-15 17:06:23 +00:00
if ( ! strcasecmp ( var - > name , " username " ) ) {
2006-05-22 21:12:30 +00:00
ast_copy_string ( client - > user , var - > value , sizeof ( client - > user ) ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " serverhost " ) ) {
2006-05-22 21:12:30 +00:00
ast_copy_string ( client - > serverhost , var - > value , sizeof ( client - > serverhost ) ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " secret " ) ) {
2006-05-22 21:12:30 +00:00
ast_copy_string ( client - > password , var - > value , sizeof ( client - > password ) ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " statusmessage " ) ) {
2006-06-01 07:49:47 +00:00
ast_copy_string ( client - > statusmessage , var - > value , sizeof ( client - > statusmessage ) ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " port " ) ) {
2006-05-22 21:12:30 +00:00
client - > port = atoi ( var - > value ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " timeout " ) ) {
2006-06-07 22:43:20 +00:00
client - > message_timeout = atoi ( var - > value ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " debug " ) ) {
2006-05-22 21:12:30 +00:00
client - > debug = ( ast_false ( var - > value ) ) ? 0 : 1 ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " type " ) ) {
if ( ! strcasecmp ( var - > value , " component " ) ) {
2006-09-21 23:55:13 +00:00
client - > component = 1 ;
2010-06-15 17:06:23 +00:00
if ( client - > distribute_events ) {
ast_log ( LOG_ERROR , " Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled. \n " ) ;
client - > distribute_events = 0 ;
}
}
} else if ( ! strcasecmp ( var - > name , " distribute_events " ) ) {
if ( ast_true ( var - > value ) ) {
if ( client - > component ) {
ast_log ( LOG_ERROR , " Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled. \n " ) ;
} else {
if ( ast_test_flag ( & pubsubflags , AJI_PUBSUB ) ) {
ast_log ( LOG_ERROR , " Only one connection can be configured for distributed events. \n " ) ;
} else {
ast_set_flag ( & pubsubflags , AJI_PUBSUB ) ;
client - > distribute_events = 1 ;
}
}
}
} else if ( ! strcasecmp ( var - > name , " pubsub_node " ) ) {
ast_copy_string ( client - > pubsub_node , var - > value , sizeof ( client - > pubsub_node ) ) ;
2006-05-22 21:12:30 +00:00
} else if ( ! strcasecmp ( var - > name , " usetls " ) ) {
client - > usetls = ( ast_false ( var - > value ) ) ? 0 : 1 ;
} else if ( ! strcasecmp ( var - > name , " usesasl " ) ) {
client - > usesasl = ( ast_false ( var - > value ) ) ? 0 : 1 ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " forceoldssl " ) ) {
2006-05-22 21:12:30 +00:00
client - > forcessl = ( ast_false ( var - > value ) ) ? 0 : 1 ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " keepalive " ) ) {
2006-05-22 21:12:30 +00:00
client - > keepalive = ( ast_false ( var - > value ) ) ? 0 : 1 ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " autoprune " ) ) {
2008-02-12 14:08:58 +00:00
ast_set2_flag ( & client - > flags , ast_true ( var - > value ) , AJI_AUTOPRUNE ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " autoregister " ) ) {
2008-02-12 14:08:58 +00:00
ast_set2_flag ( & client - > flags , ast_true ( var - > value ) , AJI_AUTOREGISTER ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " auth_policy " ) ) {
2009-12-16 20:25:27 +00:00
if ( ! strcasecmp ( var - > value , " accept " ) ) {
ast_set_flag ( & client - > flags , AJI_AUTOACCEPT ) ;
} else {
ast_clear_flag ( & client - > flags , AJI_AUTOACCEPT ) ;
}
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " buddy " ) ) {
2007-11-14 15:13:22 +00:00
aji_create_buddy ( ( char * ) var - > value , client ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " priority " ) ) {
2007-10-07 16:28:25 +00:00
client - > priority = atoi ( var - > value ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " status " ) ) {
if ( ! strcasecmp ( var - > value , " unavailable " ) ) {
2007-10-07 16:28:25 +00:00
client - > status = IKS_SHOW_UNAVAILABLE ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > value , " available " )
| | ! strcasecmp ( var - > value , " online " ) ) {
2007-10-07 16:28:25 +00:00
client - > status = IKS_SHOW_AVAILABLE ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > value , " chat " )
| | ! strcasecmp ( var - > value , " chatty " ) ) {
2007-10-07 16:28:25 +00:00
client - > status = IKS_SHOW_CHAT ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > value , " away " ) ) {
2007-10-07 16:28:25 +00:00
client - > status = IKS_SHOW_AWAY ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > value , " xa " )
| | ! strcasecmp ( var - > value , " xaway " ) ) {
2007-10-07 16:28:25 +00:00
client - > status = IKS_SHOW_XA ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > value , " dnd " ) ) {
2007-10-07 16:28:25 +00:00
client - > status = IKS_SHOW_DND ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > value , " invisible " ) ) {
2007-10-07 16:28:25 +00:00
# ifdef IKS_SHOW_INVISIBLE
client - > status = IKS_SHOW_INVISIBLE ;
# else
ast_log ( LOG_WARNING , " Your iksemel doesn't support invisible status: falling back to DND \n " ) ;
client - > status = IKS_SHOW_DND ;
# endif
2010-06-15 17:06:23 +00:00
} else {
2007-10-07 16:28:25 +00:00
ast_log ( LOG_WARNING , " Unknown presence status: %s \n " , var - > value ) ;
2010-06-15 17:06:23 +00:00
}
2011-06-01 21:31:40 +00:00
} else if ( ! strcasecmp ( var - > name , " context " ) ) {
ast_copy_string ( client - > context , var - > value , sizeof ( client - > context ) ) ;
} else if ( ! strcasecmp ( var - > name , " sendtodialplan " ) ) {
client - > send_to_dialplan = ast_true ( var - > value ) ? 1 : 0 ;
2007-10-07 16:28:25 +00:00
}
2006-10-03 00:07:45 +00:00
/* no transport support in this version */
/* else if (!strcasecmp(var->name, "transport"))
2006-05-22 21:12:30 +00:00
aji_create_transport ( var - > value , client ) ;
2006-10-03 00:07:45 +00:00
*/
2006-05-22 21:12:30 +00:00
var = var - > next ;
}
2006-08-07 21:15:28 +00:00
if ( ! flag ) {
2006-05-22 21:12:30 +00:00
ASTOBJ_UNLOCK ( client ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2006-08-07 21:15:28 +00:00
return 1 ;
}
2007-11-01 22:10:33 +00:00
ast_copy_string ( client - > name_space , ( client - > component ) ? " jabber:component:accept " : " jabber:client " , sizeof ( client - > name_space ) ) ;
client - > p = iks_stream_new ( client - > name_space , client , aji_act_hook ) ;
2006-08-07 21:15:28 +00:00
if ( ! client - > p ) {
ast_log ( LOG_ERROR , " Failed to create stream for client '%s'! \n " , client - > name ) ;
return 0 ;
}
client - > stack = iks_stack_new ( 8192 , 8192 ) ;
if ( ! client - > stack ) {
ast_log ( LOG_ERROR , " Failed to allocate stack for client '%s' \n " , client - > name ) ;
return 0 ;
2006-05-22 21:12:30 +00:00
}
2006-08-07 21:15:28 +00:00
client - > f = iks_filter_new ( ) ;
if ( ! client - > f ) {
ast_log ( LOG_ERROR , " Failed to create filter for client '%s' \n " , client - > name ) ;
return 0 ;
}
2006-09-21 23:55:13 +00:00
if ( ! strchr ( client - > user , ' / ' ) & & ! client - > component ) { /*client */
2012-08-21 21:01:11 +00:00
if ( ast_asprintf ( & resource , " %s/asterisk " , client - > user ) > = 0 ) {
2006-08-07 21:15:28 +00:00
client - > jid = iks_id_new ( client - > stack , resource ) ;
2007-06-06 21:20:11 +00:00
ast_free ( resource ) ;
2006-08-07 21:15:28 +00:00
}
2010-06-15 17:06:23 +00:00
} else {
2006-08-07 21:15:28 +00:00
client - > jid = iks_id_new ( client - > stack , client - > user ) ;
2010-06-15 17:06:23 +00:00
}
2006-09-21 23:55:13 +00:00
if ( client - > component ) {
2006-08-07 21:15:28 +00:00
iks_filter_add_rule ( client - > f , aji_dinfo_handler , client , IKS_RULE_NS , " http://jabber.org/protocol/disco#info " , IKS_RULE_DONE ) ;
iks_filter_add_rule ( client - > f , aji_ditems_handler , client , IKS_RULE_NS , " http://jabber.org/protocol/disco#items " , IKS_RULE_DONE ) ;
iks_filter_add_rule ( client - > f , aji_register_query_handler , client , IKS_RULE_SUBTYPE , IKS_TYPE_GET , IKS_RULE_NS , " jabber:iq:register " , IKS_RULE_DONE ) ;
iks_filter_add_rule ( client - > f , aji_register_approve_handler , client , IKS_RULE_SUBTYPE , IKS_TYPE_SET , IKS_RULE_NS , " jabber:iq:register " , IKS_RULE_DONE ) ;
} else {
iks_filter_add_rule ( client - > f , aji_client_info_handler , client , IKS_RULE_NS , " http://jabber.org/protocol/disco#info " , IKS_RULE_DONE ) ;
}
2010-06-15 17:06:23 +00:00
2006-08-07 21:15:28 +00:00
iks_set_log_hook ( client - > p , aji_log_hook ) ;
ASTOBJ_UNLOCK ( client ) ;
2010-06-15 17:06:23 +00:00
ASTOBJ_CONTAINER_LINK ( & clients , client ) ;
2006-05-22 21:12:30 +00:00
return 1 ;
}
2010-06-15 17:06:23 +00:00
2007-10-04 16:56:00 +00:00
#if 0
2006-05-22 21:12:30 +00:00
/*!
* \ brief creates transport .
* \ param label , buddy to dump it into .
* \ return 0.
*/
2006-10-03 00:07:45 +00:00
/* no connecting to transports today */
2006-05-22 21:12:30 +00:00
static int aji_create_transport ( char * label , struct aji_client * client )
{
char * server = NULL , * buddyname = NULL , * user = NULL , * pass = NULL ;
struct aji_buddy * buddy = NULL ;
2011-11-23 17:16:33 +00:00
int needs_unref = 1 ;
2006-05-22 21:12:30 +00:00
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , label ) ;
if ( ! buddy ) {
2011-11-23 17:16:33 +00:00
needs_unref = 0 ;
2007-06-06 21:20:11 +00:00
buddy = ast_calloc ( 1 , sizeof ( * buddy ) ) ;
2009-09-25 10:54:42 +00:00
if ( ! buddy ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
return 0 ;
}
2006-08-07 21:15:28 +00:00
ASTOBJ_INIT ( buddy ) ;
2006-05-22 21:12:30 +00:00
}
ASTOBJ_WRLOCK ( buddy ) ;
server = label ;
if ( ( buddyname = strchr ( label , ' , ' ) ) ) {
* buddyname = ' \0 ' ;
buddyname + + ;
if ( buddyname & & buddyname [ 0 ] ! = ' \0 ' ) {
if ( ( user = strchr ( buddyname , ' , ' ) ) ) {
* user = ' \0 ' ;
user + + ;
if ( user & & user [ 0 ] ! = ' \0 ' ) {
if ( ( pass = strchr ( user , ' , ' ) ) ) {
* pass = ' \0 ' ;
pass + + ;
ast_copy_string ( buddy - > pass , pass , sizeof ( buddy - > pass ) ) ;
ast_copy_string ( buddy - > user , user , sizeof ( buddy - > user ) ) ;
ast_copy_string ( buddy - > name , buddyname , sizeof ( buddy - > name ) ) ;
ast_copy_string ( buddy - > server , server , sizeof ( buddy - > server ) ) ;
2011-11-23 17:16:33 +00:00
if ( needs_unref ) {
ASTOBJ_UNMARK ( buddy ) ;
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
}
2006-05-22 21:12:30 +00:00
return 1 ;
}
}
}
}
}
ASTOBJ_UNLOCK ( buddy ) ;
2011-11-23 17:16:33 +00:00
if ( needs_unref ) {
ASTOBJ_UNMARK ( buddy ) ;
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
} else {
ASTOBJ_CONTAINER_LINK ( & client - > buddies , buddy ) ;
}
2006-05-22 21:12:30 +00:00
return 0 ;
}
2007-10-04 16:56:00 +00:00
# endif
2006-05-22 21:12:30 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2006-05-22 21:12:30 +00:00
* \ brief creates buddy .
2007-06-07 21:22:25 +00:00
* \ param label char .
2007-11-01 22:10:33 +00:00
* \ param client the configured XMPP client we use to connect to a XMPP server
2007-06-07 21:22:25 +00:00
* \ return 1 on success , 0 on failure .
2006-05-22 21:12:30 +00:00
*/
static int aji_create_buddy ( char * label , struct aji_client * client )
{
struct aji_buddy * buddy = NULL ;
2011-11-23 17:16:33 +00:00
int needs_unref = 1 ;
2010-06-15 17:06:23 +00:00
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , label ) ;
2006-05-22 21:12:30 +00:00
if ( ! buddy ) {
2011-11-23 17:16:33 +00:00
needs_unref = 0 ;
2007-06-06 21:20:11 +00:00
buddy = ast_calloc ( 1 , sizeof ( * buddy ) ) ;
2009-09-25 10:54:42 +00:00
if ( ! buddy ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
return 0 ;
}
2006-08-07 21:15:28 +00:00
ASTOBJ_INIT ( buddy ) ;
2006-05-22 21:12:30 +00:00
}
ASTOBJ_WRLOCK ( buddy ) ;
ast_copy_string ( buddy - > name , label , sizeof ( buddy - > name ) ) ;
ASTOBJ_UNLOCK ( buddy ) ;
2011-11-23 17:16:33 +00:00
if ( needs_unref ) {
2006-06-01 08:22:44 +00:00
ASTOBJ_UNMARK ( buddy ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( buddy , ast_aji_buddy_destroy ) ;
} else {
ASTOBJ_CONTAINER_LINK ( & client - > buddies , buddy ) ;
2006-06-01 08:22:44 +00:00
}
2006-05-22 21:12:30 +00:00
return 1 ;
}
2007-06-07 21:22:25 +00:00
/*!< load config file. \return 1. */
2007-08-16 21:09:46 +00:00
static int aji_load_config ( int reload )
2006-05-22 21:12:30 +00:00
{
char * cat = NULL ;
2010-10-01 17:22:30 +00:00
int debug = 0 ;
2006-05-22 21:12:30 +00:00
struct ast_config * cfg = NULL ;
struct ast_variable * var = NULL ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 } ;
2010-06-15 17:06:23 +00:00
if ( ( cfg = ast_config_load ( JABBER_CONFIG , config_flags ) ) = = CONFIG_STATUS_FILEUNCHANGED ) {
2007-08-16 21:09:46 +00:00
return - 1 ;
2010-06-15 17:06:23 +00:00
}
2006-05-22 21:12:30 +00:00
2007-02-20 07:48:12 +00:00
/* Reset flags to default value */
2009-12-16 20:25:27 +00:00
ast_set_flag ( & globalflags , AJI_AUTOREGISTER | AJI_AUTOACCEPT ) ;
2007-02-20 07:48:12 +00:00
2008-09-12 23:30:03 +00:00
if ( cfg = = CONFIG_STATUS_FILEMISSING | | cfg = = CONFIG_STATUS_FILEINVALID ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_WARNING , " No such configuration file %s \n " , JABBER_CONFIG ) ;
return 0 ;
}
cat = ast_category_browse ( cfg , NULL ) ;
for ( var = ast_variable_browse ( cfg , " general " ) ; var ; var = var - > next ) {
2008-09-09 22:08:56 +00:00
if ( ! strcasecmp ( var - > name , " debug " ) ) {
2006-05-22 21:12:30 +00:00
debug = ( ast_false ( ast_variable_retrieve ( cfg , " general " , " debug " ) ) ) ? 0 : 1 ;
2008-09-09 22:08:56 +00:00
} else if ( ! strcasecmp ( var - > name , " autoprune " ) ) {
2006-05-22 21:12:30 +00:00
ast_set2_flag ( & globalflags , ast_true ( var - > value ) , AJI_AUTOPRUNE ) ;
2008-09-09 22:08:56 +00:00
} else if ( ! strcasecmp ( var - > name , " autoregister " ) ) {
2006-05-22 21:12:30 +00:00
ast_set2_flag ( & globalflags , ast_true ( var - > value ) , AJI_AUTOREGISTER ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! strcasecmp ( var - > name , " collection_nodes " ) ) {
ast_set2_flag ( & pubsubflags , ast_true ( var - > value ) , AJI_XEP0248 ) ;
} else if ( ! strcasecmp ( var - > name , " pubsub_autocreate " ) ) {
ast_set2_flag ( & pubsubflags , ast_true ( var - > value ) , AJI_PUBSUB_AUTOCREATE ) ;
2009-12-16 20:25:27 +00:00
} else if ( ! strcasecmp ( var - > name , " auth_policy " ) ) {
if ( ! strcasecmp ( var - > value , " accept " ) ) {
ast_set_flag ( & globalflags , AJI_AUTOACCEPT ) ;
} else {
ast_clear_flag ( & globalflags , AJI_AUTOACCEPT ) ;
}
2008-09-09 22:08:56 +00:00
}
2006-05-22 21:12:30 +00:00
}
while ( cat ) {
if ( strcasecmp ( cat , " general " ) ) {
2010-06-15 17:06:23 +00:00
var = ast_variable_browse ( cfg , cat ) ;
aji_create_client ( cat , var , debug ) ;
2006-05-22 21:12:30 +00:00
}
cat = ast_category_browse ( cfg , cat ) ;
}
2007-11-07 22:09:10 +00:00
ast_config_destroy ( cfg ) ; /* or leak memory */
2006-05-22 21:12:30 +00:00
return 1 ;
}
/*!
2011-11-23 17:16:33 +00:00
* \ brief grab a aji_client structure by label name or JID . Bumps the refcount .
2008-06-02 14:35:24 +00:00
* ( without the resource string )
2010-06-15 17:06:23 +00:00
* \ param name label or JID
2007-06-07 21:22:25 +00:00
* \ return aji_client .
2006-05-22 21:12:30 +00:00
*/
2007-01-05 22:43:18 +00:00
struct aji_client * ast_aji_get_client ( const char * name )
2006-05-22 21:12:30 +00:00
{
struct aji_client * client = NULL ;
2008-06-02 14:35:24 +00:00
char * aux = NULL ;
2006-08-07 21:15:28 +00:00
2006-05-22 21:12:30 +00:00
client = ASTOBJ_CONTAINER_FIND ( & clients , name ) ;
2008-06-02 14:35:24 +00:00
if ( ! client & & strchr ( name , ' @ ' ) ) {
ASTOBJ_CONTAINER_TRAVERSE ( & clients , 1 , {
aux = ast_strdupa ( iterator - > user ) ;
if ( strchr ( aux , ' / ' ) ) {
/* strip resource for comparison */
aux = strsep ( & aux , " / " ) ;
}
2008-06-05 17:02:39 +00:00
if ( ! strncasecmp ( aux , name , strlen ( aux ) ) ) {
2011-11-23 17:16:33 +00:00
client = ASTOBJ_REF ( iterator ) ;
2010-06-15 17:06:23 +00:00
}
2008-06-02 14:35:24 +00:00
} ) ;
}
2006-05-22 21:12:30 +00:00
return client ;
}
struct aji_client_container * ast_aji_get_clients ( void )
{
return & clients ;
}
2010-06-15 17:06:23 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
2010-06-15 17:06:23 +00:00
* \ brief Send a Jabber Message via call from the Manager
2007-06-07 21:22:25 +00:00
* \ param s mansession Manager session
* \ param m message Message to send
* \ return 0
*/
2007-01-05 22:43:18 +00:00
static int manager_jabber_send ( struct mansession * s , const struct message * m )
2006-08-07 22:03:50 +00:00
{
struct aji_client * client = NULL ;
2010-06-15 17:06:23 +00:00
const char * id = astman_get_header ( m , " ActionID " ) ;
const char * jabber = astman_get_header ( m , " Jabber " ) ;
const char * screenname = astman_get_header ( m , " ScreenName " ) ;
const char * message = astman_get_header ( m , " Message " ) ;
2006-08-07 22:03:50 +00:00
if ( ast_strlen_zero ( jabber ) ) {
astman_send_error ( s , m , " No transport specified " ) ;
return 0 ;
}
if ( ast_strlen_zero ( screenname ) ) {
astman_send_error ( s , m , " No ScreenName specified " ) ;
return 0 ;
}
if ( ast_strlen_zero ( message ) ) {
astman_send_error ( s , m , " No Message specified " ) ;
return 0 ;
}
astman_send_ack ( s , m , " Attempting to send Jabber Message " ) ;
client = ast_aji_get_client ( jabber ) ;
if ( ! client ) {
astman_send_error ( s , m , " Could not find Sender " ) ;
return 0 ;
2009-05-30 19:38:58 +00:00
}
if ( strchr ( screenname , ' @ ' ) & & message ) {
ast_aji_send_chat ( client , screenname , message ) ;
2007-11-27 21:10:50 +00:00
astman_append ( s , " Response: Success \r \n " ) ;
2009-05-30 19:38:58 +00:00
} else {
astman_append ( s , " Response: Error \r \n " ) ;
2006-08-07 22:03:50 +00:00
}
2011-11-23 17:16:33 +00:00
ASTOBJ_UNREF ( client , ast_aji_client_destroy ) ;
2009-05-30 19:38:58 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2010-06-15 17:06:23 +00:00
astman_append ( s , " ActionID: %s \r \n " , id ) ;
2009-05-30 19:38:58 +00:00
}
astman_append ( s , " \r \n " ) ;
2006-08-07 22:03:50 +00:00
return 0 ;
}
2010-06-15 17:06:23 +00:00
/*!
2009-09-25 10:54:42 +00:00
* \ internal
* \ brief Reload the jabber module
*/
2007-08-16 21:09:46 +00:00
static int aji_reload ( int reload )
2006-05-22 21:12:30 +00:00
{
2007-08-16 21:09:46 +00:00
int res ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_MARKALL ( & clients ) ;
2007-08-16 21:09:46 +00:00
if ( ! ( res = aji_load_config ( reload ) ) ) {
2006-05-22 21:12:30 +00:00
ast_log ( LOG_ERROR , " JABBER: Failed to load config. \n " ) ;
2006-08-31 21:00:20 +00:00
return 0 ;
2007-08-16 21:09:46 +00:00
} else if ( res = = - 1 )
return 1 ;
2011-11-23 17:16:33 +00:00
ASTOBJ_CONTAINER_PRUNE_MARKED ( & clients , ast_aji_client_destroy ) ;
2006-08-31 21:00:20 +00:00
ASTOBJ_CONTAINER_TRAVERSE ( & clients , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
2009-09-25 10:54:42 +00:00
if ( iterator - > state = = AJI_DISCONNECTED ) {
2006-08-31 21:00:20 +00:00
if ( ! iterator - > thread )
2006-10-04 19:51:38 +00:00
ast_pthread_create_background ( & iterator - > thread , NULL , aji_recv_loop , iterator ) ;
2010-06-15 17:06:23 +00:00
} else if ( iterator - > state = = AJI_CONNECTING ) {
2006-08-31 21:00:20 +00:00
aji_get_roster ( iterator ) ;
2010-06-15 17:06:23 +00:00
if ( iterator - > distribute_events ) {
aji_init_event_distribution ( iterator ) ;
}
}
2006-08-31 21:00:20 +00:00
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
2010-06-15 17:06:23 +00:00
2006-08-31 21:00:20 +00:00
return 1 ;
2006-05-22 21:12:30 +00:00
}
2009-09-25 10:54:42 +00:00
/*!
* \ internal
* \ brief Unload the jabber module
*/
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
2006-05-22 21:12:30 +00:00
{
2011-06-01 21:31:40 +00:00
ast_msg_tech_unregister ( & msg_tech ) ;
2008-12-05 10:31:25 +00:00
ast_cli_unregister_multiple ( aji_cli , ARRAY_LEN ( aji_cli ) ) ;
2006-06-07 22:43:20 +00:00
ast_unregister_application ( app_ajisend ) ;
2009-12-07 17:59:46 +00:00
ast_unregister_application ( app_ajisendgroup ) ;
2006-10-19 17:25:43 +00:00
ast_unregister_application ( app_ajistatus ) ;
2009-12-07 17:59:46 +00:00
ast_unregister_application ( app_ajijoin ) ;
ast_unregister_application ( app_ajileave ) ;
2006-08-07 22:03:50 +00:00
ast_manager_unregister ( " JabberSend " ) ;
2007-10-04 16:56:00 +00:00
ast_custom_function_unregister ( & jabberstatus_function ) ;
2013-05-17 21:10:32 +00:00
mwi_sub = stasis_unsubscribe_and_join ( mwi_sub ) ;
device_state_sub = stasis_unsubscribe_and_join ( device_state_sub ) ;
2009-09-25 10:54:42 +00:00
ast_custom_function_unregister ( & jabberreceive_function ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_TRAVERSE ( & clients , 1 , {
2010-10-15 16:54:07 +00:00
ASTOBJ_WRLOCK ( iterator ) ;
2007-11-01 22:10:33 +00:00
ast_debug ( 3 , " JABBER: Releasing and disconnecting client: %s \n " , iterator - > name ) ;
2007-06-07 09:21:29 +00:00
iterator - > state = AJI_DISCONNECTING ;
2006-05-22 21:12:30 +00:00
ASTOBJ_UNLOCK ( iterator ) ;
2010-10-15 16:54:07 +00:00
pthread_join ( iterator - > thread , NULL ) ;
ast_aji_disconnect ( iterator ) ;
2006-05-22 21:12:30 +00:00
} ) ;
2011-11-23 17:16:33 +00:00
ASTOBJ_CONTAINER_DESTROYALL ( & clients , ast_aji_client_destroy ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_DESTROY ( & clients ) ;
2009-09-25 10:54:42 +00:00
ast_cond_destroy ( & message_received_condition ) ;
ast_mutex_destroy ( & messagelock ) ;
2006-05-22 21:12:30 +00:00
return 0 ;
}
2009-09-25 10:54:42 +00:00
/*!
* \ internal
* \ brief Unload the jabber module
*/
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2006-05-22 21:12:30 +00:00
{
ASTOBJ_CONTAINER_INIT ( & clients ) ;
2009-09-25 10:54:42 +00:00
if ( ! aji_reload ( 0 ) )
2006-08-31 21:00:20 +00:00
return AST_MODULE_LOAD_DECLINE ;
2009-06-01 16:09:42 +00:00
ast_manager_register_xml ( " JabberSend " , EVENT_FLAG_SYSTEM , manager_jabber_send ) ;
2009-02-04 21:26:15 +00:00
ast_register_application_xml ( app_ajisend , aji_send_exec ) ;
2009-12-07 17:59:46 +00:00
ast_register_application_xml ( app_ajisendgroup , aji_sendgroup_exec ) ;
2009-02-04 21:26:15 +00:00
ast_register_application_xml ( app_ajistatus , aji_status_exec ) ;
2010-06-15 17:06:23 +00:00
ast_register_application_xml ( app_ajijoin , aji_join_exec ) ;
ast_register_application_xml ( app_ajileave , aji_leave_exec ) ;
2008-12-05 10:31:25 +00:00
ast_cli_register_multiple ( aji_cli , ARRAY_LEN ( aji_cli ) ) ;
2007-10-04 16:56:00 +00:00
ast_custom_function_register ( & jabberstatus_function ) ;
2009-09-25 10:54:42 +00:00
ast_custom_function_register ( & jabberreceive_function ) ;
2011-06-01 21:31:40 +00:00
ast_msg_tech_register ( & msg_tech ) ;
2006-08-07 21:15:28 +00:00
2009-09-25 10:54:42 +00:00
ast_mutex_init ( & messagelock ) ;
ast_cond_init ( & message_received_condition , NULL ) ;
2006-05-22 21:12:30 +00:00
return 0 ;
}
2009-09-25 10:54:42 +00:00
/*!
* \ internal
* \ brief Wrapper for aji_reload
*/
2006-08-21 02:11:39 +00:00
static int reload ( void )
2006-05-22 21:12:30 +00:00
{
2007-08-16 21:09:46 +00:00
aji_reload ( 1 ) ;
2006-05-22 21:12:30 +00:00
return 0 ;
}
2010-07-20 19:35:02 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , " AJI - Asterisk Jabber Interface " ,
2006-08-21 02:11:39 +00:00
. load = load_module ,
. unload = unload_module ,
. reload = reload ,
2010-07-20 19:35:02 +00:00
. load_pri = AST_MODPRI_CHANNEL_DEPEND ,
2006-08-21 02:11:39 +00:00
) ;