From 487fb33bb9a1436ddd726b72c5ca22c9f1e02231 Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Thu, 4 Nov 2010 19:17:16 +0000 Subject: [PATCH] Started unification of CLI and AMI code. Fixed numerous bugs in AMI and CLI commands. Add AMI CapichatMute, CapichatUnmute and CapiCommand commands --- Makefile | 2 +- chan_capi_ami.c | 156 +++++++++++++++++++++++++++++++++- chan_capi_chat.c | 15 ++-- chan_capi_cli.c | 101 +--------------------- chan_capi_management_common.c | 144 +++++++++++++++++++++++++++++++ chan_capi_management_common.h | 7 ++ 6 files changed, 318 insertions(+), 107 deletions(-) create mode 100644 chan_capi_management_common.c create mode 100644 chan_capi_management_common.h diff --git a/Makefile b/Makefile index 0d59931..4ceac7c 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ SHAREDOS=chan_capi.so OBJECTS=chan_capi.o chan_capi_utils.o chan_capi_rtp.o chan_capi_command.o xlaw.o dlist.o \ chan_capi_qsig_core.o chan_capi_qsig_ecma.o chan_capi_qsig_asn197ade.o \ chan_capi_qsig_asn197no.o chan_capi_supplementary.o chan_capi_chat.o \ - chan_capi_mwi.o chan_capi_cli.o chan_capi_ami.o + chan_capi_mwi.o chan_capi_cli.o chan_capi_ami.o chan_capi_management_common.o ifeq (${USE_OWN_LIBCAPI},yes) OBJECTS += libcapi20/convert.o libcapi20/capi20.o libcapi20/capifunc.o diff --git a/chan_capi_ami.c b/chan_capi_ami.c index 1d22d3c..195c4d2 100644 --- a/chan_capi_ami.c +++ b/chan_capi_ami.c @@ -25,23 +25,34 @@ * Based on apps/app_meetme.c * */ -#ifdef CC_AST_HAS_VERSION_1_6 #include "chan_capi_platform.h" #include "chan_capi20.h" #include "chan_capi.h" +#ifdef CC_AST_HAS_VERSION_1_6 #include "chan_capi_qsig.h" #include "chan_capi_utils.h" #include "chan_capi_chat.h" +#include "chan_capi_management_common.h" #include "asterisk/manager.h" -#define CC_AMI_ACTION_NAME_CHATLIST "CapichatList" +#define CC_AMI_ACTION_NAME_CHATLIST "CapichatList" +#define CC_AMI_ACTION_NAME_CHATMUTE "CapichatMute" +#define CC_AMI_ACTION_NAME_CHATUNMUTE "CapichatUnmute" +#define CC_AMI_ACTION_NAME_CAPICOMMAND "CapiCommand" /* LOCALS */ static int pbx_capi_ami_capichat_list(struct mansession *s, const struct message *m); +static int pbx_capi_ami_capichat_mute(struct mansession *s, const struct message *m); +static int pbx_capi_ami_capichat_unmute(struct mansession *s, const struct message *m); +static int pbx_capi_ami_capichat_control(struct mansession *s, const struct message *m, int chatMute); +static int pbx_capi_ami_capicommand(struct mansession *s, const struct message *m); static int capiChatListRegistered; +static int capiChatMuteRegistered; +static int capiChatUnmuteRegistered; +static int capiCommandRegistered; static char mandescr_capichatlist[] = "Description: Lists all users in a particular CapiChat conference.\n" @@ -51,6 +62,28 @@ static char mandescr_capichatlist[] = " *ActionId: \n" " *Conference: \n"; +static char mandescr_capichatmute[] = +"Description: Mutes user in a particular CapiChat conference.\n" +"Variables:\n" +" *ActionId: \n" +" *Conference: \n" +" *Member: \n" +" *Path: \n"; + +static char mandescr_capichatunmute[] = +"Description: Unmutes user in a particular CapiChat conference.\n" +"Variables:\n" +" *ActionId: \n" +" *Conference: \n" +" *Member: \n" +" *Path: \n"; + +static char mandescr_capicommand[] = +"Description: Exec capicommand.\n" +"Variables:\n" +" *ActionId: \n" +" *Channel: \n" +" *Capicommand: \n"; void pbx_capi_ami_register(void) { @@ -59,12 +92,39 @@ void pbx_capi_ami_register(void) pbx_capi_ami_capichat_list, "List participants in a conference", mandescr_capichatlist) == 0; + + capiChatMuteRegistered = ast_manager_register2(CC_AMI_ACTION_NAME_CHATMUTE, + EVENT_FLAG_CALL, + pbx_capi_ami_capichat_mute, + "Mute a conference user", + mandescr_capichatmute) == 0; + + capiChatUnmuteRegistered = ast_manager_register2(CC_AMI_ACTION_NAME_CHATUNMUTE, + EVENT_FLAG_CALL, + pbx_capi_ami_capichat_unmute, + "Unmute a conference user", + mandescr_capichatunmute) == 0; + + capiCommandRegistered = ast_manager_register2(CC_AMI_ACTION_NAME_CAPICOMMAND, + EVENT_FLAG_CALL, + pbx_capi_ami_capicommand, + "Exec capicommand", + mandescr_capicommand) == 0; } void pbx_capi_ami_unregister(void) { if (capiChatListRegistered != 0) ast_manager_unregister(CC_AMI_ACTION_NAME_CHATLIST); + + if (capiChatMuteRegistered != 0) + ast_manager_unregister(CC_AMI_ACTION_NAME_CHATMUTE); + + if (capiChatUnmuteRegistered != 0) + ast_manager_unregister(CC_AMI_ACTION_NAME_CHATUNMUTE); + + if (capiCommandRegistered != 0) + ast_manager_unregister(CC_AMI_ACTION_NAME_CAPICOMMAND); } static int pbx_capi_ami_capichat_list(struct mansession *s, const struct message *m) { @@ -165,6 +225,98 @@ static int pbx_capi_ami_capichat_list(struct mansession *s, const struct message "\r\n", total, idText); return 0; } + +static int pbx_capi_ami_capichat_mute(struct mansession *s, const struct message *m) +{ + return pbx_capi_ami_capichat_control(s, m, 1); +} + +static int pbx_capi_ami_capichat_unmute(struct mansession *s, const struct message *m) +{ + return pbx_capi_ami_capichat_control(s, m, 0); +} + +static int pbx_capi_ami_capichat_control(struct mansession *s, const struct message *m, int chatMute) +{ + const char *roomName = astman_get_header(m, "Conference"); + const char *userName = astman_get_header(m, "Member"); + const char *voicePath = astman_get_header(m, "Path"); + const char* capiCommand; + int ret; + + if (ast_strlen_zero(roomName)) { + astman_send_error(s, m, "Capi Chat conference not specified"); + return 0; + } + + if (ast_strlen_zero(userName)) { + char* param = ast_strdupa((chatMute != 0) ? "yes" : "no"); + int ret = pbx_capi_chat_mute(NULL, param); + if (ret == 0) { + astman_send_ack(s, m, (chatMute != 0) ? "Conference muted" : "Conference unmuted"); + } else { + astman_send_error(s, m, "Failed to change mode of Capi Chat conference"); + } + return 0; + } + + if ((voicePath != NULL) && (strcmp(voicePath, "Rx") == 0)) { + capiCommand = (chatMute != 0) ? "rxdgain,-128" : "rxdgain,0"; + } else { + capiCommand = (chatMute != 0) ? "txdgain,-128" : "txdgain,0"; + } + + ret = pbx_capi_management_capicommand(userName, capiCommand); + + switch (ret) { + case 0: + astman_send_ack(s, m, (chatMute != 0) ? "User muted" : "User unmuted"); + break; + + case -4: + astman_send_error(s, m, "User not found"); + break; + + default: + astman_send_error(s, m, "Command error"); + break; + } + + return (0); +} + +static int pbx_capi_ami_capicommand(struct mansession *s, const struct message *m) +{ + const char *requiredChannelName = astman_get_header(m, "Channel"); + const char *chancapiCommand = astman_get_header(m, "Command"); + int ret = pbx_capi_management_capicommand(requiredChannelName, chancapiCommand); + + switch (ret) { + case 0: + astman_send_ack(s, m, "OK"); + break; + + case -2: + astman_send_error(s, m, "Channel name not specified"); + break; + + case -3: + astman_send_error(s, m, "Capi command name not specified"); + break; + + case -4: + astman_send_error(s, m, "Channel not found"); + break; + + case -1: + default: + astman_send_error(s, m, "Command error"); + break; + } + + return 0; +} + #else void pbx_capi_ami_register(void) { diff --git a/chan_capi_chat.c b/chan_capi_chat.c index 6619a2e..e966dac 100644 --- a/chan_capi_chat.c +++ b/chan_capi_chat.c @@ -916,13 +916,16 @@ int pbx_capi_chat_command(struct ast_channel *c, char *param) struct capi_pvt* pbx_check_resource_plci(struct ast_channel *c) { struct capi_pvt *i = NULL; - const char* id = pbx_builtin_getvar_helper(c, "RESOURCEPLCI"); - if (id != 0) { - i = (struct capi_pvt*)strtoul(id, NULL, 0); - if (i != 0 && capi_verify_resource_plci(i) != 0) { - cc_log(LOG_ERROR, "resource PLCI lost\n"); - i = 0; + if (c != NULL) { + const char* id = pbx_builtin_getvar_helper(c, "RESOURCEPLCI"); + + if (id != 0) { + i = (struct capi_pvt*)strtoul(id, NULL, 0); + if (i != 0 && capi_verify_resource_plci(i) != 0) { + cc_log(LOG_ERROR, "resource PLCI lost\n"); + i = 0; + } } } diff --git a/chan_capi_cli.c b/chan_capi_cli.c index 663a771..f586493 100644 --- a/chan_capi_cli.c +++ b/chan_capi_cli.c @@ -21,15 +21,11 @@ #include "chan_capi_utils.h" #include "chan_capi_chat.h" #include "chan_capi_cli.h" +#include "chan_capi_management_common.h" #ifdef DIVA_STATUS #include "divastatus_ifc.h" #endif -/* - LOCALS - */ -static int pbx_capi_cli_get_locks(struct capi_pvt *i); - /* * usages */ @@ -542,25 +538,11 @@ static char *pbxcli_capi_exec_capicommand(struct ast_cli_entry *e, int cmd, stru static int pbxcli_capi_exec_capicommand(int fd, int argc, char *argv[]) #endif { - int ifc_type, found, retry_search, search_loops = 10; - struct capi_pvt *i; int required_args = 4; int provided_args; const char* requiredChannelName = NULL; const char* chancapiCommand = NULL; - int ret = -1; - struct { - struct capi_pvt *head; - void (*lock_proc)(void); - void (*unlock_proc)(void); - } data[2]; - - data[0].head = capi_iflist; - data[0].lock_proc = pbx_capi_lock_interfaces; - data[0].unlock_proc = pbx_capi_unlock_interfaces; - data[1].head = (struct capi_pvt*)pbx_capi_get_nulliflist(); - data[1].lock_proc = pbx_capi_nulliflist_lock; - data[1].unlock_proc = pbx_capi_nulliflist_unlock; + int ret; #ifdef CC_AST_HAS_VERSION_1_6 if (cmd == CLI_INIT) { @@ -585,57 +567,7 @@ static int pbxcli_capi_exec_capicommand(int fd, int argc, char *argv[]) chancapiCommand = argv[3]; #endif - do { - retry_search = 0; - - for (ifc_type = 0, found = 0; (found == 0) && (ifc_type < sizeof(data)/sizeof(data[0])); ifc_type++) { - data[ifc_type].lock_proc(); - for (i = data[ifc_type].head; (i != 0); i = i->next) { - char* name; - - if ((i->used == 0) || ((i->channeltype != CAPI_CHANNELTYPE_B) && - (i->channeltype != CAPI_CHANNELTYPE_NULL))) - continue; - if (i->data_plci != 0) - continue; - - name = ast_strdup(i->vname); - if ((i->channeltype == CAPI_CHANNELTYPE_NULL) && (name != NULL)) { - char* p = strstr(name, "-DATAPLCI"); - if (p != NULL) - *p = 0; - } - - if (strcmp(requiredChannelName, (name == 0) ? i->vname : name) == 0) { - found = 1; - ast_free(name); - retry_search = pbx_capi_cli_get_locks(i); - break; - } - - ast_free(name); - } - data[ifc_type].unlock_proc(); - } - - if (retry_search != 0) { - usleep (100); - i = 0; - } - } while ((retry_search != 0) && (search_loops-- > 0)); - - if (i != NULL) { - if (i->channeltype != CAPI_CHANNELTYPE_NULL) { - struct ast_channel* c = i->owner; - ret = pbx_capi_cli_exec_capicommand(c, chancapiCommand); - cc_mutex_unlock(&i->lock); - if (c) - ast_channel_unlock (c); - } else { - ret = pbx_capi_cli_exec_capicommand(i->used, chancapiCommand); - cc_mutex_unlock(&i->lock); - } - } + ret = pbx_capi_management_capicommand(requiredChannelName, chancapiCommand); #ifdef CC_AST_HAS_VERSION_1_6 return ((ret == 0) ? CLI_SUCCESS : CLI_FAILURE); @@ -796,30 +728,3 @@ void pbx_capi_cli_unregister(void) #endif } -static int pbx_capi_cli_get_locks(struct capi_pvt *i) -{ - if (i->channeltype != CAPI_CHANNELTYPE_NULL) { - struct ast_channel* c = i->owner; - if (c != 0) { - if (ast_channel_trylock(c) == 0) { - if (ast_mutex_trylock(&i->lock) == 0) { - if (i->owner == c) { - return (0); - } else { - ast_mutex_unlock(&i->lock); - ast_channel_unlock (c); - } - } else { - ast_channel_unlock (c); - } - } - } - } else { - if (ast_mutex_trylock(&i->lock) == 0) { - return (0); - } - } - - return (-1); -} - diff --git a/chan_capi_management_common.c b/chan_capi_management_common.c new file mode 100644 index 0000000..360948b --- /dev/null +++ b/chan_capi_management_common.c @@ -0,0 +1,144 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Based on apps/app_meetme.c + * + */ +#include "chan_capi_platform.h" +#include "chan_capi20.h" +#include "chan_capi.h" +#include "chan_capi_qsig.h" +#include "chan_capi_utils.h" +#include "chan_capi_chat.h" + +/* + LOCALS + */ +static int pbx_capi_get_all_locks (struct capi_pvt *i, struct ast_channel** usedChannel); + +/*! + \brief Execute any capicommand + + \note Called from CLI or from AMI context + */ +int pbx_capi_management_capicommand(const char *requiredChannelName, const char *chancapiCommand) { + int ifc_type, retry_search, search_loops; + struct capi_pvt *i; + struct { + struct capi_pvt *head; + void (*lock_proc)(void); + void (*unlock_proc)(void); + } data[2]; + + data[0].head = capi_iflist; + data[0].lock_proc = pbx_capi_lock_interfaces; + data[0].unlock_proc = pbx_capi_unlock_interfaces; + data[1].head = (struct capi_pvt*)pbx_capi_get_nulliflist(); + data[1].lock_proc = pbx_capi_nulliflist_lock; + data[1].unlock_proc = pbx_capi_nulliflist_unlock; + + if (ast_strlen_zero(requiredChannelName)) { + return -2; + } + + if (ast_strlen_zero(chancapiCommand)) { + return -3; + } + + for (ifc_type = 0; ifc_type < sizeof(data)/sizeof(data[0]); ifc_type++) { + search_loops = 10; + do { + data[ifc_type].lock_proc(); + for (i = data[ifc_type].head, retry_search = 0; i != 0; i = i->next) { + struct ast_channel* c = NULL; + + if ((i->used == 0) || ((i->channeltype != CAPI_CHANNELTYPE_B) && + (i->channeltype != CAPI_CHANNELTYPE_NULL))) + continue; + if (i->data_plci != 0) + continue; + + if (pbx_capi_get_all_locks (i, &c) != 0) { + retry_search = 1; + break; + } + if ((!ast_strlen_zero(c->name) && (strcmp(requiredChannelName, c->name) == 0)) || + strcmp(requiredChannelName, i->vname) == 0) { + struct ast_channel* usedChannel = c; + int ret; + + data[ifc_type].unlock_proc(); + + if (i->channeltype != CAPI_CHANNELTYPE_NULL) { + ret = (pbx_capi_cli_exec_capicommand(usedChannel, chancapiCommand) == 0) ? 0 : -1; + cc_mutex_unlock(&i->lock); + ast_channel_unlock(c); + } else { + ast_channel_unlock(c); + ret = (pbx_capi_cli_exec_capicommand(usedChannel, chancapiCommand) == 0) ? 0 : -1; + cc_mutex_unlock(&i->lock); + } + + return ret; + } + cc_mutex_unlock(&i->lock); + ast_channel_unlock(c); + } + data[ifc_type].unlock_proc(); + if (retry_search != 0) { + usleep (100); + } + } while((retry_search != 0) && (search_loops-- > 0)); + } + + return -4; +} + +/*! + * \brief Try to take all locks. Called with false lock order + * one of the list locks (iflock or nullif_lock) taken + * Used by CLI/AMI + */ +static int pbx_capi_get_all_locks (struct capi_pvt *i, struct ast_channel** usedChannel) +{ + struct ast_channel* c = (i->channeltype != CAPI_CHANNELTYPE_NULL) ? i->owner : i->used; + if (c != 0) { + if (ast_channel_trylock(c) == 0) { + if (ast_mutex_trylock(&i->lock) == 0) { + struct ast_channel* cref = (i->channeltype != CAPI_CHANNELTYPE_NULL) ? i->owner : i->used; + if (cref == c) { + *usedChannel = c; + return (0); + } else { + ast_mutex_unlock(&i->lock); + ast_channel_unlock (c); + } + } else { + ast_channel_unlock (c); + } + } + } + + return (-1); +} diff --git a/chan_capi_management_common.h b/chan_capi_management_common.h new file mode 100644 index 0000000..94d2671 --- /dev/null +++ b/chan_capi_management_common.h @@ -0,0 +1,7 @@ +#ifndef __CC_MANAGEMENT_COMMON_INTERFACE_H__ +#define __CC_MANAGEMENT_COMMON_INTERFACE_H__ + + +int pbx_capi_management_capicommand(const char *requiredChannelName, const char *chancapiCommand); + +#endif