Asterisk - The Open Source Telephony Project GIT-master-0bf3178
Data Structures | Macros | Enumerations | Functions | Variables
app_meetme.c File Reference

Meet me conference bridge. More...

#include "asterisk.h"
#include <dahdi/user.h>
#include "asterisk/lock.h"
#include "asterisk/file.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/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/paths.h"
#include "asterisk/test.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/json.h"
#include "asterisk/format_compatibility.h"
#include "enter.h"
#include "leave.h"
Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

struct  announce_listitem
 
struct  ast_conf_user
 The MeetMe User object. More...
 
struct  ast_conference
 The MeetMe Conference object. More...
 
struct  confs
 
struct  volume
 

Macros

#define AST_FRAME_BITS   32
 
#define CONF_SIZE   320
 
#define CONFFLAG_DONT_DENOISE   (1ULL << 35)
 
#define CONFFLAG_INTROMSG   (1ULL << 32)
 
#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)
 
#define CONFFLAG_KILL_LAST_MAN_STANDING   (1ULL << 34)
 
#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)
 
#define CONFIG_FILE_NAME   "meetme.conf"
 
#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"
 
#define DEFAULT_AUDIO_BUFFERS   32
 
#define MAX_CONFNUM   80
 
#define MAX_PIN   80
 
#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
 
#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
 
#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"
 
#define MEETME_DELAYDETECTENDTALK   1000
 
#define MEETME_DELAYDETECTTALK   300
 
#define OPTIONS_LEN   100
 
#define STR_CONCISE   "concise"
 

Enumerations

enum  {
  ADMINFLAG_MUTED = (1 << 1) , ADMINFLAG_SELFMUTED = (1 << 2) , ADMINFLAG_KICKME = (1 << 3) , ADMINFLAG_T_REQUEST = (1 << 4) ,
  ADMINFLAG_HANGUP = (1 << 5)
}
 
enum  {
  CONFFLAG_ADMIN = (1 << 0) , CONFFLAG_MONITOR = (1 << 1) , CONFFLAG_KEYEXIT = (1 << 2) , CONFFLAG_STARMENU = (1 << 3) ,
  CONFFLAG_TALKER = (1 << 4) , CONFFLAG_QUIET = (1 << 5) , CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6) , CONFFLAG_AGI = (1 << 7) ,
  CONFFLAG_MOH = (1 << 8) , CONFFLAG_MARKEDEXIT = (1 << 9) , CONFFLAG_WAITMARKED = (1 << 10) , CONFFLAG_EXIT_CONTEXT = (1 << 11) ,
  CONFFLAG_MARKEDUSER = (1 << 12) , CONFFLAG_INTROUSER = (1 << 13) , CONFFLAG_RECORDCONF = (1<< 14) , CONFFLAG_MONITORTALKER = (1 << 15) ,
  CONFFLAG_DYNAMIC = (1 << 16) , CONFFLAG_DYNAMICPIN = (1 << 17) , CONFFLAG_EMPTY = (1 << 18) , CONFFLAG_EMPTYNOPIN = (1 << 19) ,
  CONFFLAG_ALWAYSPROMPT = (1 << 20) , CONFFLAG_OPTIMIZETALKER = (1 << 21) , CONFFLAG_NOONLYPERSON = (1 << 22) , CONFFLAG_INTROUSERNOREVIEW = (1 << 23) ,
  CONFFLAG_STARTMUTED = (1 << 24) , CONFFLAG_PASS_DTMF = (1 << 25) , CONFFLAG_KICK_CONTINUE = (1 << 26) , CONFFLAG_DURATION_STOP = (1 << 27) ,
  CONFFLAG_DURATION_LIMIT = (1 << 28)
}
 
enum  {
  OPT_ARG_WAITMARKED = 0 , OPT_ARG_EXITKEYS = 1 , OPT_ARG_DURATION_STOP = 2 , OPT_ARG_DURATION_LIMIT = 3 ,
  OPT_ARG_MOH_CLASS = 4 , OPT_ARG_INTROMSG = 5 , OPT_ARG_INTROUSER_VMREC = 6 , OPT_ARG_ARRAY_SIZE = 7
}
 
enum  announcetypes { CONF_HASJOIN , CONF_HASLEFT }
 
enum  entrance_sound { ENTER , LEAVE }
 
enum  menu_modes { MENU_DISABLED = 0 , MENU_NORMAL , MENU_ADMIN , MENU_ADMIN_EXTENDED }
 
enum  recording_state { MEETME_RECORD_OFF , MEETME_RECORD_STARTED , MEETME_RECORD_ACTIVE , MEETME_RECORD_TERMINATE }
 
enum  volume_action { VOL_UP , VOL_DOWN }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_meetme_info_eval (const char *keyword, const struct ast_conference *conf)
 
static int action_meetmelist (struct mansession *s, const struct message *m)
 
static int action_meetmelistrooms (struct mansession *s, const struct message *m)
 
static int action_meetmemute (struct mansession *s, const struct message *m)
 
static int action_meetmeunmute (struct mansession *s, const struct message *m)
 
static int admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeAdmin application. More...
 
static void * announce_thread (void *data)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static struct ast_conferencebuild_conf (const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test)
 Find or create a conference. More...
 
static int can_write (struct ast_channel *chan, struct ast_flags64 *confflags)
 
static int careful_write (int fd, unsigned char *data, int len, int block)
 
static int channel_admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command) More...
 
static char * complete_confno (const char *word, int state)
 
static char * complete_meetmecmd_list (const char *line, const char *word, int pos, int state)
 
static char * complete_meetmecmd_lock (const char *word, int pos, int state)
 
static char * complete_meetmecmd_mute_kick (const char *line, const char *word, int pos, int state)
 
static char * complete_userno (struct ast_conference *cnf, const char *word, int state)
 
static int conf_exec (struct ast_channel *chan, const char *data)
 The meetme() application. More...
 
static void conf_flush (int fd, struct ast_channel *chan)
 
static int conf_free (struct ast_conference *conf)
 Remove the conference from the list and free it. More...
 
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
 
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
 
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
 
static void conf_start_moh (struct ast_channel *chan, const char *musicclass)
 
static int count_exec (struct ast_channel *chan, const char *data)
 The MeetmeCount application. More...
 
static int dispose_conf (struct ast_conference *conf)
 Decrement reference counts, as incremented by find_conf() More...
 
static void filename_parse (char *filename, char *buffer)
 
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
 
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
 
static struct ast_conf_userfind_user (struct ast_conference *conf, const char *callerident)
 
static const char * get_announce_filename (enum announcetypes type)
 
static const char * istalking (int x)
 
static int load_config (int reload)
 
static void load_config_meetme (int reload)
 
static int load_module (void)
 Load the module. More...
 
static char * meetme_cmd_helper (struct ast_cli_args *a)
 
