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

Meet me conference bridge and Shared Line Appearances. 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  dial_trunk_args
 
struct  run_station_args
 
struct  sla_event
 
struct  sla_failed_station
 A station that failed to be dialed. More...
 
struct  sla_ringing_station
 A station that is ringing. More...
 
struct  sla_ringing_trunk
 A trunk that is ringing. More...
 
struct  sla_station
 
struct  sla_station_ref
 A reference to a station. More...
 
struct  sla_trunk
 
struct  sla_trunk_ref
 A station's reference to a trunk. More...
 
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 S(e)   case e: return # e;
 
#define SLA_CONFIG_FILE   "sla.conf"
 
#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_SLA_STATION = (1 << 26) , CONFFLAG_SLA_TRUNK = (1 << 27) ,
  CONFFLAG_KICK_CONTINUE = (1 << 28) , CONFFLAG_DURATION_STOP = (1 << 29) , CONFFLAG_DURATION_LIMIT = (1 << 30)
}
 
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  { SLA_TRUNK_OPT_MOH = (1 << 0) }
 
enum  { SLA_TRUNK_OPT_ARG_MOH_CLASS = 0 , SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1 }
 
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  sla_event_type { SLA_EVENT_HOLD , SLA_EVENT_DIAL_STATE , SLA_EVENT_RINGING_TRUNK }
 Event types that can be queued up for the SLA thread. More...
 
enum  sla_hold_access { SLA_HOLD_OPEN , SLA_HOLD_PRIVATE }
 
enum  sla_station_hangup { SLA_STATION_HANGUP_NORMAL , SLA_STATION_HANGUP_TIMEOUT }
 
enum  sla_trunk_state {
  SLA_TRUNK_STATE_IDLE , SLA_TRUNK_STATE_RINGING , SLA_TRUNK_STATE_UP , SLA_TRUNK_STATE_ONHOLD ,
  SLA_TRUNK_STATE_ONHOLD_BYME
}
 
enum  sla_which_trunk_refs { ALL_TRUNK_REFS , INACTIVE_TRUNK_REFS }
 
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)
 
static void answer_trunk_chan (struct ast_channel *chan)
 
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 struct sla_trunk_refcreate_trunk_ref (struct sla_trunk *trunk)
 
static void * dial_trunk (void *data)
 
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 struct sla_ringing_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
 
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 * run_station (void *data)
 
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)
 
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
 
static int sla_build_station (struct ast_config *cfg, const char *cat)
 
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
 
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station. More...
 
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts. More...
 
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts. More...
 
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
 
static int sla_check_device (const char *device)
 
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute. More...
 
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use. More...
 
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing. More...
 
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station. More...
 
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
 
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk. More...
 
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk. More...
 
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
 Choose the highest priority ringing trunk for a station. More...
 
static struct sla_failed_stationsla_create_failed_station (struct sla_station *station)
 
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
 
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
 
static void sla_destroy (void)
 
static void sla_dial_state_callback (struct ast_dial *dial)
 
static void sla_event_destroy (struct sla_event *event)
 
static void sla_failed_station_destroy (struct sla_failed_station *failed_station)
 
static struct sla_stationsla_find_station (const char *name)
 
static struct sla_trunksla_find_trunk (const char *name)
 
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
 
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name. More...
 
static void sla_handle_dial_state_event (void)
 
static void sla_handle_hold_event (struct sla_event *event)
 
static void sla_handle_ringing_trunk_event (void)
 
static void sla_hangup_stations (void)
 
static const char * sla_hold_str (unsigned int hold_access)
 
static int sla_in_use (void)
 
static int sla_load_config (int reload)
 
static int sla_process_timers (struct timespec *ts)
 Calculate the time until the next known event. More...
 
static void sla_queue_event (enum sla_event_type type)
 
static void sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
 Queue a SLA event from the conference. More...
 
static void sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
 
static void sla_queue_event_nolock (enum sla_event_type type)
 
static int sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
 Ring a station. More...
 
static void sla_ring_stations (void)
 Ring stations based on current set of ringing trunks. More...
 
static void sla_ringing_station_destroy (struct sla_ringing_station *ringing_station)
 
static void sla_ringing_trunk_destroy (struct sla_ringing_trunk *ringing_trunk)
 
static char * sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static enum ast_device_state sla_state (const char *data)
 
static enum ast_device_state sla_state_to_devstate (enum sla_trunk_state state)
 
static int sla_station_cmp (void *obj, void *arg, int flags)
 
static void sla_station_destructor (void *obj)
 
static int sla_station_exec (struct ast_channel *chan, const char *data)
 
static int sla_station_is_marked (void *obj, void *arg, int flags)
 
static int sla_station_mark (void *obj, void *arg, int flags)
 
static void sla_station_ref_destructor (void *obj)
 
static int sla_station_release_refs (void *obj, void *arg, int flags)
 
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
 
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
 
static void * sla_thread (void *data)
 
static int sla_trunk_cmp (void *obj, void *arg, int flags)
 
static void sla_trunk_destructor (void *obj)
 
static int sla_trunk_exec (struct ast_channel *chan, const char *data)
 
static int sla_trunk_is_marked (void *obj, void *arg, int flags)
 
static int sla_trunk_mark (void *obj, void *arg, int flags)
 
static void sla_trunk_ref_destructor (void *obj)
 
static int sla_trunk_release_refs (void *obj, void *arg, int flags)
 
 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 const char * trunkstate2str (enum sla_trunk_state state)
 
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
 
struct {
   unsigned int   attempt_callerid:1
 
   ast_cond_t   cond
 
   struct {
      struct sla_event *   first
 
      struct sla_event *   last
 
   }   event_q
 
   struct {
      struct sla_failed_station *   first
 
      struct sla_failed_station *   last
 
   }   failed_stations
 
   ast_mutex_t   lock
 
   struct {
      struct sla_ringing_station *   first
 
      struct sla_ringing_station *   last
 
   }   ringing_stations
 
   struct {
      struct sla_ringing_trunk *   first
 
      struct sla_ringing_trunk *   last
 
   }   ringing_trunks
 
   unsigned int   stop:1
 
   pthread_t   thread
 
sla
 A structure for data used by the sla thread. More...
 
static const char sla_registrar [] = "SLA"
 
static struct ao2_containersla_stations
 
static const struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
 
static struct ao2_containersla_trunks
 
static const char *const slastation_app = "SLAStation"
 
static const char *const slatrunk_app = "SLATrunk"
 

Detailed Description

Meet me conference bridge and Shared Line Appearances.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
(SLA) Russell Bryant russe.nosp@m.ll@d.nosp@m.igium.nosp@m..com

Definition in file app_meetme.c.

Macro Definition Documentation

◆ AST_FRAME_BITS

#define AST_FRAME_BITS   32

Definition at line 666 of file app_meetme.c.

◆ CONF_SIZE

#define CONF_SIZE   320

Definition at line 685 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 755 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 750 of file app_meetme.c.

◆ CONFFLAG_INTROUSER_VMREC

#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)

Definition at line 751 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 753 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 749 of file app_meetme.c.

◆ CONFIG_FILE_NAME

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 644 of file app_meetme.c.

◆ DATE_FORMAT

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

String format for scheduled conferences

Definition at line 652 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 649 of file app_meetme.c.

◆ MAX_CONFNUM

#define MAX_CONFNUM   80

Definition at line 821 of file app_meetme.c.

◆ MAX_PIN

#define MAX_PIN   80

Definition at line 822 of file app_meetme.c.

◆ MAX_SETTINGS

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

Definition at line 826 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 664 of file app_meetme.c.

◆ MEETME_DELAYDETECTTALK

#define MEETME_DELAYDETECTTALK   300

Definition at line 663 of file app_meetme.c.

◆ OPTIONS_LEN

#define OPTIONS_LEN   100

Definition at line 823 of file app_meetme.c.

◆ S

#define S (   e)    case e: return # e;

◆ SLA_CONFIG_FILE

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 645 of file app_meetme.c.

◆ STR_CONCISE

#define STR_CONCISE   "concise"

Definition at line 646 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 654 of file app_meetme.c.

654  {
655  ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
656  ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
657  ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */
658  /*! User has requested to speak */
659  ADMINFLAG_T_REQUEST = (1 << 4),
660  ADMINFLAG_HANGUP = (1 << 5), /*!< User will be leaving the conference */
661 };
@ ADMINFLAG_SELFMUTED
Definition: app_meetme.c:656
@ ADMINFLAG_KICKME
Definition: app_meetme.c:657
@ ADMINFLAG_MUTED
Definition: app_meetme.c:655
@ ADMINFLAG_HANGUP
Definition: app_meetme.c:660
@ ADMINFLAG_T_REQUEST
Definition: app_meetme.c:659

◆ 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_SLA_STATION 
CONFFLAG_SLA_TRUNK 
CONFFLAG_KICK_CONTINUE 

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

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 

Definition at line 687 of file app_meetme.c.

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

◆ 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 757 of file app_meetme.c.

757  {
758  OPT_ARG_WAITMARKED = 0,
759  OPT_ARG_EXITKEYS = 1,
762  OPT_ARG_MOH_CLASS = 4,
763  OPT_ARG_INTROMSG = 5,
765  OPT_ARG_ARRAY_SIZE = 7,
766 };
@ OPT_ARG_MOH_CLASS
Definition: app_meetme.c:762
@ OPT_ARG_DURATION_STOP
Definition: app_meetme.c:760
@ OPT_ARG_EXITKEYS
Definition: app_meetme.c:759
@ OPT_ARG_INTROMSG
Definition: app_meetme.c:763
@ OPT_ARG_DURATION_LIMIT
Definition: app_meetme.c:761
@ OPT_ARG_WAITMARKED
Definition: app_meetme.c:758
@ OPT_ARG_ARRAY_SIZE
Definition: app_meetme.c:765
@ OPT_ARG_INTROUSER_VMREC
Definition: app_meetme.c:764

◆ anonymous enum

anonymous enum
Enumerator
SLA_TRUNK_OPT_MOH 

Definition at line 7227 of file app_meetme.c.

7227  {
7228  SLA_TRUNK_OPT_MOH = (1 << 0),
7229 };
@ SLA_TRUNK_OPT_MOH
Definition: app_meetme.c:7228

◆ anonymous enum

anonymous enum
Enumerator
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 7231 of file app_meetme.c.

7231  {
7234 };
@ SLA_TRUNK_OPT_ARG_MOH_CLASS
Definition: app_meetme.c:7232
@ SLA_TRUNK_OPT_ARG_ARRAY_SIZE
Definition: app_meetme.c:7233

◆ announcetypes

Enumerator
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 828 of file app_meetme.c.

828  {
829  CONF_HASJOIN,
831 };
@ CONF_HASJOIN
Definition: app_meetme.c:829
@ CONF_HASLEFT
Definition: app_meetme.c:830

◆ entrance_sound

Enumerator
ENTER 
LEAVE 

Definition at line 673 of file app_meetme.c.

673  {
674  ENTER,
675  LEAVE
676 };
@ ENTER
Definition: app_meetme.c:674
@ LEAVE
Definition: app_meetme.c:675

◆ menu_modes

enum menu_modes
Enumerator
MENU_DISABLED 
MENU_NORMAL 
MENU_ADMIN 
MENU_ADMIN_EXTENDED 

Definition at line 2751 of file app_meetme.c.

2751  {
2752  MENU_DISABLED = 0,
2753  MENU_NORMAL,
2754  MENU_ADMIN,
2756 };
@ MENU_ADMIN
Definition: app_meetme.c:2754
@ MENU_ADMIN_EXTENDED
Definition: app_meetme.c:2755
@ MENU_DISABLED
Definition: app_meetme.c:2752
@ MENU_NORMAL
Definition: app_meetme.c:2753

◆ recording_state

Enumerator
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 678 of file app_meetme.c.

678  {
683 };
@ MEETME_RECORD_STARTED
Definition: app_meetme.c:680
@ MEETME_RECORD_OFF
Definition: app_meetme.c:679
@ MEETME_RECORD_TERMINATE
Definition: app_meetme.c:682
@ MEETME_RECORD_ACTIVE
Definition: app_meetme.c:681

◆ sla_event_type

Event types that can be queued up for the SLA thread.

Enumerator
SLA_EVENT_HOLD 

A station has put the call on hold

SLA_EVENT_DIAL_STATE 

The state of a dial has changed

SLA_EVENT_RINGING_TRUNK 

The state of a ringing trunk has changed

Definition at line 1040 of file app_meetme.c.

1040  {
1041  /*! A station has put the call on hold */
1043  /*! The state of a dial has changed */
1045  /*! The state of a ringing trunk has changed */
1047 };
@ SLA_EVENT_RINGING_TRUNK
Definition: app_meetme.c:1046
@ SLA_EVENT_HOLD
Definition: app_meetme.c:1042
@ SLA_EVENT_DIAL_STATE
Definition: app_meetme.c:1044

◆ sla_hold_access

Enumerator
SLA_HOLD_OPEN 

This means that any station can put it on hold, and any station can retrieve the call from hold.

SLA_HOLD_PRIVATE 

This means that only the station that put the call on hold may retrieve it from hold.

Definition at line 933 of file app_meetme.c.

933  {
934  /*! This means that any station can put it on hold, and any station
935  * can retrieve the call from hold. */
937  /*! This means that only the station that put the call on hold may
938  * retrieve it from hold. */
940 };
@ SLA_HOLD_OPEN
Definition: app_meetme.c:936
@ SLA_HOLD_PRIVATE
Definition: app_meetme.c:939

◆ sla_station_hangup

Enumerator
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 1073 of file app_meetme.c.

1073  {
1076 };
@ SLA_STATION_HANGUP_NORMAL
Definition: app_meetme.c:1074
@ SLA_STATION_HANGUP_TIMEOUT
Definition: app_meetme.c:1075

◆ sla_trunk_state

Enumerator
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 925 of file app_meetme.c.

925  {
931 };
@ SLA_TRUNK_STATE_ONHOLD
Definition: app_meetme.c:929
@ SLA_TRUNK_STATE_RINGING
Definition: app_meetme.c:927
@ SLA_TRUNK_STATE_UP
Definition: app_meetme.c:928
@ SLA_TRUNK_STATE_ONHOLD_BYME
Definition: app_meetme.c:930
@ SLA_TRUNK_STATE_IDLE
Definition: app_meetme.c:926

◆ sla_which_trunk_refs

Enumerator
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 920 of file app_meetme.c.

920  {
923 };
@ INACTIVE_TRUNK_REFS
Definition: app_meetme.c:922
@ ALL_TRUNK_REFS
Definition: app_meetme.c:921

◆ volume_action

Enumerator
VOL_UP 
VOL_DOWN 

Definition at line 668 of file app_meetme.c.

668  {
669  VOL_UP,
670  VOL_DOWN
671 };
@ VOL_UP
Definition: app_meetme.c:669
@ VOL_DOWN
Definition: app_meetme.c:670

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 8097 of file app_meetme.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 8097 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 7953 of file app_meetme.c.

7954 {
7955  struct ast_conference *conf;
7956  char *parse;
7957  int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
7959  AST_APP_ARG(keyword);
7961  );
7962 
7963  if (ast_strlen_zero(data)) {
7964  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
7965  return -1;
7966  }
7967 
7968  parse = ast_strdupa(data);
7970 
7971  if (ast_strlen_zero(args.keyword)) {
7972  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
7973  return -1;
7974  }
7975 
7976  if (ast_strlen_zero(args.confno)) {
7977  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
7978  return -1;
7979  }
7980 
7981  AST_LIST_LOCK(&confs);
7983  if (!strcmp(args.confno, conf->confno)) {
7984  result = acf_meetme_info_eval(args.keyword, conf);
7985  break;
7986  }
7987  }
7989 
7990  if (result > -1) {
7991  snprintf(buf, len, "%d", result);
7992  } else if (result == -1) {
7993  ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
7994  snprintf(buf, len, "0");
7995  } else if (result == -2) {
7996  ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
7997  snprintf(buf, len, "0");
7998  }
7999 
8000  return 0;
8001 }
static int acf_meetme_info_eval(const char *keyword, const struct ast_conference *conf)
Definition: app_meetme.c:7935
#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
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
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:844
struct ast_conference::@35 list
char confno[MAX_CONFNUM]
Definition: app_meetme.c:847
All configuration options for statsd client.
Definition: res_statsd.c:101
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, parse(), and result.

