@ -17,12 +17,16 @@
*/
/*! \file
* \ brief A resource for interfacing asterisk directly as a client
* or a component to a jabber compliant server .
* \ 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
*
* \ extref Iksemel http : //code.google.com/p/iksemel/
*
* \ todo If you unload this module , chan_gtalk / jingle will be dead . How do we handle that ?
* \ todo Dialplan applications need RETURN variable , like JABBERSENDSTATUS
*
*/
@ -55,6 +59,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
# include "asterisk/astdb.h"
# include "asterisk/manager.h"
/*! \todo This should really be renamed to xmpp.conf. For backwards compatibility, we
need to read both files */
# define JABBER_CONFIG "jabber.conf"
# ifndef FALSE
@ -133,8 +139,8 @@ static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
static char * ajisend_descrip =
" JabberSend(Jabber,ScreenName,Message) \n "
" Jabber - Client or transport Asterisk uses to connect to Jabber \n "
" ScreenName - User Name to message. \n "
" Message - Message to be sent to the budd y\n " ;
" ScreenName - XMPP/Jabber JID (Name) of recipient \n "
" Message - Message to be sent to the budd (UTF8) y\n " ;
static char * app_ajistatus = " JabberStatus " ;
@ -145,8 +151,9 @@ static char *ajistatus_descrip =
" Jabber - Client or transport Asterisk uses to connect to Jabber \n "
" ScreenName - User Name to retrieve status from. \n "
" Variable - Variable to store presence in will be 1-6. \n "
" In order, Online, Chatty, Away, XAway, DND, Offline \n "
" If not in roster variable will = 7 \n " ;
" In order, 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline \n "
" If not in roster variable will be set to 7 \n \n "
" Note: This application is deprecated. Please use the JABBER_STATUS() function instead. \n " ;
struct aji_client_container clients ;
struct aji_capabilities * capabilities = NULL ;
@ -407,13 +414,13 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha
) ;
if ( ! data ) {
ast_log ( LOG_ERROR , " Usage: JABBER_STATUS(<sender>,< screenname >[/<resource>])\n " ) ;
ast_log ( LOG_ERROR , " Usage: JABBER_STATUS(<sender>,< jid >[/<resource>])\n " ) ;
return 0 ;
}
AST_STANDARD_APP_ARGS ( args , data ) ;
if ( args . argc ! = 2 ) {
ast_log ( LOG_ERROR , " JABBER_STATUS requires 2 arguments .\n " ) ;
ast_log ( LOG_ERROR , " JABBER_STATUS requires 2 arguments : sender and jid .\n " ) ;
return - 1 ;
}
@ -445,8 +452,11 @@ static struct ast_custom_function jabberstatus_function = {
. syntax = " JABBER_STATUS(<sender>,<buddy>[/<resource>]) " ,
. read = acf_jabberstatus_read ,
. desc =
" Retrieves the numeric status associated with the specified buddy. If the \n "
" buddy does not exist in the buddylist, returns 7. \n " ,
" Retrieves the numeric status associated with the specified buddy (jid). If the \n "
" buddy does not exist in the buddylist, returns 7. \n "
" Status will be 1-7. \n "
" 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline \n "
" If not in roster variable will be set to 7 \n \n " ,
} ;
/*!
@ -776,8 +786,9 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom
ast_verbose ( " \n JABBER: %s INCOMING: %s \n " , client - > name , xmpp ) ;
else {
if ( strlen ( xmpp ) = = 1 ) {
if ( option_debug > 2 & & xmpp [ 0 ] = = ' ' )
if ( option_debug > 2 & & xmpp [ 0 ] = = ' ' ) {
ast_verbose ( " \n JABBER: Keep alive packet \n " ) ;
}
} else
ast_verbose ( " \n JABBER: %s OUTGOING: %s \n " , client - > name , xmpp ) ;
}
@ -1040,7 +1051,7 @@ static int aji_act_hook(void *data, int type, iks *node)
return IKS_OK ;
}
/*!
* \ brief U known
* \ brief U n known
* \ param data void
* \ param pak ikspak
* \ return IKS_FILTER_EAT .
@ -1083,7 +1094,7 @@ static int aji_register_approve_handler(void *data, ikspak *pak)
return IKS_FILTER_EAT ;
}
/*!
* \ brief register query
* \ brief register handler for incoming querys ( IQ ' s )
* \ param data incoming aji_client request
* \ param pak ikspak
* \ return IKS_FILTER_EAT .
@ -1093,14 +1104,15 @@ static int aji_register_query_handler(void *data, ikspak *pak)
struct aji_client * client = ASTOBJ_REF ( ( struct aji_client * ) data ) ;
struct aji_buddy * buddy = NULL ;
char * node = NULL ;
iks * iq = NULL , * query = NULL ;
client = ( struct aji_client * ) data ;
buddy = ASTOBJ_CONTAINER_FIND ( & client - > buddies , pak - > from - > partial ) ;
if ( ! buddy ) {
iks * iq = NULL , * query = NULL , * error = NULL , * notacceptable = NULL ;
iks * error = NULL , * notacceptable = NULL ;
ast_ verbose( " Someone.... %s tried to register but they aren't allowed \n " , pak - > from - > partial ) ;
ast_ log( LOG_ERROR , " Someone.... %s tried to register but they aren't allowed \n " , pak - > from - > partial ) ;
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
error = iks_new ( " error " ) ;
@ -1122,12 +1134,10 @@ static int aji_register_query_handler(void *data, ikspak *pak)
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( error ) ;
iks_delete ( notacceptable ) ;
} else if ( ! ( node = iks_find_attrib ( pak - > query , " node " ) ) ) {
iks * i q = NULL , * query = NULL , * i nstructions = NULL ;
iks * i nstructions = NULL ;
char * explain = " Welcome to Asterisk - the Open Source PBX. \n " ;
iq = iks_new ( " iq " ) ;
query = iks_new ( " query " ) ;
@ -1146,10 +1156,10 @@ static int aji_register_query_handler(void *data, ikspak *pak)
ast_log ( LOG_ERROR , " Out of memory. \n " ) ;
}
iks_delete ( iq ) ;
iks_delete ( query ) ;
iks_delete ( instructions ) ;
}
iks_delete ( iq ) ;
iks_delete ( query ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
return IKS_FILTER_EAT ;
}
@ -1264,7 +1274,7 @@ static int aji_client_info_handler(void *data, ikspak *pak)
resource = aji_find_resource ( buddy , pak - > from - > resource ) ;
if ( pak - > subtype = = IKS_TYPE_RESULT ) {
if ( ! resource ) {
ast_log ( LOG_NOTICE , " JABBER: Received client info from %s when not requested. \n " , pak - > from - > full ) ;
ast_log ( LOG_NOTICE , " JABBER: Received client info from %s when not requested. \n " , pak - > from - > full ) ;
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
return IKS_FILTER_EAT ;
}
@ -1686,35 +1696,35 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
}
switch ( pak - > subtype ) {
case IKS_TYPE_AVAILABLE :
ast_ verb( 5 , " JABBER: I am available ^_* %i \n " , pak - > subtype ) ;
ast_ debug( 3 , " JABBER: I am available ^_* %i \n " , pak - > subtype ) ;
break ;
case IKS_TYPE_UNAVAILABLE :
ast_ verb( 5 , " JABBER: I am unavailable ^_* %i \n " , pak - > subtype ) ;
ast_ debug( 3 , " JABBER: I am unavailable ^_* %i \n " , pak - > subtype ) ;
break ;
default :
ast_verb ( 5 , " JABBER: Ohh sexy and the wrong type: %i \n " , pak - > subtype ) ;
ast_debug ( 3 , " JABBER: Ohh sexy and the wrong type: %i \n " , pak - > subtype ) ;
}
switch ( pak - > show ) {
case IKS_SHOW_UNAVAILABLE :
ast_ verb( 5 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
ast_ debug( 3 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
break ;
case IKS_SHOW_AVAILABLE :
ast_ verb( 5 , " JABBER: type is available \n " ) ;
ast_ debug( 3 , " JABBER: type is available \n " ) ;
break ;
case IKS_SHOW_CHAT :
ast_ verb( 5 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
ast_ debug( 3 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
break ;
case IKS_SHOW_AWAY :
ast_ verb( 5 , " JABBER: type is away \n " ) ;
ast_ debug( 3 , " JABBER: type is away \n " ) ;
break ;
case IKS_SHOW_XA :
ast_ verb( 5 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
ast_ debug( 3 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
break ;
case IKS_SHOW_DND :
ast_ verb( 5 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
ast_ debug( 3 , " JABBER: type: %i subtype %i \n " , pak - > subtype , pak - > show ) ;
break ;
default :
ast_ verb( 5 , " JABBER: Kinky! how did that happen %i \n " , pak - > show ) ;
ast_ debug( 3 , " JABBER: Kinky! how did that happen %i \n " , pak - > show ) ;
}
}
@ -1893,7 +1903,7 @@ static void *aji_recv_loop(void *data)
int res = IKS_HOOK ;
while ( res ! = IKS_OK ) {
ast_ verb( 4 , " JABBER: Connecting. \n " ) ;
ast_ debug( 3 , " JABBER: Connecting. \n " ) ;
res = aji_reconnect ( client ) ;
sleep ( 4 ) ;
}
@ -1901,7 +1911,7 @@ static void *aji_recv_loop(void *data)
do {
if ( res = = IKS_NET_RWERR | | client - > timeout = = 0 ) {
while ( res ! = IKS_OK ) {
ast_ verb( 4 , " JABBER: reconnecting. \n " ) ;
ast_ debug( 3 , " JABBER: reconnecting. \n " ) ;
res = aji_reconnect ( client ) ;
sleep ( 4 ) ;
}
@ -1921,7 +1931,7 @@ static void *aji_recv_loop(void *data)
if ( res = = IKS_HOOK )
ast_log ( LOG_WARNING , " JABBER: Got hook event. \n " ) ;
else if ( res = = IKS_NET_TLSFAIL )
ast_log ( LOG_ WARNING , " JABBER: Failure in TLS. \n " ) ;
ast_log ( LOG_ ERROR , " JABBER: Failure in TLS. \n " ) ;
else if ( client - > timeout = = 0 & & client - > state = = AJI_CONNECTED ) {
res = client - > keepalive ? aji_send_raw ( client , " " ) : IKS_OK ;
if ( res = = IKS_OK )
@ -2046,6 +2056,7 @@ static int aji_register_transport2(void *data, ikspak *pak)
* \ brief goes through roster and prunes users not needed in list , or adds them accordingly .
* \ param client the configured XMPP client we use to connect to a XMPP server
* \ return void .
* \ note The messages here should be configurable .
*/
static void aji_pruneregister ( struct aji_client * client )
{
@ -2067,10 +2078,10 @@ static void aji_pruneregister(struct aji_client *client)
* be called at the same time */
if ( ast_test_flag ( & iterator - > flags , AJI_AUTOPRUNE ) ) {
res = ast_aji_send ( client , iks_make_s10n ( IKS_TYPE_UNSUBSCRIBE , iterator - > name ,
" GoodBye y our status is no longer needed by Asterisk the Open Source PBX"
" GoodBye . Y our status is no longer needed by Asterisk the Open Source PBX"
" so I am no longer subscribing to your presence. \n " ) ) ;
res = ast_aji_send ( client , iks_make_s10n ( IKS_TYPE_UNSUBSCRIBED , iterator - > name ,
" GoodBye you are no longer in the a sterisk config file so I am removing"
" GoodBye . You are no longer in the A sterisk config file so I am removing"
" your access to my presence. \n " ) ) ;
iks_insert_attrib ( removeiq , " from " , client - > jid - > full ) ;
iks_insert_attrib ( removeiq , " type " , " set " ) ;
@ -2080,7 +2091,7 @@ static void aji_pruneregister(struct aji_client *client)
res = ast_aji_send ( client , removeiq ) ;
} else if ( ast_test_flag ( & iterator - > flags , AJI_AUTOREGISTER ) ) {
res = ast_aji_send ( client , iks_make_s10n ( IKS_TYPE_SUBSCRIBE , iterator - > name ,
" Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n " ) ) ;
" Greetings ! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n " ) ) ;
ast_clear_flag ( & iterator - > flags , AJI_AUTOREGISTER ) ;
}
ASTOBJ_UNLOCK ( iterator ) ;
@ -2178,6 +2189,7 @@ static int aji_filter_roster(void *data, ikspak *pak)
ASTOBJ_UNREF ( client , aji_client_destroy ) ;
return IKS_FILTER_EAT ;
}
/*!
* \ brief reconnect to jabber server
* \ param client the configured XMPP client we use to connect to a XMPP server
@ -2199,6 +2211,7 @@ static int aji_reconnect(struct aji_client *client)
return res ;
}
/*!
* \ brief Get the roster of jabber users
* \ param client the configured XMPP client we use to connect to a XMPP server
@ -2348,7 +2361,7 @@ static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_a
e - > command = " jabber set debug {on|off} " ;
e - > usage =
" Usage: jabber set debug {on|off} \n "
" Enables/disables dumping of Jabber packets for debugging purposes.\n " ;
" Enables/disables dumping of XMPP/ Jabber packets for debugging purposes.\n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;