static char * meetme_kick_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * meetme_lock_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void meetme_menu (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
 
static void meetme_menu_admin (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
 
static void meetme_menu_admin_extended (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
 
static void meetme_menu_normal (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
 
static char * meetme_mute_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void meetme_set_defaults (void)
 
static char * meetme_show_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void meetme_stasis_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 
static void meetme_stasis_cleanup (void)
 
static void meetme_stasis_generate_msg (struct ast_conference *meetme_conference, struct ast_channel *chan, struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
 
static int meetme_stasis_init (void)
 
static int meetmemute (struct mansession *s, const struct message *m, int mute)
 
static enum ast_device_state meetmestate (const char *data)
 Callback for devicestate providers. More...
 
static void * recordthread (void *args)
 
static int reload (void)
 
static void reset_volumes (struct ast_conf_user *user)
 
static int rt_extend_conf (const char *confno)
 
static void send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
 
static int set_listen_volume (struct ast_conf_user *user, int volume)
 
static int set_talk_volume (struct ast_conf_user *user, int volume)
 
static void set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_end_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_join_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_leave_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_mute_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_talk_request_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_talking_type)
 
static struct ast_jsonstatus_to_json (int on)
 
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
 
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
 
static void tweak_volume (struct volume *vol, enum volume_action action)
 
static int unload_module (void)
 
static int user_chan_cb (void *obj, void *args, int flags)
 
static int user_listen_voldown_cb (void *obj, void *unused, int flags)
 
static int user_listen_volup_cb (void *obj, void *unused, int flags)
 
static int user_max_cmp (void *obj, void *arg, int flags)
 
static int user_no_cmp (void *obj, void *arg, int flags)
 
static int user_reset_vol_cb (void *obj, void *unused, int flags)
 
static int user_set_hangup_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_set_kickme_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_set_muted_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_set_unmuted_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_talk_voldown_cb (void *obj, void *unused, int flags)
 
static int user_talk_volup_cb (void *obj, void *unused, int flags)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, .optional_modules = "func_speex", }
 
static const char *const app = "MeetMe"
 
static const char *const app2 = "MeetMeCount"
 
static const char *const app3 = "MeetMeAdmin"
 
static const char *const app4 = "MeetMeChannelAdmin"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int audio_buffers
 The number of audio buffers to be allocated on pseudo channels when in a conference. More...
 
static struct ast_cli_entry cli_meetme []
 
static unsigned int conf_map [1024] = {0, }
 
static struct confs confs = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int earlyalert
 
static int endalert
 
static int extendby
 
static int fuzzystart
 
static const char gain_map []
 Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers. More...
 
static struct stasis_message_routermeetme_event_message_router
 
static struct ast_custom_function meetme_info_acf
 
static const struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'G' ] = { .flag = (1ULL << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'v' ] = { .flag = (1ULL << 33) , .arg_index = OPT_ARG_INTROUSER_VMREC + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'k' ] = { .flag = (1ULL << 34) }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'n' ] = { .flag = (1ULL << 35) }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
 
static int rt_log_members
 
static int rt_schedule
 

Detailed Description

Meet me conference bridge.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file app_meetme.c.

Macro Definition Documentation

◆ AST_FRAME_BITS

#define AST_FRAME_BITS   32

Definition at line 676 of file app_meetme.c.

◆ CONF_SIZE

#define CONF_SIZE   320

Definition at line 695 of file app_meetme.c.

◆ CONFFLAG_DONT_DENOISE

#define CONFFLAG_DONT_DENOISE   (1ULL << 35)

If set, don't enable a denoiser for the channel

Definition at line 763 of file app_meetme.c.

◆ CONFFLAG_INTROMSG

#define CONFFLAG_INTROMSG   (1ULL << 32)

If set play an intro announcement at start of conference

Definition at line 758 of file app_meetme.c.

◆ CONFFLAG_INTROUSER_VMREC

#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)

Definition at line 759 of file app_meetme.c.

◆ CONFFLAG_KILL_LAST_MAN_STANDING

#define CONFFLAG_KILL_LAST_MAN_STANDING   (1ULL << 34)

If there's only one person left in a conference when someone leaves, kill the conference

Definition at line 761 of file app_meetme.c.

◆ CONFFLAG_NO_AUDIO_UNTIL_UP

#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)

Do not write any audio to this channel until the state is up.

Definition at line 757 of file app_meetme.c.

◆ CONFIG_FILE_NAME

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 655 of file app_meetme.c.

◆ DATE_FORMAT

#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"

String format for scheduled conferences

Definition at line 662 of file app_meetme.c.

◆ DEFAULT_AUDIO_BUFFERS

#define DEFAULT_AUDIO_BUFFERS   32

each buffer is 20ms, so this is 640ms total

Definition at line 659 of file app_meetme.c.

◆ MAX_CONFNUM

#define MAX_CONFNUM   80

Definition at line 827 of file app_meetme.c.

◆ MAX_PIN

#define MAX_PIN   80

Definition at line 828 of file app_meetme.c.

◆ MAX_SETTINGS

#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)

Definition at line 832 of file app_meetme.c.

◆ MC_DATA_FORMAT

#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"

◆ MC_HEADER_FORMAT

#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"

◆ MEETME_DELAYDETECTENDTALK

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 674 of file app_meetme.c.

◆ MEETME_DELAYDETECTTALK

#define MEETME_DELAYDETECTTALK   300

Definition at line 673 of file app_meetme.c.

◆ OPTIONS_LEN

#define OPTIONS_LEN   100

Definition at line 829 of file app_meetme.c.

◆ STR_CONCISE

#define STR_CONCISE   "concise"

Definition at line 656 of file app_meetme.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
ADMINFLAG_MUTED 

User is muted

ADMINFLAG_SELFMUTED 

User muted self

ADMINFLAG_KICKME 

User has been kicked

ADMINFLAG_T_REQUEST 

User has requested to speak

ADMINFLAG_HANGUP 

User will be leaving the conference

Definition at line 664 of file app_meetme.c.

664 {
665 ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
666 ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
667 ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */
668 /*! User has requested to speak */
669 ADMINFLAG_T_REQUEST = (1 << 4),
670 ADMINFLAG_HANGUP = (1 << 5), /*!< User will be leaving the conference */
671};
@ ADMINFLAG_SELFMUTED
Definition: app_meetme.c:666
@ ADMINFLAG_KICKME
Definition: app_meetme.c:667
@ ADMINFLAG_MUTED
Definition: app_meetme.c:665
@ ADMINFLAG_HANGUP
Definition: app_meetme.c:670
@ ADMINFLAG_T_REQUEST
Definition: app_meetme.c:669

◆ anonymous enum

anonymous enum
Enumerator
CONFFLAG_ADMIN 

user has admin access on the conference

CONFFLAG_MONITOR 

If set the user can only receive audio from the conference

CONFFLAG_KEYEXIT 

If set asterisk will exit conference when key defined in p() option is pressed

CONFFLAG_STARMENU 

If set asterisk will provide a menu to the user when '*' is pressed

CONFFLAG_TALKER 

If set the use can only send audio to the conference

CONFFLAG_QUIET 

If set there will be no enter or leave sounds

CONFFLAG_ANNOUNCEUSERCOUNT 

If set, when user joins the conference, they will be told the number of users that are already in

CONFFLAG_AGI 

Set to run AGI Script in Background

CONFFLAG_MOH 

Set to have music on hold when user is alone in conference

CONFFLAG_MARKEDEXIT 

If set, the channel will leave the conference if all marked users leave

CONFFLAG_WAITMARKED 

If set, the MeetMe will wait until a marked user enters

CONFFLAG_EXIT_CONTEXT 

If set, the MeetMe will exit to the specified context

CONFFLAG_MARKEDUSER 

If set, the user will be marked

CONFFLAG_INTROUSER 

If set, user will be ask record name on entry of conference

CONFFLAG_RECORDCONF 

If set, the MeetMe will be recorded

CONFFLAG_MONITORTALKER 

If set, the user will be monitored if the user is talking or not

CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER 

If set, treat talking users as muted users

CONFFLAG_NOONLYPERSON 

If set, won't speak the extra prompt when the first person enters the conference

CONFFLAG_INTROUSERNOREVIEW 

If set, user will be asked to record name on entry of conference without review

CONFFLAG_STARTMUTED 

If set, the user will be initially self-muted

CONFFLAG_PASS_DTMF 

Pass DTMF through the conference

CONFFLAG_KICK_CONTINUE 

If set, the user should continue in the dialplan if kicked out

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 

Definition at line 697 of file app_meetme.c.

697 {
698 /*! user has admin access on the conference */
699 CONFFLAG_ADMIN = (1 << 0),
700 /*! If set the user can only receive audio from the conference */
701 CONFFLAG_MONITOR = (1 << 1),
702 /*! If set asterisk will exit conference when key defined in p() option is pressed */
703 CONFFLAG_KEYEXIT = (1 << 2),
704 /*! If set asterisk will provide a menu to the user when '*' is pressed */
705 CONFFLAG_STARMENU = (1 << 3),
706 /*! If set the use can only send audio to the conference */
707 CONFFLAG_TALKER = (1 << 4),
708 /*! If set there will be no enter or leave sounds */
709 CONFFLAG_QUIET = (1 << 5),
710 /*! If set, when user joins the conference, they will be told the number
711 * of users that are already in */
713 /*! Set to run AGI Script in Background */
714 CONFFLAG_AGI = (1 << 7),
715 /*! Set to have music on hold when user is alone in conference */
716 CONFFLAG_MOH = (1 << 8),
717 /*! If set, the channel will leave the conference if all marked users leave */
718 CONFFLAG_MARKEDEXIT = (1 << 9),
719 /*! If set, the MeetMe will wait until a marked user enters */
720 CONFFLAG_WAITMARKED = (1 << 10),
721 /*! If set, the MeetMe will exit to the specified context */
722 CONFFLAG_EXIT_CONTEXT = (1 << 11),
723 /*! If set, the user will be marked */
724 CONFFLAG_MARKEDUSER = (1 << 12),
725 /*! If set, user will be ask record name on entry of conference */
726 CONFFLAG_INTROUSER = (1 << 13),
727 /*! If set, the MeetMe will be recorded */
728 CONFFLAG_RECORDCONF = (1<< 14),
729 /*! If set, the user will be monitored if the user is talking or not */
730 CONFFLAG_MONITORTALKER = (1 << 15),
731 CONFFLAG_DYNAMIC = (1 << 16),
732 CONFFLAG_DYNAMICPIN = (1 << 17),
733 CONFFLAG_EMPTY = (1 << 18),
734 CONFFLAG_EMPTYNOPIN = (1 << 19),
735 CONFFLAG_ALWAYSPROMPT = (1 << 20),
736 /*! If set, treat talking users as muted users */
737 CONFFLAG_OPTIMIZETALKER = (1 << 21),
738 /*! If set, won't speak the extra prompt when the first person
739 * enters the conference */
740 CONFFLAG_NOONLYPERSON = (1 << 22),
741 /*! If set, user will be asked to record name on entry of conference
742 * without review */
743 CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
744 /*! If set, the user will be initially self-muted */
745 CONFFLAG_STARTMUTED = (1 << 24),
746 /*! Pass DTMF through the conference */
747 CONFFLAG_PASS_DTMF = (1 << 25),
748 /*! If set, the user should continue in the dialplan if kicked out */
749 CONFFLAG_KICK_CONTINUE = (1 << 26),
750 CONFFLAG_DURATION_STOP = (1 << 27),
751 CONFFLAG_DURATION_LIMIT = (1 << 28),
752};
@ CONFFLAG_INTROUSERNOREVIEW
Definition: app_meetme.c:743
@ CONFFLAG_QUIET
Definition: app_meetme.c:709
@ CONFFLAG_INTROUSER
Definition: app_meetme.c:726
@ CONFFLAG_TALKER
Definition: app_meetme.c:707
@ CONFFLAG_ALWAYSPROMPT
Definition: app_meetme.c:735
@ CONFFLAG_OPTIMIZETALKER
Definition: app_meetme.c:737
@ CONFFLAG_MARKEDUSER
Definition: app_meetme.c:724
@ CONFFLAG_MARKEDEXIT
Definition: app_meetme.c:718
@ CONFFLAG_EXIT_CONTEXT
Definition: app_meetme.c:722
@ CONFFLAG_ANNOUNCEUSERCOUNT
Definition: app_meetme.c:712
@ CONFFLAG_DURATION_LIMIT
Definition: app_meetme.c:751
@ CONFFLAG_WAITMARKED
Definition: app_meetme.c:720
@ CONFFLAG_PASS_DTMF
Definition: app_meetme.c:747
@ CONFFLAG_EMPTY
Definition: app_meetme.c:733
@ CONFFLAG_DYNAMICPIN
Definition: app_meetme.c:732
@ CONFFLAG_DURATION_STOP
Definition: app_meetme.c:750
@ CONFFLAG_STARMENU
Definition: app_meetme.c:705
@ CONFFLAG_MOH
Definition: app_meetme.c:716
@ CONFFLAG_KICK_CONTINUE
Definition: app_meetme.c:749
@ CONFFLAG_AGI
Definition: app_meetme.c:714
@ CONFFLAG_RECORDCONF
Definition: app_meetme.c:728
@ CONFFLAG_MONITORTALKER
Definition: app_meetme.c:730
@ CONFFLAG_MONITOR
Definition: app_meetme.c:701
@ CONFFLAG_NOONLYPERSON
Definition: app_meetme.c:740
@ CONFFLAG_STARTMUTED
Definition: app_meetme.c:745
@ CONFFLAG_EMPTYNOPIN
Definition: app_meetme.c:734
@ CONFFLAG_DYNAMIC
Definition: app_meetme.c:731
@ CONFFLAG_KEYEXIT
Definition: app_meetme.c:703
@ CONFFLAG_ADMIN
Definition: app_meetme.c:699

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_INTROMSG 
OPT_ARG_INTROUSER_VMREC 
OPT_ARG_ARRAY_SIZE 

Definition at line 765 of file app_meetme.c.

765 {
774};
@ OPT_ARG_MOH_CLASS
Definition: app_meetme.c:770
@ OPT_ARG_DURATION_STOP
Definition: app_meetme.c:768
@ OPT_ARG_EXITKEYS
Definition: app_meetme.c:767
@ OPT_ARG_INTROMSG
Definition: app_meetme.c:771
@ OPT_ARG_DURATION_LIMIT
Definition: app_meetme.c:769
@ OPT_ARG_WAITMARKED
Definition: app_meetme.c:766
@ OPT_ARG_ARRAY_SIZE
Definition: app_meetme.c:773
@ OPT_ARG_INTROUSER_VMREC
Definition: app_meetme.c:772

◆ announcetypes

Enumerator
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 834 of file app_meetme.c.

834 {
837};
@ CONF_HASJOIN
Definition: app_meetme.c:835
@ CONF_HASLEFT
Definition: app_meetme.c:836

◆ entrance_sound

Enumerator
ENTER 
LEAVE 

Definition at line 683 of file app_meetme.c.

683 {
684 ENTER,
685 LEAVE
686};
@ ENTER
Definition: app_meetme.c:684
@ LEAVE
Definition: app_meetme.c:685

◆ menu_modes

enum menu_modes
Enumerator
MENU_DISABLED 
MENU_NORMAL 
MENU_ADMIN 
MENU_ADMIN_EXTENDED 

Definition at line 2310 of file app_meetme.c.

2310 {
2311 MENU_DISABLED = 0,
2313 MENU_ADMIN,
2315};
@ MENU_ADMIN
Definition: app_meetme.c:2313
@ MENU_ADMIN_EXTENDED
Definition: app_meetme.c:2314
@ MENU_DISABLED
Definition: app_meetme.c:2311
@ MENU_NORMAL
Definition: app_meetme.c:2312

◆ recording_state

Enumerator
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 688 of file app_meetme.c.

688 {
693};
@ MEETME_RECORD_STARTED
Definition: app_meetme.c:690
@ MEETME_RECORD_OFF
Definition: app_meetme.c:689
@ MEETME_RECORD_TERMINATE
Definition: app_meetme.c:692
@ MEETME_RECORD_ACTIVE
Definition: app_meetme.c:691

◆ volume_action

Enumerator
VOL_UP 
VOL_DOWN 

Definition at line 678 of file app_meetme.c.

678 {
679 VOL_UP,
681};
@ VOL_UP
Definition: app_meetme.c:679
@ VOL_DOWN
Definition: app_meetme.c:680

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 5566 of file app_meetme.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 5566 of file app_meetme.c.

◆ acf_meetme_info()

static int acf_meetme_info ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 5432 of file app_meetme.c.

5433{
5434 struct ast_conference *conf;
5435 char *parse;
5436 int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
5438 AST_APP_ARG(keyword);
5440 );
5441
5442 if (ast_strlen_zero(data)) {
5443 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
5444 return -1;
5445 }
5446
5447 parse = ast_strdupa(data);
5449
5450 if (ast_strlen_zero(args.keyword)) {
5451 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
5452 return -1;
5453 }
5454
5455 if (ast_strlen_zero(args.confno)) {
5456 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
5457 return -1;
5458 }
5459
5462 if (!strcmp(args.confno, conf->confno)) {
5464 break;
5465 }
5466 }
5468
5469 if (result > -1) {
5470 snprintf(buf, len, "%d", result);
5471 } else if (result == -1) {
5472 ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
5473 snprintf(buf, len, "0");
5474 } else if (result == -2) {
5475 ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
5476 snprintf(buf, len, "0");
5477 }
5478
5479 return 0;
5480}
static int acf_meetme_info_eval(const char *keyword, const struct ast_conference *conf)
Definition: app_meetme.c:5414
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
static PGresult * result
Definition: cel_pgsql.c:84
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define LOG_ERROR
#define LOG_NOTICE
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
The MeetMe Conference object.
Definition: app_meetme.c:850
char confno[MAX_CONFNUM]
Definition: app_meetme.c:853
struct ast_conference::@34 list
All configuration options for http media cache.
const char * args

References acf_meetme_info_eval(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), buf, ast_conference::confno, len(), ast_conference::list, LOG_ERROR, LOG_NOTICE, and result.

◆ acf_meetme_info_eval()

static int acf_meetme_info_eval ( const char *  keyword,
const struct ast_conference conf 
)
static

Definition at line 5414 of file app_meetme.c.

5415{
5416 if (!strcasecmp("lock", keyword)) {
5417 return conf->locked;
5418 } else if (!strcasecmp("parties", keyword)) {
5419 return conf->users;
5420 } else if (!strcasecmp("activity", keyword)) {
5421 time_t now;
5422 now = time(NULL);
5423 return (now - conf->start);
5424 } else if (!strcasecmp("dynamic", keyword)) {
5425 return conf->isdynamic;
5426 } else {
5427 return -1;
5428 }
5429
5430}
#define NULL
Definition: resample.c:96

References NULL.

Referenced by acf_meetme_info().

◆ action_meetmelist()

static int action_meetmelist ( struct mansession s,
const struct message m 
)
static

Definition at line 5081 of file app_meetme.c.