◆ acf_meetme_info_eval()

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

Definition at line 7935 of file app_meetme.c.

7936 {
7937  if (!strcasecmp("lock", keyword)) {
7938  return conf->locked;
7939  } else if (!strcasecmp("parties", keyword)) {
7940  return conf->users;
7941  } else if (!strcasecmp("activity", keyword)) {
7942  time_t now;
7943  now = time(NULL);
7944  return (now - conf->start);
7945  } else if (!strcasecmp("dynamic", keyword)) {
7946  return conf->isdynamic;
7947  } else {
7948  return -1;
7949  }
7950 
7951 }
#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 5533 of file app_meetme.c.

5534 {
5535  const char *actionid = astman_get_header(m, "ActionID");
5536  const char *conference = astman_get_header(m, "Conference");
5537  char idText[80] = "";
5538  struct ast_conference *cnf;
5539  struct ast_conf_user *user;
5540  struct ao2_iterator user_iter;
5541  int total = 0;
5542 
5543  if (!ast_strlen_zero(actionid))
5544  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5545 
5546  if (AST_LIST_EMPTY(&confs)) {
5547  astman_send_error(s, m, "No active conferences.");
5548  return 0;
5549  }
5550 
5551  astman_send_listack(s, m, "Meetme user list will follow", "start");
5552 
5553  /* Find the right conference */
5554  AST_LIST_LOCK(&confs);
5555  AST_LIST_TRAVERSE(&confs, cnf, list) {
5556  /* If we ask for one particular, and this isn't it, skip it */
5557  if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
5558  continue;
5559 
5560  /* Show all the users */
5561  user_iter = ao2_iterator_init(cnf->usercontainer, 0);
5562  while ((user = ao2_iterator_next(&user_iter))) {
5563  total++;
5564  astman_append(s,
5565  "Event: MeetmeList\r\n"
5566  "%s"
5567  "Conference: %s\r\n"
5568  "UserNumber: %d\r\n"
5569  "CallerIDNum: %s\r\n"
5570  "CallerIDName: %s\r\n"
5571  "ConnectedLineNum: %s\r\n"
5572  "ConnectedLineName: %s\r\n"
5573  "Channel: %s\r\n"
5574  "Admin: %s\r\n"
5575  "Role: %s\r\n"
5576  "MarkedUser: %s\r\n"
5577  "Muted: %s\r\n"
5578  "Talking: %s\r\n"
5579  "\r\n",
5580  idText,
5581  cnf->confno,
5582  user->user_no,
5583  S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
5584  S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
5586  S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<no name>"),
5587  ast_channel_name(user->chan),
5588  ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
5589  ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
5590  ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
5591  user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
5592  user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
5593  ao2_ref(user, -1);
5594  }
5595  ao2_iterator_destroy(&user_iter);
5596  }
5598 
5599  /* Send final confirmation */
5600  astman_send_list_complete_start(s, m, "MeetmeListComplete", total);
5602  return 0;
5603 }
#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.
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_name(const 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:3208
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3166
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:3244
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3252
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3087
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:2827
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
static int total
Definition: res_adsi.c:968
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:898
struct ao2_container * usercontainer
Definition: app_meetme.c:877
struct ast_party_id id
Caller party ID.
Definition: channel.h:420
struct ast_party_id id
Connected party ID.
Definition: channel.h:458
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
char * str
Subscriber name (Malloced)
Definition: channel.h:264
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
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 5605 of file app_meetme.c.

5606 {
5607  const char *actionid = astman_get_header(m, "ActionID");
5608  char idText[80] = "";
5609  struct ast_conference *cnf;
5610  int totalitems = 0;
5611  int hr, min, sec;
5612  time_t now;
5613  char markedusers[5];
5614 
5615  if (!ast_strlen_zero(actionid)) {
5616  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5617  }
5618 
5619  if (AST_LIST_EMPTY(&confs)) {
5620  astman_send_error(s, m, "No active conferences.");
5621  return 0;
5622  }
5623 
5624  astman_send_listack(s, m, "Meetme conferences will follow", "start");
5625 
5626  now = time(NULL);
5627 
5628  /* Traverse the conference list */
5629  AST_LIST_LOCK(&confs);
5630  AST_LIST_TRAVERSE(&confs, cnf, list) {
5631  totalitems++;
5632 
5633  if (cnf->markedusers == 0) {
5634  strcpy(markedusers, "N/A");
5635  } else {
5636  sprintf(markedusers, "%.4d", cnf->markedusers);
5637  }
5638  hr = (now - cnf->start) / 3600;
5639  min = ((now - cnf->start) % 3600) / 60;
5640  sec = (now - cnf->start) % 60;
5641 
5642  astman_append(s,
5643  "Event: MeetmeListRooms\r\n"
5644  "%s"
5645  "Conference: %s\r\n"
5646  "Parties: %d\r\n"
5647  "Marked: %s\r\n"
5648  "Activity: %2.2d:%2.2d:%2.2d\r\n"
5649  "Creation: %s\r\n"
5650  "Locked: %s\r\n"
5651  "\r\n",
5652  idText,
5653  cnf->confno,
5654  cnf->users,
5655  markedusers,
5656  hr, min, sec,
5657  cnf->isdynamic ? "Dynamic" : "Static",
5658  cnf->locked ? "Yes" : "No");
5659  }
5661 
5662  /* Send final confirmation */
5663  astman_send_list_complete_start(s, m, "MeetmeListRoomsComplete", totalitems);
5665  return 0;
5666 }
#define min(a, b)
Definition: f2c.h:197
unsigned int isdynamic
Definition: app_meetme.c:859
unsigned int locked
Definition: app_meetme.c:860

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 5523 of file app_meetme.c.

5524 {
5525  return meetmemute(s, m, 1);
5526 }
static int meetmemute(struct mansession *s, const struct message *m, int mute)
Definition: app_meetme.c:5463

References meetmemute().

Referenced by load_module().

◆ action_meetmeunmute()

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

Definition at line 5528 of file app_meetme.c.

5529 {
5530  return meetmemute(s, m, 0);
5531 }

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 5229 of file app_meetme.c.

5229  {
5230  char *params;
5231  struct ast_conference *cnf;
5232  struct ast_conf_user *user = NULL;
5234  AST_APP_ARG(confno);
5235  AST_APP_ARG(command);
5236  AST_APP_ARG(user);
5237  );
5238  int res = 0;
5239 
5240  if (ast_strlen_zero(data)) {
5241  ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
5242  if (chan) {
5243  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5244  }
5245  return -1;
5246  }
5247 
5248  params = ast_strdupa(data);
5249  AST_STANDARD_APP_ARGS(args, params);
5250 
5251  if (!args.command) {
5252  ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
5253  if (chan) {
5254  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5255  }
5256  return -1;
5257  }
5258 
5259  AST_LIST_LOCK(&confs);
5260  AST_LIST_TRAVERSE(&confs, cnf, list) {
5261  if (!strcmp(cnf->confno, args.confno))
5262  break;
5263  }
5264 
5265  if (!cnf) {
5266  ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
5268  if (chan) {
5269  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
5270  }
5271  return 0;
5272  }
5273 
5275 
5276  if (args.user) {
5277  user = find_user(cnf, args.user);
5278  if (!user) {
5279  ast_log(LOG_NOTICE, "Specified User not found!\n");
5280  res = -2;
5281  goto usernotfound;
5282  }
5283  } else {
5284  /* fail for commands that require a user */
5285  switch (*args.command) {
5286  case 'm': /* Unmute */
5287  case 'M': /* Mute */
5288  case 't': /* Lower user's talk volume */
5289  case 'T': /* Raise user's talk volume */
5290  case 'u': /* Lower user's listen volume */
5291  case 'U': /* Raise user's listen volume */
5292  case 'r': /* Reset user's volume level */
5293  case 'k': /* Kick user */
5294  res = -2;
5295  ast_log(LOG_NOTICE, "No user specified!\n");
5296  goto usernotfound;
5297  default:
5298  break;
5299  }
5300  }
5301 
5302  switch (*args.command) {
5303  case 76: /* L: Lock */
5304  cnf->locked = 1;
5305  break;
5306  case 108: /* l: Unlock */
5307  cnf->locked = 0;
5308  break;
5309  case 75: /* K: kick all users */
5311  break;
5312  case 101: /* e: Eject last user*/
5313  {
5314  int max_no = 0;
5315  RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
5316 
5318  eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
5319  if (!eject_user) {
5320  res = -1;
5321  ast_log(LOG_NOTICE, "No last user to kick!\n");
5322  break;
5323  }
5324 
5325  if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
5326  eject_user->adminflags |= ADMINFLAG_KICKME;
5327  } else {
5328  res = -1;
5329  ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
5330  }
5331  break;
5332  }
5333  case 77: /* M: Mute */
5334  user->adminflags |= ADMINFLAG_MUTED;
5335  break;
5336  case 78: /* N: Mute all (non-admin) users */
5338  break;
5339  case 109: /* m: Unmute */
5341  break;
5342  case 110: /* n: Unmute all users */
5344  break;
5345  case 107: /* k: Kick user */
5346  user->adminflags |= ADMINFLAG_KICKME;
5347  break;
5348  case 118: /* v: Lower all users listen volume */
5350  break;
5351  case 86: /* V: Raise all users listen volume */
5353  break;
5354  case 115: /* s: Lower all users speaking volume */
5356  break;
5357  case 83: /* S: Raise all users speaking volume */
5359  break;
5360  case 82: /* R: Reset all volume levels */
5362  break;
5363  case 114: /* r: Reset user's volume level */
5365  break;
5366  case 85: /* U: Raise user's listen volume */
5368  break;
5369  case 117: /* u: Lower user's listen volume */
5371  break;
5372  case 84: /* T: Raise user's talk volume */
5374  break;
5375  case 116: /* t: Lower user's talk volume */
5377  break;
5378  case 'E': /* E: Extend conference */
5379  if (rt_extend_conf(args.confno)) {
5380  res = -1;
5381  }
5382  break;
5383  }
5384 
5385  if (args.user) {
5386  /* decrement reference from find_user */
5387  ao2_ref(user, -1);
5388  }
5389 usernotfound:
5391 
5392  dispose_conf(cnf);
5393  if (chan) {
5394  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
5395  }
5396 
5397  return 0;
5398 }
static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1508
static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2718
static int dispose_conf(struct ast_conference *conf)
Decrement reference counts, as incremented by find_conf()
Definition: app_meetme.c:2506
static int user_max_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1581
static int rt_extend_conf(const char *confno)
Definition: app_meetme.c:2525
static int user_reset_vol_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5207
static void reset_volumes(struct ast_conf_user *user)
Definition: app_meetme.c:1520
static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2740
static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1496
static struct ast_conf_user * find_user(struct ast_conference *conf, const char *callerident)
Definition: app_meetme.c:5166
static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2729
static int user_talk_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5200
static int user_listen_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5179
static int user_listen_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5186
static int user_talk_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5193
#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:755
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:902
struct ast_conf_user::@37 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:936

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(), meetme_cmd_helper(), run_station(), sla_station_exec(), and sla_stop_ringing_trunk().

