2002-05-13 22:29:39 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2002-05-13 22:29:39 +00:00
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
2002-05-13 22:29:39 +00:00
*
2004-09-07 01:22:57 +00:00
* Mark Spencer < markster @ digium . com >
2002-05-13 22:29:39 +00:00
*
2005-09-14 20:46:50 +00:00
* 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 .
*
2002-05-13 22:29:39 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Meet me conference bridge
2005-09-14 20:46:50 +00:00
*
2002-05-13 22:29:39 +00:00
*/
2005-06-06 22:39:32 +00:00
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
# include <stdlib.h>
# include <sys/ioctl.h>
# ifdef __linux__
# include <linux/zaptel.h>
# else
# include <zaptel.h>
# endif /* __linux__ */
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-04-21 06:02:45 +00:00
# include "asterisk/lock.h"
# include "asterisk/file.h"
# include "asterisk/logger.h"
# include "asterisk/channel.h"
# include "asterisk/pbx.h"
# include "asterisk/module.h"
# include "asterisk/config.h"
# include "asterisk/app.h"
# include "asterisk/dsp.h"
# include "asterisk/musiconhold.h"
# include "asterisk/manager.h"
# include "asterisk/options.h"
# include "asterisk/cli.h"
# include "asterisk/say.h"
# include "asterisk/utils.h"
2002-05-13 22:29:39 +00:00
2004-05-23 14:19:45 +00:00
static char * tdesc = " MeetMe conference bridge " ;
2002-05-13 22:29:39 +00:00
static char * app = " MeetMe " ;
static char * app2 = " MeetMeCount " ;
2004-05-22 04:11:22 +00:00
static char * app3 = " MeetMeAdmin " ;
2002-05-13 22:29:39 +00:00
2004-05-23 14:19:45 +00:00
static char * synopsis = " MeetMe conference bridge " ;
2002-05-13 22:29:39 +00:00
static char * synopsis2 = " MeetMe participant count " ;
2004-05-23 14:19:45 +00:00
static char * synopsis3 = " MeetMe conference Administration " ;
2002-05-13 22:29:39 +00:00
static char * descrip =
2004-05-23 14:19:45 +00:00
" MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe conference. \n "
2002-05-13 22:29:39 +00:00
" If the conference number is omitted, the user will be prompted to enter \n "
2004-05-27 14:35:26 +00:00
" one. \n "
" MeetMe returns 0 if user pressed # to exit (see option 'p'), otherwise -1. \n "
" Please note: A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING TO WORK! \n \n "
2004-01-11 06:07:36 +00:00
2003-02-04 15:48:42 +00:00
" The option string may contain zero or more of the following characters: \n "
2004-05-23 14:55:50 +00:00
" 'm' -- set monitor only mode (Listen only, no talking) \n "
2004-01-11 06:07:36 +00:00
" 't' -- set talk only mode. (Talk only, no listening) \n "
2005-01-30 03:07:21 +00:00
" 'T' -- set talker detection (sent to manager interface and meetme list) \n "
2005-01-07 07:23:31 +00:00
" 'i' -- announce user join/leave \n "
2003-02-04 15:48:42 +00:00
" 'p' -- allow user to exit the conference by pressing '#' \n "
2004-08-03 06:31:20 +00:00
" 'X' -- allow user to exit the conference by entering a valid single \n "
" digit extension ${MEETME_EXIT_CONTEXT} or the current context \n "
" if that variable is not defined. \n "
2003-10-29 22:52:20 +00:00
" 'd' -- dynamically add conference \n "
2004-04-08 19:38:26 +00:00
" 'D' -- dynamically add conference, prompting for a PIN \n "
" 'e' -- select an empty conference \n "
" 'E' -- select an empty pinless conference \n "
2003-06-30 02:00:02 +00:00
" 'v' -- video mode \n "
2005-01-22 04:51:30 +00:00
" 'r' -- Record conference (records as ${MEETME_RECORDINGFILE} \n "
" using format ${MEETME_RECORDINGFORMAT}). Default filename is \n "
" meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is wav. \n "
2003-09-28 21:18:51 +00:00
" 'q' -- quiet mode (don't play enter/leave sounds) \n "
2005-03-20 03:04:46 +00:00
" 'c' -- announce user(s) count on joining a conference \n "
2003-11-04 21:47:35 +00:00
" 'M' -- enable music on hold when the conference has a single caller \n "
2004-08-27 04:12:55 +00:00
" 'x' -- close the conference when last marked user exits \n "
" 'w' -- wait until the marked user enters the conference \n "
2004-01-11 06:07:36 +00:00
" 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND} \n "
2004-05-30 20:38:05 +00:00
" Default: conf-background.agi \n "
" (Note: This does not work with non-Zap channels in the same conference) \n "
2004-05-23 23:46:43 +00:00
" 's' -- Present menu (user or admin) when '*' is received ('send' to menu) \n "
2004-08-27 04:12:55 +00:00
" 'a' -- set admin mode \n "
2005-02-02 02:57:45 +00:00
" 'A' -- set marked mode \n "
" 'P' -- always prompt for the pin even if it is specified \n " ;
2002-05-13 22:29:39 +00:00
static char * descrip2 =
2003-08-20 23:32:23 +00:00
" MeetMeCount(confno[|var]): Plays back the number of users in the specifiedi \n "
" MeetMe conference. If var is specified, playback will be skipped and the value \n "
" will be returned in the variable. Returns 0 on success or -1 on a hangup. \n "
" A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY. \n " ;
2002-05-13 22:29:39 +00:00
2004-05-23 14:19:45 +00:00
static char * descrip3 =
" MeetMeAdmin(confno,command[,user]): Run admin command for conference \n "
" 'K' -- Kick all users out of conference \n "
" 'k' -- Kick one user out of conference \n "
2005-01-14 04:25:35 +00:00
" 'e' -- Eject last user that joined \n "
2004-05-23 14:19:45 +00:00
" 'L' -- Lock conference \n "
" 'l' -- Unlock conference \n "
" 'M' -- Mute conference \n "
" 'm' -- Unmute conference \n "
2004-10-11 15:40:24 +00:00
" 'N' -- Mute entire conference (except admin) \n "
" 'n' -- Unmute entire conference (except admin) \n "
2004-05-23 14:19:45 +00:00
" " ;
2004-05-22 04:11:22 +00:00
2002-05-13 22:29:39 +00:00
STANDARD_LOCAL_USER ;
LOCAL_USER_DECL ;
2004-01-11 06:07:36 +00:00
static struct ast_conference {
char confno [ AST_MAX_EXTENSION ] ; /* Conference */
2004-06-02 16:57:14 +00:00
struct ast_channel * chan ; /* Announcements channel */
2004-06-01 22:54:18 +00:00
int fd ; /* Announcements fd */
2002-05-13 22:29:39 +00:00
int zapconf ; /* Zaptel Conf # */
int users ; /* Number of active users */
2004-05-30 20:38:05 +00:00
int markedusers ; /* Number of marked users */
struct ast_conf_user * firstuser ; /* Pointer to the first user struct */
struct ast_conf_user * lastuser ; /* Pointer to the last user struct */
2002-05-13 22:29:39 +00:00
time_t start ; /* Start time (s) */
2005-01-22 04:51:30 +00:00
int recording ; /* recording status */
2004-01-11 06:07:36 +00:00
int isdynamic ; /* Created on the fly? */
2004-05-30 20:38:05 +00:00
int locked ; /* Is the conference locked? */
2005-01-22 04:51:30 +00:00
pthread_t recordthread ; /* thread for recording */
pthread_attr_t attr ; /* thread attribute */
char * recordingfilename ; /* Filename to record the Conference into */
char * recordingformat ; /* Format to record the Conference in */
2004-01-11 06:07:36 +00:00
char pin [ AST_MAX_EXTENSION ] ; /* If protected by a PIN */
2005-02-22 15:42:41 +00:00
char pinadmin [ AST_MAX_EXTENSION ] ; /* If protected by a admin PIN */
2004-01-11 06:07:36 +00:00
struct ast_conference * next ;
2002-05-13 22:29:39 +00:00
} * confs ;
2005-09-07 02:27:58 +00:00
struct volume {
int desired ; /* Desired volume adjustment */
int actual ; /* Actual volume adjustment (for channels that can't adjust) */
} ;
2004-05-22 04:11:22 +00:00
struct ast_conf_user {
2005-09-07 01:30:01 +00:00
int user_no ; /* User Number */
struct ast_conf_user * prevuser ; /* Pointer to the previous user */
struct ast_conf_user * nextuser ; /* Pointer to the next user */
int userflags ; /* Flags as set in the conference */
int adminflags ; /* Flags set by the Admin */
struct ast_channel * chan ; /* Connected channel */
int talking ; /* Is user talking */
int zapchannel ; /* Is a Zaptel channel */
char usrvalue [ 50 ] ; /* Custom User Value */
char namerecloc [ AST_MAX_EXTENSION ] ; /* Name Recorded file Location */
time_t jointime ; /* Time the user joined the conference */
2005-09-07 02:27:58 +00:00
struct volume talk ;
struct volume listen ;
2004-05-22 04:11:22 +00:00
} ;
# define ADMINFLAG_MUTED (1 << 1) /* User is muted */
# define ADMINFLAG_KICKME (1 << 2) /* User is kicked */
2005-01-30 03:07:21 +00:00
# define MEETME_DELAYDETECTTALK 300
# define MEETME_DELAYDETECTENDTALK 1000
2004-05-22 04:11:22 +00:00
2005-09-07 01:30:01 +00:00
enum volume_action {
VOL_UP ,
VOL_DOWN ,
} ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( conflock ) ;
2002-05-13 22:29:39 +00:00
2004-05-22 04:11:22 +00:00
static int admin_exec ( struct ast_channel * chan , void * data ) ;
2005-01-22 04:51:30 +00:00
static void * recordthread ( void * args ) ;
2002-05-13 22:29:39 +00:00
# include "enter.h"
# include "leave.h"
# define ENTER 0
# define LEAVE 1
2005-01-22 04:51:30 +00:00
# define MEETME_RECORD_OFF 0
# define MEETME_RECORD_ACTIVE 1
# define MEETME_RECORD_TERMINATE 2
2004-06-14 03:12:46 +00:00
# define CONF_SIZE 320
2002-05-13 22:29:39 +00:00
2003-02-04 15:48:42 +00:00
# define CONFFLAG_ADMIN (1 << 1) /* If set the user has admin access on the conference */
# define CONFFLAG_MONITOR (1 << 2) /* If set the user can only receive audio from the conference */
# define CONFFLAG_POUNDEXIT (1 << 3) /* If set asterisk will exit conference when '#' is pressed */
# define CONFFLAG_STARMENU (1 << 4) /* If set asterisk will provide a menu to the user what '*' is pressed */
# define CONFFLAG_TALKER (1 << 5) /* If set the use can only send audio to the conference */
# define CONFFLAG_QUIET (1 << 6) /* If set there will be no enter or leave sounds */
2003-06-30 02:00:02 +00:00
# define CONFFLAG_VIDEO (1 << 7) /* Set to enable video mode */
2003-09-28 21:18:51 +00:00
# define CONFFLAG_AGI (1 << 8) /* Set to run AGI Script in Background */
2004-05-23 14:19:45 +00:00
# define CONFFLAG_MOH (1 << 9) /* Set to have music on hold when user is alone in conference */
2004-08-27 04:12:55 +00:00
# define CONFFLAG_MARKEDEXIT (1 << 10) /* If set the MeetMe will return if all marked with this flag left */
# define CONFFLAG_WAITMARKED (1 << 11) /* If set, the MeetMe will wait until a marked user enters */
# define CONFFLAG_EXIT_CONTEXT (1 << 12) /* If set, the MeetMe will exit to the specified context */
# define CONFFLAG_MARKEDUSER (1 << 13) /* If set, the user will be marked */
2005-01-07 07:23:31 +00:00
# define CONFFLAG_INTROUSER (1 << 14) /* If set, user will be ask record name on entry of conference */
2005-01-22 04:51:30 +00:00
# define CONFFLAG_RECORDCONF (1<< 15) /* If set, the MeetMe will be recorded */
2005-01-30 03:07:21 +00:00
# define CONFFLAG_MONITORTALKER (1 << 16) /* If set, the user will be monitored if the user is talking or not */
2005-03-12 05:37:32 +00:00
# define CONFFLAG_DYNAMIC (1 << 17)
# define CONFFLAG_DYNAMICPIN (1 << 18)
# define CONFFLAG_EMPTY (1 << 19)
# define CONFFLAG_EMPTYNOPIN (1 << 20)
# define CONFFLAG_ALWAYSPROMPT (1 << 21)
2005-03-20 03:04:46 +00:00
# define CONFFLAG_ANNOUNCEUSERCOUNT (1 << 22) /* If set, when user joins the conference, they will be told the number of users that are already in */
2005-03-12 05:37:32 +00:00
AST_DECLARE_OPTIONS ( meetme_opts , {
[ ' a ' ] = { CONFFLAG_ADMIN } ,
2005-03-20 03:04:46 +00:00
[ ' c ' ] = { CONFFLAG_ANNOUNCEUSERCOUNT } ,
2005-03-12 05:37:32 +00:00
[ ' T ' ] = { CONFFLAG_MONITORTALKER } ,
[ ' i ' ] = { CONFFLAG_INTROUSER } ,
[ ' m ' ] = { CONFFLAG_MONITOR } ,
[ ' p ' ] = { CONFFLAG_POUNDEXIT } ,
[ ' s ' ] = { CONFFLAG_STARMENU } ,
[ ' t ' ] = { CONFFLAG_TALKER } ,
[ ' q ' ] = { CONFFLAG_QUIET } ,
[ ' M ' ] = { CONFFLAG_MOH } ,
[ ' x ' ] = { CONFFLAG_MARKEDEXIT } ,
[ ' X ' ] = { CONFFLAG_EXIT_CONTEXT } ,
[ ' A ' ] = { CONFFLAG_MARKEDUSER } ,
[ ' b ' ] = { CONFFLAG_AGI } ,
[ ' w ' ] = { CONFFLAG_WAITMARKED } ,
[ ' r ' ] = { CONFFLAG_RECORDCONF } ,
[ ' d ' ] = { CONFFLAG_DYNAMIC } ,
[ ' D ' ] = { CONFFLAG_DYNAMICPIN } ,
[ ' e ' ] = { CONFFLAG_EMPTY } ,
[ ' E ' ] = { CONFFLAG_EMPTYNOPIN } ,
[ ' P ' ] = { CONFFLAG_ALWAYSPROMPT } ,
} ) ;
2005-01-30 03:07:21 +00:00
static char * istalking ( int x )
{
if ( x > 0 )
return " (talking) " ;
else if ( x < 0 )
return " (unmonitored) " ;
else
return " (not talking) " ;
}
2003-02-04 15:48:42 +00:00
2002-05-13 22:29:39 +00:00
static int careful_write ( int fd , unsigned char * data , int len )
{
int res ;
2004-06-02 16:57:14 +00:00
int x ;
2002-05-13 22:29:39 +00:00
while ( len ) {
2004-06-02 16:57:14 +00:00
x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT ;
res = ioctl ( fd , ZT_IOMUX , & x ) ;
if ( res > = 0 )
res = write ( fd , data , len ) ;
2002-05-13 22:29:39 +00:00
if ( res < 1 ) {
if ( errno ! = EAGAIN ) {
ast_log ( LOG_WARNING , " Failed to write audio data to conference: %s \n " , strerror ( errno ) ) ;
return - 1 ;
} else
return 0 ;
}
len - = res ;
data + = res ;
}
return 0 ;
}
2005-09-07 01:30:01 +00:00
/* Map 'volume' levels from -5 through +5 into
decibel ( dB ) settings for channel drivers
Note : these are not a straight linear - to - dB
conversion . . . the numbers have been modified
to give the user a better level of adjustability
*/
static signed char gain_map [ ] = {
- 15 ,
- 13 ,
- 10 ,
- 6 ,
0 ,
0 ,
0 ,
6 ,
10 ,
13 ,
15 ,
} ;
2005-09-07 01:39:11 +00:00
static int set_talk_volume ( struct ast_conf_user * user , int volume )
2005-09-07 01:30:01 +00:00
{
signed char gain_adjust ;
/* attempt to make the adjustment in the channel driver;
if successful , don ' t adjust in the frame reading routine
*/
gain_adjust = gain_map [ volume + 5 ] ;
2005-09-07 01:39:11 +00:00
return ast_channel_setoption ( user - > chan , AST_OPTION_RXGAIN , & gain_adjust , sizeof ( gain_adjust ) , 0 ) ;
2005-09-07 01:30:01 +00:00
}
2005-09-07 02:27:58 +00:00
static int set_listen_volume ( struct ast_conf_user * user , int volume )
{
signed char gain_adjust ;
/* attempt to make the adjustment in the channel driver;
if successful , don ' t adjust in the frame reading routine
*/
gain_adjust = gain_map [ volume + 5 ] ;
return ast_channel_setoption ( user - > chan , AST_OPTION_TXGAIN , & gain_adjust , sizeof ( gain_adjust ) , 0 ) ;
}
static void tweak_volume ( struct volume * vol , enum volume_action action )
2005-09-07 01:30:01 +00:00
{
switch ( action ) {
case VOL_UP :
2005-09-07 02:27:58 +00:00
switch ( vol - > desired ) {
2005-09-07 01:30:01 +00:00
case 5 :
break ;
case 0 :
2005-09-07 02:27:58 +00:00
vol - > desired = 2 ;
2005-09-07 01:30:01 +00:00
break ;
case - 2 :
2005-09-07 02:27:58 +00:00
vol - > desired = 0 ;
2005-09-07 01:30:01 +00:00
break ;
default :
2005-09-07 02:27:58 +00:00
vol - > desired + + ;
2005-09-07 01:30:01 +00:00
break ;
}
break ;
case VOL_DOWN :
2005-09-07 02:27:58 +00:00
switch ( vol - > desired ) {
2005-09-07 01:30:01 +00:00
case - 5 :
break ;
case 2 :
2005-09-07 02:27:58 +00:00
vol - > desired = 0 ;
2005-09-07 01:30:01 +00:00
break ;
case 0 :
2005-09-07 02:27:58 +00:00
vol - > desired = - 2 ;
2005-09-07 01:30:01 +00:00
break ;
default :
2005-09-07 02:27:58 +00:00
vol - > desired - - ;
2005-09-07 01:30:01 +00:00
break ;
}
}
2005-09-07 02:27:58 +00:00
}
static void tweak_talk_volume ( struct ast_conf_user * user , enum volume_action action )
{
tweak_volume ( & user - > talk , action ) ;
/* attempt to make the adjustment in the channel driver;
if successful , don ' t adjust in the frame reading routine
*/
if ( ! set_talk_volume ( user , user - > talk . desired ) )
user - > talk . actual = 0 ;
else
user - > talk . actual = user - > talk . desired ;
}
static void tweak_listen_volume ( struct ast_conf_user * user , enum volume_action action )
{
tweak_volume ( & user - > listen , action ) ;
2005-09-07 01:30:01 +00:00
/* attempt to make the adjustment in the channel driver;
if successful , don ' t adjust in the frame reading routine
*/
2005-09-07 02:27:58 +00:00
if ( ! set_listen_volume ( user , user - > listen . desired ) )
user - > listen . actual = 0 ;
2005-09-07 01:30:01 +00:00
else
2005-09-07 02:27:58 +00:00
user - > listen . actual = user - > listen . desired ;
2005-09-07 01:30:01 +00:00
}
2005-09-07 14:15:37 +00:00
static void reset_volumes ( struct ast_conf_user * user )
{
signed char zero_volume = 0 ;
ast_channel_setoption ( user - > chan , AST_OPTION_TXGAIN , & zero_volume , sizeof ( zero_volume ) , 0 ) ;
ast_channel_setoption ( user - > chan , AST_OPTION_RXGAIN , & zero_volume , sizeof ( zero_volume ) , 0 ) ;
}
2005-02-16 03:50:41 +00:00
static void conf_play ( struct ast_channel * chan , struct ast_conference * conf , int sound )
2002-05-13 22:29:39 +00:00
{
unsigned char * data ;
int len ;
2005-02-16 03:50:41 +00:00
int res = - 1 ;
if ( ! chan - > _softhangup )
res = ast_autoservice_start ( chan ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & conflock ) ;
2002-05-13 22:29:39 +00:00
switch ( sound ) {
case ENTER :
data = enter ;
len = sizeof ( enter ) ;
break ;
case LEAVE :
data = leave ;
len = sizeof ( leave ) ;
break ;
default :
data = NULL ;
len = 0 ;
}
if ( data )
2004-06-01 22:54:18 +00:00
careful_write ( conf - > fd , data , len ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conflock ) ;
2005-02-16 03:50:41 +00:00
if ( ! res )
ast_autoservice_stop ( chan ) ;
2002-05-13 22:29:39 +00:00
}
2005-02-22 15:42:41 +00:00
static struct ast_conference * build_conf ( char * confno , char * pin , char * pinadmin , int make , int dynamic )
2002-05-13 22:29:39 +00:00
{
2004-01-11 06:07:36 +00:00
struct ast_conference * cnf ;
2002-05-13 22:29:39 +00:00
struct zt_confinfo ztc ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & conflock ) ;
2002-05-13 22:29:39 +00:00
cnf = confs ;
while ( cnf ) {
if ( ! strcmp ( confno , cnf - > confno ) )
break ;
cnf = cnf - > next ;
}
2004-01-11 06:07:36 +00:00
if ( ! cnf & & ( make | | dynamic ) ) {
cnf = malloc ( sizeof ( struct ast_conference ) ) ;
2002-05-13 22:29:39 +00:00
if ( cnf ) {
/* Make a new one */
2004-01-11 06:07:36 +00:00
memset ( cnf , 0 , sizeof ( struct ast_conference ) ) ;
2005-07-07 23:17:04 +00:00
ast_copy_string ( cnf - > confno , confno , sizeof ( cnf - > confno ) ) ;
ast_copy_string ( cnf - > pin , pin , sizeof ( cnf - > pin ) ) ;
ast_copy_string ( cnf - > pinadmin , pinadmin , sizeof ( cnf - > pinadmin ) ) ;
2004-08-27 04:12:55 +00:00
cnf - > markedusers = 0 ;
2004-10-26 22:25:43 +00:00
cnf - > chan = ast_request ( " zap " , AST_FORMAT_ULAW , " pseudo " , NULL ) ;
2004-06-02 16:57:14 +00:00
if ( cnf - > chan ) {
cnf - > fd = cnf - > chan - > fds [ 0 ] ; /* for use by conf_play() */
} else {
ast_log ( LOG_WARNING , " Unable to open pseudo channel - trying device \n " ) ;
cnf - > fd = open ( " /dev/zap/pseudo " , O_RDWR ) ;
if ( cnf - > fd < 0 ) {
ast_log ( LOG_WARNING , " Unable to open pseudo device \n " ) ;
free ( cnf ) ;
cnf = NULL ;
goto cnfout ;
}
2002-05-13 22:29:39 +00:00
}
memset ( & ztc , 0 , sizeof ( ztc ) ) ;
/* Setup a new zap conference */
2004-01-11 06:07:36 +00:00
ztc . chan = 0 ;
2002-05-13 22:29:39 +00:00
ztc . confno = - 1 ;
2005-01-22 04:51:30 +00:00
ztc . confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON ;
2004-06-01 22:54:18 +00:00
if ( ioctl ( cnf - > fd , ZT_SETCONF , & ztc ) ) {
2002-05-13 22:29:39 +00:00
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
2004-06-02 16:57:14 +00:00
if ( cnf - > chan )
ast_hangup ( cnf - > chan ) ;
else
close ( cnf - > fd ) ;
2002-05-13 22:29:39 +00:00
free ( cnf ) ;
cnf = NULL ;
goto cnfout ;
}
2004-05-30 20:38:05 +00:00
/* Fill the conference struct */
2002-05-13 22:29:39 +00:00
cnf - > start = time ( NULL ) ;
cnf - > zapconf = ztc . confno ;
2004-01-11 06:07:36 +00:00
cnf - > isdynamic = dynamic ;
2004-05-30 20:38:05 +00:00
cnf - > firstuser = NULL ;
cnf - > lastuser = NULL ;
cnf - > locked = 0 ;
2002-05-13 22:29:39 +00:00
if ( option_verbose > 2 )
2004-05-23 14:19:45 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Created MeetMe conference %d for conference '%s' \n " , cnf - > zapconf , cnf - > confno ) ;
2002-05-13 22:29:39 +00:00
cnf - > next = confs ;
confs = cnf ;
} else
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
}
cnfout :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conflock ) ;
2002-05-13 22:29:39 +00:00
return cnf ;
}
static int confs_show ( int fd , int argc , char * * argv )
{
2004-05-22 04:11:22 +00:00
ast_cli ( fd , " Deprecated! Please use 'meetme' instead. \n " ) ;
2004-05-30 20:38:05 +00:00
return RESULT_SUCCESS ;
2004-05-22 04:11:22 +00:00
}
static char show_confs_usage [ ] =
" Deprecated! Please use 'meetme' instead. \n " ;
static struct ast_cli_entry cli_show_confs = {
2004-05-30 20:38:05 +00:00
{ " show " , " conferences " , NULL } , confs_show ,
" Show status of conferences " , show_confs_usage , NULL } ;
2004-05-22 04:11:22 +00:00
static int conf_cmd ( int fd , int argc , char * * argv ) {
/* Process the command */
struct ast_conference * cnf ;
struct ast_conf_user * user ;
2002-05-13 22:29:39 +00:00
int hr , min , sec ;
2004-05-23 14:19:45 +00:00
int i = 0 , total = 0 ;
2002-05-13 22:29:39 +00:00
time_t now ;
2004-06-21 02:37:34 +00:00
char * header_format = " %-14s %-14s %-10s %-8s %-8s \n " ;
char * data_format = " %-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s \n " ;
2004-05-22 04:11:22 +00:00
char cmdline [ 1024 ] = " " ;
2004-05-23 14:19:45 +00:00
2004-05-22 04:11:22 +00:00
if ( argc > 8 )
ast_cli ( fd , " Invalid Arguments. \n " ) ;
/* Check for length so no buffer will overflow... */
for ( i = 0 ; i < argc ; i + + ) {
if ( strlen ( argv [ i ] ) > 100 )
ast_cli ( fd , " Invalid Arguments. \n " ) ;
}
if ( argc = = 1 ) {
2004-05-23 14:19:45 +00:00
/* 'MeetMe': List all the conferences */
2002-05-13 22:29:39 +00:00
now = time ( NULL ) ;
2004-05-30 20:38:05 +00:00
cnf = confs ;
if ( ! cnf ) {
2004-05-23 14:19:45 +00:00
ast_cli ( fd , " No active MeetMe conferences. \n " ) ;
2002-05-13 22:29:39 +00:00
return RESULT_SUCCESS ;
}
2004-06-21 02:37:34 +00:00
ast_cli ( fd , header_format , " Conf Num " , " Parties " , " Marked " , " Activity " , " Creation " ) ;
2004-05-30 20:38:05 +00:00
while ( cnf ) {
2004-08-27 04:12:55 +00:00
if ( cnf - > markedusers = = 0 )
2005-07-07 23:17:04 +00:00
strcpy ( cmdline , " N/A " ) ;
2004-06-21 02:37:34 +00:00
else
snprintf ( cmdline , sizeof ( cmdline ) , " %4.4d " , cnf - > markedusers ) ;
2004-05-30 20:38:05 +00:00
hr = ( now - cnf - > start ) / 3600 ;
min = ( ( now - cnf - > start ) % 3600 ) / 60 ;
sec = ( now - cnf - > start ) % 60 ;
2002-05-13 22:29:39 +00:00
2004-06-21 02:37:34 +00:00
ast_cli ( fd , data_format , cnf - > confno , cnf - > users , cmdline , hr , min , sec , cnf - > isdynamic ? " Dynamic " : " Static " ) ;
2004-01-11 06:07:36 +00:00
2004-05-23 14:19:45 +00:00
total + = cnf - > users ;
cnf = cnf - > next ;
}
ast_cli ( fd , " * Total number of MeetMe users: %d \n " , total ) ;
return RESULT_SUCCESS ;
2004-05-22 04:11:22 +00:00
}
if ( argc < 3 )
return RESULT_SHOWUSAGE ;
2005-07-07 23:17:04 +00:00
ast_copy_string ( cmdline , argv [ 2 ] , sizeof ( cmdline ) ) ; /* Argv 2: conference number */
2004-05-23 14:19:45 +00:00
if ( strstr ( argv [ 1 ] , " lock " ) ) {
2004-05-22 04:11:22 +00:00
if ( strcmp ( argv [ 1 ] , " lock " ) = = 0 ) {
/* Lock */
2004-07-14 07:22:30 +00:00
strncat ( cmdline , " |L " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
2004-05-22 04:11:22 +00:00
} else {
/* Unlock */
2004-07-14 07:22:30 +00:00
strncat ( cmdline , " |l " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
2004-05-22 04:11:22 +00:00
}
2004-05-23 14:19:45 +00:00
} else if ( strstr ( argv [ 1 ] , " mute " ) ) {
2004-05-22 04:11:22 +00:00
if ( argc < 4 )
return RESULT_SHOWUSAGE ;
if ( strcmp ( argv [ 1 ] , " mute " ) = = 0 ) {
/* Mute */
2004-10-11 15:40:24 +00:00
if ( strcmp ( argv [ 3 ] , " all " ) = = 0 ) {
strncat ( cmdline , " |N " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
} else {
strncat ( cmdline , " |M| " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
strncat ( cmdline , argv [ 3 ] , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
}
2004-05-22 04:11:22 +00:00
} else {
/* Unmute */
2004-10-11 15:40:24 +00:00
if ( strcmp ( argv [ 3 ] , " all " ) = = 0 ) {
strncat ( cmdline , " |n " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
} else {
strncat ( cmdline , " |m| " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
strncat ( cmdline , argv [ 3 ] , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
}
2004-05-22 04:11:22 +00:00
}
} else if ( strcmp ( argv [ 1 ] , " kick " ) = = 0 ) {
if ( argc < 4 )
return RESULT_SHOWUSAGE ;
if ( strcmp ( argv [ 3 ] , " all " ) = = 0 ) {
/* Kick all */
2004-07-14 07:22:30 +00:00
strncat ( cmdline , " |K " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
2004-05-22 04:11:22 +00:00
} else {
/* Kick a single user */
2004-07-14 07:22:30 +00:00
strncat ( cmdline , " |k| " , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
strncat ( cmdline , argv [ 3 ] , sizeof ( cmdline ) - strlen ( cmdline ) - 1 ) ;
2004-05-22 04:11:22 +00:00
}
} else if ( strcmp ( argv [ 1 ] , " list " ) = = 0 ) {
/* List all the users in a conference */
if ( ! confs ) {
ast_cli ( fd , " No active conferences. \n " ) ;
return RESULT_SUCCESS ;
}
cnf = confs ;
/* Find the right conference */
while ( cnf ) {
if ( strcmp ( cnf - > confno , argv [ 2 ] ) = = 0 )
break ;
if ( cnf - > next ) {
cnf = cnf - > next ;
} else {
ast_cli ( fd , " No such conference: %s. \n " , argv [ 2 ] ) ;
return RESULT_SUCCESS ;
}
}
/* Show all the users */
user = cnf - > firstuser ;
while ( user ) {
2005-08-08 02:32:37 +00:00
ast_cli ( fd , " User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s \n " , user - > user_no , user - > chan - > cid . cid_num ? user - > chan - > cid . cid_num : " <unknown> " , user - > chan - > cid . cid_name ? user - > chan - > cid . cid_name : " <no name> " , user - > chan - > name , ( user - > userflags & CONFFLAG_ADMIN ) ? " (Admin) " : " " , ( user - > userflags & CONFFLAG_MONITOR ) ? " (Listen only) " : " " , ( user - > adminflags & ADMINFLAG_MUTED ) ? " (Admn Muted) " : " " , istalking ( user - > talking ) ) ;
2004-05-22 04:11:22 +00:00
user = user - > nextuser ;
}
2005-02-26 06:49:07 +00:00
ast_cli ( fd , " %d users in that conference. \n " , cnf - > users ) ;
2004-05-22 04:11:22 +00:00
return RESULT_SUCCESS ;
} else
return RESULT_SHOWUSAGE ;
2004-05-23 14:19:45 +00:00
ast_log ( LOG_DEBUG , " Cmdline: %s \n " , cmdline ) ;
2004-05-22 04:11:22 +00:00
admin_exec ( NULL , cmdline ) ;
return 0 ;
2002-05-13 22:29:39 +00:00
}
2004-05-22 04:11:22 +00:00
static char * complete_confcmd ( char * line , char * word , int pos , int state ) {
# define CONF_COMMANDS 6
int which = 0 , x = 0 ;
struct ast_conference * cnf = NULL ;
struct ast_conf_user * usr = NULL ;
char * confno = NULL ;
char usrno [ 50 ] = " " ;
char cmds [ CONF_COMMANDS ] [ 20 ] = { " lock " , " unlock " , " mute " , " unmute " , " kick " , " list " } ;
char * myline ;
if ( pos = = 1 ) {
/* Command */
for ( x = 0 ; x < CONF_COMMANDS ; x + + ) {
if ( ! strncasecmp ( cmds [ x ] , word , strlen ( word ) ) ) {
if ( + + which > state ) {
return strdup ( cmds [ x ] ) ;
}
}
}
} else if ( pos = = 2 ) {
/* Conference Number */
ast_mutex_lock ( & conflock ) ;
cnf = confs ;
while ( cnf ) {
if ( ! strncasecmp ( word , cnf - > confno , strlen ( word ) ) ) {
if ( + + which > state )
break ;
}
cnf = cnf - > next ;
}
ast_mutex_unlock ( & conflock ) ;
return cnf ? strdup ( cnf - > confno ) : NULL ;
} else if ( pos = = 3 ) {
/* User Number || Conf Command option*/
if ( strstr ( line , " mute " ) | | strstr ( line , " kick " ) ) {
2004-10-11 15:40:24 +00:00
if ( ( state = = 0 ) & & ( strstr ( line , " kick " ) | | strstr ( line , " mute " ) ) & & ! ( strncasecmp ( word , " all " , strlen ( word ) ) ) ) {
2004-05-22 04:11:22 +00:00
return strdup ( " all " ) ;
}
which + + ;
ast_mutex_lock ( & conflock ) ;
cnf = confs ;
2002-05-13 22:29:39 +00:00
2004-05-22 04:11:22 +00:00
/* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
2004-05-23 14:55:50 +00:00
myline = ast_strdupa ( line ) ;
2004-05-22 04:11:22 +00:00
if ( strsep ( & myline , " " ) & & strsep ( & myline , " " ) & & ! confno ) {
while ( ( confno = strsep ( & myline , " " ) ) & & ( strcmp ( confno , " " ) = = 0 ) )
;
}
while ( cnf ) {
if ( strcmp ( confno , cnf - > confno ) = = 0 ) {
break ;
}
cnf = cnf - > next ;
}
if ( cnf ) {
/* Search for the user */
usr = cnf - > firstuser ;
while ( usr ) {
2005-04-29 17:00:33 +00:00
snprintf ( usrno , sizeof ( usrno ) , " %d " , usr - > user_no ) ;
2004-05-22 04:11:22 +00:00
if ( ! strncasecmp ( word , usrno , strlen ( word ) ) ) {
if ( + + which > state )
break ;
}
usr = usr - > nextuser ;
}
}
ast_mutex_unlock ( & conflock ) ;
return usr ? strdup ( usrno ) : NULL ;
}
}
return NULL ;
}
2004-05-30 20:38:05 +00:00
2004-05-22 04:11:22 +00:00
static char conf_usage [ ] =
2004-05-23 14:19:45 +00:00
" Usage: meetme (un)lock|(un)mute|kick|list <confno> <usernumber> \n "
2004-05-22 04:11:22 +00:00
" Executes a command for the conference or on a conferee \n " ;
static struct ast_cli_entry cli_conf = {
2004-05-30 20:38:05 +00:00
{ " meetme " , NULL , NULL } , conf_cmd ,
" Execute a command on a conference or conferee " , conf_usage , complete_confcmd } ;
2002-05-13 22:29:39 +00:00
2005-03-03 23:33:11 +00:00
static void conf_flush ( int fd )
{
int x ;
x = ZT_FLUSH_ALL ;
2005-03-05 15:25:08 +00:00
if ( ioctl ( fd , ZT_FLUSH , & x ) )
2005-03-03 23:33:11 +00:00
ast_log ( LOG_WARNING , " Error flushing channel \n " ) ;
}
2005-07-07 22:36:40 +00:00
/* Remove the conference from the list and free it.
We assume that this was called while holding conflock . */
static int conf_free ( struct ast_conference * conf )
{
struct ast_conference * prev = NULL , * cur = confs ;
while ( cur ) {
if ( cur = = conf ) {
if ( prev )
prev - > next = conf - > next ;
else
confs = conf - > next ;
break ;
}
prev = cur ;
cur = cur - > next ;
}
if ( ! cur )
ast_log ( LOG_WARNING , " Conference not found \n " ) ;
if ( conf - > recording = = MEETME_RECORD_ACTIVE ) {
conf - > recording = MEETME_RECORD_TERMINATE ;
ast_mutex_unlock ( & conflock ) ;
while ( 1 ) {
ast_mutex_lock ( & conflock ) ;
if ( conf - > recording = = MEETME_RECORD_OFF )
break ;
ast_mutex_unlock ( & conflock ) ;
}
}
if ( conf - > chan )
ast_hangup ( conf - > chan ) ;
else
close ( conf - > fd ) ;
free ( conf ) ;
return 0 ;
}
2004-01-11 06:07:36 +00:00
static int conf_run ( struct ast_channel * chan , struct ast_conference * conf , int confflags )
2002-05-13 22:29:39 +00:00
{
2004-05-30 20:38:05 +00:00
struct ast_conf_user * user = malloc ( sizeof ( struct ast_conf_user ) ) ;
2005-01-14 04:25:35 +00:00
struct ast_conf_user * usr = NULL ;
2002-05-13 22:29:39 +00:00
int fd ;
2005-04-02 23:26:27 +00:00
struct zt_confinfo ztc , ztc_empty ;
2002-05-13 22:29:39 +00:00
struct ast_frame * f ;
struct ast_channel * c ;
struct ast_frame fr ;
int outfd ;
int ms ;
int nfds ;
int res ;
int flags ;
2003-02-04 15:48:42 +00:00
int retryzap ;
int origfd ;
2003-11-04 21:47:35 +00:00
int musiconhold = 0 ;
2003-02-04 15:48:42 +00:00
int firstpass = 0 ;
2004-06-23 04:55:04 +00:00
int origquiet ;
2005-03-17 20:29:51 +00:00
int lastmarked = 0 ;
int currentmarked = 0 ;
2003-02-04 15:48:42 +00:00
int ret = - 1 ;
2003-06-30 02:00:02 +00:00
int x ;
2004-05-30 20:24:48 +00:00
int menu_active = 0 ;
int using_pseudo = 0 ;
2005-01-07 07:23:31 +00:00
int duration = 20 ;
2005-01-30 03:07:21 +00:00
struct ast_dsp * dsp = NULL ;
2002-05-13 22:29:39 +00:00
2003-09-28 21:18:51 +00:00
struct ast_app * app ;
char * agifile ;
char * agifiledefault = " conf-background.agi " ;
2004-07-14 07:22:30 +00:00
char meetmesecs [ 30 ] = " " ;
2005-07-10 23:49:57 +00:00
char exitcontext [ AST_MAX_CONTEXT ] = " " ;
2005-01-22 04:51:30 +00:00
char recordingtmp [ AST_MAX_EXTENSION ] = " " ;
2004-09-07 01:22:57 +00:00
int dtmf ;
2003-09-28 21:18:51 +00:00
2002-05-13 22:29:39 +00:00
ZT_BUFFERINFO bi ;
char __buf [ CONF_SIZE + AST_FRIENDLY_OFFSET ] ;
char * buf = __buf + AST_FRIENDLY_OFFSET ;
2003-11-04 21:47:35 +00:00
2004-07-14 07:22:30 +00:00
if ( ! user ) {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
return ( ret ) ;
}
memset ( user , 0 , sizeof ( struct ast_conf_user ) ) ;
2005-01-22 04:51:30 +00:00
if ( confflags & CONFFLAG_RECORDCONF & & conf - > recording ! = MEETME_RECORD_ACTIVE ) {
conf - > recordingfilename = pbx_builtin_getvar_helper ( chan , " MEETME_RECORDINGFILE " ) ;
if ( ! conf - > recordingfilename ) {
snprintf ( recordingtmp , sizeof ( recordingtmp ) , " meetme-conf-rec-%s-%s " , conf - > confno , chan - > uniqueid ) ;
conf - > recordingfilename = ast_strdupa ( recordingtmp ) ;
}
conf - > recordingformat = pbx_builtin_getvar_helper ( chan , " MEETME_RECORDINGFORMAT " ) ;
if ( ! conf - > recordingformat ) {
snprintf ( recordingtmp , sizeof ( recordingtmp ) , " wav " ) ;
conf - > recordingformat = ast_strdupa ( recordingtmp ) ;
}
pthread_attr_init ( & conf - > attr ) ;
pthread_attr_setdetachstate ( & conf - > attr , PTHREAD_CREATE_DETACHED ) ;
ast_verbose ( VERBOSE_PREFIX_4 " Starting recording of MeetMe Conference %s into file %s.%s. \n " , conf - > confno , conf - > recordingfilename , conf - > recordingformat ) ;
ast_pthread_create ( & conf - > recordthread , & conf - > attr , recordthread , conf ) ;
}
2004-05-30 20:38:05 +00:00
user - > user_no = 0 ; /* User number 0 means starting up user! (dead - not in the list!) */
2004-11-25 03:23:07 +00:00
time ( & user - > jointime ) ;
2004-05-22 04:11:22 +00:00
if ( conf - > locked ) {
/* Sorry, but this confernce is locked! */
if ( ! ast_streamfile ( chan , " conf-locked " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
goto outrun ;
}
2005-01-07 07:23:31 +00:00
2004-08-27 04:12:55 +00:00
if ( confflags & CONFFLAG_MARKEDUSER )
conf - > markedusers + + ;
2004-05-22 04:11:22 +00:00
2004-06-17 05:21:54 +00:00
ast_mutex_lock ( & conflock ) ;
2004-05-30 20:38:05 +00:00
if ( conf - > firstuser = = NULL ) {
2004-05-22 04:11:22 +00:00
/* Fill the first new User struct */
2004-05-30 20:38:05 +00:00
user - > user_no = 1 ;
user - > nextuser = NULL ;
user - > prevuser = NULL ;
conf - > firstuser = user ;
conf - > lastuser = user ;
} else {
/* Fill the new user struct */
user - > user_no = conf - > lastuser - > user_no + 1 ;
user - > prevuser = conf - > lastuser ;
user - > nextuser = NULL ;
if ( conf - > lastuser - > nextuser ! = NULL ) {
ast_log ( LOG_WARNING , " Error in User Management! \n " ) ;
2004-06-28 22:10:50 +00:00
ast_mutex_unlock ( & conflock ) ;
goto outrun ;
2004-05-30 20:38:05 +00:00
} else {
conf - > lastuser - > nextuser = user ;
conf - > lastuser = user ;
}
}
2004-05-22 04:11:22 +00:00
user - > chan = chan ;
user - > userflags = confflags ;
user - > adminflags = 0 ;
2005-01-30 03:07:21 +00:00
user - > talking = - 1 ;
2004-05-22 04:11:22 +00:00
ast_mutex_unlock ( & conflock ) ;
2004-06-23 04:55:04 +00:00
origquiet = confflags & CONFFLAG_QUIET ;
2004-08-03 06:31:20 +00:00
if ( confflags & CONFFLAG_EXIT_CONTEXT ) {
if ( ( agifile = pbx_builtin_getvar_helper ( chan , " MEETME_EXIT_CONTEXT " ) ) )
2005-07-07 23:17:04 +00:00
ast_copy_string ( exitcontext , agifile , sizeof ( exitcontext ) ) ;
2004-08-03 06:31:20 +00:00
else if ( ! ast_strlen_zero ( chan - > macrocontext ) )
2005-07-07 23:17:04 +00:00
ast_copy_string ( exitcontext , chan - > macrocontext , sizeof ( exitcontext ) ) ;
2004-08-03 06:31:20 +00:00
else
2005-07-07 23:17:04 +00:00
ast_copy_string ( exitcontext , chan - > context , sizeof ( exitcontext ) ) ;
2004-08-03 06:31:20 +00:00
}
2005-01-07 07:23:31 +00:00
2005-03-12 05:37:32 +00:00
if ( ! ( confflags & CONFFLAG_QUIET ) & & ( confflags & CONFFLAG_INTROUSER ) ) {
snprintf ( user - > namerecloc , sizeof ( user - > namerecloc ) , " %s/meetme/meetme-username-%s-%d " , ast_config_AST_SPOOL_DIR , conf - > confno , user - > user_no ) ;
2005-01-23 09:05:01 +00:00
ast_record_review ( chan , " vm-rec-name " , user - > namerecloc , 10 , " sln " , & duration , NULL ) ;
2005-03-12 05:37:32 +00:00
}
2005-01-07 07:23:31 +00:00
2005-05-19 01:09:46 +00:00
conf - > users + + ;
2005-03-17 20:29:51 +00:00
if ( ! ( confflags & CONFFLAG_QUIET ) ) {
if ( conf - > users = = 1 & & ! ( confflags & CONFFLAG_WAITMARKED ) )
if ( ! ast_streamfile ( chan , " conf-onlyperson " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
if ( ( confflags & CONFFLAG_WAITMARKED ) & & conf - > markedusers = = 0 )
if ( ! ast_streamfile ( chan , " conf-waitforleader " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
2003-02-04 15:48:42 +00:00
}
2002-05-13 22:29:39 +00:00
2005-03-20 03:04:46 +00:00
if ( ! ( confflags & CONFFLAG_QUIET ) & & ( confflags & CONFFLAG_ANNOUNCEUSERCOUNT ) & & conf - > users > 1 ) {
int keepplaying = 1 ;
if ( conf - > users = = 2 ) {
if ( ! ast_streamfile ( chan , " conf-onlyone " , chan - > language ) ) {
res = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
if ( res > 0 )
keepplaying = 0 ;
else if ( res = = - 1 )
goto outrun ;
}
} else {
if ( ! ast_streamfile ( chan , " conf-thereare " , chan - > language ) ) {
res = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
if ( res > 0 )
keepplaying = 0 ;
else if ( res = = - 1 )
goto outrun ;
}
if ( keepplaying ) {
res = ast_say_number ( chan , conf - > users - 1 , AST_DIGIT_ANY , chan - > language , ( char * ) NULL ) ;
if ( res > 0 )
keepplaying = 0 ;
else if ( res = = - 1 )
goto outrun ;
}
if ( keepplaying & & ! ast_streamfile ( chan , " conf-otherinparty " , chan - > language ) ) {
res = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
if ( res > 0 )
keepplaying = 0 ;
else if ( res = = - 1 )
goto outrun ;
}
}
}
2004-06-14 03:12:46 +00:00
/* Set it into linear mode (write) */
if ( ast_set_write_format ( chan , AST_FORMAT_SLINEAR ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to set '%s' to write linear mode \n " , chan - > name ) ;
goto outrun ;
}
2003-06-30 02:00:02 +00:00
2004-06-14 03:12:46 +00:00
/* Set it into linear mode (read) */
if ( ast_set_read_format ( chan , AST_FORMAT_SLINEAR ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to set '%s' to read linear mode \n " , chan - > name ) ;
goto outrun ;
2002-05-13 22:29:39 +00:00
}
2003-02-04 15:48:42 +00:00
ast_indicate ( chan , - 1 ) ;
retryzap = strcasecmp ( chan - > type , " Zap " ) ;
2005-09-25 03:57:53 +00:00
user - > zapchannel = ! retryzap ;
2002-05-13 22:29:39 +00:00
zapretry :
2003-02-04 15:48:42 +00:00
origfd = chan - > fds [ 0 ] ;
if ( retryzap ) {
2002-05-13 22:29:39 +00:00
fd = open ( " /dev/zap/pseudo " , O_RDWR ) ;
if ( fd < 0 ) {
ast_log ( LOG_WARNING , " Unable to open pseudo channel: %s \n " , strerror ( errno ) ) ;
goto outrun ;
}
2004-05-30 20:24:48 +00:00
using_pseudo = 1 ;
2002-05-13 22:29:39 +00:00
/* Make non-blocking */
flags = fcntl ( fd , F_GETFL ) ;
if ( flags < 0 ) {
ast_log ( LOG_WARNING , " Unable to get flags: %s \n " , strerror ( errno ) ) ;
close ( fd ) ;
goto outrun ;
}
if ( fcntl ( fd , F_SETFL , flags | O_NONBLOCK ) ) {
ast_log ( LOG_WARNING , " Unable to set flags: %s \n " , strerror ( errno ) ) ;
close ( fd ) ;
goto outrun ;
}
/* Setup buffering information */
memset ( & bi , 0 , sizeof ( bi ) ) ;
2004-06-14 03:12:46 +00:00
bi . bufsize = CONF_SIZE / 2 ;
2002-05-13 22:29:39 +00:00
bi . txbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . rxbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . numbufs = 4 ;
if ( ioctl ( fd , ZT_SET_BUFINFO , & bi ) ) {
ast_log ( LOG_WARNING , " Unable to set buffering information: %s \n " , strerror ( errno ) ) ;
close ( fd ) ;
goto outrun ;
}
2004-06-14 03:12:46 +00:00
x = 1 ;
if ( ioctl ( fd , ZT_SETLINEAR , & x ) ) {
ast_log ( LOG_WARNING , " Unable to set linear mode: %s \n " , strerror ( errno ) ) ;
close ( fd ) ;
goto outrun ;
2003-06-30 02:00:02 +00:00
}
2002-05-13 22:29:39 +00:00
nfds = 1 ;
} else {
/* XXX Make sure we're not running on a pseudo channel XXX */
fd = chan - > fds [ 0 ] ;
nfds = 0 ;
}
memset ( & ztc , 0 , sizeof ( ztc ) ) ;
2005-04-02 23:26:27 +00:00
memset ( & ztc_empty , 0 , sizeof ( ztc_empty ) ) ;
2002-05-13 22:29:39 +00:00
/* Check to see if we're in a conference... */
ztc . chan = 0 ;
if ( ioctl ( fd , ZT_GETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error getting conference \n " ) ;
close ( fd ) ;
goto outrun ;
}
if ( ztc . confmode ) {
/* Whoa, already in a conference... Retry... */
if ( ! retryzap ) {
ast_log ( LOG_DEBUG , " Zap channel is in a conference already, retrying with pseudo \n " ) ;
retryzap = 1 ;
goto zapretry ;
}
}
memset ( & ztc , 0 , sizeof ( ztc ) ) ;
/* Add us to the conference */
ztc . chan = 0 ;
ztc . confno = conf - > zapconf ;
2005-01-07 07:23:31 +00:00
ast_mutex_lock ( & conflock ) ;
if ( ! ( confflags & CONFFLAG_QUIET ) & & ( confflags & CONFFLAG_INTROUSER ) & & conf - > users > 1 ) {
2005-02-01 06:48:50 +00:00
if ( conf - > chan & & ast_fileexists ( user - > namerecloc , NULL , NULL ) ) {
2005-01-07 07:23:31 +00:00
if ( ! ast_streamfile ( conf - > chan , user - > namerecloc , chan - > language ) )
ast_waitstream ( conf - > chan , " " ) ;
if ( ! ast_streamfile ( conf - > chan , " conf-hasjoin " , chan - > language ) )
ast_waitstream ( conf - > chan , " " ) ;
}
}
2003-02-04 15:48:42 +00:00
if ( confflags & CONFFLAG_MONITOR )
ztc . confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER ;
else if ( confflags & CONFFLAG_TALKER )
ztc . confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
else
ztc . confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER ;
2002-05-13 22:29:39 +00:00
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
close ( fd ) ;
2005-01-07 07:23:31 +00:00
ast_mutex_unlock ( & conflock ) ;
2002-05-13 22:29:39 +00:00
goto outrun ;
}
ast_log ( LOG_DEBUG , " Placed channel %s in ZAP conf %d \n " , chan - > name , conf - > zapconf ) ;
2004-05-13 19:02:47 +00:00
manager_event ( EVENT_FLAG_CALL , " MeetmeJoin " ,
" Channel: %s \r \n "
" Uniqueid: %s \r \n "
2004-08-02 15:28:12 +00:00
" Meetme: %s \r \n "
2005-04-29 17:00:33 +00:00
" Usernum: %d \r \n " ,
2004-08-02 15:28:12 +00:00
chan - > name , chan - > uniqueid , conf - > confno , user - > user_no ) ;
2004-05-13 19:02:47 +00:00
2003-02-04 15:48:42 +00:00
if ( ! firstpass & & ! ( confflags & CONFFLAG_MONITOR ) & & ! ( confflags & CONFFLAG_ADMIN ) ) {
firstpass = 1 ;
if ( ! ( confflags & CONFFLAG_QUIET ) )
2005-03-29 06:34:50 +00:00
if ( ! ( confflags & CONFFLAG_WAITMARKED ) | | ( conf - > markedusers > = 1 ) )
2005-03-17 20:29:51 +00:00
conf_play ( chan , conf , ENTER ) ;
2003-02-04 15:48:42 +00:00
}
2005-03-05 15:25:08 +00:00
conf_flush ( fd ) ;
2005-01-07 07:23:31 +00:00
ast_mutex_unlock ( & conflock ) ;
2003-09-28 21:18:51 +00:00
if ( confflags & CONFFLAG_AGI ) {
/* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
or use default filename of conf - background . agi */
agifile = pbx_builtin_getvar_helper ( chan , " MEETME_AGI_BACKGROUND " ) ;
if ( ! agifile )
agifile = agifiledefault ;
2005-09-07 01:30:01 +00:00
if ( user - > zapchannel ) {
2003-09-28 21:18:51 +00:00
/* Set CONFMUTE mode on Zap channel to mute DTMF tones */
x = 1 ;
ast_channel_setoption ( chan , AST_OPTION_TONE_VERIFY , & x , sizeof ( char ) , 0 ) ;
}
/* Find a pointer to the agi app and execute the script */
app = pbx_findapp ( " agi " ) ;
if ( app ) {
ret = pbx_exec ( chan , app , agifile , 1 ) ;
} else {
ast_log ( LOG_WARNING , " Could not find application (agi) \n " ) ;
ret = - 2 ;
}
2005-09-07 01:30:01 +00:00
if ( user - > zapchannel ) {
2004-05-30 20:38:05 +00:00
/* Remove CONFMUTE mode on Zap channel */
2003-09-28 21:18:51 +00:00
x = 0 ;
2004-05-30 20:38:05 +00:00
ast_channel_setoption ( chan , AST_OPTION_TONE_VERIFY , & x , sizeof ( char ) , 0 ) ;
}
} else {
2005-09-07 01:30:01 +00:00
if ( user - > zapchannel & & ( confflags & CONFFLAG_STARMENU ) ) {
2004-05-30 20:38:05 +00:00
/* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
x = 1 ;
ast_channel_setoption ( chan , AST_OPTION_TONE_VERIFY , & x , sizeof ( char ) , 0 ) ;
}
2005-01-30 03:07:21 +00:00
if ( confflags & CONFFLAG_MONITORTALKER & & ! ( dsp = ast_dsp_new ( ) ) ) {
ast_log ( LOG_WARNING , " Unable to allocate DSP! \n " ) ;
res = - 1 ;
}
2004-05-30 20:38:05 +00:00
for ( ; ; ) {
2005-09-07 01:30:01 +00:00
int menu_was_active = 0 ;
2004-05-23 14:19:45 +00:00
outfd = - 1 ;
ms = - 1 ;
2005-09-07 01:30:01 +00:00
/* if we have just exited from the menu, and the user had a channel-driver
volume adjustment , restore it
*/
2005-09-07 02:27:58 +00:00
if ( ! menu_active & & menu_was_active & & user - > listen . desired & & ! user - > listen . actual )
set_talk_volume ( user , user - > listen . desired ) ;
2005-09-07 01:30:01 +00:00
menu_was_active = menu_active ;
2005-03-17 20:29:51 +00:00
currentmarked = conf - > markedusers ;
if ( ! ( confflags & CONFFLAG_QUIET ) & & ( confflags & CONFFLAG_MARKEDUSER ) & & ( confflags & CONFFLAG_WAITMARKED ) & & lastmarked = = 0 ) {
if ( currentmarked = = 1 & & conf - > users > 1 ) {
ast_say_number ( chan , conf - > users - 1 , AST_DIGIT_ANY , chan - > language , ( char * ) NULL ) ;
if ( conf - > users - 1 = = 1 ) {
if ( ! ast_streamfile ( chan , " conf-userwilljoin " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
} else {
if ( ! ast_streamfile ( chan , " conf-userswilljoin " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
}
}
if ( conf - > users = = 1 & & ! ( confflags & CONFFLAG_MARKEDUSER ) )
if ( ! ast_streamfile ( chan , " conf-onlyperson " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
}
2004-05-23 14:19:45 +00:00
c = ast_waitfor_nandfds ( & chan , 1 , & fd , nfds , NULL , & outfd , & ms ) ;
2004-05-30 20:38:05 +00:00
/* Update the struct with the actual confflags */
user - > userflags = confflags ;
2005-03-17 20:29:51 +00:00
if ( confflags & CONFFLAG_WAITMARKED ) {
if ( currentmarked = = 0 ) {
if ( lastmarked ! = 0 ) {
if ( ! ( confflags & CONFFLAG_QUIET ) )
if ( ! ast_streamfile ( chan , " conf-leaderhasleft " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
if ( confflags & CONFFLAG_MARKEDEXIT )
break ;
else {
ztc . confmode = ZT_CONF_CONF ;
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
close ( fd ) ;
goto outrun ;
}
}
}
if ( musiconhold = = 0 & & ( confflags & CONFFLAG_MOH ) ) {
ast_moh_start ( chan , NULL ) ;
musiconhold = 1 ;
} else {
ztc . confmode = ZT_CONF_CONF ;
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
close ( fd ) ;
goto outrun ;
}
}
} else if ( currentmarked > = 1 & & lastmarked = = 0 ) {
if ( confflags & CONFFLAG_MONITOR )
ztc . confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER ;
else if ( confflags & CONFFLAG_TALKER )
ztc . confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
else
ztc . confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER ;
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
close ( fd ) ;
goto outrun ;
}
if ( musiconhold & & ( confflags & CONFFLAG_MOH ) ) {
ast_moh_stop ( chan ) ;
musiconhold = 0 ;
}
if ( ! ( confflags & CONFFLAG_QUIET ) & & ! ( confflags & CONFFLAG_MARKEDUSER ) ) {
if ( ! ast_streamfile ( chan , " conf-placeintoconf " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
conf_play ( chan , conf , ENTER ) ;
}
}
}
2004-05-23 14:19:45 +00:00
/* trying to add moh for single person conf */
2005-03-21 03:23:05 +00:00
if ( ( confflags & CONFFLAG_MOH ) & & ! ( confflags & CONFFLAG_WAITMARKED ) ) {
2004-05-23 14:19:45 +00:00
if ( conf - > users = = 1 ) {
if ( musiconhold = = 0 ) {
ast_moh_start ( chan , NULL ) ;
musiconhold = 1 ;
}
} else {
if ( musiconhold ) {
ast_moh_stop ( chan ) ;
musiconhold = 0 ;
}
2003-11-04 21:47:35 +00:00
}
}
2004-05-30 20:38:05 +00:00
/* Leave if the last marked user left */
2005-03-21 02:06:58 +00:00
if ( currentmarked = = 0 & & lastmarked ! = 0 & & ( confflags & CONFFLAG_MARKEDEXIT ) ) {
2004-06-21 02:37:34 +00:00
ret = - 1 ;
2004-05-30 20:38:05 +00:00
break ;
}
2004-05-22 04:11:22 +00:00
/* Check if the admin changed my modes */
if ( user - > adminflags ) {
/* Set the new modes */
if ( ( user - > adminflags & ADMINFLAG_MUTED ) & & ( ztc . confmode & ZT_CONF_TALKER ) ) {
ztc . confmode ^ = ZT_CONF_TALKER ;
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
2004-05-30 20:38:05 +00:00
ast_log ( LOG_WARNING , " Error setting conference - Un/Mute \n " ) ;
ret = - 1 ;
break ;
}
2004-05-22 04:11:22 +00:00
}
if ( ! ( user - > adminflags & ADMINFLAG_MUTED ) & & ! ( confflags & CONFFLAG_MONITOR ) & & ! ( ztc . confmode & ZT_CONF_TALKER ) ) {
ztc . confmode | = ZT_CONF_TALKER ;
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
2004-05-30 20:38:05 +00:00
ast_log ( LOG_WARNING , " Error setting conference - Un/Mute \n " ) ;
ret = - 1 ;
break ;
}
2004-05-22 04:11:22 +00:00
}
if ( user - > adminflags & ADMINFLAG_KICKME ) {
2004-12-19 21:13:41 +00:00
/* You have been kicked. */
2004-05-22 04:11:22 +00:00
if ( ! ast_streamfile ( chan , " conf-kicked " , chan - > language ) )
2004-05-30 20:38:05 +00:00
ast_waitstream ( chan , " " ) ;
2004-05-22 04:11:22 +00:00
ret = 0 ;
2004-05-30 20:38:05 +00:00
break ;
2004-05-22 04:11:22 +00:00
}
} else if ( ! ( confflags & CONFFLAG_MONITOR ) & & ! ( ztc . confmode & ZT_CONF_TALKER ) ) {
ztc . confmode | = ZT_CONF_TALKER ;
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
2004-05-30 20:38:05 +00:00
ast_log ( LOG_WARNING , " Error setting conference - Un/Mute \n " ) ;
2004-05-22 04:11:22 +00:00
ret = - 1 ;
break ;
2004-05-30 20:38:05 +00:00
}
2004-05-22 04:11:22 +00:00
}
2003-11-04 21:47:35 +00:00
2004-06-28 22:10:50 +00:00
if ( c ) {
if ( c - > fds [ 0 ] ! = origfd ) {
if ( using_pseudo ) {
/* Kill old pseudo */
close ( fd ) ;
2005-09-25 03:57:53 +00:00
using_pseudo = 0 ;
2004-06-28 22:10:50 +00:00
}
ast_log ( LOG_DEBUG , " Ooh, something swapped out under us, starting over \n " ) ;
2005-09-25 03:57:53 +00:00
retryzap = strcasecmp ( c - > type , " Zap " ) ;
user - > zapchannel = ! retryzap ;
2004-06-28 22:10:50 +00:00
goto zapretry ;
2003-02-04 15:48:42 +00:00
}
2004-06-28 22:10:50 +00:00
f = ast_read ( c ) ;
2005-02-02 02:20:34 +00:00
if ( ! f )
2004-06-28 22:10:50 +00:00
break ;
2005-01-30 03:07:21 +00:00
if ( ( f - > frametype = = AST_FRAME_VOICE ) & & ( f - > subclass = = AST_FORMAT_SLINEAR ) ) {
2005-10-28 16:36:10 +00:00
if ( user - > talk . actual )
ast_frame_adjust_volume ( f , user - > talk . actual ) ;
2005-01-30 03:07:21 +00:00
if ( confflags & CONFFLAG_MONITORTALKER ) {
int totalsilence ;
if ( user - > talking = = - 1 )
user - > talking = 0 ;
res = ast_dsp_silence ( dsp , f , & totalsilence ) ;
if ( ! user - > talking & & totalsilence < MEETME_DELAYDETECTTALK ) {
user - > talking = 1 ;
manager_event ( EVENT_FLAG_CALL , " MeetmeTalking " ,
" Channel: %s \r \n "
" Uniqueid: %s \r \n "
" Meetme: %s \r \n "
2005-04-29 17:00:33 +00:00
" Usernum: %d \r \n " ,
2005-01-30 03:07:21 +00:00
chan - > name , chan - > uniqueid , conf - > confno , user - > user_no ) ;
}
if ( user - > talking & & totalsilence > MEETME_DELAYDETECTENDTALK ) {
user - > talking = 0 ;
manager_event ( EVENT_FLAG_CALL , " MeetmeStopTalking " ,
" Channel: %s \r \n "
" Uniqueid: %s \r \n "
" Meetme: %s \r \n "
2005-04-29 17:00:33 +00:00
" Usernum: %d \r \n " ,
2005-01-30 03:07:21 +00:00
chan - > name , chan - > uniqueid , conf - > confno , user - > user_no ) ;
}
}
2005-03-20 18:02:45 +00:00
if ( using_pseudo ) {
/* Carefully write */
careful_write ( fd , f - > data , f - > datalen ) ;
}
2005-01-30 03:07:21 +00:00
} else if ( ( f - > frametype = = AST_FRAME_DTMF ) & & ( confflags & CONFFLAG_EXIT_CONTEXT ) ) {
2004-08-03 06:31:20 +00:00
char tmp [ 2 ] ;
tmp [ 0 ] = f - > subclass ;
tmp [ 1 ] = ' \0 ' ;
2005-09-07 19:13:00 +00:00
if ( ast_goto_if_exists ( chan , exitcontext , tmp , 1 ) ) {
2004-08-03 06:31:20 +00:00
ret = 0 ;
break ;
2005-09-07 19:13:00 +00:00
} else if ( option_debug > 1 )
ast_log ( LOG_DEBUG , " Exit by single digit did not work in meetme. Extension %s does not exist in context %s \n " , tmp , exitcontext ) ;
2004-08-03 06:31:20 +00:00
} else if ( ( f - > frametype = = AST_FRAME_DTMF ) & & ( f - > subclass = = ' # ' ) & & ( confflags & CONFFLAG_POUNDEXIT ) ) {
2004-06-28 22:10:50 +00:00
ret = 0 ;
break ;
2004-05-30 20:38:05 +00:00
} else if ( ( ( f - > frametype = = AST_FRAME_DTMF ) & & ( f - > subclass = = ' * ' ) & & ( confflags & CONFFLAG_STARMENU ) ) | | ( ( f - > frametype = = AST_FRAME_DTMF ) & & menu_active ) ) {
2005-04-02 23:26:27 +00:00
if ( ioctl ( fd , ZT_SETCONF , & ztc_empty ) ) {
2005-03-03 23:33:11 +00:00
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
close ( fd ) ;
ast_mutex_unlock ( & conflock ) ;
goto outrun ;
}
2005-09-07 01:30:01 +00:00
/* if we are entering the menu, and the user has a channel-driver
volume adjustment , clear it
*/
2005-09-07 02:27:58 +00:00
if ( ! menu_active & & user - > talk . desired & & ! user - > talk . actual )
2005-09-07 01:39:11 +00:00
set_talk_volume ( user , 0 ) ;
2005-09-07 01:30:01 +00:00
2004-06-28 22:10:50 +00:00
if ( musiconhold ) {
ast_moh_stop ( chan ) ;
2003-02-04 15:48:42 +00:00
}
2004-06-28 22:10:50 +00:00
if ( ( confflags & CONFFLAG_ADMIN ) ) {
/* Admin menu */
if ( ! menu_active ) {
menu_active = 1 ;
/* Record this sound! */
2005-01-14 04:25:35 +00:00
if ( ! ast_streamfile ( chan , " conf-adminmenu " , chan - > language ) )
2004-09-07 01:22:57 +00:00
dtmf = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
2005-01-14 04:25:35 +00:00
else
2004-09-07 01:22:57 +00:00
dtmf = 0 ;
} else
dtmf = f - > subclass ;
if ( dtmf ) {
switch ( dtmf ) {
2005-09-07 02:27:58 +00:00
case ' 1 ' : /* Un/Mute */
menu_active = 0 ;
if ( ztc . confmode & ZT_CONF_TALKER ) {
2004-06-28 22:10:50 +00:00
ztc . confmode = ZT_CONF_CONF | ZT_CONF_LISTENER ;
confflags | = CONFFLAG_MONITOR ^ CONFFLAG_TALKER ;
2005-09-07 02:27:58 +00:00
} else {
ztc . confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER ;
confflags ^ = CONFFLAG_MONITOR | CONFFLAG_TALKER ;
}
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference - Un/Mute \n " ) ;
ret = - 1 ;
2005-09-07 01:30:01 +00:00
break ;
2005-09-07 02:27:58 +00:00
}
if ( ztc . confmode & ZT_CONF_TALKER ) {
if ( ! ast_streamfile ( chan , " conf-unmuted " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
} else {
if ( ! ast_streamfile ( chan , " conf-muted " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
}
break ;
case ' 2 ' : /* Un/Lock the Conference */
menu_active = 0 ;
if ( conf - > locked ) {
conf - > locked = 0 ;
if ( ! ast_streamfile ( chan , " conf-unlockednow " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
} else {
conf - > locked = 1 ;
if ( ! ast_streamfile ( chan , " conf-lockednow " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
}
break ;
case ' 3 ' : /* Eject last user */
menu_active = 0 ;
usr = conf - > lastuser ;
if ( ( usr - > chan - > name = = chan - > name ) | | ( usr - > userflags & CONFFLAG_ADMIN ) ) {
if ( ! ast_streamfile ( chan , " conf-errormenu " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
} else
usr - > adminflags | = ADMINFLAG_KICKME ;
ast_stopstream ( chan ) ;
break ;
2005-09-07 01:30:01 +00:00
2005-09-07 02:27:58 +00:00
case ' 4 ' :
tweak_listen_volume ( user , VOL_DOWN ) ;
break ;
2005-09-07 01:30:01 +00:00
2005-09-07 02:27:58 +00:00
case ' 6 ' :
tweak_listen_volume ( user , VOL_UP ) ;
break ;
2005-09-07 01:30:01 +00:00
2005-09-07 02:27:58 +00:00
case ' 7 ' :
tweak_talk_volume ( user , VOL_DOWN ) ;
break ;
case ' 8 ' :
menu_active = 0 ;
break ;
case ' 9 ' :
tweak_talk_volume ( user , VOL_UP ) ;
break ;
default :
menu_active = 0 ;
/* Play an error message! */
if ( ! ast_streamfile ( chan , " conf-errormenu " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
break ;
2004-05-30 20:38:05 +00:00
}
2004-06-28 22:10:50 +00:00
}
} else {
/* User menu */
if ( ! menu_active ) {
menu_active = 1 ;
/* Record this sound! */
if ( ! ast_streamfile ( chan , " conf-usermenu " , chan - > language ) )
2004-09-07 01:22:57 +00:00
dtmf = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
else
dtmf = 0 ;
} else
dtmf = f - > subclass ;
if ( dtmf ) {
switch ( dtmf ) {
case ' 1 ' : /* Un/Mute */
2004-06-28 22:10:50 +00:00
menu_active = 0 ;
if ( ztc . confmode & ZT_CONF_TALKER ) {
ztc . confmode = ZT_CONF_CONF | ZT_CONF_LISTENER ;
confflags | = CONFFLAG_MONITOR ^ CONFFLAG_TALKER ;
} else if ( ! ( user - > adminflags & ADMINFLAG_MUTED ) ) {
ztc . confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER ;
confflags ^ = CONFFLAG_MONITOR | CONFFLAG_TALKER ;
}
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference - Un/Mute \n " ) ;
ret = - 1 ;
2004-05-30 20:38:05 +00:00
break ;
2004-06-28 22:10:50 +00:00
}
if ( ztc . confmode & ZT_CONF_TALKER ) {
if ( ! ast_streamfile ( chan , " conf-unmuted " , chan - > language ) )
2004-05-30 20:38:05 +00:00
ast_waitstream ( chan , " " ) ;
2004-06-28 22:10:50 +00:00
} else {
if ( ! ast_streamfile ( chan , " conf-muted " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
}
break ;
2005-09-07 02:27:58 +00:00
case ' 4 ' :
tweak_listen_volume ( user , VOL_DOWN ) ;
2005-09-07 01:30:01 +00:00
break ;
2005-09-07 02:27:58 +00:00
case ' 6 ' :
tweak_listen_volume ( user , VOL_UP ) ;
2005-09-07 01:30:01 +00:00
break ;
case ' 7 ' :
2005-09-07 01:39:11 +00:00
tweak_talk_volume ( user , VOL_DOWN ) ;
2005-09-07 01:30:01 +00:00
break ;
2005-09-07 02:27:58 +00:00
case ' 8 ' :
menu_active = 0 ;
break ;
case ' 9 ' :
tweak_talk_volume ( user , VOL_UP ) ;
break ;
default :
menu_active = 0 ;
/* Play an error message! */
if ( ! ast_streamfile ( chan , " conf-errormenu " , chan - > language ) )
ast_waitstream ( chan , " " ) ;
break ;
2004-05-30 20:38:05 +00:00
}
}
2004-06-28 22:10:50 +00:00
}
if ( musiconhold ) {
ast_moh_start ( chan , NULL ) ;
}
2005-04-02 23:26:27 +00:00
2005-03-03 23:33:11 +00:00
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
close ( fd ) ;
ast_mutex_unlock ( & conflock ) ;
goto outrun ;
}
conf_flush ( fd ) ;
2005-02-02 02:20:34 +00:00
} else if ( option_debug ) {
ast_log ( LOG_DEBUG , " Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d \n " , chan - > name , f - > frametype , f - > subclass ) ;
2002-05-13 22:29:39 +00:00
}
2004-06-28 22:10:50 +00:00
ast_frfree ( f ) ;
} else if ( outfd > - 1 ) {
res = read ( outfd , buf , CONF_SIZE ) ;
if ( res > 0 ) {
memset ( & fr , 0 , sizeof ( fr ) ) ;
fr . frametype = AST_FRAME_VOICE ;
fr . subclass = AST_FORMAT_SLINEAR ;
fr . datalen = res ;
fr . samples = res / 2 ;
fr . data = buf ;
fr . offset = AST_FRIENDLY_OFFSET ;
2005-09-07 02:27:58 +00:00
if ( user - > listen . actual )
2005-10-28 16:36:10 +00:00
ast_frame_adjust_volume ( & fr , user - > listen . actual ) ;
2004-06-28 22:10:50 +00:00
if ( ast_write ( chan , & fr ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to write frame to channel: %s \n " , strerror ( errno ) ) ;
/* break; */
}
} else
ast_log ( LOG_WARNING , " Failed to read frame: %s \n " , strerror ( errno ) ) ;
2002-05-13 22:29:39 +00:00
}
2005-03-17 20:29:51 +00:00
lastmarked = currentmarked ;
2002-05-13 22:29:39 +00:00
}
}
2004-05-30 20:24:48 +00:00
if ( using_pseudo )
2002-05-13 22:29:39 +00:00
close ( fd ) ;
2002-08-11 02:12:40 +00:00
else {
/* Take out of conference */
ztc . chan = 0 ;
ztc . confno = 0 ;
ztc . confmode = 0 ;
if ( ioctl ( fd , ZT_SETCONF , & ztc ) ) {
ast_log ( LOG_WARNING , " Error setting conference \n " ) ;
}
}
2005-01-07 07:23:31 +00:00
2005-09-07 14:15:37 +00:00
reset_volumes ( user ) ;
2005-01-07 07:23:31 +00:00
ast_mutex_lock ( & conflock ) ;
2003-02-04 15:48:42 +00:00
if ( ! ( confflags & CONFFLAG_QUIET ) & & ! ( confflags & CONFFLAG_MONITOR ) & & ! ( confflags & CONFFLAG_ADMIN ) )
2005-02-16 03:50:41 +00:00
conf_play ( chan , conf , LEAVE ) ;
2002-05-13 22:29:39 +00:00
2005-02-01 20:05:30 +00:00
if ( ! ( confflags & CONFFLAG_QUIET ) & & ( confflags & CONFFLAG_INTROUSER ) ) {
if ( ast_fileexists ( user - > namerecloc , NULL , NULL ) ) {
if ( ( conf - > chan ) & & ( conf - > users > 1 ) ) {
if ( ! ast_streamfile ( conf - > chan , user - > namerecloc , chan - > language ) )
ast_waitstream ( conf - > chan , " " ) ;
if ( ! ast_streamfile ( conf - > chan , " conf-hasleft " , chan - > language ) )
ast_waitstream ( conf - > chan , " " ) ;
}
2005-01-07 07:23:31 +00:00
ast_filedelete ( user - > namerecloc , NULL ) ;
}
}
ast_mutex_unlock ( & conflock ) ;
2002-05-13 22:29:39 +00:00
outrun :
2004-06-17 05:21:54 +00:00
ast_mutex_lock ( & conflock ) ;
2005-09-07 14:15:37 +00:00
if ( confflags & CONFFLAG_MONITORTALKER & & dsp )
2005-01-30 03:07:21 +00:00
ast_dsp_free ( dsp ) ;
2004-05-30 20:38:05 +00:00
if ( user - > user_no ) { /* Only cleanup users who really joined! */
2004-06-02 23:27:50 +00:00
manager_event ( EVENT_FLAG_CALL , " MeetmeLeave " ,
2005-09-07 14:15:37 +00:00
" Channel: %s \r \n "
" Uniqueid: %s \r \n "
" Meetme: %s \r \n "
" Usernum: %d \r \n " ,
chan - > name , chan - > uniqueid , conf - > confno , user - > user_no ) ;
2004-05-30 20:38:05 +00:00
conf - > users - - ;
2004-08-27 04:12:55 +00:00
if ( confflags & CONFFLAG_MARKEDUSER )
2004-06-21 02:37:34 +00:00
conf - > markedusers - - ;
2004-06-02 23:27:50 +00:00
if ( ! conf - > users ) {
/* No more users -- close this one out */
2005-07-07 22:36:40 +00:00
conf_free ( conf ) ;
2004-05-30 20:38:05 +00:00
} else {
/* Remove the user struct */
2004-06-02 23:27:50 +00:00
if ( user = = conf - > firstuser ) {
2004-06-17 04:42:03 +00:00
if ( user - > nextuser ) {
/* There is another entry */
user - > nextuser - > prevuser = NULL ;
} else {
/* We are the only entry */
conf - > lastuser = NULL ;
}
/* In either case */
2004-06-02 23:27:50 +00:00
conf - > firstuser = user - > nextuser ;
} else if ( user = = conf - > lastuser ) {
2004-06-17 04:42:03 +00:00
if ( user - > prevuser )
user - > prevuser - > nextuser = NULL ;
else
ast_log ( LOG_ERROR , " Bad bad bad! We're the last, not the first, but nobody before us?? \n " ) ;
2004-06-02 23:27:50 +00:00
conf - > lastuser = user - > prevuser ;
2004-05-30 20:38:05 +00:00
} else {
2004-06-17 04:42:03 +00:00
if ( user - > nextuser )
user - > nextuser - > prevuser = user - > prevuser ;
else
ast_log ( LOG_ERROR , " Bad! Bad! Bad! user->nextuser is NULL but we're not the end! \n " ) ;
if ( user - > prevuser )
user - > prevuser - > nextuser = user - > nextuser ;
else
ast_log ( LOG_ERROR , " Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning! \n " ) ;
2004-05-30 20:38:05 +00:00
}
}
2004-11-25 03:23:07 +00:00
/* Return the number of seconds the user was in the conf */
2005-04-29 17:00:33 +00:00
snprintf ( meetmesecs , sizeof ( meetmesecs ) , " %d " , ( int ) ( time ( NULL ) - user - > jointime ) ) ;
2004-11-25 03:23:07 +00:00
pbx_builtin_setvar_helper ( chan , " MEETMESECS " , meetmesecs ) ;
2002-05-13 22:29:39 +00:00
}
2004-05-22 04:11:22 +00:00
free ( user ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conflock ) ;
2003-02-04 15:48:42 +00:00
return ret ;
2002-05-13 22:29:39 +00:00
}
2004-04-08 19:38:26 +00:00
static struct ast_conference * find_conf ( struct ast_channel * chan , char * confno , int make , int dynamic , char * dynamic_pin )
2002-05-13 22:29:39 +00:00
{
struct ast_config * cfg ;
struct ast_variable * var ;
2004-06-17 02:42:42 +00:00
struct ast_conference * cnf ;
2004-01-11 06:07:36 +00:00
/* Check first in the conference list */
ast_mutex_lock ( & conflock ) ;
2004-06-17 02:42:42 +00:00
cnf = confs ;
2004-01-11 06:07:36 +00:00
while ( cnf ) {
if ( ! strcmp ( confno , cnf - > confno ) )
2002-05-13 22:29:39 +00:00
break ;
2004-01-11 06:07:36 +00:00
cnf = cnf - > next ;
2002-05-13 22:29:39 +00:00
}
2004-01-11 06:07:36 +00:00
ast_mutex_unlock ( & conflock ) ;
if ( ! cnf ) {
2003-10-29 22:52:20 +00:00
if ( dynamic ) {
2004-01-11 06:07:36 +00:00
/* No need to parse meetme.conf */
2004-04-08 19:38:26 +00:00
ast_log ( LOG_DEBUG , " Building dynamic conference '%s' \n " , confno ) ;
if ( dynamic_pin ) {
if ( dynamic_pin [ 0 ] = = ' q ' ) {
/* Query the user to enter a PIN */
ast_app_getdata ( chan , " conf-getpin " , dynamic_pin , AST_MAX_EXTENSION - 1 , 0 ) ;
}
2005-02-22 15:42:41 +00:00
cnf = build_conf ( confno , dynamic_pin , " " , make , dynamic ) ;
2004-04-08 19:38:26 +00:00
} else {
2005-02-22 15:42:41 +00:00
cnf = build_conf ( confno , " " , " " , make , dynamic ) ;
2004-04-08 19:38:26 +00:00
}
2004-01-11 06:07:36 +00:00
} else {
/* Check the config */
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( " meetme.conf " ) ;
2004-01-11 06:07:36 +00:00
if ( ! cfg ) {
ast_log ( LOG_WARNING , " No meetme.conf file :( \n " ) ;
return NULL ;
}
var = ast_variable_browse ( cfg , " rooms " ) ;
while ( var ) {
if ( ! strcasecmp ( var - > name , " conf " ) ) {
/* Separate the PIN */
2005-02-22 15:42:41 +00:00
char * pin , * pinadmin , * conf ;
2004-01-11 06:07:36 +00:00
2005-02-22 15:42:41 +00:00
if ( ( pinadmin = ast_strdupa ( var - > value ) ) ) {
2005-02-23 05:09:10 +00:00
conf = strsep ( & pinadmin , " |, " ) ;
pin = strsep ( & pinadmin , " |, " ) ;
2004-01-11 06:07:36 +00:00
if ( ! strcasecmp ( conf , confno ) ) {
/* Bingo it's a valid conference */
if ( pin )
2005-02-22 15:42:41 +00:00
if ( pinadmin )
cnf = build_conf ( confno , pin , pinadmin , make , dynamic ) ;
else
cnf = build_conf ( confno , pin , " " , make , dynamic ) ;
2004-01-11 06:07:36 +00:00
else
2005-02-22 15:42:41 +00:00
if ( pinadmin )
cnf = build_conf ( confno , " " , pinadmin , make , dynamic ) ;
else
cnf = build_conf ( confno , " " , " " , make , dynamic ) ;
2004-01-11 06:07:36 +00:00
break ;
}
}
}
var = var - > next ;
}
if ( ! var ) {
ast_log ( LOG_DEBUG , " %s isn't a valid conference \n " , confno ) ;
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2004-01-11 06:07:36 +00:00
}
2004-08-02 13:10:15 +00:00
} else if ( dynamic_pin ) {
2004-08-02 02:58:15 +00:00
/* Correct for the user selecting 'D' instead of 'd' to have
someone join into a conference that has already been created
with a pin . */
if ( dynamic_pin [ 0 ] = = ' q ' )
dynamic_pin [ 0 ] = ' \0 ' ;
2002-05-13 22:29:39 +00:00
}
return cnf ;
}
2004-05-23 14:19:45 +00:00
/*--- count_exec: The MeetmeCount application */
2002-05-13 22:29:39 +00:00
static int count_exec ( struct ast_channel * chan , void * data )
{
struct localuser * u ;
int res = 0 ;
2004-01-11 06:07:36 +00:00
struct ast_conference * conf ;
int count ;
char * confnum , * localdata ;
2003-08-20 23:32:23 +00:00
char val [ 80 ] = " 0 " ;
2004-01-11 06:07:36 +00:00
2005-10-26 19:48:14 +00:00
if ( ast_strlen_zero ( data ) ) {
2002-05-13 22:29:39 +00:00
ast_log ( LOG_WARNING , " MeetMeCount requires an argument (conference number) \n " ) ;
return - 1 ;
}
2005-10-19 18:19:02 +00:00
2002-05-13 22:29:39 +00:00
LOCAL_USER_ADD ( u ) ;
2005-10-19 18:19:02 +00:00
localdata = ast_strdupa ( data ) ;
if ( ! localdata ) {
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
2003-08-20 23:32:23 +00:00
confnum = strsep ( & localdata , " | " ) ;
2004-04-08 19:38:26 +00:00
conf = find_conf ( chan , confnum , 0 , 0 , NULL ) ;
2002-05-13 22:29:39 +00:00
if ( conf )
2004-01-11 06:07:36 +00:00
count = conf - > users ;
2002-05-13 22:29:39 +00:00
else
2004-01-11 06:07:36 +00:00
count = 0 ;
2005-10-26 19:48:14 +00:00
if ( ! ast_strlen_zero ( localdata ) ) {
2004-01-11 06:07:36 +00:00
/* have var so load it and exit */
2005-04-29 17:00:33 +00:00
snprintf ( val , sizeof ( val ) , " %d " , count ) ;
2004-01-11 06:07:36 +00:00
pbx_builtin_setvar_helper ( chan , localdata , val ) ;
} else {
if ( chan - > _state ! = AST_STATE_UP )
ast_answer ( chan ) ;
2004-04-29 02:30:14 +00:00
res = ast_say_number ( chan , count , " " , chan - > language , ( char * ) NULL ) ; /* Needs gender */
2003-08-20 23:32:23 +00:00
}
2002-05-13 22:29:39 +00:00
LOCAL_USER_REMOVE ( u ) ;
return res ;
}
2004-05-23 14:19:45 +00:00
/*--- conf_exec: The meetme() application */
2002-05-13 22:29:39 +00:00
static int conf_exec ( struct ast_channel * chan , void * data )
{
int res = - 1 ;
struct localuser * u ;
2004-01-11 06:07:36 +00:00
char confno [ AST_MAX_EXTENSION ] = " " ;
2002-05-13 22:29:39 +00:00
int allowretry = 0 ;
int retrycnt = 0 ;
2004-01-11 06:07:36 +00:00
struct ast_conference * cnf ;
2005-03-12 05:37:32 +00:00
struct ast_flags confflags = { 0 } ;
2003-10-29 22:52:20 +00:00
int dynamic = 0 ;
2004-04-08 19:38:26 +00:00
int empty = 0 , empty_no_pin = 0 ;
2005-02-02 02:57:45 +00:00
int always_prompt = 0 ;
2004-04-08 19:38:26 +00:00
char * notdata , * info , * inflags = NULL , * inpin = NULL , the_pin [ AST_MAX_EXTENSION ] = " " ;
2003-09-28 21:18:51 +00:00
2005-10-19 18:19:02 +00:00
LOCAL_USER_ADD ( u ) ;
2005-10-26 19:48:14 +00:00
if ( ast_strlen_zero ( data ) ) {
2002-05-13 22:29:39 +00:00
allowretry = 1 ;
2004-01-11 06:31:42 +00:00
notdata = " " ;
} else {
notdata = data ;
2002-05-13 22:29:39 +00:00
}
2005-10-19 18:19:02 +00:00
2002-08-11 02:12:40 +00:00
if ( chan - > _state ! = AST_STATE_UP )
2002-05-13 22:29:39 +00:00
ast_answer ( chan ) ;
2005-10-19 18:19:02 +00:00
info = ast_strdupa ( notdata ) ;
2003-02-04 15:48:42 +00:00
if ( info ) {
2004-01-11 06:07:36 +00:00
char * tmp = strsep ( & info , " | " ) ;
2005-07-07 23:17:04 +00:00
ast_copy_string ( confno , tmp , sizeof ( confno ) ) ;
2004-05-27 14:35:26 +00:00
if ( ast_strlen_zero ( confno ) ) {
2004-01-11 06:31:42 +00:00
allowretry = 1 ;
}
2003-02-04 15:48:42 +00:00
}
2004-01-11 06:07:36 +00:00
if ( info )
inflags = strsep ( & info , " | " ) ;
if ( info )
inpin = strsep ( & info , " | " ) ;
2004-04-08 19:38:26 +00:00
if ( inpin )
2005-07-07 23:17:04 +00:00
ast_copy_string ( the_pin , inpin , sizeof ( the_pin ) ) ;
2004-01-11 06:07:36 +00:00
if ( inflags ) {
2005-03-12 05:37:32 +00:00
ast_parseoptions ( meetme_opts , & confflags , NULL , inflags ) ;
dynamic = ast_test_flag ( & confflags , CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN ) ;
if ( ast_test_flag ( & confflags , CONFFLAG_DYNAMICPIN ) & & ! inpin )
2005-07-07 23:17:04 +00:00
strcpy ( the_pin , " q " ) ;
2005-03-12 05:37:32 +00:00
empty = ast_test_flag ( & confflags , CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN ) ;
empty_no_pin = ast_test_flag ( & confflags , CONFFLAG_EMPTYNOPIN ) ;
always_prompt = ast_test_flag ( & confflags , CONFFLAG_ALWAYSPROMPT ) ;
2002-05-13 22:29:39 +00:00
}
2004-01-11 06:07:36 +00:00
do {
if ( retrycnt > 3 )
allowretry = 0 ;
2004-04-08 19:38:26 +00:00
if ( empty ) {
int i , map [ 1024 ] ;
struct ast_config * cfg ;
struct ast_variable * var ;
int confno_int ;
memset ( map , 0 , sizeof ( map ) ) ;
ast_mutex_lock ( & conflock ) ;
cnf = confs ;
while ( cnf ) {
if ( sscanf ( cnf - > confno , " %d " , & confno_int ) = = 1 ) {
/* Disqualify in use conference */
if ( confno_int > = 0 & & confno_int < 1024 )
map [ confno_int ] + + ;
}
cnf = cnf - > next ;
}
ast_mutex_unlock ( & conflock ) ;
2004-06-28 22:10:50 +00:00
/* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
if ( ( empty_no_pin ) | | ( ! dynamic ) ) {
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( " meetme.conf " ) ;
2004-06-28 22:10:50 +00:00
if ( cfg ) {
var = ast_variable_browse ( cfg , " rooms " ) ;
while ( var ) {
if ( ! strcasecmp ( var - > name , " conf " ) ) {
char * stringp = ast_strdupa ( var - > value ) ;
if ( stringp ) {
char * confno_tmp = strsep ( & stringp , " |, " ) ;
int found = 0 ;
if ( sscanf ( confno_tmp , " %d " , & confno_int ) = = 1 ) {
if ( ( confno_int > = 0 ) & & ( confno_int < 1024 ) ) {
if ( stringp & & empty_no_pin ) {
map [ confno_int ] + + ;
}
2004-04-08 19:38:26 +00:00
}
}
2004-06-28 22:10:50 +00:00
if ( ! dynamic ) {
/* For static: run through the list and see if this conference is empty */
ast_mutex_lock ( & conflock ) ;
cnf = confs ;
while ( cnf ) {
if ( ! strcmp ( confno_tmp , cnf - > confno ) ) {
/* The conference exists, therefore it's not empty */
found = 1 ;
break ;
}
cnf = cnf - > next ;
2004-04-08 19:38:26 +00:00
}
2004-06-28 22:10:50 +00:00
ast_mutex_unlock ( & conflock ) ;
if ( ! found ) {
/* At this point, we have a confno_tmp (static conference) that is empty */
if ( ( empty_no_pin & & ( ( ! stringp ) | | ( stringp & & ( stringp [ 0 ] = = ' \0 ' ) ) ) ) | | ( ! empty_no_pin ) ) {
2005-04-13 23:33:47 +00:00
/* Case 1: empty_no_pin and pin is nonexistent (NULL)
2004-06-28 22:10:50 +00:00
* Case 2 : empty_no_pin and pin is blank ( but not NULL )
* Case 3 : not empty_no_pin
*/
2005-07-07 23:17:04 +00:00
ast_copy_string ( confno , confno_tmp , sizeof ( confno ) ) ;
2004-06-28 22:10:50 +00:00
break ;
/* XXX the map is not complete (but we do have a confno) */
}
2004-04-08 19:38:26 +00:00
}
}
2004-06-28 22:10:50 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2004-04-08 19:38:26 +00:00
}
}
2004-06-28 22:10:50 +00:00
var = var - > next ;
2004-04-08 19:38:26 +00:00
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2004-04-08 19:38:26 +00:00
}
}
/* Select first conference number not in use */
2004-06-28 22:10:50 +00:00
if ( ast_strlen_zero ( confno ) & & dynamic ) {
2004-04-08 19:38:26 +00:00
for ( i = 0 ; i < 1024 ; i + + ) {
2004-06-28 22:10:50 +00:00
if ( ! map [ i ] ) {
2004-07-14 07:22:30 +00:00
snprintf ( confno , sizeof ( confno ) , " %d " , i ) ;
2004-04-08 19:38:26 +00:00
break ;
}
}
}
/* Not found? */
2004-05-27 14:35:26 +00:00
if ( ast_strlen_zero ( confno ) ) {
2004-04-08 19:38:26 +00:00
res = ast_streamfile ( chan , " conf-noempty " , chan - > language ) ;
if ( ! res )
ast_waitstream ( chan , " " ) ;
} else {
if ( sscanf ( confno , " %d " , & confno_int ) = = 1 ) {
res = ast_streamfile ( chan , " conf-enteringno " , chan - > language ) ;
if ( ! res ) {
ast_waitstream ( chan , " " ) ;
res = ast_say_digits ( chan , confno_int , " " , chan - > language ) ;
}
2004-06-28 22:10:50 +00:00
} else {
ast_log ( LOG_ERROR , " Could not scan confno '%s' \n " , confno ) ;
2004-04-08 19:38:26 +00:00
}
}
}
2004-05-27 14:35:26 +00:00
while ( allowretry & & ( ast_strlen_zero ( confno ) ) & & ( + + retrycnt < 4 ) ) {
2004-01-11 06:07:36 +00:00
/* Prompt user for conference number */
res = ast_app_getdata ( chan , " conf-getconfno " , confno , sizeof ( confno ) - 1 , 0 ) ;
if ( res < 0 ) {
/* Don't try to validate when we catch an error */
2004-07-14 07:22:30 +00:00
confno [ 0 ] = ' \0 ' ;
2004-01-11 06:07:36 +00:00
allowretry = 0 ;
break ;
2002-05-13 22:29:39 +00:00
}
}
2004-05-27 14:35:26 +00:00
if ( ! ast_strlen_zero ( confno ) ) {
2004-01-11 06:07:36 +00:00
/* Check the validity of the conference */
2004-04-08 19:38:26 +00:00
cnf = find_conf ( chan , confno , 1 , dynamic , the_pin ) ;
2004-01-11 06:07:36 +00:00
if ( ! cnf ) {
res = ast_streamfile ( chan , " conf-invalid " , chan - > language ) ;
if ( ! res )
ast_waitstream ( chan , " " ) ;
res = - 1 ;
if ( allowretry )
2004-07-14 07:22:30 +00:00
confno [ 0 ] = ' \0 ' ;
2004-01-11 06:07:36 +00:00
} else {
2005-03-12 05:37:32 +00:00
if ( ( ! ast_strlen_zero ( cnf - > pin ) & & ! ast_test_flag ( & confflags , CONFFLAG_ADMIN ) ) | | ( ! ast_strlen_zero ( cnf - > pinadmin ) & & ast_test_flag ( & confflags , CONFFLAG_ADMIN ) ) ) {
2004-07-27 03:08:00 +00:00
char pin [ AST_MAX_EXTENSION ] = " " ;
int j ;
/* Allow the pin to be retried up to 3 times */
for ( j = 0 ; j < 3 ; j + + ) {
2005-02-02 02:57:45 +00:00
if ( * the_pin & & ( always_prompt = = 0 ) ) {
2005-07-07 23:17:04 +00:00
ast_copy_string ( pin , the_pin , sizeof ( pin ) ) ;
2004-07-27 03:08:00 +00:00
res = 0 ;
} else {
/* Prompt user for pin if pin is required */
2004-07-27 03:10:26 +00:00
res = ast_app_getdata ( chan , " conf-getpin " , pin + strlen ( pin ) , sizeof ( pin ) - 1 - strlen ( pin ) , 0 ) ;
2004-07-27 03:08:00 +00:00
}
if ( res > = 0 ) {
2005-02-22 15:42:41 +00:00
if ( ! strcasecmp ( pin , cnf - > pin ) | | ( ! ast_strlen_zero ( cnf - > pinadmin ) & & ! strcasecmp ( pin , cnf - > pinadmin ) ) ) {
2004-07-27 03:08:00 +00:00
/* Pin correct */
allowretry = 0 ;
2005-02-22 15:42:41 +00:00
if ( ! ast_strlen_zero ( cnf - > pinadmin ) & & ! strcasecmp ( pin , cnf - > pinadmin ) )
2005-03-12 05:37:32 +00:00
ast_set_flag ( & confflags , CONFFLAG_ADMIN ) ;
2004-07-27 03:08:00 +00:00
/* Run the conference */
2005-03-12 05:37:32 +00:00
res = conf_run ( chan , cnf , confflags . flags ) ;
2004-07-27 03:08:00 +00:00
break ;
} else {
/* Pin invalid */
res = ast_streamfile ( chan , " conf-invalidpin " , chan - > language ) ;
if ( ! res )
2004-07-27 03:10:26 +00:00
ast_waitstream ( chan , AST_DIGIT_ANY ) ;
if ( res < 0 )
break ;
pin [ 0 ] = res ;
pin [ 1 ] = ' \0 ' ;
2004-07-27 03:08:00 +00:00
res = - 1 ;
if ( allowretry )
confno [ 0 ] = ' \0 ' ;
}
2004-01-13 04:42:39 +00:00
} else {
2005-07-07 22:36:40 +00:00
/* failed when getting the pin */
2004-01-13 04:42:39 +00:00
res = - 1 ;
2004-07-27 03:08:00 +00:00
allowretry = 0 ;
2005-07-07 22:36:40 +00:00
/* see if we need to get rid of the conference */
ast_mutex_lock ( & conflock ) ;
if ( ! cnf - > users ) {
conf_free ( cnf ) ;
}
ast_mutex_unlock ( & conflock ) ;
2004-07-27 03:08:00 +00:00
break ;
}
/* Don't retry pin with a static pin */
2005-02-02 02:57:45 +00:00
if ( * the_pin & & ( always_prompt = = 0 ) ) {
2004-07-27 03:08:00 +00:00
break ;
2004-01-12 23:21:29 +00:00
}
}
} else {
/* No pin required */
allowretry = 0 ;
/* Run the conference */
2005-03-12 05:37:32 +00:00
res = conf_run ( chan , cnf , confflags . flags ) ;
2004-01-11 06:07:36 +00:00
}
}
}
} while ( allowretry ) ;
2005-07-07 22:36:40 +00:00
2002-05-13 22:29:39 +00:00
LOCAL_USER_REMOVE ( u ) ;
2005-07-07 22:36:40 +00:00
2002-05-13 22:29:39 +00:00
return res ;
}
2004-05-22 04:11:22 +00:00
static struct ast_conf_user * find_user ( struct ast_conference * conf , char * callerident ) {
struct ast_conf_user * user = NULL ;
char usrno [ 1024 ] = " " ;
if ( conf & & callerident ) {
user = conf - > firstuser ;
while ( user ) {
2005-04-29 17:00:33 +00:00
snprintf ( usrno , sizeof ( usrno ) , " %d " , user - > user_no ) ;
2004-05-22 04:11:22 +00:00
if ( strcmp ( usrno , callerident ) = = 0 )
return user ;
user = user - > nextuser ;
}
}
return NULL ;
}
2004-05-23 14:19:45 +00:00
/*--- admin_exec: The MeetMeadmin application */
/* MeetMeAdmin(confno, command, caller) */
2004-05-22 04:11:22 +00:00
static int admin_exec ( struct ast_channel * chan , void * data ) {
char * params , * command = NULL , * caller = NULL , * conf = NULL ;
struct ast_conference * cnf ;
struct ast_conf_user * user = NULL ;
2005-10-19 18:19:02 +00:00
struct localuser * u ;
LOCAL_USER_ADD ( u ) ;
2004-05-22 04:11:22 +00:00
ast_mutex_lock ( & conflock ) ;
/* The param has the conference number the user and the command to execute */
2005-10-26 19:48:14 +00:00
if ( ! ast_strlen_zero ( data ) ) {
2004-05-22 04:11:22 +00:00
params = ast_strdupa ( ( char * ) data ) ;
conf = strsep ( & params , " | " ) ;
command = strsep ( & params , " | " ) ;
caller = strsep ( & params , " | " ) ;
2004-10-20 04:27:31 +00:00
if ( ! command ) {
ast_log ( LOG_WARNING , " MeetmeAdmin requires a command! \n " ) ;
ast_mutex_unlock ( & conflock ) ;
2005-10-19 18:19:02 +00:00
LOCAL_USER_REMOVE ( u ) ;
2004-10-20 04:27:31 +00:00
return - 1 ;
}
2004-05-30 20:38:05 +00:00
cnf = confs ;
while ( cnf ) {
if ( strcmp ( cnf - > confno , conf ) = = 0 )
break ;
cnf = cnf - > next ;
}
if ( caller )
user = find_user ( cnf , caller ) ;
2004-05-22 04:11:22 +00:00
if ( cnf ) {
switch ( ( int ) ( * command ) ) {
case 76 : /* L: Lock */
cnf - > locked = 1 ;
break ;
case 108 : /* l: Unlock */
cnf - > locked = 0 ;
break ;
case 75 : /* K: kick all users*/
user = cnf - > firstuser ;
while ( user ) {
user - > adminflags | = ADMINFLAG_KICKME ;
if ( user - > nextuser ) {
user = user - > nextuser ;
} else {
break ;
}
}
break ;
2005-01-14 05:10:00 +00:00
case 101 : /* e: Eject last user*/
user = cnf - > lastuser ;
if ( ! ( user - > userflags & CONFFLAG_ADMIN ) ) {
user - > adminflags | = ADMINFLAG_KICKME ;
break ;
} else
ast_log ( LOG_NOTICE , " Not kicking last user, is an Admin! \n " ) ;
break ;
2004-05-22 04:11:22 +00:00
case 77 : /* M: Mute */
if ( user ) {
user - > adminflags | = ADMINFLAG_MUTED ;
} else {
2005-01-14 04:25:35 +00:00
ast_log ( LOG_NOTICE , " Specified User not found! \n " ) ;
2004-05-22 04:11:22 +00:00
}
break ;
2004-10-11 15:40:24 +00:00
case 78 : /* N: Mute all users */
user = cnf - > firstuser ;
while ( user ) {
if ( user & & ! ( user - > userflags & CONFFLAG_ADMIN ) )
user - > adminflags | = ADMINFLAG_MUTED ;
if ( user - > nextuser ) {
user = user - > nextuser ;
} else {
break ;
}
}
break ;
2004-05-22 04:11:22 +00:00
case 109 : /* m: Unmute */
if ( user & & ( user - > adminflags & ADMINFLAG_MUTED ) ) {
user - > adminflags ^ = ADMINFLAG_MUTED ;
} else {
ast_log ( LOG_NOTICE , " Specified User not found or he muted himself! " ) ;
}
break ;
2004-10-11 15:40:24 +00:00
case 110 : /* n: Unmute all users */
user = cnf - > firstuser ;
while ( user ) {
if ( user & & ( user - > adminflags & ADMINFLAG_MUTED ) ) {
user - > adminflags ^ = ADMINFLAG_MUTED ;
}
if ( user - > nextuser ) {
user = user - > nextuser ;
} else {
break ;
}
}
break ;
2004-05-22 04:11:22 +00:00
case 107 : /* k: Kick user */
if ( user ) {
user - > adminflags | = ADMINFLAG_KICKME ;
} else {
ast_log ( LOG_NOTICE , " Specified User not found! " ) ;
}
break ;
}
} else {
ast_log ( LOG_NOTICE , " Conference Number not found \n " ) ;
}
}
ast_mutex_unlock ( & conflock ) ;
2005-10-19 18:19:02 +00:00
LOCAL_USER_REMOVE ( u ) ;
2004-05-22 04:11:22 +00:00
return 0 ;
}
2005-01-22 04:51:30 +00:00
static void * recordthread ( void * args )
{
struct ast_conference * cnf ;
struct ast_frame * f = NULL ;
int flags ;
struct ast_filestream * s ;
int res = 0 ;
cnf = ( struct ast_conference * ) args ;
2005-02-01 06:48:50 +00:00
if ( ! cnf | | ! cnf - > chan ) {
pthread_exit ( 0 ) ;
}
2005-01-22 04:51:30 +00:00
ast_stopstream ( cnf - > chan ) ;
flags = O_CREAT | O_TRUNC | O_WRONLY ;
s = ast_writefile ( cnf - > recordingfilename , cnf - > recordingformat , NULL , flags , 0 , 0644 ) ;
if ( s ) {
cnf - > recording = MEETME_RECORD_ACTIVE ;
while ( ast_waitfor ( cnf - > chan , - 1 ) > - 1 ) {
f = ast_read ( cnf - > chan ) ;
if ( ! f ) {
res = - 1 ;
break ;
}
if ( f - > frametype = = AST_FRAME_VOICE ) {
res = ast_writestream ( s , f ) ;
if ( res )
break ;
}
ast_frfree ( f ) ;
if ( cnf - > recording = = MEETME_RECORD_TERMINATE ) {
ast_mutex_lock ( & conflock ) ;
ast_mutex_unlock ( & conflock ) ;
break ;
}
}
cnf - > recording = MEETME_RECORD_OFF ;
ast_closestream ( s ) ;
}
pthread_exit ( 0 ) ;
}
2002-05-13 22:29:39 +00:00
int unload_module ( void )
{
2005-10-18 22:52:21 +00:00
int res ;
res = ast_cli_unregister ( & cli_show_confs ) ;
res | = ast_cli_unregister ( & cli_conf ) ;
res | = ast_unregister_application ( app3 ) ;
res | = ast_unregister_application ( app2 ) ;
res | = ast_unregister_application ( app ) ;
2002-05-13 22:29:39 +00:00
STANDARD_HANGUP_LOCALUSERS ;
2005-10-18 22:52:21 +00:00
return res ;
2002-05-13 22:29:39 +00:00
}
int load_module ( void )
{
2005-10-18 22:52:21 +00:00
int res ;
res = ast_cli_register ( & cli_show_confs ) ;
res | = ast_cli_register ( & cli_conf ) ;
res | = ast_register_application ( app3 , admin_exec , synopsis3 , descrip3 ) ;
res | = ast_register_application ( app2 , count_exec , synopsis2 , descrip2 ) ;
res | = ast_register_application ( app , conf_exec , synopsis , descrip ) ;
2002-05-13 22:29:39 +00:00
2005-10-18 22:52:21 +00:00
return res ;
}
2005-01-07 07:23:31 +00:00
2002-05-13 22:29:39 +00:00
char * description ( void )
{
return tdesc ;
}
int usecount ( void )
{
int res ;
STANDARD_USECOUNT ( res ) ;
return res ;
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}
2005-01-07 07:23:31 +00:00