5082{
5083 const char *actionid = astman_get_header(m, "ActionID");
5084 const char *conference = astman_get_header(m, "Conference");
5085 char idText[80] = "";
5086 struct ast_conference *cnf;
5087 struct ast_conf_user *user;
5088 struct ao2_iterator user_iter;
5089 int total = 0;
5090
5091 if (!ast_strlen_zero(actionid))
5092 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5093
5094 if (AST_LIST_EMPTY(&confs)) {
5095 astman_send_error(s, m, "No active conferences.");
5096 return 0;
5097 }
5098
5099 astman_send_listack(s, m, "Meetme user list will follow", "start");
5100
5101 /* Find the right conference */
5103 AST_LIST_TRAVERSE(&confs, cnf, list) {
5104 /* If we ask for one particular, and this isn't it, skip it */
5105 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
5106 continue;
5107
5108 /* Show all the users */
5109 user_iter = ao2_iterator_init(cnf->usercontainer, 0);
5110 while ((user = ao2_iterator_next(&user_iter))) {
5111 total++;
5112 astman_append(s,
5113 "Event: MeetmeList\r\n"
5114 "%s"
5115 "Conference: %s\r\n"
5116 "UserNumber: %d\r\n"
5117 "CallerIDNum: %s\r\n"
5118 "CallerIDName: %s\r\n"
5119 "ConnectedLineNum: %s\r\n"
5120 "ConnectedLineName: %s\r\n"
5121 "Channel: %s\r\n"
5122 "Admin: %s\r\n"
5123 "Role: %s\r\n"
5124 "MarkedUser: %s\r\n"
5125 "Muted: %s\r\n"
5126 "Talking: %s\r\n"
5127 "\r\n",
5128 idText,
5129 cnf->confno,
5130 user->user_no,
5132 S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
5135 ast_channel_name(user->chan),
5136 ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
5137 ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
5138 ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
5139 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
5140 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
5141 ao2_ref(user, -1);
5142 }
5143 ao2_iterator_destroy(&user_iter);
5144 }
5146
5147 /* Send final confirmation */
5148 astman_send_list_complete_start(s, m, "MeetmeListComplete", total);
5150 return 0;
5151}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:2011
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1969
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:2047
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2055
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1890
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
static int total
Definition: res_adsi.c:970
static char user[512]
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
The MeetMe User object.
Definition: app_meetme.c:904
struct ao2_container * usercontainer
Definition: app_meetme.c:883
struct ast_party_id id
Caller party ID.
Definition: channel.h:422
struct ast_party_id id
Connected party ID.
Definition: channel.h:460
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:281
char * str
Subscriber name (Malloced)
Definition: channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293
structure to hold users read from users.conf
#define ast_test_flag64(p, flag)
Definition: utils.h:120

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_caller(), ast_channel_connected(), ast_channel_name(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag64, astman_append(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_party_caller::id, ast_party_connected_line::id, ast_party_id::name, ast_party_id::number, S_COR, ast_party_name::str, ast_party_number::str, total, user, ast_conference::usercontainer, ast_party_name::valid, and ast_party_number::valid.

Referenced by load_module().

◆ action_meetmelistrooms()

static int action_meetmelistrooms ( struct mansession s,
const struct message m 
)
static

Definition at line 5153 of file app_meetme.c.

5154{
5155 const char *actionid = astman_get_header(m, "ActionID");
5156 char idText[80] = "";
5157 struct ast_conference *cnf;
5158 int totalitems = 0;
5159 int hr, min, sec;
5160 time_t now;
5161 char markedusers[5];
5162
5163 if (!ast_strlen_zero(actionid)) {
5164 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5165 }
5166
5167 if (AST_LIST_EMPTY(&confs)) {
5168 astman_send_error(s, m, "No active conferences.");
5169 return 0;
5170 }
5171
5172 astman_send_listack(s, m, "Meetme conferences will follow", "start");
5173
5174 now = time(NULL);
5175
5176 /* Traverse the conference list */
5178 AST_LIST_TRAVERSE(&confs, cnf, list) {
5179 totalitems++;
5180
5181 if (cnf->markedusers == 0) {
5182 strcpy(markedusers, "N/A");
5183 } else {
5184 sprintf(markedusers, "%.4d", cnf->markedusers);
5185 }
5186 hr = (now - cnf->start) / 3600;
5187 min = ((now - cnf->start) % 3600) / 60;
5188 sec = (now - cnf->start) % 60;
5189
5190 astman_append(s,
5191 "Event: MeetmeListRooms\r\n"
5192 "%s"
5193 "Conference: %s\r\n"
5194 "Parties: %d\r\n"
5195 "Marked: %s\r\n"
5196 "Activity: %2.2d:%2.2d:%2.2d\r\n"
5197 "Creation: %s\r\n"
5198 "Locked: %s\r\n"
5199 "\r\n",
5200 idText,
5201 cnf->confno,
5202 cnf->users,
5204 hr, min, sec,
5205 cnf->isdynamic ? "Dynamic" : "Static",
5206 cnf->locked ? "Yes" : "No");
5207 }
5209
5210 /* Send final confirmation */
5211 astman_send_list_complete_start(s, m, "MeetmeListRoomsComplete", totalitems);
5213 return 0;
5214}
#define min(a, b)
Definition: f2c.h:197
unsigned int isdynamic
Definition: app_meetme.c:865
unsigned int locked
Definition: app_meetme.c:866

References AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_conference::confno, ast_conference::isdynamic, ast_conference::list, ast_conference::locked, ast_conference::markedusers, min, NULL, ast_conference::start, and ast_conference::users.

Referenced by load_module().

◆ action_meetmemute()

static int action_meetmemute ( struct mansession s,
const struct message m 
)
static

Definition at line 5071 of file app_meetme.c.

5072{
5073 return meetmemute(s, m, 1);
5074}
static int meetmemute(struct mansession *s, const struct message *m, int mute)
Definition: app_meetme.c:5011

References meetmemute().

Referenced by load_module().

◆ action_meetmeunmute()

static int action_meetmeunmute ( struct mansession s,
const struct message m 
)
static

Definition at line 5076 of file app_meetme.c.

5077{
5078 return meetmemute(s, m, 0);
5079}

References meetmemute().

Referenced by load_module().

◆ admin_exec()

static int admin_exec ( struct ast_channel chan,
const char *  data 
)
static

The MeetMeAdmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 4777 of file app_meetme.c.

4777 {
4778 char *params;
4779 struct ast_conference *cnf;
4780 struct ast_conf_user *user = NULL;
4782 AST_APP_ARG(confno);
4783 AST_APP_ARG(command);
4785 );
4786 int res = 0;
4787
4788 if (ast_strlen_zero(data)) {
4789 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
4790 if (chan) {
4791 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
4792 }
4793 return -1;
4794 }
4795
4796 params = ast_strdupa(data);
4797 AST_STANDARD_APP_ARGS(args, params);
4798
4799 if (!args.command) {
4800 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
4801 if (chan) {
4802 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
4803 }
4804 return -1;
4805 }
4806
4808 AST_LIST_TRAVERSE(&confs, cnf, list) {
4809 if (!strcmp(cnf->confno, args.confno))
4810 break;
4811 }
4812
4813 if (!cnf) {
4814 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
4816 if (chan) {
4817 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
4818 }
4819 return 0;
4820 }
4821
4823
4824 if (args.user) {
4825 user = find_user(cnf, args.user);
4826 if (!user) {
4827 ast_log(LOG_NOTICE, "Specified User not found!\n");
4828 res = -2;
4829 goto usernotfound;
4830 }
4831 } else {
4832 /* fail for commands that require a user */
4833 switch (*args.command) {
4834 case 'm': /* Unmute */
4835 case 'M': /* Mute */
4836 case 't': /* Lower user's talk volume */
4837 case 'T': /* Raise user's talk volume */
4838 case 'u': /* Lower user's listen volume */
4839 case 'U': /* Raise user's listen volume */
4840 case 'r': /* Reset user's volume level */
4841 case 'k': /* Kick user */
4842 res = -2;
4843 ast_log(LOG_NOTICE, "No user specified!\n");
4844 goto usernotfound;
4845 default:
4846 break;
4847 }
4848 }
4849
4850 switch (*args.command) {
4851 case 76: /* L: Lock */
4852 cnf->locked = 1;
4853 break;
4854 case 108: /* l: Unlock */
4855 cnf->locked = 0;
4856 break;
4857 case 75: /* K: kick all users */
4859 break;
4860 case 101: /* e: Eject last user*/
4861 {
4862 int max_no = 0;
4863 RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
4864
4866 eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
4867 if (!eject_user) {
4868 res = -1;
4869 ast_log(LOG_NOTICE, "No last user to kick!\n");
4870 break;
4871 }
4872
4873 if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
4874 eject_user->adminflags |= ADMINFLAG_KICKME;
4875 } else {
4876 res = -1;
4877 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
4878 }
4879 break;
4880 }
4881 case 77: /* M: Mute */
4882 user->adminflags |= ADMINFLAG_MUTED;
4883 break;
4884 case 78: /* N: Mute all (non-admin) users */
4886 break;
4887 case 109: /* m: Unmute */
4889 break;
4890 case 110: /* n: Unmute all users */
4892 break;
4893 case 107: /* k: Kick user */
4894 user->adminflags |= ADMINFLAG_KICKME;
4895 break;
4896 case 118: /* v: Lower all users listen volume */
4898 break;
4899 case 86: /* V: Raise all users listen volume */
4901 break;
4902 case 115: /* s: Lower all users speaking volume */
4904 break;
4905 case 83: /* S: Raise all users speaking volume */
4907 break;
4908 case 82: /* R: Reset all volume levels */
4910 break;
4911 case 114: /* r: Reset user's volume level */
4913 break;
4914 case 85: /* U: Raise user's listen volume */
4916 break;
4917 case 117: /* u: Lower user's listen volume */
4919 break;
4920 case 84: /* T: Raise user's talk volume */
4922 break;
4923 case 116: /* t: Lower user's talk volume */
4925 break;
4926 case 'E': /* E: Extend conference */
4927 if (rt_extend_conf(args.confno)) {
4928 res = -1;
4929 }
4930 break;
4931 }
4932
4933 if (args.user) {
4934 /* decrement reference from find_user */
4935 ao2_ref(user, -1);
4936 }
4937usernotfound:
4939
4940 dispose_conf(cnf);
4941 if (chan) {
4942 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
4943 }
4944
4945 return 0;
4946}
static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1328
static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2277
static int dispose_conf(struct ast_conference *conf)
Decrement reference counts, as incremented by find_conf()
Definition: app_meetme.c:2065
static int user_max_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1401
static int rt_extend_conf(const char *confno)
Definition: app_meetme.c:2084
static int user_reset_vol_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4755
static void reset_volumes(struct ast_conf_user *user)
Definition: app_meetme.c:1340
static struct ast_conf_user * find_user(struct ast_conference *conf, const char *callerident)
Definition: app_meetme.c:4714
static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2299
static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1316
static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2288
static int user_talk_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4748
static int user_listen_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4727
static int user_listen_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4734
static int user_talk_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4741
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_NODATA
Definition: astobj2.h:1044
#define LOG_WARNING
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
struct ast_channel * chan
Definition: app_meetme.c:908
struct ast_conf_user::@36 list
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ao2_callback, ao2_cleanup, ao2_find, ao2_ref, args, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag64, ast_conf_user::chan, CONFFLAG_ADMIN, ast_conference::confno, dispose_conf(), find_user(), ast_conf_user::list, ast_conference::locked, LOG_NOTICE, LOG_WARNING, NULL, OBJ_NODATA, pbx_builtin_setvar_helper(), RAII_VAR, ast_conference::refcount, reset_volumes(), rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), user_listen_voldown_cb(), user_listen_volup_cb(), user_max_cmp(), user_reset_vol_cb(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), user_talk_voldown_cb(), user_talk_volup_cb(), ast_conference::usercontainer, VOL_DOWN, and VOL_UP.

Referenced by load_module(), and meetme_cmd_helper().

◆ announce_thread()

static void * announce_thread ( void *  data)
static

Definition at line 2176 of file app_meetme.c.

2177{
2178 struct announce_listitem *current;
2179 struct ast_conference *conf = data;
2180 int res;
2181 char filename[PATH_MAX] = "";
2183 AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2184
2185 while (!conf->announcethread_stop) {
2186 ast_mutex_lock(&conf->announcelistlock);
2187 if (conf->announcethread_stop) {
2188 ast_mutex_unlock(&conf->announcelistlock);
2189 break;
2190 }
2191 if (AST_LIST_EMPTY(&conf->announcelist))
2192 ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
2193
2194 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2195 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2196
2197 ast_mutex_unlock(&conf->announcelistlock);
2198 if (conf->announcethread_stop) {
2199 break;
2200 }
2201
2202 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2203 ast_debug(1, "About to play %s\n", current->namerecloc);
2204 if (!ast_fileexists(current->namerecloc, NULL, NULL))
2205 continue;
2206 if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2207 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2208 res = ast_waitstream(current->confchan, "");
2209 if (!res) {
2210 ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2211 if (!ast_streamfile(current->confchan, filename, current->language))
2212 ast_waitstream(current->confchan, "");
2213 }
2214 }
2215 if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2216 /* only remove it if it isn't a VM recording file */
2217 ast_filedelete(current->namerecloc, NULL);
2218 }
2219 }
2220 }
2221
2222 /* thread marked to stop, clean up */
2223 while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2224 /* only delete if it's a vm rec */
2225 if (!current->vmrec) {
2226 ast_filedelete(current->namerecloc, NULL);
2227 }
2228 ao2_ref(current, -1);
2229 }
2230 return NULL;
2231}
static const char * get_announce_filename(enum announcetypes type)
Definition: app_meetme.c:2162
#define PATH_MAX
Definition: asterisk.h:40
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1141
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1840
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:783
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
size_t current
Definition: main/cli.c:113
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Definition: search.h:40

References ao2_ref, ast_check_hangup(), ast_cond_wait, ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, ast_streamfile(), ast_waitstream(), CONF_HASLEFT, current, get_announce_filename(), NULL, and PATH_MAX.

Referenced by conf_run().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 5566 of file app_meetme.c.

◆ build_conf()

static struct ast_conference * build_conf ( const char *  confno,
const char *  pin,
const char *  pinadmin,
int  make,
int  dynamic,
int  refcount,
const struct ast_channel chan,
struct ast_test *  test 
)
static

Find or create a conference.

Parameters
confnoThe conference name/number
pinThe regular user pin
pinadminThe admin pin
makeMake the conf if it doesn't exist
dynamicMark the newly created conference as dynamic
refcountHow many references to mark on the conference
chanThe asterisk channel
test
Returns
A pointer to the conference struct, or NULL if it wasn't found and make or dynamic were not set.

Definition at line 1428 of file app_meetme.c.

1431{
1432 struct ast_conference *cnf;
1433 struct dahdi_confinfo dahdic = { 0, };
1434 int confno_int = 0;
1436
1438
1439 AST_LIST_TRAVERSE(&confs, cnf, list) {
1440 if (!strcmp(confno, cnf->confno))
1441 break;
1442 }
1443
1444 if (cnf || (!make && !dynamic) || !cap_slin)
1445 goto cnfout;
1446
1448 /* Make a new one */
1449 cnf = ast_calloc(1, sizeof(*cnf));
1450 if (!cnf) {
1451 goto cnfout;
1452 }
1453
1455 NULL, user_no_cmp);
1456 if (!cnf->usercontainer) {
1457 goto cnfout;
1458 }
1459
1460 ast_mutex_init(&cnf->playlock);
1466 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1467 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1468 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1469 ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
1470
1471 /* Setup a new dahdi conference */
1472 dahdic.confno = -1;
1473 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1474 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1475 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1476 if (test) {
1477 /* if we are creating a conference for a unit test, it is not neccesary
1478 * to open a pseudo channel, so, if we fail continue creating
1479 * the conference. */
1480 ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1481 } else {
1482 ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1483 if (cnf->fd >= 0)
1484 close(cnf->fd);
1485 ao2_ref(cnf->usercontainer, -1);
1490 ast_free(cnf);
1491 cnf = NULL;
1492 goto cnfout;
1493 }
1494 }
1495
1496 cnf->dahdiconf = dahdic.confno;
1497
1498 /* Setup a new channel for playback of audio files */
1499 cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
1500 if (cnf->chan) {
1503 dahdic.chan = 0;
1504 dahdic.confno = cnf->dahdiconf;
1505 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1506 if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
1507 if (test) {
1508 ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1509 }
1510 ast_log(LOG_WARNING, "Error setting conference\n");
1511 if (cnf->chan)
1512 ast_hangup(cnf->chan);
1513 else
1514 close(cnf->fd);
1515 ao2_ref(cnf->usercontainer, -1);
1520 ast_free(cnf);
1521 cnf = NULL;
1522 goto cnfout;
1523 }
1524 }
1525
1526 /* Fill the conference struct */
1527 cnf->start = time(NULL);
1528 cnf->maxusers = 0x7fffffff;
1529 cnf->isdynamic = dynamic ? 1 : 0;
1530 ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1531 AST_LIST_INSERT_HEAD(&confs, cnf, list);
1532
1533 /* Reserve conference number in map */
1534 if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1535 conf_map[confno_int] = 1;
1536
1537cnfout:
1538 ao2_cleanup(cap_slin);
1539 if (cnf)
1540 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1541
1543
1544 return cnf;
1545}
static int user_no_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1389
static unsigned int conf_map[1024]
Definition: app_meetme.c:896
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2560
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_channel_fd(const struct ast_channel *chan, int which)
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5781
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5822
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6373
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
#define ast_verb(level,...)
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_destroy(a)
Definition: lock.h:188
ast_mutex_t announcethreadlock
Definition: app_meetme.c:887
pthread_t announcethread
Definition: app_meetme.c:886
ast_mutex_t recordthreadlock
Definition: app_meetme.c:869
char pinadmin[MAX_PIN]
Definition: app_meetme.c:874
ast_mutex_t playlock
Definition: app_meetme.c:851
struct ast_channel * chan
Definition: app_meetme.c:854
pthread_t recordthread
Definition: app_meetme.c:868
char pin[MAX_PIN]
Definition: app_meetme.c:873
char uniqueid[32]
Definition: app_meetme.c:875
ast_mutex_t listenlock
Definition: app_meetme.c:852
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
#define ast_test_status_update(a, b, c...)
Definition: test.h:129

References ast_conference::announcethread, ast_conference::announcethreadlock, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_list, ao2_ref, ast_atomic_fetchadd_int(), ast_calloc, ast_channel_fd(), ast_channel_uniqueid(), ast_copy_string(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_slin, ast_free, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_mutex_destroy, ast_mutex_init, AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_test_status_update, ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, NULL, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, ast_conference::uniqueid, user_no_cmp(), and ast_conference::usercontainer.

Referenced by find_conf(), and find_conf_realtime().

◆ can_write()

static int can_write ( struct ast_channel chan,
struct ast_flags64 confflags 
)
static

Definition at line 2233 of file app_meetme.c.

2234{
2236 return 1;
2237 }
2238
2239 return (ast_channel_state(chan) == AST_STATE_UP);
2240}
#define CONFFLAG_NO_AUDIO_UNTIL_UP
Definition: app_meetme.c:757
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42

References AST_STATE_UP, ast_test_flag64, ast_conference::chan, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

◆ careful_write()

static int careful_write ( int  fd,
unsigned char *  data,
int  len,
int  block 
)
static

Definition at line 1230 of file app_meetme.c.

1231{
1232 int res;
1233 int x;
1234
1235 while (len) {
1236 if (block) {
1237 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
1238 res = ioctl(fd, DAHDI_IOMUX, &x);
1239 } else
1240 res = 0;
1241 if (res >= 0)
1242 res = write(fd, data, len);
1243 if (res < 1) {
1244 if (errno != EAGAIN) {
1245 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
1246 return -1;
1247 } else
1248 return 0;
1249 }
1250 len -= res;
1251 data += res;
1252 }
1253
1254 return 0;
1255}
int errno

References ast_log, errno, len(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

◆ channel_admin_exec()

static int channel_admin_exec ( struct ast_channel chan,
const char *  data 
)
static

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command)

Definition at line 4950 of file app_meetme.c.