◆ announce_thread()

static void* announce_thread ( void *  data)
static

Definition at line 2617 of file app_meetme.c.

2618 {
2619  struct announce_listitem *current;
2620  struct ast_conference *conf = data;
2621  int res;
2622  char filename[PATH_MAX] = "";
2624  AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2625 
2626  while (!conf->announcethread_stop) {
2627  ast_mutex_lock(&conf->announcelistlock);
2628  if (conf->announcethread_stop) {
2629  ast_mutex_unlock(&conf->announcelistlock);
2630  break;
2631  }
2632  if (AST_LIST_EMPTY(&conf->announcelist))
2633  ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
2634 
2635  AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2636  AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2637 
2638  ast_mutex_unlock(&conf->announcelistlock);
2639  if (conf->announcethread_stop) {
2640  break;
2641  }
2642 
2643  for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2644  ast_debug(1, "About to play %s\n", current->namerecloc);
2645  if (!ast_fileexists(current->namerecloc, NULL, NULL))
2646  continue;
2647  if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2648  if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2649  res = ast_waitstream(current->confchan, "");
2650  if (!res) {
2651  ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2652  if (!ast_streamfile(current->confchan, filename, current->language))
2653  ast_waitstream(current->confchan, "");
2654  }
2655  }
2656  if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2657  /* only remove it if it isn't a VM recording file */
2658  ast_filedelete(current->namerecloc, NULL);
2659  }
2660  }
2661  }
2662 
2663  /* thread marked to stop, clean up */
2664  while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2665  /* only delete if it's a vm rec */
2666  if (!current->vmrec) {
2667  ast_filedelete(current->namerecloc, NULL);
2668  }
2669  ao2_ref(current, -1);
2670  }
2671  return NULL;
2672 }
static const char * get_announce_filename(enum announcetypes type)
Definition: app_meetme.c:2603
#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:1291
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1127
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1139
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1817
#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_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:203
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:187
size_t current
Definition: main/cli.c:113
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
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().

◆ answer_trunk_chan()

static void answer_trunk_chan ( struct ast_channel chan)
static

Definition at line 6074 of file app_meetme.c.

6075 {
6076  ast_answer(chan);
6077  ast_indicate(chan, -1);
6078 }
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2806
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4312

References ast_answer(), ast_indicate(), and sla_trunk_ref::chan.

Referenced by run_station(), sla_handle_dial_state_event(), and sla_station_exec().

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 8097 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 1608 of file app_meetme.c.

1611 {
1612  struct ast_conference *cnf;
1613  struct dahdi_confinfo dahdic = { 0, };
1614  int confno_int = 0;
1616 
1617  AST_LIST_LOCK(&confs);
1618 
1619  AST_LIST_TRAVERSE(&confs, cnf, list) {
1620  if (!strcmp(confno, cnf->confno))
1621  break;
1622  }
1623 
1624  if (cnf || (!make && !dynamic) || !cap_slin)
1625  goto cnfout;
1626 
1627  ast_format_cap_append(cap_slin, ast_format_slin, 0);
1628  /* Make a new one */
1629  cnf = ast_calloc(1, sizeof(*cnf));
1630  if (!cnf) {
1631  goto cnfout;
1632  }
1633 
1635  NULL, user_no_cmp);
1636  if (!cnf->usercontainer) {
1637  goto cnfout;
1638  }
1639 
1640  ast_mutex_init(&cnf->playlock);
1641  ast_mutex_init(&cnf->listenlock);
1646  ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1647  ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1648  ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1649  ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
1650 
1651  /* Setup a new dahdi conference */
1652  dahdic.confno = -1;
1653  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1654  cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1655  if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1656  if (test) {
1657  /* if we are creating a conference for a unit test, it is not neccesary
1658  * to open a pseudo channel, so, if we fail continue creating
1659  * the conference. */
1660  ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1661  } else {
1662  ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1663  if (cnf->fd >= 0)
1664  close(cnf->fd);
1665  ao2_ref(cnf->usercontainer, -1);
1666  ast_mutex_destroy(&cnf->playlock);
1670  ast_free(cnf);
1671  cnf = NULL;
1672  goto cnfout;
1673  }
1674  }
1675 
1676  cnf->dahdiconf = dahdic.confno;
1677 
1678  /* Setup a new channel for playback of audio files */
1679  cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
1680  if (cnf->chan) {
1683  dahdic.chan = 0;
1684  dahdic.confno = cnf->dahdiconf;
1685  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1686  if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
1687  if (test) {
1688  ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1689  }
1690  ast_log(LOG_WARNING, "Error setting conference\n");
1691  if (cnf->chan)
1692  ast_hangup(cnf->chan);
1693  else
1694  close(cnf->fd);
1695  ao2_ref(cnf->usercontainer, -1);
1696  ast_mutex_destroy(&cnf->playlock);
1700  ast_free(cnf);
1701  cnf = NULL;
1702  goto cnfout;
1703  }
1704  }
1705 
1706  /* Fill the conference struct */
1707  cnf->start = time(NULL);
1708  cnf->maxusers = 0x7fffffff;
1709  cnf->isdynamic = dynamic ? 1 : 0;
1710  ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1711  AST_LIST_INSERT_HEAD(&confs, cnf, list);
1712 
1713  /* Reserve conference number in map */
1714  if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1715  conf_map[confno_int] = 1;
1716 
1717 cnfout:
1718  ao2_cleanup(cap_slin);
1719  if (cnf)
1720  ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1721 
1723 
1724  return cnf;
1725 }
static int user_no_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1569
static unsigned int conf_map[1024]
Definition: app_meetme.c:890
#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:2542
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:6432
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:5839
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5880
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:184
#define ast_mutex_destroy(a)
Definition: lock.h:186
ast_mutex_t announcethreadlock
Definition: app_meetme.c:881
pthread_t announcethread
Definition: app_meetme.c:880
ast_mutex_t recordthreadlock
Definition: app_meetme.c:863
char pinadmin[MAX_PIN]
Definition: app_meetme.c:868
ast_mutex_t playlock
Definition: app_meetme.c:845
struct ast_channel * chan
Definition: app_meetme.c:848
pthread_t recordthread
Definition: app_meetme.c:862
char pin[MAX_PIN]
Definition: app_meetme.c:867
char uniqueid[32]
Definition: app_meetme.c:869
ast_mutex_t listenlock
Definition: app_meetme.c:846
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 dial_trunk(), find_conf(), find_conf_realtime(), run_station(), sla_state(), and sla_station_exec().

◆ can_write()

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

Definition at line 2674 of file app_meetme.c.

2675 {
2676  if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
2677  return 1;
2678  }
2679 
2680  return (ast_channel_state(chan) == AST_STATE_UP);
2681 }
#define CONFFLAG_NO_AUDIO_UNTIL_UP
Definition: app_meetme.c:749
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 1410 of file app_meetme.c.

1411 {
1412  int res;
1413  int x;
1414 
1415  while (len) {
1416  if (block) {
1417  x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
1418  res = ioctl(fd, DAHDI_IOMUX, &x);
1419  } else
1420  res = 0;
1421  if (res >= 0)
1422  res = write(fd, data, len);
1423  if (res < 1) {
1424  if (errno != EAGAIN) {
1425  ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
1426  return -1;
1427  } else
1428  return 0;
1429  }
1430  len -= res;
1431  data += res;
1432  }
1433 
1434  return 0;
1435 }
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 5402 of file app_meetme.c.

5402  {
5403  char *params;
5404  struct ast_conference *conf = NULL;
5405  struct ast_conf_user *user = NULL;
5407  AST_APP_ARG(channel);
5408  AST_APP_ARG(command);
5409  );
5410 
5411  if (ast_strlen_zero(data)) {
5412  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
5413  return -1;
5414  }
5415 
5416  params = ast_strdupa(data);
5417  AST_STANDARD_APP_ARGS(args, params);
5418 
5419  if (!args.channel) {
5420  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
5421  return -1;
5422  }
5423 
5424  if (!args.command) {
5425  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
5426  return -1;
5427  }
5428 
5429  AST_LIST_LOCK(&confs);
5431  if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
5432  break;
5433  }
5434  }
5435 
5436  if (!user) {
5437  ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
5439  return 0;
5440  }
5441 
5442  /* perform the specified action */
5443  switch (*args.command) {
5444  case 77: /* M: Mute */
5445  user->adminflags |= ADMINFLAG_MUTED;
5446  break;
5447  case 109: /* m: Unmute */
5448  user->adminflags &= ~ADMINFLAG_MUTED;
5449  break;
5450  case 107: /* k: Kick user */
5451  user->adminflags |= ADMINFLAG_KICKME;
5452  break;
5453  default: /* unknown command */
5454  ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
5455  break;
5456  }
5457  ao2_ref(user, -1);
5459 
5460  return 0;
5461 }
static int user_chan_cb(void *obj, void *args, int flags)
Definition: app_meetme.c:5214

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 1727 of file app_meetme.c.

