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
*
2008-01-08 20:58:56 +00:00
* \ extref 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
*/
/*** MODULEINFO
< depend > iksemel < / depend >
2011-07-05 22:11:40 +00:00
< use type = " external " > openssl < / use >
2011-07-14 20:28:54 +00:00
< support_level > extended < / support_level >
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/event.h"
# 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
< application name = " JabberSend " language = " en_US " >
< 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 >
< ref type = " function " > JABBER_STATUS < / ref >
< ref type = " function " > JABBER_RECEIVE < / ref >
< / see - also >
< / application >
< function name = " JABBER_RECEIVE " language = " en_US " >
< 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 >
< ref type = " function " > JABBER_STATUS < / ref >
< ref type = " application " > JabberSend < / ref >
< / see - also >
< / function >
< function name = " JABBER_STATUS " language = " en_US " >
< 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 >
< ref type = " function " > JABBER_RECEIVE < / ref >
< ref type = " application " > JabberSend < / ref >
< / see - also >
< / function >
2009-12-07 17:59:46 +00:00
< application name = " JabberSendGroup " language = " en_US " >
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 >
2009-12-07 17:59:46 +00:00
< application name = " JabberJoin " language = " en_US " >
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 >
2009-12-07 17:59:46 +00:00
< application name = " JabberLeave " language = " en_US " >
< 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 >
< application name = " JabberStatus " language = " en_US " >
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 >
2009-12-07 17:59:46 +00:00
< / application >
2009-06-01 16:09:42 +00:00
< manager name = " JabberSend " language = " en_US " >
< 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 ) ;
2006-05-22 21:12:30 +00:00
static void aji_buddy_destroy ( struct aji_buddy * obj ) ;
static void aji_client_destroy ( struct aji_client * 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 ) ;
static char * aji_test ( 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 ,
const char * device_state ) ;
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 ,
const char * context , const char * oldmsgs , const char * newmsgs ) ;
static void aji_devstate_cb ( const struct ast_event * ast_event , void * data ) ;
static void aji_mwi_cb ( const struct ast_event * ast_event , void * data ) ;
static iks * aji_build_publish_skeleton ( struct aji_client * client , const char * node ,
const char * event_type ) ;
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 " ) ,
AST_CLI_DEFINE ( aji_test , " Shows roster, but is generally used for mog's debugging. " ) ,
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 ;
2010-06-15 17:06:23 +00:00
static struct ast_event_sub * mwi_sub = NULL ;
static struct ast_event_sub * 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 .
*/
static void aji_client_destroy ( struct aji_client * obj )
{
2006-06-07 22:43:20 +00:00
struct aji_message * tmp ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_DESTROYALL ( & obj - > buddies , aji_buddy_destroy ) ;
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 .
*/
static void aji_buddy_destroy ( struct aji_buddy * obj )
{
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 ) ;
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
}
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 ) ;
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
}
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 )
{
char * aux = NULL , * parse = NULL ;
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 ;
}
client = ast_aji_get_client ( args . account ) ;
if ( ! client ) {
ast_log ( LOG_WARNING , " Could not find client %s, exiting \n " , args . account ) ;
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 ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
return - 1 ;
}
}
jidlen = strlen ( jid . screenname ) ;
resourcelen = ast_strlen_zero ( jid . resource ) ? 0 : strlen ( jid . resource ) ;
ast_debug ( 3 , " Waiting for an XMPP message from %s \n " , args . jid ) ;
start = ast_tvnow ( ) ;
if ( ast_autoservice_start ( chan ) < 0 ) {
ast_log ( LOG_WARNING , " Cannot start autoservice for channel %s \n " , chan - > name ) ;
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 ;
aux = ast_strdupa ( tmp - > message ) ;
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 ) ;
}
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
if ( ast_autoservice_stop ( chan ) < 0 ) {
ast_log ( LOG_WARNING , " Cannot stop autoservice for channel %s \n " , chan - > name ) ;
}
/* return if we timed out */
if ( ! found ) {
ast_log ( LOG_NOTICE , " Timed out : no message received from %s \n " , args . jid ) ;
return - 1 ;
}
ast_copy_string ( buf , aux , buflen ) ;
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
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 ( strchr ( args . jid , ' / ' ) ) {
ast_log ( LOG_ERROR , " Invalid room name : resource must not be appended \n " ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
2009-12-07 17:59:46 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
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 ( strchr ( args . jid , ' / ' ) ) {
ast_log ( LOG_ERROR , " Invalid room name, resource must not be appended \n " ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) {
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
}
2009-12-07 17:59:46 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
}
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 ) ;
}
/*
* XXX Reference leak here . See note with ast_aji_get_client ( ) about the problems
* with that function .
*/
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
2009-12-07 17:59:46 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ret ;
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 ) ;
2010-06-15 17:06:23 +00:00
if ( ! ( ret = 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 */
2010-06-15 17:06:23 +00:00
if ( ! ( ret = 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 */
2010-06-15 17:06:23 +00:00
if ( ( ret = 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 */
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
2010-06-15 17:06:23 +00:00
if ( ! ast_strlen_zero ( xmpp ) ) {
2007-04-09 18:13:30 +00:00
manager_event ( EVENT_FLAG_USER , " JabberEvent " , " Account: %s \r \n Packet: %s \r \n " , client - > name , xmpp ) ;
2010-06-15 17:06:23 +00:00
}
2006-08-07 21:15:28 +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
}
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
}
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 ;
2007-10-04 16:56:00 +00:00
s = alloca ( len ) ;
2007-10-15 13:51:21 +00:00
base64 = 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 */
2006-09-19 23:57:04 +00:00
ASTOBJ_UNREF ( client , 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 ) {
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 " ) ;
2008-06-27 07:28:17 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 " ) ;
2007-11-01 22:10:33 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
return IKS_HOOK ;
}
2008-06-27 07:28:17 +00:00
# endif
2006-05-22 21:12:30 +00:00
break ;
}
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 ) {
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 " ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
return IKS_HOOK ;
break ;
case IKS_NODE_STOP :
ast_log ( LOG_WARNING , " JABBER: Disconnected \n " ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) ;
handshake = NULL ;
2008-11-02 18:52:13 +00:00
if ( 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-05-22 21:12:30 +00:00
handshake = NULL ;
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 " ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
return IKS_HOOK ;
case IKS_NODE_STOP :
ast_log ( LOG_WARNING , " JABBER: Disconnected \n " ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 :
2007-10-04 16:56:00 +00:00
ast_debug ( 1 , " JABBER: I don't know anything about paktype '%d' \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 ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
2006-05-22 21:12:30 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ;
2006-05-22 21:12:30 +00:00
char * node = 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 ) ;
2010-06-15 17:06:23 +00:00
} else if ( ! ( node = 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 ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
}
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
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 ) ;
2006-06-07 22:43:20 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) ;
}
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) ;
resource = aji_find_resource ( buddy , pak - > from - > resource ) ;
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 " ) ;
2006-09-19 23:57:04 +00:00
return IKS_FILTER_EAT ;
}
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 ) ;
2006-10-03 22:36:51 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
}
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) {
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 " ) ;
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 ) ;
ASTOBJ_UNREF ( buddy , 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 :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: I am available ^_* %i \n " , pak - > subtype ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_TYPE_UNAVAILABLE :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: I am unavailable ^_* %i \n " , pak - > subtype ) ;
2007-10-07 15:56:22 +00:00
break ;
default :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: Ohh sexy and the wrong type: %i \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 :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: type: %i subtype %i \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 :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: type: %i subtype %i \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 :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
2007-10-07 15:56:22 +00:00
break ;
case IKS_SHOW_DND :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
2007-10-07 15:56:22 +00:00
break ;
default :
2008-08-06 13:34:08 +00:00
ast_debug ( 3 , " JABBER: Kinky! how did that happen %i \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 " ,
2010-03-18 15:59:19 +00:00
" Account: %s \r \n JID: %s \r \n Status: %d \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 ) ;
}
default :
if ( option_verbose > 4 ) {
ast_verbose ( VERBOSE_PREFIX_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 ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_PRUNE_MARKED ( & client - > buddies , aji_buddy_destroy ) ;
}
/*!
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 " ) ;
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 ) ;
} else if ( ! iks_strcmp ( iks_find_attrib ( x , " subscription " ) , " none " ) | | ! iks_strcmp ( iks_find_attrib ( x , " subscription " ) , " from " ) ) {
2009-09-25 10:54:42 +00:00
/* subscribe to buddy's presence only
2008-06-24 17:50:22 +00:00
if we really need to */
ast_set_flag ( & buddy - > flags , AJI_AUTOREGISTER ) ;
}
ASTOBJ_UNLOCK ( buddy ) ;
if ( buddy ) {
ASTOBJ_CONTAINER_LINK ( & client - > buddies , buddy ) ;
ASTOBJ_UNREF ( buddy , 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 ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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 ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
}
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
*/
static void aji_mwi_cb ( const struct ast_event * ast_event , void * data )
{
const char * mailbox ;
const char * context ;
char oldmsgs [ 10 ] ;
char newmsgs [ 10 ] ;
2010-06-15 18:16:04 +00:00
struct aji_client * client ;
2010-06-15 17:06:23 +00:00
if ( ast_eid_cmp ( & ast_eid_default , ast_event_get_ie_raw ( ast_event , AST_EVENT_IE_EID ) ) )
{
/* If the event didn't originate from this server, don't send it back out. */
2011-02-04 16:55:39 +00:00
ast_debug ( 1 , " Returning here \n " ) ;
2010-06-15 17:06:23 +00:00
return ;
}
2010-06-15 18:16:04 +00:00
client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2010-06-15 17:06:23 +00:00
mailbox = ast_event_get_ie_str ( ast_event , AST_EVENT_IE_MAILBOX ) ;
context = ast_event_get_ie_str ( ast_event , AST_EVENT_IE_CONTEXT ) ;
snprintf ( oldmsgs , sizeof ( oldmsgs ) , " %d " ,
ast_event_get_ie_uint ( ast_event , AST_EVENT_IE_OLDMSGS ) ) ;
snprintf ( newmsgs , sizeof ( newmsgs ) , " %d " ,
ast_event_get_ie_uint ( ast_event , AST_EVENT_IE_NEWMSGS ) ) ;
aji_publish_mwi ( client , mailbox , context , oldmsgs , newmsgs ) ;
}
/*!
* \ brief Callback function for device state events
* \ param ast_event
* \ param data void pointer to ast_client structure
* \ return void
*/
static void aji_devstate_cb ( const struct ast_event * ast_event , void * data )
{
const char * device ;
const char * device_state ;
2010-06-15 18:16:04 +00:00
struct aji_client * client ;
2010-06-15 17:06:23 +00:00
if ( ast_eid_cmp ( & ast_eid_default , ast_event_get_ie_raw ( ast_event , AST_EVENT_IE_EID ) ) )
{
/* If the event didn't originate from this server, don't send it back out. */
2011-02-04 16:55:39 +00:00
ast_debug ( 1 , " Returning here \n " ) ;
2010-06-15 17:06:23 +00:00
return ;
}
2010-06-15 18:16:04 +00:00
client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
2010-06-15 17:06:23 +00:00
device = ast_event_get_ie_str ( ast_event , AST_EVENT_IE_DEVICE ) ;
device_state = ast_devstate_str ( ast_event_get_ie_uint ( ast_event , AST_EVENT_IE_STATE ) ) ;
aji_publish_device_state ( client , device , device_state ) ;
}
/*!
* \ 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 ) {
mwi_sub = ast_event_subscribe ( AST_EVENT_MWI , aji_mwi_cb , " aji_mwi_subscription " ,
client , AST_EVENT_IE_END ) ;
}
if ( ! device_state_sub ) {
if ( ast_enable_distributed_devstate ( ) ) {
return ;
}
device_state_sub = ast_event_subscribe ( AST_EVENT_DEVICE_STATE_CHANGE ,
aji_devstate_cb , " aji_devstate_subscription " , client , AST_EVENT_IE_END ) ;
ast_event_dump_cache ( device_state_sub ) ;
}
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
* \ return IKS_FILTER_EAT
*/
static int aji_handle_pubsub_event ( void * data , ikspak * pak )
{
char * item_id , * device_state , * context ;
int oldmsgs , newmsgs ;
iks * item , * item_content ;
struct ast_eid pubsub_eid ;
struct ast_event * event ;
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 " ) ) {
device_state = iks_find_cdata ( item , " state " ) ;
if ( ! ( event = ast_event_new ( AST_EVENT_DEVICE_STATE_CHANGE ,
AST_EVENT_IE_DEVICE , AST_EVENT_IE_PLTYPE_STR , item_id , AST_EVENT_IE_STATE ,
AST_EVENT_IE_PLTYPE_UINT , ast_devstate_val ( device_state ) , AST_EVENT_IE_EID ,
AST_EVENT_IE_PLTYPE_RAW , & pubsub_eid , sizeof ( pubsub_eid ) ,
AST_EVENT_IE_END ) ) ) {
return IKS_FILTER_EAT ;
}
} else if ( ! strcasecmp ( iks_name ( item_content ) , " mailbox " ) ) {
context = strsep ( & item_id , " @ " ) ;
sscanf ( iks_find_cdata ( item_content , " OLDMSGS " ) , " %10d " , & oldmsgs ) ;
sscanf ( iks_find_cdata ( item_content , " NEWMSGS " ) , " %10d " , & newmsgs ) ;
if ( ! ( event = ast_event_new ( AST_EVENT_MWI , AST_EVENT_IE_MAILBOX ,
AST_EVENT_IE_PLTYPE_STR , item_id , AST_EVENT_IE_CONTEXT ,
AST_EVENT_IE_PLTYPE_STR , context , AST_EVENT_IE_OLDMSGS ,
AST_EVENT_IE_PLTYPE_UINT , oldmsgs , AST_EVENT_IE_NEWMSGS ,
AST_EVENT_IE_PLTYPE_UINT , newmsgs , AST_EVENT_IE_EID , AST_EVENT_IE_PLTYPE_RAW ,
& pubsub_eid , sizeof ( pubsub_eid ) , AST_EVENT_IE_END ) ) ) {
return IKS_FILTER_EAT ;
}
} 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 ;
}
ast_event_queue_and_cache ( event ) ;
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 ,
const char * event_type )
{
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 ) ;
return item ;
}
/*!
* \ 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 ,
const char * device_state )
{
iks * request = aji_build_publish_skeleton ( client , device , " device_state " ) ;
iks * state ;
char eid_str [ 20 ] ;
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 ) ;
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
* \ param device the name of the device whose state to publish
* \ param device_state the state to publish
* \ return void
*/
static void aji_publish_mwi ( struct aji_client * client , const char * mailbox ,
const char * context , const char * oldmsgs , const char * newmsgs )
{
char full_mailbox [ AST_MAX_EXTENSION + AST_MAX_CONTEXT ] ;
char eid_str [ 20 ] ;
2010-06-15 18:16:04 +00:00
iks * mailbox_node , * request ;
2010-06-15 17:06:23 +00:00
snprintf ( full_mailbox , sizeof ( full_mailbox ) , " %s@%s " , mailbox , context ) ;
2010-06-15 18:16:04 +00:00
request = aji_build_publish_skeleton ( client , full_mailbox , " message_waiting " ) ;
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 " ) ;
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
if ( ! orig_pubsub ) {
ast_log ( LOG_ERROR , " Error isn't a PubSub error, why are we here? \n " ) ;
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 ;
}
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 ) ;
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 ) ;
}
}
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 ) ;
}
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 ] ;
}
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 , " Listing pubsub nodes. \n " ) ;
aji_request_pubsub_nodes ( client , collection ) ;
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 ] ) ;
}
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 ] ) ;
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
* \ 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
* \ 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 ) ;
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 ) ;
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
2007-09-18 22:43:45 +00:00
* \ brief Send test message for debugging .
* \ return CLI_SUCCESS , CLI_FAILURE .
2006-05-22 21:12:30 +00:00
*/
2007-09-18 22:43:45 +00:00
static char * aji_test ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-05-22 21:12:30 +00:00
{
struct aji_client * client ;
struct aji_resource * resource ;
2010-11-26 18:31:48 +00:00
const char * name ;
2006-06-07 22:43:20 +00:00
struct aji_message * tmp ;
2006-08-07 21:15:28 +00:00
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " jabber test " ;
e - > usage =
2010-11-26 18:31:48 +00:00
" Usage: jabber test <connection> \n "
2007-09-18 22:43:45 +00:00
" Sends test message for debugging purposes. A specific client \n "
2010-11-26 18:31:48 +00:00
" as configured in jabber.conf must be specified. \n " ;
2007-09-18 22:43:45 +00:00
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2010-11-26 18:31:48 +00:00
if ( a - > argc ! = 3 ) {
2007-09-18 22:43:45 +00:00
return CLI_SHOWUSAGE ;
2010-06-15 17:06:23 +00:00
}
2010-11-26 18:31:48 +00:00
name = a - > argv [ 2 ] ;
2006-05-22 21:12:30 +00:00
if ( ! ( client = ASTOBJ_CONTAINER_FIND ( & clients , name ) ) ) {
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " Unable to find client '%s'! \n " , name ) ;
return CLI_FAILURE ;
2006-05-22 21:12:30 +00:00
}
2006-08-08 17:07:41 +00:00
/* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
2007-11-06 18:44:19 +00:00
ast_aji_send_chat ( client , " mogorman@astjab.org " , " blahblah " ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_TRAVERSE ( & client - > buddies , 1 , {
ASTOBJ_RDLOCK ( iterator ) ;
ast_verbose ( " User: %s \n " , iterator - > name ) ;
for ( resource = iterator - > resources ; resource ; resource = resource - > next ) {
ast_verbose ( " Resource: %s \n " , resource - > resource ) ;
2009-09-25 10:54:42 +00:00
if ( resource - > cap ) {
2006-05-22 21:12:30 +00:00
ast_verbose ( " client: %s \n " , resource - > cap - > parent - > node ) ;
ast_verbose ( " version: %s \n " , resource - > cap - > version ) ;
ast_verbose ( " Jingle Capable: %d \n " , resource - > cap - > jingle ) ;
}
ast_verbose ( " Priority: %d \n " , resource - > priority ) ;
2009-09-25 10:54:42 +00:00
ast_verbose ( " Status: %d \n " , resource - > status ) ;
2010-06-15 17:06:23 +00:00
ast_verbose ( " Message: %s \n " , S_OR ( resource - > description , " " ) ) ;
2006-05-22 21:12:30 +00:00
}
ASTOBJ_UNLOCK ( iterator ) ;
} ) ;
2006-06-07 22:43:20 +00:00
ast_verbose ( " \n Oooh a working message stack! \n " ) ;
2006-06-09 16:08:33 +00:00
AST_LIST_LOCK ( & client - > messages ) ;
AST_LIST_TRAVERSE ( & client - > messages , tmp , list ) {
2009-09-25 10:54:42 +00:00
//ast_verbose(" Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
2006-06-07 22:43:20 +00:00
}
2006-06-09 16:08:33 +00:00
AST_LIST_UNLOCK ( & client - > messages ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
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
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 ) ;
ASTOBJ_UNREF ( client , 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 */
2006-08-07 21:15:28 +00:00
resource = NULL ;
2008-11-02 18:52:13 +00:00
if ( 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 ;
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , label ) ;
if ( ! buddy ) {
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 ) ) ;
return 1 ;
}
}
}
}
}
ASTOBJ_UNLOCK ( buddy ) ;
2006-06-01 08:22:44 +00:00
ASTOBJ_UNMARK ( buddy ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_LINK ( & client - > buddies , buddy ) ;
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 ;
int flag = 0 ;
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 ) {
flag = 1 ;
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 ) ;
2010-06-15 17:06:23 +00:00
if ( flag ) {
2006-05-22 21:12:30 +00:00
ASTOBJ_CONTAINER_LINK ( & client - > buddies , buddy ) ;
2010-06-15 17:06:23 +00:00
} else {
2006-06-01 08:22:44 +00:00
ASTOBJ_UNMARK ( buddy ) ;
2006-05-22 21:12:30 +00:00
ASTOBJ_UNREF ( buddy , aji_buddy_destroy ) ;
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 ;
}
/*!
2010-06-15 17:06:23 +00:00
* \ brief grab a aji_client structure by label name or JID
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 .
2011-06-01 21:31:40 +00:00
*
* XXX \ bug This function leads to reference leaks all over the place .
* ASTOBJ_CONTAINER_FIND ( ) returns a reference , but if the
* client is found via the traversal , no reference is returned .
* None of the calling code releases references . This code needs
* to be changed to always return a reference , and all of the users
* need to be fixed to release them .
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 ) ) ) {
2008-06-02 14:35:24 +00:00
client = 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
}
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 ;
2006-08-31 21:00:20 +00:00
ASTOBJ_CONTAINER_PRUNE_MARKED ( & clients , aji_client_destroy ) ;
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 ) ;
2010-06-15 17:06:23 +00:00
if ( mwi_sub ) {
ast_event_unsubscribe ( mwi_sub ) ;
}
if ( device_state_sub ) {
ast_event_unsubscribe ( 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
} ) ;
ASTOBJ_CONTAINER_DESTROYALL ( & clients , aji_client_destroy ) ;
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
) ;