4950 {
4951 char *params;
4952 struct ast_conference *conf = NULL;
4953 struct ast_conf_user *user = NULL;
4955 AST_APP_ARG(channel);
4956 AST_APP_ARG(command);
4957 );
4958
4959 if (ast_strlen_zero(data)) {
4960 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
4961 return -1;
4962 }
4963
4964 params = ast_strdupa(data);
4965 AST_STANDARD_APP_ARGS(args, params);
4966
4967 if (!args.channel) {
4968 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
4969 return -1;
4970 }
4971
4972 if (!args.command) {
4973 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
4974 return -1;
4975 }
4976
4979 if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
4980 break;
4981 }
4982 }
4983
4984 if (!user) {
4985 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
4987 return 0;
4988 }
4989
4990 /* perform the specified action */
4991 switch (*args.command) {
4992 case 77: /* M: Mute */
4993 user->adminflags |= ADMINFLAG_MUTED;
4994 break;
4995 case 109: /* m: Unmute */
4996 user->adminflags &= ~ADMINFLAG_MUTED;
4997 break;
4998 case 107: /* k: Kick user */
4999 user->adminflags |= ADMINFLAG_KICKME;
5000 break;
5001 default: /* unknown command */
5002 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
5003 break;
5004 }
5005 ao2_ref(user, -1);
5007
5008 return 0;
5009}
static int user_chan_cb(void *obj, void *args, int flags)
Definition: app_meetme.c:4762

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ao2_callback, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conf_user::list, LOG_NOTICE, LOG_WARNING, NULL, and user_chan_cb().

Referenced by load_module().

◆ complete_confno()

static char * complete_confno ( const char *  word,
int  state 
)
static

Definition at line 1547 of file app_meetme.c.

1548{
1549 struct ast_conference *cnf;
1550 char *ret = NULL;
1551 int which = 0;
1552 int len = strlen(word);
1553
1555 AST_LIST_TRAVERSE(&confs, cnf, list) {
1556 if (!strncmp(word, cnf->confno, len) && ++which > state) {
1557 /* dup before releasing the lock */
1558 ret = ast_strdup(cnf->confno);
1559 break;
1560 }
1561 }
1563 return ret;
1564}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
short word

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_conference::confno, len(), ast_conference::list, and NULL.

Referenced by complete_meetmecmd_list(), complete_meetmecmd_lock(), and complete_meetmecmd_mute_kick().

◆ complete_meetmecmd_list()

static char * complete_meetmecmd_list ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 1636 of file app_meetme.c.

1637{
1638 int len;
1639
1640 if (pos == 2) {
1641 len = strlen(word);
1642 if (!strncasecmp(word, STR_CONCISE, len)) {
1643 if (state == 0) {
1644 return ast_strdup(STR_CONCISE);
1645 }
1646 --state;
1647 }
1648
1649 return complete_confno(word, state);
1650 }
1651 if (pos == 3 && state == 0) {
1652 char *saved = NULL;
1653 char *myline;
1654 char *confno;
1655
1656 /* Extract the confno from the command line. */
1657 myline = ast_strdupa(line);
1658 strtok_r(myline, " ", &saved);
1659 strtok_r(NULL, " ", &saved);
1660 confno = strtok_r(NULL, " ", &saved);
1661
1662 if (!strcasecmp(confno, STR_CONCISE)) {
1663 /* There is nothing valid in this position now. */
1664 return NULL;
1665 }
1666
1667 len = strlen(word);
1668 if (!strncasecmp(word, STR_CONCISE, len)) {
1669 return ast_strdup(STR_CONCISE);
1670 }
1671 }
1672 return NULL;
1673}
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1547
#define STR_CONCISE
Definition: app_meetme.c:656
enum cc_state state
Definition: ccss.c:393

References ast_strdup, ast_strdupa, complete_confno(), ast_conference::confno, len(), NULL, state, and STR_CONCISE.

Referenced by meetme_show_cmd().

◆ complete_meetmecmd_lock()

static char * complete_meetmecmd_lock ( const char *  word,
int  pos,
int  state 
)
static

Definition at line 1628 of file app_meetme.c.

1629{
1630 if (pos == 2) {
1631 return complete_confno(word, state);
1632 }
1633 return NULL;
1634}

References complete_confno(), and NULL.

Referenced by meetme_lock_cmd().

◆ complete_meetmecmd_mute_kick()

static char * complete_meetmecmd_mute_kick ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 1588 of file app_meetme.c.

1589{
1590 if (pos == 2) {
1591 return complete_confno(word, state);
1592 }
1593 if (pos == 3) {
1594 int len = strlen(word);
1595 char *ret = NULL;
1596 char *saved = NULL;
1597 char *myline;
1598 char *confno;
1599 struct ast_conference *cnf;
1600
1601 if (!strncasecmp(word, "all", len)) {
1602 if (state == 0) {
1603 return ast_strdup("all");
1604 }
1605 --state;
1606 }
1607
1608 /* Extract the confno from the command line. */
1609 myline = ast_strdupa(line);
1610 strtok_r(myline, " ", &saved);
1611 strtok_r(NULL, " ", &saved);
1612 confno = strtok_r(NULL, " ", &saved);
1613
1615 AST_LIST_TRAVERSE(&confs, cnf, list) {
1616 if (!strcmp(confno, cnf->confno)) {
1617 ret = complete_userno(cnf, word, state);
1618 break;
1619 }
1620 }
1622
1623 return ret;
1624 }
1625 return NULL;
1626}
static char * complete_userno(struct ast_conference *cnf, const char *word, int state)
Definition: app_meetme.c:1566

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, complete_confno(), complete_userno(), ast_conference::confno, len(), ast_conference::list, NULL, and state.

Referenced by meetme_kick_cmd(), and meetme_mute_cmd().

◆ complete_userno()

static char * complete_userno ( struct ast_conference cnf,
const char *  word,
int  state 
)
static

Definition at line 1566 of file app_meetme.c.

1567{
1568 char usrno[50];
1569 struct ao2_iterator iter;
1570 struct ast_conf_user *usr;
1571 char *ret = NULL;
1572 int which = 0;
1573 int len = strlen(word);
1574
1575 iter = ao2_iterator_init(cnf->usercontainer, 0);
1576 for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
1577 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1578 if (!strncmp(word, usrno, len) && ++which > state) {
1579 ao2_ref(usr, -1);
1580 ret = ast_strdup(usrno);
1581 break;
1582 }
1583 }
1584 ao2_iterator_destroy(&iter);
1585 return ret;
1586}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, len(), NULL, ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by complete_meetmecmd_mute_kick().

◆ conf_exec()

static int conf_exec ( struct ast_channel chan,
const char *  data 
)
static

The meetme() application.

Definition at line 4389 of file app_meetme.c.

4390{
4391 int res = -1;
4392 char confno[MAX_CONFNUM] = "";
4393 int allowretry = 0;
4394 int retrycnt = 0;
4395 struct ast_conference *cnf = NULL;
4396 struct ast_flags64 confflags = {0};
4397 struct ast_flags config_flags = { 0 };
4398 int dynamic = 0;
4399 int empty = 0, empty_no_pin = 0;
4400 int always_prompt = 0;
4401 const char *notdata;
4402 char *info, the_pin[MAX_PIN] = "";
4404 AST_APP_ARG(confno);
4406 AST_APP_ARG(pin);
4407 );
4408 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
4409
4410 if (ast_strlen_zero(data)) {
4411 allowretry = 1;
4412 notdata = "";
4413 } else {
4414 notdata = data;
4415 }
4416
4417 if (ast_channel_state(chan) != AST_STATE_UP)
4418 ast_answer(chan);
4419
4420 info = ast_strdupa(notdata);
4421
4423
4424 if (args.confno) {
4425 ast_copy_string(confno, args.confno, sizeof(confno));
4426 if (ast_strlen_zero(confno)) {
4427 allowretry = 1;
4428 }
4429 }
4430
4431 if (args.pin)
4432 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
4433
4434 if (args.options) {
4435 ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
4436 dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
4438 strcpy(the_pin, "q");
4439
4440 empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
4441 empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
4442 always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
4443 }
4444
4445 do {
4446 if (retrycnt > 3)
4447 allowretry = 0;
4448 if (empty) {
4449 int i;
4450 struct ast_config *cfg;
4451 struct ast_variable *var;
4452 int confno_int;
4453
4454 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
4455 if ((empty_no_pin) || (!dynamic)) {
4456 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4457 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
4458 var = ast_variable_browse(cfg, "rooms");
4459 while (var) {
4460 char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
4461 if (!strcasecmp(var->name, "conf")) {
4462 int found = 0;
4463 ast_copy_string(parse, var->value, sizeof(parse));
4464 confno_tmp = strsep(&stringp, "|,");
4465 if (!dynamic) {
4466 /* For static: run through the list and see if this conference is empty */
4468 AST_LIST_TRAVERSE(&confs, cnf, list) {
4469 if (!strcmp(confno_tmp, cnf->confno)) {
4470 /* The conference exists, therefore it's not empty */
4471 found = 1;
4472 break;
4473 }
4474 }
4476 cnf = NULL;
4477 if (!found) {
4478 /* At this point, we have a confno_tmp (static conference) that is empty */
4479 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
4480 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4481 * Case 2: empty_no_pin and pin is blank (but not NULL)
4482 * Case 3: not empty_no_pin
4483 */
4484 ast_copy_string(confno, confno_tmp, sizeof(confno));
4485 break;
4486 }
4487 }
4488 }
4489 }
4490 var = var->next;
4491 }
4492 ast_config_destroy(cfg);
4493 }
4494
4495 if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
4496 const char *catg;
4497 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
4498 const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
4499 const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
4500 if (ast_strlen_zero(confno_tmp)) {
4501 continue;
4502 }
4503 if (!dynamic) {
4504 int found = 0;
4505 /* For static: run through the list and see if this conference is empty */
4507 AST_LIST_TRAVERSE(&confs, cnf, list) {
4508 if (!strcmp(confno_tmp, cnf->confno)) {
4509 /* The conference exists, therefore it's not empty */
4510 found = 1;
4511 break;
4512 }
4513 }
4515 if (!found) {
4516 /* At this point, we have a confno_tmp (realtime conference) that is empty */
4517 if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
4518 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4519 * Case 2: empty_no_pin and pin is blank (but not NULL)
4520 * Case 3: not empty_no_pin
4521 */
4522 ast_copy_string(confno, confno_tmp, sizeof(confno));
4523 break;
4524 }
4525 }
4526 }
4527 }
4528 ast_config_destroy(cfg);
4529 }
4530 }
4531
4532 /* Select first conference number not in use */
4533 if (ast_strlen_zero(confno) && dynamic) {
4535 for (i = 0; i < ARRAY_LEN(conf_map); i++) {
4536 if (!conf_map[i]) {
4537 snprintf(confno, sizeof(confno), "%d", i);
4538 conf_map[i] = 1;
4539 break;
4540 }
4541 }
4543 }
4544
4545 /* Not found? */
4546 if (ast_strlen_zero(confno)) {
4547 res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
4548 ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
4549 if (!res)
4550 ast_waitstream(chan, "");
4551 } else {
4552 if (sscanf(confno, "%30d", &confno_int) == 1) {
4553 if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
4554 res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
4555 if (!res) {
4556 ast_waitstream(chan, "");
4557 res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
4558 }
4559 }
4560 } else {
4561 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
4562 }
4563 }
4564 }
4565
4566 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
4567 /* Prompt user for conference number */
4568 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
4569 if (res < 0) {
4570 /* Don't try to validate when we catch an error */
4571 confno[0] = '\0';
4572 allowretry = 0;
4573 break;
4574 }
4575 }
4576 if (!ast_strlen_zero(confno)) {
4577 /* Check the validity of the conference */
4578 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
4579 sizeof(the_pin), 1, &confflags);
4580 if (!cnf) {
4581 int too_early = 0;
4582
4583 cnf = find_conf_realtime(chan, confno, 1, dynamic,
4584 the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
4585 if (rt_schedule && too_early)
4586 allowretry = 0;
4587 }
4588
4589 if (!cnf) {
4590 if (allowretry) {
4591 confno[0] = '\0';
4592 res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
4593 if (!res)
4594 ast_waitstream(chan, "");
4595 res = -1;
4596 }
4597 } else {
4598 /* Conference requires a pin for specified access level */
4599 int req_pin = !ast_strlen_zero(cnf->pin) ||
4600 (!ast_strlen_zero(cnf->pinadmin) &&
4601 ast_test_flag64(&confflags, CONFFLAG_ADMIN));
4602 /* The following logic was derived from a
4603 * 4 variable truth table and defines which
4604 * circumstances are not exempt from pin
4605 * checking.
4606 * If this needs to be modified, write the
4607 * truth table back out from the boolean
4608 * expression AB+A'D+C', change the erroneous
4609 * result, and rederive the expression.
4610 * Variables:
4611 * A: pin provided?
4612 * B: always prompt?
4613 * C: dynamic?
4614 * D: has users? */
4615 int not_exempt = !cnf->isdynamic;
4616 not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
4617 not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
4618 if (req_pin && not_exempt) {
4619 char pin[MAX_PIN] = "";
4620 int j;
4621
4622 /* Allow the pin to be retried up to 3 times */
4623 for (j = 0; j < 3; j++) {
4624 if (*the_pin && (always_prompt == 0)) {
4625 ast_copy_string(pin, the_pin, sizeof(pin));
4626 res = 0;
4627 } else {
4628 /* Prompt user for pin if pin is required */
4629 ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
4630 "Channel: %s",
4631 ast_channel_name(chan));
4632 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
4633 }
4634 if (res >= 0) {
4635 if ((!strcasecmp(pin, cnf->pin) &&
4636 (ast_strlen_zero(cnf->pinadmin) ||
4637 !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
4638 (!ast_strlen_zero(cnf->pinadmin) &&
4639 !strcasecmp(pin, cnf->pinadmin))) {
4640 /* Pin correct */
4641 allowretry = 0;
4642 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
4643 if (!ast_strlen_zero(cnf->adminopts)) {
4644 char *opts = ast_strdupa(cnf->adminopts);
4645 ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
4646 }
4647 } else {
4648 if (!ast_strlen_zero(cnf->useropts)) {
4649 char *opts = ast_strdupa(cnf->useropts);
4650 ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
4651 }
4652 }
4653 /* Run the conference */
4654 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
4655 res = conf_run(chan, cnf, &confflags, optargs);
4656 break;
4657 } else {
4658 /* Pin invalid */
4659 if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
4660 res = ast_waitstream(chan, AST_DIGIT_ANY);
4661 ast_stopstream(chan);
4662 } else {
4663 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
4664 break;
4665 }
4666 if (res < 0)
4667 break;
4668 pin[0] = res;
4669 pin[1] = '\0';
4670 res = -1;
4671 if (allowretry)
4672 confno[0] = '\0';
4673 }
4674 } else {
4675 /* failed when getting the pin */
4676 res = -1;
4677 allowretry = 0;
4678 /* see if we need to get rid of the conference */
4679 break;
4680 }
4681
4682 /* Don't retry pin with a static pin */
4683 if (*the_pin && (always_prompt == 0)) {
4684 break;
4685 }
4686 }
4687 } else {
4688 /* No pin required */
4689 allowretry = 0;
4690
4691 /* For RealTime conferences without a pin
4692 * should still support loading options
4693 */
4694 if (!ast_strlen_zero(cnf->useropts)) {
4695 char *opts = ast_strdupa(cnf->useropts);
4696 ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
4697 }
4698
4699 /* Run the conference */
4700 res = conf_run(chan, cnf, &confflags, optargs);
4701 }
4702 dispose_conf(cnf);
4703 cnf = NULL;
4704 }
4705 }
4706 } while (allowretry);
4707
4708 if (cnf)
4709 dispose_conf(cnf);
4710
4711 return res;
4712}
static const struct ast_app_option meetme_opts[128]
Definition: app_meetme.c:810
static struct ast_conference * find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
Definition: app_meetme.c:4053
#define CONFIG_FILE_NAME
Definition: app_meetme.c:655
#define MAX_PIN
Definition: app_meetme.c:828
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
Definition: app_meetme.c:2740
#define MAX_CONFNUM
Definition: app_meetme.c:827
static struct ast_conference * find_conf(struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
Definition: app_meetme.c:4240
static int rt_schedule
Definition: app_meetme.c:818
#define MAX_SETTINGS
Definition: app_meetme.c:832
#define var
Definition: ast_expr2f.c:605
const char * ast_channel_language(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2824
#define SENTINEL
Definition: compiler.h:87
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
#define AST_DIGIT_ANY
Definition: file.h:48
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
Definition: main/app.c:188
int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3071
char * strsep(char **str, const char *delims)
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3637
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:784
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
def info(msg)
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8275
char * recordingformat
Definition: app_meetme.c:872
const char * useropts
Definition: app_meetme.c:877
char * recordingfilename
Definition: app_meetme.c:871
const char * adminopts
Definition: app_meetme.c:878
Structure used to handle a large number of boolean flags == used only in app_dial?
Definition: utils.h:204
Structure used to handle boolean flags.
Definition: utils.h:199
Structure for variables, used for configurations and for channel variables.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
static struct test_options options
#define ARRAY_LEN(a)
Definition: utils.h:666

References ast_conference::adminopts, args, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options64(), ast_category_browse(), ast_channel_language(), ast_channel_name(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime_multientry(), ast_log, ast_say_digits(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_test_suite_event_notify, ast_variable_browse(), ast_variable_retrieve(), ast_verb, ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), sip_to_pjsip::info(), ast_conference::isdynamic, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, NULL, OPT_ARG_ARRAY_SIZE, options, ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, rt_schedule, SENTINEL, strsep(), ast_conference::useropts, ast_conference::users, and var.

Referenced by load_module().

◆ conf_flush()

static void conf_flush ( int  fd,
struct ast_channel chan 
)
static

Definition at line 1944 of file app_meetme.c.

1945{
1946 int x;
1947
1948 /* read any frames that may be waiting on the channel
1949 and throw them away
1950 */
1951 if (chan) {
1952 struct ast_frame *f;
1953
1954 /* when no frames are available, this will wait
1955 for 1 millisecond maximum
1956 */
1957 while (ast_waitfor(chan, 1) > 0) {
1958 f = ast_read(chan);
1959 if (f)
1960 ast_frfree(f);
1961 else /* channel was hung up or something else happened */
1962 break;
1963 }
1964 }
1965
1966 /* flush any data sitting in the pseudo channel */
1967 x = DAHDI_FLUSH_ALL;
1968 if (ioctl(fd, DAHDI_FLUSH, &x))
1969 ast_log(LOG_WARNING, "Error flushing channel\n");
1970
1971}
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3181
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
#define ast_frfree(fr)
Data structure associated with a single frame of data.

References ast_frfree, ast_log, ast_read(), ast_waitfor(), and LOG_WARNING.

Referenced by conf_run().

◆ conf_free()

static int conf_free ( struct ast_conference conf)
static

Remove the conference from the list and free it.

We assume that this was called while holding conflock.

Definition at line 1976 of file app_meetme.c.

1977{
1978 int x;
1979 struct announce_listitem *item;
1980
1981 AST_LIST_REMOVE(&confs, conf, list);
1982
1983 meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
1984
1985 if (conf->recording == MEETME_RECORD_ACTIVE) {
1986 conf->recording = MEETME_RECORD_TERMINATE;
1988 while (1) {
1989 usleep(1);
1991 if (conf->recording == MEETME_RECORD_OFF)
1992 break;
1994 }
1995 }
1996
1997 for (x = 0; x < AST_FRAME_BITS; x++) {
1998 if (conf->transframe[x])
1999 ast_frfree(conf->transframe[x]);
2000 if (conf->transpath[x])
2001 ast_translator_free_path(conf->transpath[x]);
2002 }
2003 if (conf->announcethread != AST_PTHREADT_NULL) {
2004 ast_mutex_lock(&conf->announcelistlock);
2005 conf->announcethread_stop = 1;
2007 ast_cond_signal(&conf->announcelist_addition);
2008 ast_mutex_unlock(&conf->announcelistlock);
2009 pthread_join(conf->announcethread, NULL);
2010
2011 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2012 /* If it's a voicemail greeting file we don't want to remove it */
2013 if (!item->vmrec){
2014 ast_filedelete(item->namerecloc, NULL);
2015 }
2016 ao2_ref(item, -1);
2017 }
2018 ast_mutex_destroy(&conf->announcelistlock);
2019 }
2020
2021 if (conf->origframe)
2022 ast_frfree(conf->origframe);
2023 ast_hangup(conf->lchan);
2024 ast_hangup(conf->chan);
2025 if (conf->fd >= 0)
2026 close(conf->fd);
2027 if (conf->recordingfilename) {
2028 ast_free(conf->recordingfilename);
2029 }
2030 if (conf->usercontainer) {
2031 ao2_ref(conf->usercontainer, -1);
2032 }
2033 if (conf->recordingformat) {
2034 ast_free(conf->recordingformat);
2035 }
2036 ast_mutex_destroy(&conf->playlock);
2037 ast_mutex_destroy(&conf->listenlock);
2038 ast_mutex_destroy(&conf->recordthreadlock);
2039 ast_mutex_destroy(&conf->announcethreadlock);
2040 ast_free(conf);
2041
2042 return 0;
2043}
static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan, struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
Definition: app_meetme.c:1165
#define AST_FRAME_BITS
Definition: app_meetme.c:676
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2490
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define ast_cond_signal(cond)
Definition: lock.h:203
static struct aco_type item
Definition: test_config.c:1463
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:476

References ao2_ref, ast_cond_signal, ast_filedelete(), AST_FRAME_BITS, ast_free, ast_frfree, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), item, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, meetme_stasis_generate_msg(), and NULL.

Referenced by dispose_conf().

◆ conf_play()

static void conf_play ( struct ast_channel chan,
struct ast_conference conf,
enum entrance_sound  sound 
)
static

Definition at line 1348 of file app_meetme.c.

1349{
1350 unsigned char *data;
1351 int len;
1352 int res = -1;
1353
1354 ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
1355 "Conference: %s\r\n"
1356 "Marked: %d",
1357 ast_channel_name(chan),
1358 conf->confno,
1359 conf->markedusers);
1360
1361 if (!ast_check_hangup(chan))
1362 res = ast_autoservice_start(chan);
1363
1365
1366 switch(sound) {
1367 case ENTER:
1368 data = enter;
1369 len = sizeof(enter);
1370 break;
1371 case LEAVE:
1372 data = leave;
1373 len = sizeof(leave);
1374 break;
1375 default:
1376 data = NULL;
1377 len = 0;
1378 }
1379 if (data) {
1380 careful_write(conf->fd, data, len, 1);
1381 }
1382
1384
1385 if (!res)
1387}
static int careful_write(int fd, unsigned char *data, int len, int block)
Definition: app_meetme.c:1230
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
static unsigned char enter[]
Definition: enter.h:12
static unsigned char leave[]
Definition: leave.h:12