1728 {
1729  struct ast_conference *cnf;
1730  char *ret = NULL;
1731  int which = 0;
1732  int len = strlen(word);
1733 
1734  AST_LIST_LOCK(&confs);
1735  AST_LIST_TRAVERSE(&confs, cnf, list) {
1736  if (!strncmp(word, cnf->confno, len) && ++which > state) {
1737  /* dup before releasing the lock */
1738  ret = ast_strdup(cnf->confno);
1739  break;
1740  }
1741  }
1743  return ret;
1744 }
#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 1816 of file app_meetme.c.

1817 {
1818  int len;
1819 
1820  if (pos == 2) {
1821  len = strlen(word);
1822  if (!strncasecmp(word, STR_CONCISE, len)) {
1823  if (state == 0) {
1824  return ast_strdup(STR_CONCISE);
1825  }
1826  --state;
1827  }
1828 
1829  return complete_confno(word, state);
1830  }
1831  if (pos == 3 && state == 0) {
1832  char *saved = NULL;
1833  char *myline;
1834  char *confno;
1835 
1836  /* Extract the confno from the command line. */
1837  myline = ast_strdupa(line);
1838  strtok_r(myline, " ", &saved);
1839  strtok_r(NULL, " ", &saved);
1840  confno = strtok_r(NULL, " ", &saved);
1841 
1842  if (!strcasecmp(confno, STR_CONCISE)) {
1843  /* There is nothing valid in this position now. */
1844  return NULL;
1845  }
1846 
1847  len = strlen(word);
1848  if (!strncasecmp(word, STR_CONCISE, len)) {
1849  return ast_strdup(STR_CONCISE);
1850  }
1851  }
1852  return NULL;
1853 }
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1727
#define STR_CONCISE
Definition: app_meetme.c:646
enum sip_cc_notify_state state
Definition: chan_sip.c:966

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 1808 of file app_meetme.c.

1809 {
1810  if (pos == 2) {
1811  return complete_confno(word, state);
1812  }
1813  return NULL;
1814 }

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 1768 of file app_meetme.c.

1769 {
1770  if (pos == 2) {
1771  return complete_confno(word, state);
1772  }
1773  if (pos == 3) {
1774  int len = strlen(word);
1775  char *ret = NULL;
1776  char *saved = NULL;
1777  char *myline;
1778  char *confno;
1779  struct ast_conference *cnf;
1780 
1781  if (!strncasecmp(word, "all", len)) {
1782  if (state == 0) {
1783  return ast_strdup("all");
1784  }
1785  --state;
1786  }
1787 
1788  /* Extract the confno from the command line. */
1789  myline = ast_strdupa(line);
1790  strtok_r(myline, " ", &saved);
1791  strtok_r(NULL, " ", &saved);
1792  confno = strtok_r(NULL, " ", &saved);
1793 
1794  AST_LIST_LOCK(&confs);
1795  AST_LIST_TRAVERSE(&confs, cnf, list) {
1796  if (!strcmp(confno, cnf->confno)) {
1797  ret = complete_userno(cnf, word, state);
1798  break;
1799  }
1800  }
1802 
1803  return ret;
1804  }
1805  return NULL;
1806 }
static char * complete_userno(struct ast_conference *cnf, const char *word, int state)
Definition: app_meetme.c:1746

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 1746 of file app_meetme.c.

1747 {
1748  char usrno[50];
1749  struct ao2_iterator iter;
1750  struct ast_conf_user *usr;
1751  char *ret = NULL;
1752  int which = 0;
1753  int len = strlen(word);
1754 
1755  iter = ao2_iterator_init(cnf->usercontainer, 0);
1756  for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
1757  snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1758  if (!strncmp(word, usrno, len) && ++which > state) {
1759  ao2_ref(usr, -1);
1760  ret = ast_strdup(usrno);
1761  break;
1762  }
1763  }
1764  ao2_iterator_destroy(&iter);
1765  return ret;
1766 }

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 4841 of file app_meetme.c.

4842 {
4843  int res = -1;
4844  char confno[MAX_CONFNUM] = "";
4845  int allowretry = 0;
4846  int retrycnt = 0;
4847  struct ast_conference *cnf = NULL;
4848  struct ast_flags64 confflags = {0};
4849  struct ast_flags config_flags = { 0 };
4850  int dynamic = 0;
4851  int empty = 0, empty_no_pin = 0;
4852  int always_prompt = 0;
4853  const char *notdata;
4854  char *info, the_pin[MAX_PIN] = "";
4856  AST_APP_ARG(confno);
4858  AST_APP_ARG(pin);
4859  );
4860  char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
4861 
4862  if (ast_strlen_zero(data)) {
4863  allowretry = 1;
4864  notdata = "";
4865  } else {
4866  notdata = data;
4867  }
4868 
4869  if (ast_channel_state(chan) != AST_STATE_UP)
4870  ast_answer(chan);
4871 
4872  info = ast_strdupa(notdata);
4873 
4875 
4876  if (args.confno) {
4877  ast_copy_string(confno, args.confno, sizeof(confno));
4878  if (ast_strlen_zero(confno)) {
4879  allowretry = 1;
4880  }
4881  }
4882 
4883  if (args.pin)
4884  ast_copy_string(the_pin, args.pin, sizeof(the_pin));
4885 
4886  if (args.options) {
4887  ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
4888  dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
4889  if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
4890  strcpy(the_pin, "q");
4891 
4892  empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
4893  empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
4894  always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
4895  }
4896 
4897  do {
4898  if (retrycnt > 3)
4899  allowretry = 0;
4900  if (empty) {
4901  int i;
4902  struct ast_config *cfg;
4903  struct ast_variable *var;
4904  int confno_int;
4905 
4906  /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
4907  if ((empty_no_pin) || (!dynamic)) {
4908  cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4909  if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
4910  var = ast_variable_browse(cfg, "rooms");
4911  while (var) {
4912  char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
4913  if (!strcasecmp(var->name, "conf")) {
4914  int found = 0;
4915  ast_copy_string(parse, var->value, sizeof(parse));
4916  confno_tmp = strsep(&stringp, "|,");
4917  if (!dynamic) {
4918  /* For static: run through the list and see if this conference is empty */
4919  AST_LIST_LOCK(&confs);
4920  AST_LIST_TRAVERSE(&confs, cnf, list) {
4921  if (!strcmp(confno_tmp, cnf->confno)) {
4922  /* The conference exists, therefore it's not empty */
4923  found = 1;
4924  break;
4925  }
4926  }
4928  cnf = NULL;
4929  if (!found) {
4930  /* At this point, we have a confno_tmp (static conference) that is empty */
4931  if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
4932  /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4933  * Case 2: empty_no_pin and pin is blank (but not NULL)
4934  * Case 3: not empty_no_pin
4935  */
4936  ast_copy_string(confno, confno_tmp, sizeof(confno));
4937  break;
4938  }
4939  }
4940  }
4941  }
4942  var = var->next;
4943  }
4944  ast_config_destroy(cfg);
4945  }
4946 
4947  if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
4948  const char *catg;
4949  for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
4950  const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
4951  const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
4952  if (ast_strlen_zero(confno_tmp)) {
4953  continue;
4954  }
4955  if (!dynamic) {
4956  int found = 0;
4957  /* For static: run through the list and see if this conference is empty */
4958  AST_LIST_LOCK(&confs);
4959  AST_LIST_TRAVERSE(&confs, cnf, list) {
4960  if (!strcmp(confno_tmp, cnf->confno)) {
4961  /* The conference exists, therefore it's not empty */
4962  found = 1;
4963  break;
4964  }
4965  }
4967  if (!found) {
4968  /* At this point, we have a confno_tmp (realtime conference) that is empty */
4969  if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
4970  /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4971  * Case 2: empty_no_pin and pin is blank (but not NULL)
4972  * Case 3: not empty_no_pin
4973  */
4974  ast_copy_string(confno, confno_tmp, sizeof(confno));
4975  break;
4976  }
4977  }
4978  }
4979  }
4980  ast_config_destroy(cfg);
4981  }
4982  }
4983 
4984  /* Select first conference number not in use */
4985  if (ast_strlen_zero(confno) && dynamic) {
4986  AST_LIST_LOCK(&confs);
4987  for (i = 0; i < ARRAY_LEN(conf_map); i++) {
4988  if (!conf_map[i]) {
4989  snprintf(confno, sizeof(confno), "%d", i);
4990  conf_map[i] = 1;
4991  break;
4992  }
4993  }
4995  }
4996 
4997  /* Not found? */
4998  if (ast_strlen_zero(confno)) {
4999  res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
5000  ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
5001  if (!res)
5002  ast_waitstream(chan, "");
5003  } else {
5004  if (sscanf(confno, "%30d", &confno_int) == 1) {
5005  if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
5006  res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
5007  if (!res) {
5008  ast_waitstream(chan, "");
5009  res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
5010  }
5011  }
5012  } else {
5013  ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
5014  }
5015  }
5016  }
5017 
5018  while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
5019  /* Prompt user for conference number */
5020  res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
5021  if (res < 0) {
5022  /* Don't try to validate when we catch an error */
5023  confno[0] = '\0';
5024  allowretry = 0;
5025  break;
5026  }
5027  }
5028  if (!ast_strlen_zero(confno)) {
5029  /* Check the validity of the conference */
5030  cnf = find_conf(chan, confno, 1, dynamic, the_pin,
5031  sizeof(the_pin), 1, &confflags);
5032  if (!cnf) {
5033  int too_early = 0;
5034 
5035  cnf = find_conf_realtime(chan, confno, 1, dynamic,
5036  the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
5037  if (rt_schedule && too_early)
5038  allowretry = 0;
5039  }
5040 
5041  if (!cnf) {
5042  if (allowretry) {
5043  confno[0] = '\0';
5044  res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
5045  if (!res)
5046  ast_waitstream(chan, "");
5047  res = -1;
5048  }
5049  } else {
5050  /* Conference requires a pin for specified access level */
5051  int req_pin = !ast_strlen_zero(cnf->pin) ||
5052  (!ast_strlen_zero(cnf->pinadmin) &&
5053  ast_test_flag64(&confflags, CONFFLAG_ADMIN));
5054  /* The following logic was derived from a
5055  * 4 variable truth table and defines which
5056  * circumstances are not exempt from pin
5057  * checking.
5058  * If this needs to be modified, write the
5059  * truth table back out from the boolean
5060  * expression AB+A'D+C', change the erroneous
5061  * result, and rederive the expression.
5062  * Variables:
5063  * A: pin provided?
5064  * B: always prompt?
5065  * C: dynamic?
5066  * D: has users? */
5067  int not_exempt = !cnf->isdynamic;
5068  not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
5069  not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
5070  if (req_pin && not_exempt) {
5071  char pin[MAX_PIN] = "";
5072  int j;
5073 
5074  /* Allow the pin to be retried up to 3 times */
5075  for (j = 0; j < 3; j++) {
5076  if (*the_pin && (always_prompt == 0)) {
5077  ast_copy_string(pin, the_pin, sizeof(pin));
5078  res = 0;
5079  } else {
5080  /* Prompt user for pin if pin is required */
5081  ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
5082  "Channel: %s",
5083  ast_channel_name(chan));
5084  res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
5085  }
5086  if (res >= 0) {
5087  if ((!strcasecmp(pin, cnf->pin) &&
5088  (ast_strlen_zero(cnf->pinadmin) ||
5089  !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
5090  (!ast_strlen_zero(cnf->pinadmin) &&
5091  !strcasecmp(pin, cnf->pinadmin))) {
5092  /* Pin correct */
5093  allowretry = 0;
5094  if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
5095  if (!ast_strlen_zero(cnf->adminopts)) {
5096  char *opts = ast_strdupa(cnf->adminopts);
5097  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5098  }
5099  } else {
5100  if (!ast_strlen_zero(cnf->useropts)) {
5101  char *opts = ast_strdupa(cnf->useropts);
5102  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5103  }
5104  }
5105  /* Run the conference */
5106  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
5107  res = conf_run(chan, cnf, &confflags, optargs);
5108  break;
5109  } else {
5110  /* Pin invalid */
5111  if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
5112  res = ast_waitstream(chan, AST_DIGIT_ANY);
5113  ast_stopstream(chan);
5114  } else {
5115  ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
5116  break;
5117  }
5118  if (res < 0)
5119  break;
5120  pin[0] = res;
5121  pin[1] = '\0';
5122  res = -1;
5123  if (allowretry)
5124  confno[0] = '\0';
5125  }
5126  } else {
5127  /* failed when getting the pin */
5128  res = -1;
5129  allowretry = 0;
5130  /* see if we need to get rid of the conference */
5131  break;
5132  }
5133 
5134  /* Don't retry pin with a static pin */
5135  if (*the_pin && (always_prompt == 0)) {
5136  break;
5137  }
5138  }
5139  } else {
5140  /* No pin required */
5141  allowretry = 0;
5142 
5143  /* For RealTime conferences without a pin
5144  * should still support loading options
5145  */
5146  if (!ast_strlen_zero(cnf->useropts)) {
5147  char *opts = ast_strdupa(cnf->useropts);
5148  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5149  }
5150 
5151  /* Run the conference */
5152  res = conf_run(chan, cnf, &confflags, optargs);
5153  }
5154  dispose_conf(cnf);
5155  cnf = NULL;
5156  }
5157  }
5158  } while (allowretry);
5159 
5160  if (cnf)
5161  dispose_conf(cnf);
5162 
5163  return res;
5164 }
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:4692
static const struct ast_app_option meetme_opts[128]
Definition: app_meetme.c:802
#define CONFIG_FILE_NAME
Definition: app_meetme.c:644
#define MAX_PIN
Definition: app_meetme.c:822
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
Definition: app_meetme.c:3181
#define MAX_CONFNUM
Definition: app_meetme.c:821
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:4504
static int rt_schedule
Definition: app_meetme.c:812
#define MAX_SETTINGS
Definition: app_meetme.c:826
#define var
Definition: ast_expr2f.c:614
const char * ast_channel_language(const struct ast_channel *chan)
#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
int 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:3131
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:3327
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3521
#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:768
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:8336
char * recordingformat
Definition: app_meetme.c:866
const char * useropts
Definition: app_meetme.c:871
char * recordingfilename
Definition: app_meetme.c:865
const char * adminopts
Definition: app_meetme.c:872
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:661

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, parse(), 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 2301 of file app_meetme.c.