References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), ast_check_hangup(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_suite_event_notify, careful_write(), ENTER, enter, LEAVE, leave, len(), and NULL.

Referenced by conf_run().

◆ conf_queue_dtmf()

static void conf_queue_dtmf ( const struct ast_conference conf,
const struct ast_conf_user sender,
struct ast_frame f 
)
static

Definition at line 2045 of file app_meetme.c.

2047{
2048 struct ast_conf_user *user;
2049 struct ao2_iterator user_iter;
2050
2051 user_iter = ao2_iterator_init(conf->usercontainer, 0);
2052 while ((user = ao2_iterator_next(&user_iter))) {
2053 if (user == sender) {
2054 ao2_ref(user, -1);
2055 continue;
2056 }
2057 if (ast_write(user->chan, f) < 0)
2058 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
2059 ao2_ref(user, -1);
2060 }
2061 ao2_iterator_destroy(&user_iter);
2062}
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5163

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_name(), ast_log, ast_write(), LOG_WARNING, and user.

Referenced by conf_run().

◆ conf_run()

static int conf_run ( struct ast_channel chan,
struct ast_conference conf,
struct ast_flags64 confflags,
char *  optargs[] 
)
static

Definition at line 2740 of file app_meetme.c.

2741{
2742 struct ast_conf_user *user = NULL;
2743 int fd;
2744 struct dahdi_confinfo dahdic, dahdic_empty;
2745 struct ast_frame *f;
2746 struct ast_channel *c;
2747 struct ast_frame fr;
2748 int outfd;
2749 int ms;
2750 int nfds;
2751 int res;
2752 int retrydahdi;
2753 int origfd;
2754 int musiconhold = 0, mohtempstopped = 0;
2755 int firstpass = 0;
2756 int lastmarked = 0;
2757 int currentmarked = 0;
2758 int ret = -1;
2759 int x;
2760 enum menu_modes menu_mode = MENU_DISABLED;
2761 int talkreq_manager = 0;
2762 int using_pseudo = 0;
2763 int duration = 20;
2764 int sent_event = 0;
2765 int checked = 0;
2766 int announcement_played = 0;
2767 struct timeval now;
2768 struct ast_dsp *dsp = NULL;
2769 struct ast_app *agi_app;
2770 char *agifile;
2771 const char *agifiledefault = "conf-background.agi", *tmpvar;
2772 char meetmesecs[30] = "";
2773 char exitcontext[AST_MAX_CONTEXT] = "";
2774 char recordingtmp[AST_MAX_EXTENSION * 2] = "";
2775 char members[10] = "";
2776 int dtmf = 0, opt_waitmarked_timeout = 0;
2777 time_t timeout = 0;
2778 struct dahdi_bufferinfo bi;
2779 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
2780 char *buf = __buf + AST_FRIENDLY_OFFSET;
2781 char *exitkeys = NULL;
2782 unsigned int calldurationlimit = 0;
2783 long timelimit = 0;
2784 long play_warning = 0;
2785 long warning_freq = 0;
2786 const char *warning_sound = NULL;
2787 const char *end_sound = NULL;
2788 char *parse;
2789 long time_left_ms = 0;
2790 struct timeval nexteventts = { 0, };
2791 int to;
2792 int setusercount = 0;
2793 int confsilence = 0, totalsilence = 0;
2794 char *mailbox, *context;
2796
2797 if (!cap_slin) {
2798 goto conf_run_cleanup;
2799 }
2801
2802 if (!(user = ao2_alloc(sizeof(*user), NULL))) {
2803 goto conf_run_cleanup;
2804 }
2805
2806 /* Possible timeout waiting for marked user */
2807 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
2809 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
2810 (opt_waitmarked_timeout > 0)) {
2811 timeout = time(NULL) + opt_waitmarked_timeout;
2812 }
2813
2815 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
2816 ast_verb(3, "Setting call duration limit to %u seconds.\n", calldurationlimit);
2817 }
2818
2820 char *limit_str, *warning_str, *warnfreq_str;
2821 const char *var;
2822
2823 parse = optargs[OPT_ARG_DURATION_LIMIT];
2824 limit_str = strsep(&parse, ":");
2825 warning_str = strsep(&parse, ":");
2826 warnfreq_str = parse;
2827
2828 timelimit = atol(limit_str);
2829 if (warning_str)
2830 play_warning = atol(warning_str);
2831 if (warnfreq_str)
2832 warning_freq = atol(warnfreq_str);
2833
2834 if (!timelimit) {
2835 timelimit = play_warning = warning_freq = 0;
2836 warning_sound = NULL;
2837 } else if (play_warning > timelimit) {
2838 if (!warning_freq) {
2839 play_warning = 0;
2840 } else {
2841 while (play_warning > timelimit)
2842 play_warning -= warning_freq;
2843 if (play_warning < 1)
2844 play_warning = warning_freq = 0;
2845 }
2846 }
2847
2848 ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
2849 if (play_warning) {
2850 ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
2851 }
2852 if (warning_freq) {
2853 ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
2854 }
2855
2856 ast_channel_lock(chan);
2857 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
2858 var = ast_strdupa(var);
2859 }
2860 ast_channel_unlock(chan);
2861
2862 warning_sound = var ? var : "timeleft";
2863
2864 ast_channel_lock(chan);
2865 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
2866 var = ast_strdupa(var);
2867 }
2868 ast_channel_unlock(chan);
2869
2870 end_sound = var ? var : NULL;
2871
2872 /* undo effect of S(x) in case they are both used */
2873 calldurationlimit = 0;
2874 /* more efficient do it like S(x) does since no advanced opts */
2875 if (!play_warning && !end_sound && timelimit) {
2876 calldurationlimit = timelimit / 1000;
2877 timelimit = play_warning = warning_freq = 0;
2878 } else {
2879 ast_debug(2, "Limit Data for this call:\n");
2880 ast_debug(2, "- timelimit = %ld\n", timelimit);
2881 ast_debug(2, "- play_warning = %ld\n", play_warning);
2882 ast_debug(2, "- warning_freq = %ld\n", warning_freq);
2883 ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
2884 ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
2885 }
2886 }
2887
2888 /* Get exit keys */
2889 if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
2890 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
2891 exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
2892 else
2893 exitkeys = ast_strdupa("#"); /* Default */
2894 }
2895
2896 if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
2897 if (!conf->recordingfilename) {
2898 const char *var;
2899 ast_channel_lock(chan);
2900 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
2901 conf->recordingfilename = ast_strdup(var);
2902 }
2903 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
2904 conf->recordingformat = ast_strdup(var);
2905 }
2906 ast_channel_unlock(chan);
2907 if (!conf->recordingfilename) {
2908 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
2909 conf->recordingfilename = ast_strdup(recordingtmp);
2910 }
2911 if (!conf->recordingformat) {
2912 conf->recordingformat = ast_strdup("wav");
2913 }
2914 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
2915 conf->confno, conf->recordingfilename, conf->recordingformat);
2916 }
2917 }
2918
2919 ast_mutex_lock(&conf->recordthreadlock);
2920 if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
2921 ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
2924 dahdic.chan = 0;
2925 dahdic.confno = conf->dahdiconf;
2926 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
2927 if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
2928 ast_log(LOG_WARNING, "Error starting listen channel\n");
2929 ast_hangup(conf->lchan);
2930 conf->lchan = NULL;
2931 } else {
2933 }
2934 }
2935 ast_mutex_unlock(&conf->recordthreadlock);
2936
2937 ast_mutex_lock(&conf->announcethreadlock);
2938 if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
2940 ast_mutex_init(&conf->announcelistlock);
2941 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2943 }
2944 ast_mutex_unlock(&conf->announcethreadlock);
2945
2946 time(&user->jointime);
2947
2948 user->timelimit = timelimit;
2949 user->play_warning = play_warning;
2950 user->warning_freq = warning_freq;
2951 user->warning_sound = warning_sound;
2952 user->end_sound = end_sound;
2953
2954 if (calldurationlimit > 0) {
2955 time(&user->kicktime);
2956 user->kicktime = user->kicktime + calldurationlimit;
2957 }
2958
2959 if (ast_tvzero(user->start_time))
2960 user->start_time = ast_tvnow();
2961 time_left_ms = user->timelimit;
2962
2963 if (user->timelimit) {
2964 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
2965 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
2966 }
2967
2968 if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
2969 /* Sorry, but this conference is locked! */
2970 if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
2971 ast_waitstream(chan, "");
2972 goto outrun;
2973 }
2974
2975 ast_mutex_lock(&conf->playlock);
2976
2977 if (rt_schedule && conf->maxusers) {
2978 if (conf->users >= conf->maxusers) {
2979 /* Sorry, but this confernce has reached the participant limit! */
2980 ast_mutex_unlock(&conf->playlock);
2981 if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
2982 ast_waitstream(chan, "");
2983 goto outrun;
2984 }
2985 }
2986
2987 ao2_lock(conf->usercontainer);
2988 ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
2989 user->user_no++;
2990 ao2_link(conf->usercontainer, user);
2991 ao2_unlock(conf->usercontainer);
2992
2993 user->chan = chan;
2994 user->userflags = *confflags;
2995 user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
2996 if (!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
2997 user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
2998 }
2999 user->talking = -1;
3000
3001 ast_mutex_unlock(&conf->playlock);
3002
3004 char destdir[PATH_MAX];
3005
3006 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
3007
3008 if (ast_mkdir(destdir, 0777) != 0) {
3009 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
3010 goto outrun;
3011 }
3012
3015 mailbox = strsep(&context, "@");
3016
3017 if (ast_strlen_zero(mailbox)) {
3018 /* invalid input, clear the v flag*/
3020 ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
3021 } else {
3022 if (ast_strlen_zero(context)) {
3023 context = "default";
3024 }
3025 /* if there is no mailbox we don't need to do this logic */
3026 snprintf(user->namerecloc, sizeof(user->namerecloc),
3027 "%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
3028
3029 /* if the greeting doesn't exist then use the temp file method instead, clear flag v */
3030 if (!ast_fileexists(user->namerecloc, NULL, NULL)){
3031 snprintf(user->namerecloc, sizeof(user->namerecloc),
3032 "%s/meetme-username-%s-%d", destdir,
3033 conf->confno, user->user_no);
3035 }
3036 }
3037 } else {
3038 snprintf(user->namerecloc, sizeof(user->namerecloc),
3039 "%s/meetme-username-%s-%d", destdir,
3040 conf->confno, user->user_no);
3041 }
3042
3043 res = 0;
3044 if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) && !ast_fileexists(user->namerecloc, NULL, NULL))
3045 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
3046 else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
3047 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
3048 if (res == -1)
3049 goto outrun;
3050
3051 }
3052
3053 ast_mutex_lock(&conf->playlock);
3054
3055 if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
3056 conf->markedusers++;
3057 conf->users++;
3058 if (rt_log_members) {
3059 /* Update table */
3060 snprintf(members, sizeof(members), "%d", conf->users);
3062 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
3063 "members", RQ_UINTEGER1, strlen(members),
3064 NULL);
3065 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
3066 }
3067 setusercount = 1;
3068
3069 /* This device changed state now - if this is the first user */
3070 if (conf->users == 1)
3072
3073 ast_mutex_unlock(&conf->playlock);
3074
3075 /* return the unique ID of the conference */
3076 pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
3077
3078 if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
3079 ast_channel_lock(chan);
3080 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
3081 ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
3082 } else {
3084 }
3085 ast_channel_unlock(chan);
3086 }
3087
3088 /* Play an arbitrary intro message */
3089 if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
3090 !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
3091 if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
3092 ast_waitstream(chan, "");
3093 }
3094 }
3095
3097 if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
3098 if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
3099 ast_waitstream(chan, "");
3100 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
3101 if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
3102 ast_waitstream(chan, "");
3103 }
3104
3105 if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
3106 int keepplaying = 1;
3107
3108 if (conf->users == 2) {
3109 if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
3110 res = ast_waitstream(chan, AST_DIGIT_ANY);
3111 ast_stopstream(chan);
3112 if (res > 0)
3113 keepplaying = 0;
3114 else if (res == -1)
3115 goto outrun;
3116 }
3117 } else {
3118 if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
3119 res = ast_waitstream(chan, AST_DIGIT_ANY);
3120 ast_stopstream(chan);
3121 if (res > 0)
3122 keepplaying = 0;
3123 else if (res == -1)
3124 goto outrun;
3125 }
3126 if (keepplaying) {
3127 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3128 if (res > 0)
3129 keepplaying = 0;
3130 else if (res == -1)
3131 goto outrun;
3132 }
3133 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3134 res = ast_waitstream(chan, AST_DIGIT_ANY);
3135 ast_stopstream(chan);
3136 if (res > 0)
3137 keepplaying = 0;
3138 else if (res == -1)
3139 goto outrun;
3140 }
3141 }
3142 }
3143
3145 /* We're leaving this alone until the state gets changed to up */
3146 ast_indicate(chan, -1);
3147 }
3148
3149 if (ast_set_write_format(chan, ast_format_slin) < 0) {
3150 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
3151 goto outrun;
3152 }
3153
3154 if (ast_set_read_format(chan, ast_format_slin) < 0) {
3155 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
3156 goto outrun;
3157 }
3158
3159 /* Reduce background noise from each participant */
3160 if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE)) {
3161 ast_func_write(chan, "DENOISE(rx)", "on");
3162 }
3163
3164 retrydahdi = (strcasecmp(ast_channel_tech(chan)->type, "DAHDI") || (ast_channel_audiohooks(chan)) ? 1 : 0);
3165 user->dahdichannel = !retrydahdi;
3166
3167 dahdiretry:
3168 origfd = ast_channel_fd(chan, 0);
3169 if (retrydahdi) {
3170 /* open pseudo in non-blocking mode */
3171 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
3172 if (fd < 0) {
3173 ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
3174 goto outrun;
3175 }
3176 using_pseudo = 1;
3177 /* Setup buffering information */
3178 memset(&bi, 0, sizeof(bi));
3179 bi.bufsize = CONF_SIZE / 2;
3180 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
3181 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
3182 bi.numbufs = audio_buffers;
3183 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
3184 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
3185 close(fd);
3186 goto outrun;
3187 }
3188 x = 1;
3189 if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
3190 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
3191 close(fd);
3192 goto outrun;
3193 }
3194 nfds = 1;
3195 } else {
3196 /* XXX Make sure we're not running on a pseudo channel XXX */
3197 fd = ast_channel_fd(chan, 0);
3198 nfds = 0;
3199 }
3200 memset(&dahdic, 0, sizeof(dahdic));
3201 memset(&dahdic_empty, 0, sizeof(dahdic_empty));
3202 /* Check to see if we're in a conference... */
3203 dahdic.chan = 0;
3204 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
3205 ast_log(LOG_WARNING, "Error getting conference\n");
3206 close(fd);
3207 goto outrun;
3208 }
3209 if (dahdic.confmode) {
3210 /* Whoa, already in a conference... Retry... */
3211 if (!retrydahdi) {
3212 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
3213 retrydahdi = 1;
3214 goto dahdiretry;
3215 }
3216 }
3217 memset(&dahdic, 0, sizeof(dahdic));
3218 /* Add us to the conference */
3219 dahdic.chan = 0;
3220 dahdic.confno = conf->dahdiconf;
3221
3222 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
3224 struct announce_listitem *item;
3225 if (!(item = ao2_alloc(sizeof(*item), NULL)))
3226 goto outrun;
3227 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
3228 ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
3229 item->confchan = conf->chan;
3230 item->confusers = conf->users;
3232 item->vmrec = 1;
3233 }
3234 item->announcetype = CONF_HASJOIN;
3235 ast_mutex_lock(&conf->announcelistlock);
3236 ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
3237 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
3238 ast_cond_signal(&conf->announcelist_addition);
3239 ast_mutex_unlock(&conf->announcelistlock);
3240
3241 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
3242 ;
3243 }
3244 ao2_ref(item, -1);
3245 }
3246
3247 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
3248 dahdic.confmode = DAHDI_CONF_CONF;
3249 else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
3250 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3251 else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
3252 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3253 else
3254 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3255
3256 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3257 ast_log(LOG_WARNING, "Error setting conference\n");
3258 close(fd);
3259 goto outrun;
3260 }
3261 ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
3262
3263 if (!sent_event) {
3264 meetme_stasis_generate_msg(conf, chan, user, meetme_join_type(), NULL);
3265 sent_event = 1;
3266 }
3267
3268 if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
3269 !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3270 firstpass = 1;
3271 if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
3273 (conf->markedusers >= 1))) {
3274 conf_play(chan, conf, ENTER);
3275 }
3276 }
3277
3278 conf_flush(fd, chan);
3279
3280 if (dsp)
3281 ast_dsp_free(dsp);
3282
3283 if (!(dsp = ast_dsp_new())) {
3284 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
3285 res = -1;
3286 }
3287
3288 if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
3289 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
3290 or use default filename of conf-background.agi */
3291
3292 ast_channel_lock(chan);
3293 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
3294 agifile = ast_strdupa(tmpvar);
3295 } else {
3296 agifile = ast_strdupa(agifiledefault);
3297 }
3298 ast_channel_unlock(chan);
3299
3300 if (user->dahdichannel) {
3301 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
3302 x = 1;
3303 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3304 }
3305 /* Find a pointer to the agi app and execute the script */
3306 agi_app = pbx_findapp("agi");
3307 if (agi_app) {
3308 ret = pbx_exec(chan, agi_app, agifile);
3309 } else {
3310 ast_log(LOG_WARNING, "Could not find application (agi)\n");
3311 ret = -2;
3312 }
3313 if (user->dahdichannel) {
3314 /* Remove CONFMUTE mode on DAHDI channel */
3315 x = 0;
3316 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3317 }
3318 } else {
3319 int lastusers = conf->users;
3320 if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
3321 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
3322 x = 1;
3323 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3324 }
3325
3326 for (;;) {
3327 int menu_was_active = 0;
3328
3329 outfd = -1;
3330 ms = -1;
3331 now = ast_tvnow();
3332
3333 if (rt_schedule && conf->endtime) {
3334 char currenttime[32];
3335 long localendtime = 0;
3336 int extended = 0;
3337 struct ast_tm tm;
3338 struct ast_variable *var, *origvar;
3339 struct timeval tmp;
3340
3341 if (now.tv_sec % 60 == 0) {
3342 if (!checked) {
3343 ast_localtime(&now, &tm, NULL);
3344 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
3345 var = origvar = ast_load_realtime("meetme", "confno",
3346 conf->confno, "starttime <=", currenttime,
3347 "endtime >=", currenttime, NULL);
3348
3349 for ( ; var; var = var->next) {
3350 if (!strcasecmp(var->name, "endtime")) {
3351 struct ast_tm endtime_tm;
3352 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
3353 tmp = ast_mktime(&endtime_tm, NULL);
3354 localendtime = tmp.tv_sec;
3355 }
3356 }
3357 ast_variables_destroy(origvar);
3358
3359 /* A conference can be extended from the
3360 Admin/User menu or by an external source */
3361 if (localendtime > conf->endtime){
3362 conf->endtime = localendtime;
3363 extended = 1;
3364 }
3365
3366 if (conf->endtime && (now.tv_sec >= conf->endtime)) {
3367 ast_verbose("Quitting time...\n");
3368 goto outrun;
3369 }
3370
3371 if (!announcement_played && conf->endalert) {
3372 if (now.tv_sec + conf->endalert >= conf->endtime) {
3373 if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
3374 ast_waitstream(chan, "");
3375 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
3376 if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
3377 ast_waitstream(chan, "");
3378 if (musiconhold) {
3379 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3380 }
3381 announcement_played = 1;
3382 }
3383 }
3384
3385 if (extended) {
3386 announcement_played = 0;
3387 }
3388
3389 checked = 1;
3390 }
3391 } else {
3392 checked = 0;
3393 }
3394 }
3395
3396 if (user->kicktime && (user->kicktime <= now.tv_sec)) {
3397 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3398 ret = 0;
3399 } else {
3400 ret = -1;
3401 }
3402 break;
3403 }
3404
3405 to = -1;
3406 if (user->timelimit) {
3407 int minutes = 0, seconds = 0, remain = 0;
3408
3409 to = ast_tvdiff_ms(nexteventts, now);
3410 if (to < 0) {
3411 to = 0;
3412 }
3413 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
3414 if (time_left_ms < to) {
3415 to = time_left_ms;
3416 }
3417
3418 if (time_left_ms <= 0) {
3419 if (user->end_sound) {
3420 res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
3421 res = ast_waitstream(chan, "");
3422 }
3423 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3424 ret = 0;
3425 } else {
3426 ret = -1;
3427 }
3428 break;
3429 }
3430
3431 if (!to) {
3432 if (time_left_ms >= 5000) {
3433
3434 remain = (time_left_ms + 500) / 1000;
3435 if (remain / 60 >= 1) {
3436 minutes = remain / 60;
3437 seconds = remain % 60;
3438 } else {
3439 seconds = remain;
3440 }
3441
3442 /* force the time left to round up if appropriate */
3443 if (user->warning_sound && user->play_warning) {
3444 if (!strcmp(user->warning_sound, "timeleft")) {
3445
3446 res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
3447 res = ast_waitstream(chan, "");
3448 if (minutes) {
3449 res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3450 res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
3451 res = ast_waitstream(chan, "");
3452 }
3453 if (seconds) {
3454 res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3455 res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
3456 res = ast_waitstream(chan, "");
3457 }
3458 } else {
3459 res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
3460 res = ast_waitstream(chan, "");
3461 }
3462 if (musiconhold) {
3463 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3464 }
3465 }
3466 }
3467 if (user->warning_freq) {
3468 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
3469 } else {
3470 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3471 }
3472 }
3473 }
3474
3475 now = ast_tvnow();
3476 if (timeout && now.tv_sec >= timeout) {
3477 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3478 ret = 0;
3479 } else {
3480 ret = -1;
3481 }
3482 break;
3483 }
3484
3485 /* if we have just exited from the menu, and the user had a channel-driver
3486 volume adjustment, restore it
3487 */
3488 if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
3489 set_talk_volume(user, user->listen.desired);
3490 }
3491
3492 menu_was_active = menu_mode;
3493
3494 currentmarked = conf->markedusers;
3495 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3498 lastmarked == 0) {
3499 if (currentmarked == 1 && conf->users > 1) {
3500 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3501 if (conf->users - 1 == 1) {
3502 if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
3503 ast_waitstream(chan, "");
3504 }
3505 } else {
3506 if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
3507 ast_waitstream(chan, "");
3508 }
3509 }
3510 }
3511 if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
3512 if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
3513 ast_waitstream(chan, "");
3514 }
3515 }
3516 }
3517
3518 /* Update the struct with the actual confflags */
3519 user->userflags = *confflags;
3520
3521 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
3522 if (currentmarked == 0) {
3523 if (lastmarked != 0) {
3524 if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
3525 if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
3526 ast_waitstream(chan, "");
3527 }
3528 }
3529 if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
3530 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3531 ret = 0;
3532 }
3533 break;
3534 } else {
3535 dahdic.confmode = DAHDI_CONF_CONF;
3536 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3537 ast_log(LOG_WARNING, "Error setting conference\n");
3538 close(fd);
3539 goto outrun;
3540 }
3541 }
3542 }
3543 if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
3544 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3545 musiconhold = 1;
3546 }
3547 } else if (currentmarked >= 1 && lastmarked == 0) {
3548 /* Marked user entered, so cancel timeout */
3549 timeout = 0;
3550 if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
3551 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3552 } else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
3553 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3554 } else {
3555 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3556 }
3557 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3558 ast_log(LOG_WARNING, "Error setting conference\n");
3559 close(fd);
3560 goto outrun;
3561 }
3562 if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
3563 ast_moh_stop(chan);
3564 musiconhold = 0;
3565 }
3566 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3567 !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
3568 if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
3569 ast_waitstream(chan, "");
3570 }
3571 conf_play(chan, conf, ENTER);
3572 }
3573 }
3574 }
3575
3576 /* trying to add moh for single person conf */
3577 if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
3578 if (conf->users == 1) {
3579 if (!musiconhold) {
3580 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3581 musiconhold = 1;
3582 }
3583 } else {
3584 if (musiconhold) {
3585 ast_moh_stop(chan);
3586 musiconhold = 0;
3587 }
3588 }
3589 }
3590
3591 /* Leave if the last marked user left */
3592 if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
3593 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3594 ret = 0;
3595 } else {
3596 ret = -1;
3597 }
3598 break;
3599 }
3600
3601 /* Throw a TestEvent if a user exit did not cause this user to leave the conference */
3602 if (conf->users != lastusers) {
3603 if (conf->users < lastusers) {
3604 ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
3605 }
3606 lastusers = conf->users;
3607 }
3608
3609 /* Check if my modes have changed */
3610
3611 /* If I should be muted but am still talker, mute me */
3612 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
3613 RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
3614 dahdic.confmode ^= DAHDI_CONF_TALKER;
3615 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3616 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
3617 ret = -1;
3618 break;
3619 }
3620
3621 /* Indicate user is not talking anymore - change him to unmonitored state */
3624 }
3625 meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
3626 }
3627
3628 /* If I should be un-muted but am not talker, un-mute me */
3629 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
3630 RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
3631 dahdic.confmode |= DAHDI_CONF_TALKER;
3632 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3633 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
3634 ret = -1;
3635 break;
3636 }
3637 meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
3638 }
3639
3640 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
3641 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
3642
3643 RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
3644 talkreq_manager = 1;
3645 meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
3646 }
3647
3648 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
3649 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
3650 RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
3651 talkreq_manager = 0;
3652 meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
3653 }
3654
3655 /* If user have been hung up, exit the conference */
3656 if (user->adminflags & ADMINFLAG_HANGUP) {
3657 ret = 0;
3658 break;
3659 }
3660
3661 /* If I have been kicked, exit the conference */
3662 if (user->adminflags & ADMINFLAG_KICKME) {
3663 /* You have been kicked. */
3664 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3665 !ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
3666 ast_waitstream(chan, "");
3667 }
3668 ret = 0;
3669 break;
3670 }
3671
3672 /* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
3673 if (ast_check_hangup(chan)) {
3674 break;
3675 }
3676
3677 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
3678
3679 if (c) {
3680 char dtmfstr[2] = "";
3681
3682 if (ast_channel_fd(c, 0) != origfd || (user->dahdichannel && ast_channel_audiohooks(c))) {
3683 if (using_pseudo) {
3684 /* Kill old pseudo */
3685 close(fd);
3686 using_pseudo = 0;
3687 }
3688 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
3689 retrydahdi = (strcasecmp(ast_channel_tech(c)->type, "DAHDI") || ast_channel_audiohooks(c) ? 1 : 0);
3690 user->dahdichannel = !retrydahdi;
3691 goto dahdiretry;
3692 }
3693 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
3694 f = ast_read_noaudio(c);
3695 } else {
3696 f = ast_read(c);
3697 }
3698 if (!f) {
3699 break;
3700 }
3701 if (f->frametype == AST_FRAME_DTMF) {
3702 dtmfstr[0] = f->subclass.integer;
3703 dtmfstr[1] = '\0';
3704 }
3705
3707 if (user->talk.actual) {
3708 ast_frame_adjust_volume(f, user->talk.actual);
3709 }
3710
3712 if (user->talking == -1) {
3713 user->talking = 0;
3714 }
3715
3716 res = ast_dsp_silence(dsp, f, &totalsilence);
3717 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
3719 }
3720
3721 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
3723 }
3724 }
3725 if (using_pseudo) {
3726 /* Absolutely do _not_ use careful_write here...
3727 it is important that we read data from the channel
3728 as fast as it arrives, and feed it into the conference.
3729 The buffering in the pseudo channel will take care of any
3730 timing differences, unless they are so drastic as to lose
3731 audio frames (in which case carefully writing would only
3732 have delayed the audio even further).
3733 */
3734 /* As it turns out, we do want to use careful write. We just
3735 don't want to block, but we do want to at least *try*
3736 to write out all the samples.
3737 */
3738 if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
3739 careful_write(fd, f->data.ptr, f->datalen, 0);
3740 }
3741 }
3742 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
3743 if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3745 }
3746 /* Take out of conference */
3747 if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
3748 ast_log(LOG_WARNING, "Error setting conference\n");
3749 close(fd);
3750 ast_frfree(f);
3751 goto outrun;
3752 }
3753
3754 /* if we are entering the menu, and the user has a channel-driver
3755 volume adjustment, clear it
3756 */
3757 if (!menu_mode && user->talk.desired && !user->talk.actual) {
3759 }
3760
3761 if (musiconhold) {
3762 ast_moh_stop(chan);
3763 } else if (!menu_mode) {
3764 char *menu_to_play;
3765 if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3766 menu_mode = MENU_ADMIN;
3767 menu_to_play = "conf-adminmenu-18";
3768 } else {
3769 menu_mode = MENU_NORMAL;
3770 menu_to_play = "conf-usermenu-162";
3771 }
3772
3773 if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
3774 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
3775 ast_stopstream(chan);
3776 } else {
3777 dtmf = 0;
3778 }
3779 } else {
3780 dtmf = f->subclass.integer;
3781 }
3782
3783 if (dtmf > 0) {
3784 meetme_menu(&menu_mode, &dtmf, conf, confflags,
3785 chan, user, recordingtmp, sizeof(recordingtmp), cap_slin);
3786 }
3787
3788 if (musiconhold && !menu_mode) {
3789 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3790 }
3791
3792 /* Put back into conference */
3793 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3794 ast_log(LOG_WARNING, "Error setting conference\n");
3795 close(fd);
3796 ast_frfree(f);
3797 goto outrun;
3798 }
3799
3800 conf_flush(fd, chan);
3801 /*
3802 * Since options using DTMF could absorb DTMF meant for the
3803 * conference menu, we have to check them after the menu.
3804 */
3805 } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
3806 if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3808 }
3809
3810 if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
3811 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
3812 ret = 0;
3813 ast_frfree(f);
3814 break;
3815 } else {
3816 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
3817 }
3818 } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
3819 (strchr(exitkeys, f->subclass.integer))) {
3820 pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
3821
3822 if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3824 }
3825 ret = 0;
3826 ast_frfree(f);
3827 break;
3829 && ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3831 } else if (f->frametype == AST_FRAME_NULL) {
3832 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
3833 } else if (f->frametype == AST_FRAME_CONTROL) {
3834 switch (f->subclass.integer) {
3835 case AST_CONTROL_BUSY:
3837 ast_frfree(f);
3838 goto outrun;
3839 break;
3840 default:
3841 ast_debug(1,
3842 "Got ignored control frame on channel %s, f->frametype=%u,f->subclass=%d\n",
3844 }
3845 } else {
3846 ast_debug(1,
3847 "Got unrecognized frame on channel %s, f->frametype=%u,f->subclass=%d\n",
3849 }
3850 ast_frfree(f);
3851 } else if (outfd > -1) {
3852 res = read(outfd, buf, CONF_SIZE);
3853 if (res > 0) {
3854 memset(&fr, 0, sizeof(fr));
3855 fr.frametype = AST_FRAME_VOICE;
3856 fr.subclass.format = ast_format_slin;
3857 fr.datalen = res;
3858 fr.samples = res / 2;
3859 fr.data.ptr = buf;
3860 fr.offset = AST_FRIENDLY_OFFSET;
3861 if (!user->listen.actual &&
3862 (ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
3863 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
3864 (!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
3865 )) {
3866 int idx;
3867 for (idx = 0; idx < AST_FRAME_BITS; idx++) {
3869 break;
3870 }
3871 }
3872 if (idx >= AST_FRAME_BITS) {
3873 goto bailoutandtrynormal;
3874 }
3875 ast_mutex_lock(&conf->listenlock);
3876 if (!conf->transframe[idx]) {
3877 if (conf->origframe) {
3878 if (musiconhold
3879 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
3880 && !ast_dsp_silence(dsp, conf->origframe, &confsilence)
3881 && confsilence < MEETME_DELAYDETECTTALK) {
3882 ast_moh_stop(chan);
3883 mohtempstopped = 1;
3884 }
3885 if (!conf->transpath[idx]) {
3887 }
3888 if (conf->transpath[idx]) {
3889 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
3890 if (!conf->transframe[idx]) {
3891 conf->transframe[idx] = &ast_null_frame;
3892 }
3893 }
3894 }
3895 }
3896 if (conf->transframe[idx]) {
3897 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
3898 can_write(chan, confflags)) {
3899 struct ast_frame *cur;
3900 /* the translator may have returned a list of frames, so
3901 write each one onto the channel
3902 */
3903 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
3904 if (ast_write(chan, cur)) {
3905 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
3906 break;
3907 }
3908 }
3909 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
3910 mohtempstopped = 0;
3911 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3912 }
3913 }
3914 } else {
3915 ast_mutex_unlock(&conf->listenlock);
3916 goto bailoutandtrynormal;
3917 }
3918 ast_mutex_unlock(&conf->listenlock);
3919 } else {
3920bailoutandtrynormal:
3921 if (musiconhold
3922 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
3923 && !ast_dsp_silence(dsp, &fr, &confsilence)
3924 && confsilence < MEETME_DELAYDETECTTALK) {
3925 ast_moh_stop(chan);
3926 mohtempstopped = 1;
3927 }
3928 if (user->listen.actual) {
3929 ast_frame_adjust_volume(&fr, user->listen.actual);
3930 }
3931 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
3932 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
3933 }
3934 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
3935 mohtempstopped = 0;
3936 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3937 }
3938 }
3939 } else {
3940 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
3941 }
3942 }
3943 lastmarked = currentmarked;
3944 }
3945 }
3946
3947 if (musiconhold) {
3948 ast_moh_stop(chan);
3949 }
3950
3951 if (using_pseudo) {
3952 close(fd);
3953 } else {
3954 /* Take out of conference */
3955 dahdic.chan = 0;
3956 dahdic.confno = 0;
3957 dahdic.confmode = 0;
3958 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3959 ast_log(LOG_WARNING, "Error setting conference\n");
3960 }
3961 }
3962
3964
3965 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
3966 !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3967 conf_play(chan, conf, LEAVE);
3968 }
3969
3971 struct announce_listitem *item;
3972 if (!(item = ao2_alloc(sizeof(*item), NULL)))
3973 goto outrun;
3974 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
3975 ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
3976 item->confchan = conf->chan;
3977 item->confusers = conf->users;
3978 item->announcetype = CONF_HASLEFT;
3980 item->vmrec = 1;
3981 }
3982 ast_mutex_lock(&conf->announcelistlock);
3983 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
3984 ast_cond_signal(&conf->announcelist_addition);
3985 ast_mutex_unlock(&conf->announcelistlock);
3986 } else if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) && !ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC) && conf->users == 1) {
3987 /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
3988 ast_filedelete(user->namerecloc, NULL);
3989 }
3990
3991 outrun:
3993
3994 if (dsp) {
3995 ast_dsp_free(dsp);
3996 }
3997
3998 if (user->user_no) {
3999 /* Only cleanup users who really joined! */
4000 now = ast_tvnow();
4001
4002 if (sent_event) {
4003 meetme_stasis_generate_msg(conf, chan, user, meetme_leave_type(), NULL);
4004 }
4005
4006 if (setusercount) {
4007 conf->users--;
4008 if (rt_log_members) {
4009 /* Update table */
4010 snprintf(members, sizeof(members), "%d", conf->users);
4012 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
4013 "members", RQ_UINTEGER1, strlen(members),
4014 NULL);
4015 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
4016 }
4017 if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
4018 conf->markedusers--;
4019 }
4020 }
4021 /* Remove ourselves from the container */
4022 ao2_unlink(conf->usercontainer, user);
4023
4024 /* Change any states */
4025 if (!conf->users) {
4027 }
4028
4029 /* This flag is meant to kill a conference with only one participant remaining. */
4030 if (conf->users == 1 && ast_test_flag64(confflags, CONFFLAG_KILL_LAST_MAN_STANDING)) {
4031 ao2_callback(conf->usercontainer, 0, user_set_hangup_cb, NULL);
4032 }
4033
4034 /* Return the number of seconds the user was in the conf */
4035 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
4036 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
4037
4038 /* Return the RealTime bookid for CDR linking */
4039 if (rt_schedule) {
4040 pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
4041 }
4042 }
4043 ao2_ref(user, -1);
4045
4046
4047conf_run_cleanup:
4048 ao2_cleanup(cap_slin);
4049
4050 return ret;
4051}
static int rt_log_members
Definition: app_meetme.c:825
menu_modes
Definition: app_meetme.c:2310
#define CONFFLAG_DONT_DENOISE
Definition: app_meetme.c:763
#define CONF_SIZE
Definition: app_meetme.c:695
static void * recordthread(void *args)
Definition: app_meetme.c:5241
#define MEETME_DELAYDETECTENDTALK
Definition: app_meetme.c:674
static void conf_flush(int fd, struct ast_channel *chan)
Definition: app_meetme.c:1944
static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
Definition: app_meetme.c:2233
static int set_talk_volume(struct ast_conf_user *user, int volume)
Definition: app_meetme.c:1257
static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
Definition: app_meetme.c:2146
static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
Definition: app_meetme.c:1348
static void meetme_menu(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
Definition: app_meetme.c:2716
static void * announce_thread(void *data)
Definition: app_meetme.c:2176
#define CONFFLAG_KILL_LAST_MAN_STANDING
Definition: app_meetme.c:761
static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2266
#define CONFFLAG_INTROUSER_VMREC
Definition: app_meetme.c:759
#define CONFFLAG_INTROMSG
Definition: app_meetme.c:758
#define MEETME_DELAYDETECTTALK
Definition: app_meetme.c:673
static int audio_buffers
The number of audio buffers to be allocated on pseudo channels when in a conference.
Definition: app_meetme.c:928
static void conf_queue_dtmf(const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
Definition: app_meetme.c:2045
static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
Definition: app_meetme.c:2248
#define DATE_FORMAT
Definition: app_meetme.c:662
static struct ast_json * status_to_json(int on)
Definition: app_meetme.c:1146
static char exitcontext[AST_MAX_CONTEXT]
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static int tmp()
Definition: bt_open.c:389
static const char type[]
Definition: chan_ooh323.c:109
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:3007
#define ast_channel_lock(chan)
Definition: channel.h:2968
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_audiohook_list * ast_channel_audiohooks(const struct ast_channel *chan)
struct ast_format * ast_channel_rawwriteformat(struct ast_channel *chan)
struct ast_frame * ast_read_noaudio(struct ast_channel *chan)
Reads a frame, returning AST_FRAME_NULL frame if audio.
Definition: channel.c:4286
#define AST_MAX_CONTEXT
Definition: channel.h:135
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7444
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4296
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1593
#define ast_channel_unlock(chan)
Definition: channel.h:2969
#define AST_MAX_EXTENSION
Definition: channel.h:134
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
@ AST_DEVSTATE_NOT_CACHABLE
Definition: devicestate.h:69
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1488
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition: format.h:36
int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path)
Record a file based on input from a channel. Use default accept and cancel DTMF. This function will p...
Definition: main/app.c:2154
int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
Allow to record message and have a review option.
Definition: main/app.c:2646
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3564
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3674
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3521
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format)
Convert a format structure to its respective bitfield.
#define AST_FRAME_DTMF
#define AST_OPTION_TONE_VERIFY
int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
Adjusts the volume of the audio samples contained in a frame.
Definition: main/frame.c:787
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_NULL
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_VOICE
@ AST_FRAME_CONTROL
@ AST_CONTROL_BUSY
@ AST_CONTROL_CONGESTION
struct ast_frame ast_null_frame
Definition: main/frame.c:79
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2357
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm....
Definition: localtime.c:2550
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7798
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8781
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8257
ast_app: A registered application
Definition: pbx_app.c:45
Main Channel structure associated with a channel.
Definition: dsp.c:407
struct ast_format * format
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Abstract JSON element (object, array, string, int, ...).
static struct test_val c
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2297
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition: translate.c:566
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition: translate.c:486
#define ast_clear_flag64(p, flag)
Definition: utils.h:134
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597

References ADMINFLAG_HANGUP, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, announce_thread(), ao2_alloc, ao2_callback, ao2_cleanup, ao2_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_audiohooks(), ast_channel_context(), ast_channel_fd(), ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_rawwriteformat(), ast_channel_setoption(), ast_channel_tech(), ast_channel_uniqueid(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag64, ast_cond_signal, ast_config_AST_SPOOL_DIR, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_DEVSTATE_NOT_CACHABLE, AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), ast_fileexists(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_compatibility_format2bitfield(), ast_format_slin, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_json_unref(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_moh_stop(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_test_suite_event_notify, ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_variables_destroy(), ast_verb, ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), audio_buffers, buf, c, can_write(), careful_write(), conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DONT_DENOISE, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROMSG, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_KILL_LAST_MAN_STANDING, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, voicemailpwcheck::context, ast_frame::data, ast_frame::datalen, DATE_FORMAT, ENTER, errno, exitcontext, ast_frame_subclass::format, ast_frame::frametype, ast_frame_subclass::integer, item, LEAVE, LOG_WARNING, voicemailpwcheck::mailbox, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, meetme_menu(), meetme_stasis_generate_msg(), MENU_ADMIN, MENU_DISABLED, MENU_NORMAL, NULL, OBJ_NODATA, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_INTROMSG, OPT_ARG_INTROUSER_VMREC, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, PATH_MAX, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_frame::ptr, RAII_VAR, recordthread(), reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, rt_log_members, rt_schedule, ast_frame::samples, set_talk_volume(), set_user_talking(), status_to_json(), strsep(), ast_frame::subclass, THRESHOLD_SILENCE, tmp(), type, user_max_cmp(), user_set_hangup_cb(), and var.

Referenced by conf_exec().

◆ conf_start_moh()

static void conf_start_moh ( struct ast_channel chan,
const char *  musicclass 
)
static

Definition at line 2146 of file app_meetme.c.

2147{
2148 char *original_moh;
2149
2150 ast_channel_lock(chan);
2151 original_moh = ast_strdupa(ast_channel_musicclass(chan));
2152 ast_channel_musicclass_set(chan, musicclass);
2153 ast_channel_unlock(chan);
2154
2155 ast_moh_start(chan, original_moh, NULL);
2156
2157 ast_channel_lock(chan);
2158 ast_channel_musicclass_set(chan, original_moh);
2159 ast_channel_unlock(chan);
2160}
const char * ast_channel_musicclass(const struct ast_channel *chan)
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7788

References ast_channel_lock, ast_channel_musicclass(), ast_channel_unlock, ast_moh_start(), ast_strdupa, and NULL.

Referenced by conf_run().

◆ count_exec()

static int count_exec ( struct ast_channel chan,
const char *  data 
)
static

The MeetmeCount application.

Definition at line 4344 of file app_meetme.c.

4345{
4346 int res = 0;
4347 struct ast_conference *conf;
4348 int count;
4349 char *localdata;
4350 char val[80] = "0";
4353 AST_APP_ARG(varname);
4354 );
4355
4356 if (ast_strlen_zero(data)) {
4357 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
4358 return -1;
4359 }
4360
4361 localdata = ast_strdupa(data);
4362
4363 AST_STANDARD_APP_ARGS(args, localdata);
4364
4365 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
4366
4367 if (conf) {
4368 count = conf->users;
4370 conf = NULL;
4371 } else
4372 count = 0;
4373
4374 if (!ast_strlen_zero(args.varname)) {
4375 /* have var so load it and exit */
4376 snprintf(val, sizeof(val), "%d", count);
4378 } else {
4381 }
4382 res = ast_say_number(chan, count, "", ast_channel_language(chan), (char *) NULL); /* Needs gender */
4383 }
4384
4385 return res;
4386}
Definition: ast_expr2.c:325