2302 {
2303  int x;
2304 
2305  /* read any frames that may be waiting on the channel
2306  and throw them away
2307  */
2308  if (chan) {
2309  struct ast_frame *f;
2310 
2311  /* when no frames are available, this will wait
2312  for 1 millisecond maximum
2313  */
2314  while (ast_waitfor(chan, 1) > 0) {
2315  f = ast_read(chan);
2316  if (f)
2317  ast_frfree(f);
2318  else /* channel was hung up or something else happened */
2319  break;
2320  }
2321  }
2322 
2323  /* flush any data sitting in the pseudo channel */
2324  x = DAHDI_FLUSH_ALL;
2325  if (ioctl(fd, DAHDI_FLUSH, &x))
2326  ast_log(LOG_WARNING, "Error flushing channel\n");
2327 
2328 }
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3163
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4292
#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 2333 of file app_meetme.c.

2334 {
2335  int x;
2336  struct announce_listitem *item;
2337 
2338  AST_LIST_REMOVE(&confs, conf, list);
2339 
2340  meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
2341 
2342  if (conf->recording == MEETME_RECORD_ACTIVE) {
2343  conf->recording = MEETME_RECORD_TERMINATE;
2345  while (1) {
2346  usleep(1);
2347  AST_LIST_LOCK(&confs);
2348  if (conf->recording == MEETME_RECORD_OFF)
2349  break;
2351  }
2352  }
2353 
2354  for (x = 0; x < AST_FRAME_BITS; x++) {
2355  if (conf->transframe[x])
2356  ast_frfree(conf->transframe[x]);
2357  if (conf->transpath[x])
2358  ast_translator_free_path(conf->transpath[x]);
2359  }
2360  if (conf->announcethread != AST_PTHREADT_NULL) {
2361  ast_mutex_lock(&conf->announcelistlock);
2362  conf->announcethread_stop = 1;
2364  ast_cond_signal(&conf->announcelist_addition);
2365  ast_mutex_unlock(&conf->announcelistlock);
2366  pthread_join(conf->announcethread, NULL);
2367 
2368  while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2369  /* If it's a voicemail greeting file we don't want to remove it */
2370  if (!item->vmrec){
2371  ast_filedelete(item->namerecloc, NULL);
2372  }
2373  ao2_ref(item, -1);
2374  }
2375  ast_mutex_destroy(&conf->announcelistlock);
2376  }
2377 
2378  if (conf->origframe)
2379  ast_frfree(conf->origframe);
2380  ast_hangup(conf->lchan);
2381  ast_hangup(conf->chan);
2382  if (conf->fd >= 0)
2383  close(conf->fd);
2384  if (conf->recordingfilename) {
2385  ast_free(conf->recordingfilename);
2386  }
2387  if (conf->usercontainer) {
2388  ao2_ref(conf->usercontainer, -1);
2389  }
2390  if (conf->recordingformat) {
2391  ast_free(conf->recordingformat);
2392  }
2393  ast_mutex_destroy(&conf->playlock);
2394  ast_mutex_destroy(&conf->listenlock);
2395  ast_mutex_destroy(&conf->recordthreadlock);
2396  ast_mutex_destroy(&conf->announcethreadlock);
2397  ast_free(conf);
2398 
2399  return 0;
2400 }
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:1345
#define AST_FRAME_BITS
Definition: app_meetme.c:666
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1148
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2470
#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:201
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:475

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 1528 of file app_meetme.c.

1529 {
1530  unsigned char *data;
1531  int len;
1532  int res = -1;
1533 
1534  ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
1535  "Conference: %s\r\n"
1536  "Marked: %d",
1537  ast_channel_name(chan),
1538  conf->confno,
1539  conf->markedusers);
1540 
1541  if (!ast_check_hangup(chan))
1542  res = ast_autoservice_start(chan);
1543 
1544  AST_LIST_LOCK(&confs);
1545 
1546  switch(sound) {
1547  case ENTER:
1548  data = enter;
1549  len = sizeof(enter);
1550  break;
1551  case LEAVE:
1552  data = leave;
1553  len = sizeof(leave);
1554  break;
1555  default:
1556  data = NULL;
1557  len = 0;
1558  }
1559  if (data) {
1560  careful_write(conf->fd, data, len, 1);
1561  }
1562 
1564 
1565  if (!res)
1566  ast_autoservice_stop(chan);
1567 }
static int careful_write(int fd, unsigned char *data, int len, int block)
Definition: app_meetme.c:1410
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 2402 of file app_meetme.c.

2404 {
2405  struct ast_conf_user *user;
2406  struct ao2_iterator user_iter;
2407 
2408  user_iter = ao2_iterator_init(conf->usercontainer, 0);
2409  while ((user = ao2_iterator_next(&user_iter))) {
2410  if (user == sender) {
2411  ao2_ref(user, -1);
2412  continue;
2413  }
2414  if (ast_write(user->chan, f) < 0)
2415  ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
2416  ao2_ref(user, -1);
2417  }
2418  ao2_iterator_destroy(&user_iter);
2419 }
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:5179

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 3181 of file app_meetme.c.