References args, ast_answer(), AST_APP_ARG, ast_channel_language(), AST_DECLARE_APP_ARGS, ast_log, ast_say_number(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_conference::chan, ast_conference::confno, dispose_conf(), find_conf(), LOG_WARNING, NULL, and pbx_builtin_setvar_helper().

Referenced by load_module().

◆ dispose_conf()

static int dispose_conf ( struct ast_conference conf)
static

Decrement reference counts, as incremented by find_conf()

Definition at line 2065 of file app_meetme.c.

2066{
2067 int res = 0;
2068 int confno_int = 0;
2069
2071 if (ast_atomic_dec_and_test(&conf->refcount)) {
2072 /* Take the conference room number out of an inuse state */
2073 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
2074 conf_map[confno_int] = 0;
2075 }
2076 conf_free(conf);
2077 res = 1;
2078 }
2080
2081 return res;
2082}
static int conf_free(struct ast_conference *conf)
Remove the conference from the list and free it.
Definition: app_meetme.c:1976
int ast_atomic_dec_and_test(volatile int *p)
decrement *p by 1 and return true if the variable has reached 0.
Definition: lock.h:767

References ast_atomic_dec_and_test(), AST_LIST_LOCK, AST_LIST_UNLOCK, conf_free(), and conf_map.

Referenced by admin_exec(), conf_exec(), and count_exec().

◆ filename_parse()

static void filename_parse ( char *  filename,
char *  buffer 
)
static

Definition at line 5222 of file app_meetme.c.

5223{
5224 char *slash;
5225 if (ast_strlen_zero(filename)) {
5226 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
5227 } else if (filename[0] != '/') {
5228 snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
5229 } else {
5230 ast_copy_string(buffer, filename, PATH_MAX);
5231 }
5232
5233 slash = buffer;
5234 if ((slash = strrchr(slash, '/'))) {
5235 *slash = '\0';
5236 ast_mkdir(buffer, 0777);
5237 *slash = '/';
5238 }
5239}

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log, ast_mkdir(), ast_strlen_zero(), LOG_WARNING, and PATH_MAX.

Referenced by recordthread().

◆ find_conf()

static struct ast_conference * find_conf ( struct ast_channel chan,
char *  confno,
int  make,
int  dynamic,
char *  dynamic_pin,
size_t  pin_buf_len,
int  refcount,
struct ast_flags64 confflags 
)
static

Definition at line 4240 of file app_meetme.c.

4242{
4243 struct ast_config *cfg;
4244 struct ast_variable *var;
4245 struct ast_flags config_flags = { 0 };
4246 struct ast_conference *cnf;
4247
4252 );
4253
4254 /* Check first in the conference list */
4255 ast_debug(1, "The requested confno is '%s'?\n", confno);
4257 AST_LIST_TRAVERSE(&confs, cnf, list) {
4258 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
4259 if (!strcmp(confno, cnf->confno))
4260 break;
4261 }
4262 if (cnf) {
4263 cnf->refcount += refcount;
4264 }
4266
4267 if (!cnf) {
4268 if (dynamic) {
4269 /* No need to parse meetme.conf */
4270 ast_debug(1, "Building dynamic conference '%s'\n", confno);
4271 if (dynamic_pin) {
4272 if (dynamic_pin[0] == 'q') {
4273 /* Query the user to enter a PIN */
4274 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
4275 return NULL;
4276 }
4277 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
4278 } else {
4279 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
4280 }
4281 } else {
4282 /* Check the config */
4283 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4284 if (!cfg) {
4285 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
4286 return NULL;
4287 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
4288 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
4289 return NULL;
4290 }
4291
4292 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
4293 char parse[MAX_SETTINGS];
4294
4295 if (strcasecmp(var->name, "conf"))
4296 continue;
4297
4298 ast_copy_string(parse, var->value, sizeof(parse));
4299
4301 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
4302 if (!strcasecmp(args.confno, confno)) {
4303 /* Bingo it's a valid conference */
4304 cnf = build_conf(args.confno,
4305 S_OR(args.pin, ""),
4306 S_OR(args.pinadmin, ""),
4307 make, dynamic, refcount, chan, NULL);
4308 break;
4309 }
4310 }
4311 if (!var) {
4312 ast_log(LOG_WARNING, "%s isn't a valid conference\n", confno);
4313 }
4314 ast_config_destroy(cfg);
4315 }
4316 } else if (dynamic_pin) {
4317 /* Correct for the user selecting 'D' instead of 'd' to have
4318 someone join into a conference that has already been created
4319 with a pin. */
4320 if (dynamic_pin[0] == 'q') {
4321 dynamic_pin[0] = '\0';
4322 }
4323 }
4324
4325 if (cnf) {
4326 if (confflags && !cnf->chan &&
4327 !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4329 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
4331 }
4332
4333 if (confflags && !cnf->chan &&
4335 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
4337 }
4338 }
4339
4340 return cnf;
4341}
static struct ast_conference * build_conf(const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test)
Find or create a conference.
Definition: app_meetme.c:1428
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80

References args, AST_APP_ARG, ast_app_getdata(), ast_clear_flag64, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_test_flag64, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, ast_conference::list, LOG_ERROR, LOG_WARNING, MAX_SETTINGS, NULL, ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, S_OR, and var.

Referenced by conf_exec(), and count_exec().

◆ find_conf_realtime()

static struct ast_conference * find_conf_realtime ( struct ast_channel chan,
char *  confno,
int  make,
int  dynamic,
char *  dynamic_pin,
size_t  pin_buf_len,
int  refcount,
struct ast_flags64 confflags,
int *  too_early,
char **  optargs 
)
static

Definition at line 4053 of file app_meetme.c.

4055{
4056 struct ast_variable *var, *origvar;
4057 struct ast_conference *cnf;
4058
4059 *too_early = 0;
4060
4061 /* Check first in the conference list */
4063 AST_LIST_TRAVERSE(&confs, cnf, list) {
4064 if (!strcmp(confno, cnf->confno)) {
4065 break;
4066 }
4067 }
4068 if (cnf) {
4069 cnf->refcount += refcount;
4070 }
4072
4073 if (!cnf) {
4074 char *pin = NULL, *pinadmin = NULL; /* For temp use */
4075 int maxusers = 0;
4076 struct timeval now;
4077 char recordingfilename[256] = "";
4078 char recordingformat[11] = "";
4079 char currenttime[32] = "";
4080 char eatime[32] = "";
4081 char bookid[51] = "";
4082 char recordingtmp[AST_MAX_EXTENSION * 2] = "";
4083 char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
4084 char adminopts[OPTIONS_LEN + 1] = "";
4085 struct ast_tm tm, etm;
4086 struct timeval endtime = { .tv_sec = 0 };
4087 const char *var2;
4088
4089 if (rt_schedule) {
4090 now = ast_tvnow();
4091
4092 ast_localtime(&now, &tm, NULL);
4093 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
4094
4095 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
4096
4097 var = ast_load_realtime("meetme", "confno",
4098 confno, "starttime <= ", currenttime, "endtime >= ",
4099 currenttime, NULL);
4100
4101 if (!var && fuzzystart) {
4102 now = ast_tvnow();
4103 now.tv_sec += fuzzystart;
4104
4105 ast_localtime(&now, &tm, NULL);
4106 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
4107 var = ast_load_realtime("meetme", "confno",
4108 confno, "starttime <= ", currenttime, "endtime >= ",
4109 currenttime, NULL);
4110 }
4111
4112 if (!var && earlyalert) {
4113 now = ast_tvnow();
4114 now.tv_sec += earlyalert;
4115 ast_localtime(&now, &etm, NULL);
4116 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
4117 var = ast_load_realtime("meetme", "confno",
4118 confno, "starttime <= ", eatime, "endtime >= ",
4119 currenttime, NULL);
4120 if (var) {
4121 *too_early = 1;
4122 }
4123 }
4124
4125 } else {
4126 var = ast_load_realtime("meetme", "confno", confno, NULL);
4127 }
4128
4129 if (!var) {
4130 return NULL;
4131 }
4132
4133 if (rt_schedule && *too_early) {
4134 /* Announce that the caller is early and exit */
4135 if (!ast_streamfile(chan, "conf-has-not-started", ast_channel_language(chan))) {
4136 ast_waitstream(chan, "");
4137 }
4139 return NULL;
4140 }
4141
4142 for (origvar = var; var; var = var->next) {
4143 if (!strcasecmp(var->name, "pin")) {
4144 pin = ast_strdupa(var->value);
4145 } else if (!strcasecmp(var->name, "adminpin")) {
4146 pinadmin = ast_strdupa(var->value);
4147 } else if (!strcasecmp(var->name, "bookId")) {
4148 ast_copy_string(bookid, var->value, sizeof(bookid));
4149 } else if (!strcasecmp(var->name, "opts")) {
4150 ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
4151 } else if (!strcasecmp(var->name, "maxusers")) {
4152 maxusers = atoi(var->value);
4153 } else if (!strcasecmp(var->name, "adminopts")) {
4154 ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
4155 } else if (!strcasecmp(var->name, "recordingfilename")) {
4156 ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
4157 } else if (!strcasecmp(var->name, "recordingformat")) {
4158 ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
4159 } else if (!strcasecmp(var->name, "endtime")) {
4160 struct ast_tm endtime_tm;
4161 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
4162 endtime = ast_mktime(&endtime_tm, NULL);
4163 }
4164 }
4165
4166 ast_variables_destroy(origvar);
4167
4168 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
4169
4170 if (cnf) {
4171 struct ast_flags64 tmp_flags;
4172
4173 cnf->maxusers = maxusers;
4174 cnf->endalert = endalert;
4175 cnf->endtime = endtime.tv_sec;
4176 cnf->useropts = ast_strdup(useropts);
4177 cnf->adminopts = ast_strdup(adminopts);
4178 cnf->bookid = ast_strdup(bookid);
4179 if (!ast_strlen_zero(recordingfilename)) {
4180 cnf->recordingfilename = ast_strdup(recordingfilename);
4181 }
4182 if (!ast_strlen_zero(recordingformat)) {
4183 cnf->recordingformat = ast_strdup(recordingformat);
4184 }
4185
4186 /* Parse the other options into confflags -- need to do this in two
4187 * steps, because the parse_options routine zeroes the buffer. */
4188 ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
4189 ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
4190
4191 if (strchr(cnf->useropts, 'r')) {
4192 if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
4193 ast_channel_lock(chan);
4194 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
4196 cnf->recordingfilename = ast_strdup(var2);
4197 }
4198 ast_channel_unlock(chan);
4200 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, ast_channel_uniqueid(chan));
4202 cnf->recordingfilename = ast_strdup(recordingtmp);
4203 }
4204 }
4205 if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
4206 ast_channel_lock(chan);
4207 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
4209 cnf->recordingformat = ast_strdup(var2);
4210 }
4211 ast_channel_unlock(chan);
4212 if (ast_strlen_zero(cnf->recordingformat)) {
4214 cnf->recordingformat = ast_strdup("wav");
4215 }
4216 }
4217 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
4218 }
4219 }
4220 }
4221
4222 if (cnf) {
4223 if (confflags->flags && !cnf->chan &&
4224 !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4226 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");