3182 {
3183  struct ast_conf_user *user = NULL;
3184  int fd;
3185  struct dahdi_confinfo dahdic, dahdic_empty;
3186  struct ast_frame *f;
3187  struct ast_channel *c;
3188  struct ast_frame fr;
3189  int outfd;
3190  int ms;
3191  int nfds;
3192  int res;
3193  int retrydahdi;
3194  int origfd;
3195  int musiconhold = 0, mohtempstopped = 0;
3196  int firstpass = 0;
3197  int lastmarked = 0;
3198  int currentmarked = 0;
3199  int ret = -1;
3200  int x;
3201  enum menu_modes menu_mode = MENU_DISABLED;
3202  int talkreq_manager = 0;
3203  int using_pseudo = 0;
3204  int duration = 20;
3205  int sent_event = 0;
3206  int checked = 0;
3207  int announcement_played = 0;
3208  struct timeval now;
3209  struct ast_dsp *dsp = NULL;
3210  struct ast_app *agi_app;
3211  char *agifile;
3212  const char *agifiledefault = "conf-background.agi", *tmpvar;
3213  char meetmesecs[30] = "";
3214  char exitcontext[AST_MAX_CONTEXT] = "";
3215  char recordingtmp[AST_MAX_EXTENSION * 2] = "";
3216  char members[10] = "";
3217  int dtmf = 0, opt_waitmarked_timeout = 0;
3218  time_t timeout = 0;
3219  struct dahdi_bufferinfo bi;
3220  char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
3221  char *buf = __buf + AST_FRIENDLY_OFFSET;
3222  char *exitkeys = NULL;
3223  unsigned int calldurationlimit = 0;
3224  long timelimit = 0;
3225  long play_warning = 0;
3226  long warning_freq = 0;
3227  const char *warning_sound = NULL;
3228  const char *end_sound = NULL;
3229  char *parse;
3230  long time_left_ms = 0;
3231  struct timeval nexteventts = { 0, };
3232  int to;
3233  int setusercount = 0;
3234  int confsilence = 0, totalsilence = 0;
3235  char *mailbox, *context;
3237 
3238  if (!cap_slin) {
3239  goto conf_run_cleanup;
3240  }
3241  ast_format_cap_append(cap_slin, ast_format_slin, 0);
3242 
3243  if (!(user = ao2_alloc(sizeof(*user), NULL))) {
3244  goto conf_run_cleanup;
3245  }
3246 
3247  /* Possible timeout waiting for marked user */
3248  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3249  !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
3250  (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
3251  (opt_waitmarked_timeout > 0)) {
3252  timeout = time(NULL) + opt_waitmarked_timeout;
3253  }
3254 
3256  calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
3257  ast_verb(3, "Setting call duration limit to %u seconds.\n", calldurationlimit);
3258  }
3259 
3261  char *limit_str, *warning_str, *warnfreq_str;
3262  const char *var;
3263 
3264  parse = optargs[OPT_ARG_DURATION_LIMIT];
3265  limit_str = strsep(&parse, ":");
3266  warning_str = strsep(&parse, ":");
3267  warnfreq_str = parse;
3268 
3269  timelimit = atol(limit_str);
3270  if (warning_str)
3271  play_warning = atol(warning_str);
3272  if (warnfreq_str)
3273  warning_freq = atol(warnfreq_str);
3274 
3275  if (!timelimit) {
3276  timelimit = play_warning = warning_freq = 0;
3277  warning_sound = NULL;
3278  } else if (play_warning > timelimit) {
3279  if (!warning_freq) {
3280  play_warning = 0;
3281  } else {
3282  while (play_warning > timelimit)
3283  play_warning -= warning_freq;
3284  if (play_warning < 1)
3285  play_warning = warning_freq = 0;
3286  }
3287  }
3288 
3289  ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
3290  if (play_warning) {
3291  ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
3292  }
3293  if (warning_freq) {
3294  ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
3295  }
3296 
3297  ast_channel_lock(chan);
3298  if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
3299  var = ast_strdupa(var);
3300  }
3301  ast_channel_unlock(chan);
3302 
3303  warning_sound = var ? var : "timeleft";
3304 
3305  ast_channel_lock(chan);
3306  if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
3307  var = ast_strdupa(var);
3308  }
3309  ast_channel_unlock(chan);
3310 
3311  end_sound = var ? var : NULL;
3312 
3313  /* undo effect of S(x) in case they are both used */
3314  calldurationlimit = 0;
3315  /* more efficient do it like S(x) does since no advanced opts */
3316  if (!play_warning && !end_sound && timelimit) {
3317  calldurationlimit = timelimit / 1000;
3318  timelimit = play_warning = warning_freq = 0;
3319  } else {
3320  ast_debug(2, "Limit Data for this call:\n");
3321  ast_debug(2, "- timelimit = %ld\n", timelimit);
3322  ast_debug(2, "- play_warning = %ld\n", play_warning);
3323  ast_debug(2, "- warning_freq = %ld\n", warning_freq);
3324  ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
3325  ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
3326  }
3327  }
3328 
3329  /* Get exit keys */
3330  if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
3331  if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
3332  exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
3333  else
3334  exitkeys = ast_strdupa("#"); /* Default */
3335  }
3336 
3337  if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
3338  if (!conf->recordingfilename) {
3339  const char *var;
3340  ast_channel_lock(chan);
3341  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3342  conf->recordingfilename = ast_strdup(var);
3343  }
3344  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3345  conf->recordingformat = ast_strdup(var);
3346  }
3347  ast_channel_unlock(chan);
3348  if (!conf->recordingfilename) {
3349  snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3350  conf->recordingfilename = ast_strdup(recordingtmp);
3351  }
3352  if (!conf->recordingformat) {
3353  conf->recordingformat = ast_strdup("wav");
3354  }
3355  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3356  conf->confno, conf->recordingfilename, conf->recordingformat);
3357  }
3358  }
3359 
3360  ast_mutex_lock(&conf->recordthreadlock);
3361  if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
3362  ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3365  dahdic.chan = 0;
3366  dahdic.confno = conf->dahdiconf;
3367  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
3368  if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
3369  ast_log(LOG_WARNING, "Error starting listen channel\n");
3370  ast_hangup(conf->lchan);
3371  conf->lchan = NULL;
3372  } else {
3374  }
3375  }
3376  ast_mutex_unlock(&conf->recordthreadlock);
3377 
3378  ast_mutex_lock(&conf->announcethreadlock);
3379  if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3381  ast_mutex_init(&conf->announcelistlock);
3382  AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
3384  }
3385  ast_mutex_unlock(&conf->announcethreadlock);
3386 
3387  time(&user->jointime);
3388 
3389  user->timelimit = timelimit;
3390  user->play_warning = play_warning;
3391  user->warning_freq = warning_freq;
3392  user->warning_sound = warning_sound;
3393  user->end_sound = end_sound;
3394 
3395  if (calldurationlimit > 0) {
3396  time(&user->kicktime);
3397  user->kicktime = user->kicktime + calldurationlimit;
3398  }
3399 
3400  if (ast_tvzero(user->start_time))
3401  user->start_time = ast_tvnow();
3402  time_left_ms = user->timelimit;
3403 
3404  if (user->timelimit) {
3405  nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3406  nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
3407  }
3408 
3409  if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
3410  /* Sorry, but this conference is locked! */
3411  if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
3412  ast_waitstream(chan, "");
3413  goto outrun;
3414  }
3415 
3416  ast_mutex_lock(&conf->playlock);
3417 
3418  if (rt_schedule && conf->maxusers) {
3419  if (conf->users >= conf->maxusers) {
3420  /* Sorry, but this confernce has reached the participant limit! */
3421  ast_mutex_unlock(&conf->playlock);
3422  if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
3423  ast_waitstream(chan, "");
3424  goto outrun;
3425  }
3426  }
3427 
3428  ao2_lock(conf->usercontainer);
3429  ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
3430  user->user_no++;
3431  ao2_link(conf->usercontainer, user);
3432  ao2_unlock(conf->usercontainer);
3433 
3434  user->chan = chan;
3435  user->userflags = *confflags;
3436  user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
3437  if (!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3438  user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
3439  }
3440  user->talking = -1;
3441 
3442  ast_mutex_unlock(&conf->playlock);
3443 
3445  char destdir[PATH_MAX];
3446 
3447  snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
3448 
3449  if (ast_mkdir(destdir, 0777) != 0) {
3450  ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
3451  goto outrun;
3452  }
3453 
3454  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
3456  mailbox = strsep(&context, "@");
3457 
3458  if (ast_strlen_zero(mailbox)) {
3459  /* invalid input, clear the v flag*/
3461  ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
3462  } else {
3463  if (ast_strlen_zero(context)) {
3464  context = "default";
3465  }
3466  /* if there is no mailbox we don't need to do this logic */
3467  snprintf(user->namerecloc, sizeof(user->namerecloc),
3468  "%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
3469 
3470  /* if the greeting doesn't exist then use the temp file method instead, clear flag v */
3471  if (!ast_fileexists(user->namerecloc, NULL, NULL)){
3472  snprintf(user->namerecloc, sizeof(user->namerecloc),
3473  "%s/meetme-username-%s-%d", destdir,
3474  conf->confno, user->user_no);
3476  }
3477  }
3478  } else {
3479  snprintf(user->namerecloc, sizeof(user->namerecloc),
3480  "%s/meetme-username-%s-%d", destdir,
3481  conf->confno, user->user_no);
3482  }
3483 
3484  res = 0;
3485  if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) && !ast_fileexists(user->namerecloc, NULL, NULL))
3486  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);
3487  else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
3488  res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
3489  if (res == -1)
3490  goto outrun;
3491 
3492  }
3493 
3494  ast_mutex_lock(&conf->playlock);
3495 
3496  if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
3497  conf->markedusers++;
3498  conf->users++;
3499  if (rt_log_members) {
3500  /* Update table */
3501  snprintf(members, sizeof(members), "%d", conf->users);
3502  ast_realtime_require_field("meetme",
3503  "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
3504  "members", RQ_UINTEGER1, strlen(members),
3505  NULL);
3506  ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
3507  }
3508  setusercount = 1;
3509 
3510  /* This device changed state now - if this is the first user */
3511  if (conf->users == 1)
3513 
3514  ast_mutex_unlock(&conf->playlock);
3515 
3516  /* return the unique ID of the conference */
3517  pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
3518 
3519  if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
3520  ast_channel_lock(chan);
3521  if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
3522  ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
3523  } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
3525  } else {
3527  }
3528  ast_channel_unlock(chan);
3529  }
3530 
3531  /* Play an arbitrary intro message */
3532  if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
3533  !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
3534  if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
3535  ast_waitstream(chan, "");
3536  }
3537  }
3538 
3539  if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
3540  if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
3541  if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
3542  ast_waitstream(chan, "");
3543  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
3544  if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
3545  ast_waitstream(chan, "");
3546  }
3547 
3548  if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
3549  int keepplaying = 1;
3550 
3551  if (conf->users == 2) {
3552  if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
3553  res = ast_waitstream(chan, AST_DIGIT_ANY);
3554  ast_stopstream(chan);
3555  if (res > 0)
3556  keepplaying = 0;
3557  else if (res == -1)
3558  goto outrun;
3559  }
3560  } else {
3561  if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
3562  res = ast_waitstream(chan, AST_DIGIT_ANY);
3563  ast_stopstream(chan);
3564  if (res > 0)
3565  keepplaying = 0;
3566  else if (res == -1)
3567  goto outrun;
3568  }
3569  if (keepplaying) {
3570  res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3571  if (res > 0)
3572  keepplaying = 0;
3573  else if (res == -1)
3574  goto outrun;
3575  }
3576  if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3577  res = ast_waitstream(chan, AST_DIGIT_ANY);
3578  ast_stopstream(chan);
3579  if (res > 0)
3580  keepplaying = 0;
3581  else if (res == -1)
3582  goto outrun;
3583  }
3584  }
3585  }
3586 
3587  if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
3588  /* We're leaving this alone until the state gets changed to up */
3589  ast_indicate(chan, -1);
3590  }
3591 
3592  if (ast_set_write_format(chan, ast_format_slin) < 0) {
3593  ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
3594  goto outrun;
3595  }
3596 
3597  if (ast_set_read_format(chan, ast_format_slin) < 0) {
3598  ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
3599  goto outrun;
3600  }
3601 
3602  /* Reduce background noise from each participant */
3603  if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE)) {
3604  ast_func_write(chan, "DENOISE(rx)", "on");
3605  }
3606 
3607  retrydahdi = (strcasecmp(ast_channel_tech(chan)->type, "DAHDI") || (ast_channel_audiohooks(chan) || ast_channel_monitor(chan)) ? 1 : 0);
3608  user->dahdichannel = !retrydahdi;
3609 
3610  dahdiretry:
3611  origfd = ast_channel_fd(chan, 0);
3612  if (retrydahdi) {
3613  /* open pseudo in non-blocking mode */
3614  fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
3615  if (fd < 0) {
3616  ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
3617  goto outrun;
3618  }
3619  using_pseudo = 1;
3620  /* Setup buffering information */
3621  memset(&bi, 0, sizeof(bi));
3622  bi.bufsize = CONF_SIZE / 2;
3623  bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
3624  bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
3625  bi.numbufs = audio_buffers;
3626  if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
3627  ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
3628  close(fd);
3629  goto outrun;
3630  }
3631  x = 1;
3632  if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
3633  ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
3634  close(fd);
3635  goto outrun;
3636  }
3637  nfds = 1;
3638  } else {
3639  /* XXX Make sure we're not running on a pseudo channel XXX */
3640  fd = ast_channel_fd(chan, 0);
3641  nfds = 0;
3642  }
3643  memset(&dahdic, 0, sizeof(dahdic));
3644  memset(&dahdic_empty, 0, sizeof(dahdic_empty));
3645  /* Check to see if we're in a conference... */
3646  dahdic.chan = 0;
3647  if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
3648  ast_log(LOG_WARNING, "Error getting conference\n");
3649  close(fd);
3650  goto outrun;
3651  }
3652  if (dahdic.confmode) {
3653  /* Whoa, already in a conference... Retry... */
3654  if (!retrydahdi) {
3655  ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
3656  retrydahdi = 1;
3657  goto dahdiretry;
3658  }
3659  }
3660  memset(&dahdic, 0, sizeof(dahdic));
3661  /* Add us to the conference */
3662  dahdic.chan = 0;
3663  dahdic.confno = conf->dahdiconf;
3664 
3665  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
3666  ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) || ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)) && conf->users > 1) {
3667  struct announce_listitem *item;
3668  if (!(item = ao2_alloc(sizeof(*item), NULL)))
3669  goto outrun;
3670  ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
3671  ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
3672  item->confchan = conf->chan;
3673  item->confusers = conf->users;
3674  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
3675  item->vmrec = 1;
3676  }
3677  item->announcetype = CONF_HASJOIN;
3678  ast_mutex_lock(&conf->announcelistlock);
3679  ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
3680  AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
3681  ast_cond_signal(&conf->announcelist_addition);
3682  ast_mutex_unlock(&conf->announcelistlock);
3683 
3684  while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
3685  ;
3686  }
3687  ao2_ref(item, -1);
3688  }
3689 
3690  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
3691  dahdic.confmode = DAHDI_CONF_CONF;
3692  else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
3693  dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3694  else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
3695  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3696  else
3697  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3698 
3699  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3700  ast_log(LOG_WARNING, "Error setting conference\n");
3701  close(fd);
3702  goto outrun;
3703  }
3704  ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
3705 
3706  if (!sent_event) {
3707  meetme_stasis_generate_msg(conf, chan, user, meetme_join_type(), NULL);
3708  sent_event = 1;
3709  }
3710 
3711  if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
3712  !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3713  firstpass = 1;
3714  if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
3715  if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
3716  (conf->markedusers >= 1))) {
3717  conf_play(chan, conf, ENTER);
3718  }
3719  }
3720 
3721  conf_flush(fd, chan);
3722 
3723  if (dsp)
3724  ast_dsp_free(dsp);
3725 
3726  if (!(dsp = ast_dsp_new())) {
3727  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
3728  res = -1;
3729  }
3730 
3731  if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
3732  /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
3733  or use default filename of conf-background.agi */
3734 
3735  ast_channel_lock(chan);
3736  if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
3737  agifile = ast_strdupa(tmpvar);
3738  } else {
3739  agifile = ast_strdupa(agifiledefault);
3740  }
3741  ast_channel_unlock(chan);
3742 
3743  if (user->dahdichannel) {
3744  /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
3745  x = 1;
3746  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3747  }
3748  /* Find a pointer to the agi app and execute the script */
3749  agi_app = pbx_findapp("agi");
3750  if (agi_app) {
3751  ret = pbx_exec(chan, agi_app, agifile);
3752  } else {
3753  ast_log(LOG_WARNING, "Could not find application (agi)\n");
3754  ret = -2;
3755  }
3756  if (user->dahdichannel) {
3757  /* Remove CONFMUTE mode on DAHDI channel */
3758  x = 0;
3759  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3760  }
3761  } else {
3762  int lastusers = conf->users;
3763  if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
3764  /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
3765  x = 1;
3766  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3767  }
3768 
3769  for (;;) {
3770  int menu_was_active = 0;
3771 
3772  outfd = -1;
3773  ms = -1;
3774  now = ast_tvnow();
3775 
3776  if (rt_schedule && conf->endtime) {
3777  char currenttime[32];
3778  long localendtime = 0;
3779  int extended = 0;
3780  struct ast_tm tm;
3781  struct ast_variable *var, *origvar;
3782  struct timeval tmp;
3783 
3784  if (now.tv_sec % 60 == 0) {
3785  if (!checked) {
3786  ast_localtime(&now, &tm, NULL);
3787  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
3788  var = origvar = ast_load_realtime("meetme", "confno",
3789  conf->confno, "starttime <=", currenttime,
3790  "endtime >=", currenttime, NULL);
3791 
3792  for ( ; var; var = var->next) {
3793  if (!strcasecmp(var->name, "endtime")) {
3794  struct ast_tm endtime_tm;
3795  ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
3796  tmp = ast_mktime(&endtime_tm, NULL);
3797  localendtime = tmp.tv_sec;
3798  }
3799  }
3800  ast_variables_destroy(origvar);
3801 
3802  /* A conference can be extended from the
3803  Admin/User menu or by an external source */
3804  if (localendtime > conf->endtime){
3805  conf->endtime = localendtime;
3806  extended = 1;
3807  }
3808 
3809  if (conf->endtime && (now.tv_sec >= conf->endtime)) {
3810  ast_verbose("Quitting time...\n");
3811  goto outrun;
3812  }
3813 
3814  if (!announcement_played && conf->endalert) {
3815  if (now.tv_sec + conf->endalert >= conf->endtime) {
3816  if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
3817  ast_waitstream(chan, "");
3818  ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
3819  if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
3820  ast_waitstream(chan, "");
3821  if (musiconhold) {
3822  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3823  }
3824  announcement_played = 1;
3825  }
3826  }
3827 
3828  if (extended) {
3829  announcement_played = 0;
3830  }
3831 
3832  checked = 1;
3833  }
3834  } else {
3835  checked = 0;
3836  }
3837  }
3838 
3839  if (user->kicktime && (user->kicktime <= now.tv_sec)) {
3840  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3841  ret = 0;
3842  } else {
3843  ret = -1;
3844  }
3845  break;
3846  }
3847 
3848  to = -1;
3849  if (user->timelimit) {
3850  int minutes = 0, seconds = 0, remain = 0;
3851 
3852  to = ast_tvdiff_ms(nexteventts, now);
3853  if (to < 0) {
3854  to = 0;
3855  }
3856  time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
3857  if (time_left_ms < to) {
3858  to = time_left_ms;
3859  }
3860 
3861  if (time_left_ms <= 0) {
3862  if (user->end_sound) {
3863  res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
3864  res = ast_waitstream(chan, "");
3865  }
3866  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3867  ret = 0;
3868  } else {
3869  ret = -1;
3870  }
3871  break;
3872  }
3873 
3874  if (!to) {
3875  if (time_left_ms >= 5000) {
3876 
3877  remain = (time_left_ms + 500) / 1000;
3878  if (remain / 60 >= 1) {
3879  minutes = remain / 60;
3880  seconds = remain % 60;
3881  } else {
3882  seconds = remain;
3883  }
3884 
3885  /* force the time left to round up if appropriate */
3886  if (user->warning_sound && user->play_warning) {
3887  if (!strcmp(user->warning_sound, "timeleft")) {
3888 
3889  res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
3890  res = ast_waitstream(chan, "");
3891  if (minutes) {
3892  res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3893  res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
3894  res = ast_waitstream(chan, "");
3895  }
3896  if (seconds) {
3897  res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3898  res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
3899  res = ast_waitstream(chan, "");
3900  }
3901  } else {
3902  res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
3903  res = ast_waitstream(chan, "");
3904  }
3905  if (musiconhold) {
3906  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3907  }
3908  }
3909  }
3910  if (user->warning_freq) {
3911  nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
3912  } else {
3913  nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3914  }
3915  }
3916  }
3917 
3918  now = ast_tvnow();
3919  if (timeout && now.tv_sec >= timeout) {
3920  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3921  ret = 0;
3922  } else {
3923  ret = -1;
3924  }
3925  break;
3926  }
3927 
3928  /* if we have just exited from the menu, and the user had a channel-driver
3929  volume adjustment, restore it
3930  */
3931  if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
3932  set_talk_volume(user, user->listen.desired);
3933  }
3934 
3935  menu_was_active = menu_mode;
3936 
3937  currentmarked = conf->markedusers;
3938  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3939  ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
3940  ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3941  lastmarked == 0) {
3942  if (currentmarked == 1 && conf->users > 1) {
3943  ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3944  if (conf->users - 1 == 1) {
3945  if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
3946  ast_waitstream(chan, "");
3947  }
3948  } else {
3949  if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
3950  ast_waitstream(chan, "");
3951  }
3952  }
3953  }
3954  if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
3955  if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
3956  ast_waitstream(chan, "");
3957  }
3958  }
3959  }
3960 
3961  /* Update the struct with the actual confflags */
3962  user->userflags = *confflags;
3963 
3964  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
3965  if (currentmarked == 0) {
3966  if (lastmarked != 0) {
3967  if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
3968  if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
3969  ast_waitstream(chan, "");
3970  }
3971  }
3972  if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
3973  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3974  ret = 0;
3975  }
3976  break;
3977  } else {
3978  dahdic.confmode = DAHDI_CONF_CONF;
3979  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3980  ast_log(LOG_WARNING, "Error setting conference\n");
3981  close(fd);
3982  goto outrun;
3983  }
3984  }
3985  }
3986  if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
3987  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3988  musiconhold = 1;
3989  }
3990  } else if (currentmarked >= 1 && lastmarked == 0) {
3991  /* Marked user entered, so cancel timeout */
3992  timeout = 0;
3993  if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
3994  dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3995  } else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
3996  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3997  } else {
3998  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3999  }
4000  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4001  ast_log(LOG_WARNING, "Error setting conference\n");
4002  close(fd);
4003  goto outrun;
4004  }
4005  if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
4006  ast_moh_stop(chan);
4007  musiconhold = 0;
4008  }
4009  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4010  !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
4011  if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
4012  ast_waitstream(chan, "");
4013  }
4014  conf_play(chan, conf, ENTER);
4015  }
4016  }
4017  }
4018 
4019  /* trying to add moh for single person conf */
4020  if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
4021  if (conf->users == 1) {
4022  if (!musiconhold) {
4023  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4024  musiconhold = 1;
4025  }
4026  } else {
4027  if (musiconhold) {
4028  ast_moh_stop(chan);
4029  musiconhold = 0;
4030  }
4031  }
4032  }
4033 
4034  /* Leave if the last marked user left */
4035  if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
4036  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
4037  ret = 0;
4038  } else {
4039  ret = -1;
4040  }
4041  break;
4042  }
4043 
4044  /* Throw a TestEvent if a user exit did not cause this user to leave the conference */
4045  if (conf->users != lastusers) {
4046  if (conf->users < lastusers) {
4047  ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
4048  }
4049  lastusers = conf->users;
4050  }
4051 
4052  /* Check if my modes have changed */
4053 
4054  /* If I should be muted but am still talker, mute me */
4055  if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
4056  RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
4057  dahdic.confmode ^= DAHDI_CONF_TALKER;
4058  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4059  ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
4060  ret = -1;
4061  break;
4062  }
4063 
4064  /* Indicate user is not talking anymore - change him to unmonitored state */
4067  }
4068  meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
4069  }
4070 
4071  /* If I should be un-muted but am not talker, un-mute me */
4072  if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
4073  RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
4074  dahdic.confmode |= DAHDI_CONF_TALKER;
4075  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4076  ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
4077  ret = -1;
4078  break;
4079  }
4080  meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
4081  }
4082 
4083  if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
4084  (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
4085 
4086  RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
4087  talkreq_manager = 1;
4088  meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
4089  }
4090 
4091  if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
4092  !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
4093  RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
4094  talkreq_manager = 0;
4095  meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
4096  }
4097 
4098  /* If user have been hung up, exit the conference */
4099  if (user->adminflags & ADMINFLAG_HANGUP) {
4100  ret = 0;
4101  break;
4102  }
4103 
4104  /* If I have been kicked, exit the conference */
4105  if (user->adminflags & ADMINFLAG_KICKME) {
4106  /* You have been kicked. */
4107  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4108  !ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
4109  ast_waitstream(chan, "");
4110  }
4111  ret = 0;
4112  break;
4113  }
4114 
4115  /* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
4116  if (ast_check_hangup(chan)) {
4117  break;
4118  }
4119 
4120  c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
4121 
4122  if (c) {
4123  char dtmfstr[2] = "";
4124 
4125  if (ast_channel_fd(c, 0) != origfd || (user->dahdichannel && (ast_channel_audiohooks(c) || ast_channel_monitor(c)))) {
4126  if (using_pseudo) {
4127  /* Kill old pseudo */
4128  close(fd);
4129  using_pseudo = 0;
4130  }
4131  ast_debug(1, "Ooh, something swapped out under us, starting over\n");
4132  retrydahdi = (strcasecmp(ast_channel_tech(c)->type, "DAHDI") || (ast_channel_audiohooks(c) || ast_channel_monitor(c)) ? 1 : 0);
4133  user->dahdichannel = !retrydahdi;
4134  goto dahdiretry;
4135  }
4136  if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
4137  f = ast_read_noaudio(c);
4138  } else {
4139  f = ast_read(c);
4140  }
4141  if (!f) {
4142  break;
4143  }
4144  if (f->frametype == AST_FRAME_DTMF) {
4145  dtmfstr[0] = f->subclass.integer;
4146  dtmfstr[1] = '\0';
4147  }
4148 
4150  if (user->talk.actual) {
4151  ast_frame_adjust_volume(f, user->talk.actual);
4152  }
4153 
4155  if (user->talking == -1) {
4156  user->talking = 0;
4157  }
4158 
4159  res = ast_dsp_silence(dsp, f, &totalsilence);
4160  if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
4162  }
4163 
4164  if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
4166  }
4167  }
4168  if (using_pseudo) {
4169  /* Absolutely do _not_ use careful_write here...
4170  it is important that we read data from the channel
4171  as fast as it arrives, and feed it into the conference.
4172  The buffering in the pseudo channel will take care of any
4173  timing differences, unless they are so drastic as to lose
4174  audio frames (in which case carefully writing would only
4175  have delayed the audio even further).
4176  */
4177  /* As it turns out, we do want to use careful write. We just
4178  don't want to block, but we do want to at least *try*
4179  to write out all the samples.
4180  */
4181  if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
4182  careful_write(fd, f->data.ptr, f->datalen, 0);
4183  }
4184  }
4185  } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
4186  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4187  conf_queue_dtmf(conf, user, f);
4188  }
4189  /* Take out of conference */
4190  if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
4191  ast_log(LOG_WARNING, "Error setting conference\n");
4192  close(fd);
4193  ast_frfree(f);
4194  goto outrun;
4195  }
4196 
4197  /* if we are entering the menu, and the user has a channel-driver
4198  volume adjustment, clear it
4199  */
4200  if (!menu_mode && user->talk.desired && !user->talk.actual) {
4201  set_talk_volume(user, 0);
4202  }
4203 
4204  if (musiconhold) {
4205  ast_moh_stop(chan);
4206  } else if (!menu_mode) {
4207  char *menu_to_play;
4208  if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
4209  menu_mode = MENU_ADMIN;
4210  menu_to_play = "conf-adminmenu-18";
4211  } else {
4212  menu_mode = MENU_NORMAL;
4213  menu_to_play = "conf-usermenu-162";
4214  }
4215 
4216  if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
4217  dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
4218  ast_stopstream(chan);
4219  } else {
4220  dtmf = 0;
4221  }
4222  } else {
4223  dtmf = f->subclass.integer;
4224  }
4225 
4226  if (dtmf > 0) {
4227  meetme_menu(&menu_mode, &dtmf, conf, confflags,
4228  chan, user, recordingtmp, sizeof(recordingtmp), cap_slin);
4229  }
4230 
4231  if (musiconhold && !menu_mode) {
4232  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4233  }
4234 
4235  /* Put back into conference */
4236  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4237  ast_log(LOG_WARNING, "Error setting conference\n");
4238  close(fd);
4239  ast_frfree(f);
4240  goto outrun;
4241  }
4242 
4243  conf_flush(fd, chan);
4244  /*
4245  * Since options using DTMF could absorb DTMF meant for the
4246  * conference menu, we have to check them after the menu.
4247  */
4248  } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
4249  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4250  conf_queue_dtmf(conf, user, f);
4251  }
4252 
4253  if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
4254  ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
4255  ret = 0;
4256  ast_frfree(f);
4257  break;
4258  } else {
4259  ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
4260  }
4261  } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
4262  (strchr(exitkeys, f->subclass.integer))) {
4263  pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
4264 
4265  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4266  conf_queue_dtmf(conf, user, f);
4267  }
4268  ret = 0;
4269  ast_frfree(f);
4270  break;
4271  } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
4272  && ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4273  conf_queue_dtmf(conf, user, f);
4274  } else if (ast_test_flag64(confflags, CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
4275  switch (f->subclass.integer) {
4276  case AST_CONTROL_HOLD:
4278  break;
4279  default:
4280  break;
4281  }
4282  } else if (f->frametype == AST_FRAME_NULL) {
4283  /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
4284  } else if (f->frametype == AST_FRAME_CONTROL) {
4285  switch (f->subclass.integer) {
4286  case AST_CONTROL_BUSY:
4288  ast_frfree(f);
4289  goto outrun;
4290  break;
4291  default:
4292  ast_debug(1,
4293  "Got ignored control frame on channel %s, f->frametype=%u,f->subclass=%d\n",
4294  ast_channel_name(chan), f->frametype, f->subclass.integer);
4295  }
4296  } else {
4297  ast_debug(1,
4298  "Got unrecognized frame on channel %s, f->frametype=%u,f->subclass=%d\n",
4299  ast_channel_name(chan), f->frametype, f->subclass.integer);
4300  }
4301  ast_frfree(f);
4302  } else if (outfd > -1) {
4303  res = read(outfd, buf, CONF_SIZE);
4304  if (res > 0) {
4305  memset(&fr, 0, sizeof(fr));
4306  fr.frametype = AST_FRAME_VOICE;
4307  fr.subclass.format = ast_format_slin;
4308  fr.datalen = res;
4309  fr.samples = res / 2;
4310  fr.data.ptr = buf;
4311  fr.offset = AST_FRIENDLY_OFFSET;
4312  if (!user->listen.actual &&
4313  (ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
4314  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
4315  (!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
4316  )) {
4317  int idx;
4318  for (idx = 0; idx < AST_FRAME_BITS; idx++) {
4320  break;
4321  }
4322  }
4323  if (idx >= AST_FRAME_BITS) {
4324  goto bailoutandtrynormal;
4325  }
4326  ast_mutex_lock(&conf->listenlock);
4327  if (!conf->transframe[idx]) {
4328  if (conf->origframe) {
4329  if (musiconhold
4330  && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
4331  && !ast_dsp_silence(dsp, conf->origframe, &confsilence)
4332  && confsilence < MEETME_DELAYDETECTTALK) {
4333  ast_moh_stop(chan);
4334  mohtempstopped = 1;
4335  }
4336  if (!conf->transpath[idx]) {
4338  }
4339  if (conf->transpath[idx]) {
4340  conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
4341  if (!conf->transframe[idx]) {
4342  conf->transframe[idx] = &ast_null_frame;
4343  }
4344  }
4345  }
4346  }
4347  if (conf->transframe[idx]) {
4348  if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
4349  can_write(chan, confflags)) {
4350  struct ast_frame *cur;
4351  /* the translator may have returned a list of frames, so
4352  write each one onto the channel
4353  */
4354  for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
4355  if (ast_write(chan, cur)) {
4356  ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
4357  break;
4358  }
4359  }
4360  if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
4361  mohtempstopped = 0;
4362  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4363  }
4364  }
4365  } else {
4366  ast_mutex_unlock(&conf->listenlock);
4367  goto bailoutandtrynormal;
4368  }
4369  ast_mutex_unlock(&conf->listenlock);
4370  } else {
4371 bailoutandtrynormal:
4372  if (musiconhold
4373  && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
4374  && !ast_dsp_silence(dsp, &fr, &confsilence)
4375  && confsilence < MEETME_DELAYDETECTTALK) {
4376  ast_moh_stop(chan);
4377  mohtempstopped = 1;
4378  }
4379  if (user->listen.actual) {
4380  ast_frame_adjust_volume(&fr, user->listen.actual);
4381  }
4382  if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
4383  ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
4384  }
4385  if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
4386  mohtempstopped = 0;
4387  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4388  }
4389  }
4390  } else {
4391  ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
4392  }
4393  }
4394  lastmarked = currentmarked;
4395  }
4396  }
4397 
4398  if (musiconhold) {
4399  ast_moh_stop(chan);
4400  }
4401 
4402  if (using_pseudo) {
4403  close(fd);
4404  } else {
4405  /* Take out of conference */
4406  dahdic.chan = 0;
4407  dahdic.confno = 0;
4408  dahdic.confmode = 0;
4409  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4410  ast_log(LOG_WARNING, "Error setting conference\n");
4411  }
4412  }
4413 
4415 
4416  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
4417  !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
4418  conf_play(chan, conf, LEAVE);
4419  }
4420 
4422  struct announce_listitem *item;
4423  if (!(item = ao2_alloc(sizeof(*item), NULL)))
4424  goto outrun;
4425  ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
4426  ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
4427  item->confchan = conf->chan;
4428  item->confusers = conf->users;
4429  item->announcetype = CONF_HASLEFT;
4430  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
4431  item->vmrec = 1;
4432  }
4433  ast_mutex_lock(&conf->announcelistlock);
4434  AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
4435  ast_cond_signal(&conf->announcelist_addition);
4436  ast_mutex_unlock(&conf->announcelistlock);
4437  } 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) {
4438  /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
4439  ast_filedelete(user->namerecloc, NULL);
4440  }
4441 
4442  outrun:
4443  AST_LIST_LOCK(&confs);
4444 
4445  if (dsp) {
4446  ast_dsp_free(dsp);
4447  }
4448 
4449  if (user->user_no) {
4450  /* Only cleanup users who really joined! */
4451  now = ast_tvnow();
4452 
4453  if (sent_event) {
4454  meetme_stasis_generate_msg(conf, chan, user, meetme_leave_type(), NULL);
4455  }
4456 
4457  if (setusercount) {
4458  conf->users--;
4459  if (rt_log_members) {
4460  /* Update table */
4461  snprintf(members, sizeof(members), "%d", conf->users);
4462  ast_realtime_require_field("meetme",
4463  "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
4464  "members", RQ_UINTEGER1, strlen(members),
4465  NULL);
4466  ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
4467  }
4468  if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
4469  conf->markedusers--;
4470  }
4471  }
4472  /* Remove ourselves from the container */
4473  ao2_unlink(conf->usercontainer, user);
4474 
4475  /* Change any states */
4476  if (!conf->users) {
4478  }
4479 
4480  /* This flag is meant to kill a conference with only one participant remaining. */
4481  if (conf->users == 1 && ast_test_flag64(confflags, CONFFLAG_KILL_LAST_MAN_STANDING)) {
4482  ao2_callback(conf->usercontainer, 0, user_set_hangup_cb, NULL);
4483  }
4484 
4485  /* Return the number of seconds the user was in the conf */
4486  snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
4487  pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
4488 
4489  /* Return the RealTime bookid for CDR linking */
4490  if (rt_schedule) {
4491  pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
4492  }
4493  }
4494  ao2_ref(user, -1);
4496 
4497 
4498 conf_run_cleanup:
4499  ao2_cleanup(cap_slin);
4500 
4501  return ret;
4502 }
static int rt_log_members
Definition: app_meetme.c:819
static void * announce_thread(void *data)
Definition: app_meetme.c:2617
static struct ast_json * status_to_json(int on)
Definition: app_meetme.c:1326
menu_modes
Definition: app_meetme.c:2751
#define CONFFLAG_DONT_DENOISE
Definition: app_meetme.c:755
#define CONF_SIZE
Definition: app_meetme.c:685
static void * recordthread(void *args)
Definition: app_meetme.c:5693
#define MEETME_DELAYDETECTENDTALK
Definition: app_meetme.c:664
static void conf_flush(int fd, struct ast_channel *chan)
Definition: app_meetme.c:2301
static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
Definition: app_meetme.c:2674
static int set_talk_volume(struct ast_conf_user *user, int volume)
Definition: app_meetme.c:1437
static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
Definition: app_meetme.c:2587
static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
Queue a SLA event from the conference.
Definition: app_meetme.c:2464
static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
Definition: app_meetme.c:1528
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:3157
#define CONFFLAG_KILL_LAST_MAN_STANDING
Definition: app_meetme.c:753
static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2707
#define CONFFLAG_INTROUSER_VMREC
Definition: app_meetme.c:751
#define CONFFLAG_INTROMSG
Definition: app_meetme.c:750
#define MEETME_DELAYDETECTTALK
Definition: app_meetme.c:663
static int audio_buffers
The number of audio buffers to be allocated on pseudo channels when in a conference.
Definition: app_meetme.c:1108
static void conf_queue_dtmf(const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
Definition: app_meetme.c:2402
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:2689
#define DATE_FORMAT
Definition: app_meetme.c:652
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 char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:207
static const char type[]
Definition: chan_ooh323.c:109
static const struct _map_x_s dtmfstr[]
mapping between dtmf flags and strings
Definition: chan_sip.c:20602
struct ast_frame * ast_read_noaudio(struct ast_channel *chan)
Reads a frame, returning AST_FRAME_NULL frame if audio.
Definition: channel.c:4302
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:2989
#define ast_channel_lock(chan)
Definition: channel.h:2922
struct ast_audiohook_list * ast_channel_audiohooks(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
#define AST_MAX_CONTEXT
Definition: channel.h:135
struct ast_channel_monitor * ast_channel_monitor(const struct ast_channel *chan)
struct ast_format * ast_channel_rawwriteformat(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:7505
const char * ast_channel_macrocontext(const struct ast_channel *chan)
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1568
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#define AST_MAX_EXTENSION
Definition: channel.h:134
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
@ 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:1773
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1748
@ 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:1486
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1999
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:2214
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:2706
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3405
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3448
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3558
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