Asterisk - The Open Source Telephony Project  18.5.0
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_join_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_leave_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_end_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_mute_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_talking_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_talk_request_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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .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 664 of file app_meetme.c.

Referenced by conf_free(), conf_run(), and recordthread().

◆ CONF_SIZE

#define CONF_SIZE   320

Definition at line 683 of file app_meetme.c.

Referenced by conf_run().

◆ CONFFLAG_DONT_DENOISE

#define CONFFLAG_DONT_DENOISE   (1ULL << 35)

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

Definition at line 753 of file app_meetme.c.

Referenced by conf_run().

◆ CONFFLAG_INTROMSG

#define CONFFLAG_INTROMSG   (1ULL << 32)

If set play an intro announcement at start of conference

Definition at line 748 of file app_meetme.c.

Referenced by conf_run().

◆ CONFFLAG_INTROUSER_VMREC

#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)

Definition at line 749 of file app_meetme.c.

Referenced by conf_run(), find_conf(), and find_conf_realtime().

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

Referenced by conf_run().

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

Referenced by can_write(), conf_run(), and sla_trunk_exec().

◆ CONFIG_FILE_NAME

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 642 of file app_meetme.c.

Referenced by conf_exec(), find_conf(), and load_config_meetme().

◆ DATE_FORMAT

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

String format for scheduled conferences

Definition at line 650 of file app_meetme.c.

Referenced by conf_run(), find_conf_realtime(), and rt_extend_conf().

◆ DEFAULT_AUDIO_BUFFERS

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 647 of file app_meetme.c.

Referenced by load_config_meetme(), and meetme_set_defaults().

◆ MAX_CONFNUM

#define MAX_CONFNUM   80

◆ MAX_PIN

#define MAX_PIN   80

Definition at line 820 of file app_meetme.c.

Referenced by conf_exec(), and conf_get_pin().

◆ MAX_SETTINGS

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

Definition at line 824 of file app_meetme.c.

Referenced by conf_exec(), and find_conf().

◆ MC_DATA_FORMAT

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

Referenced by meetme_show_cmd().

◆ MC_HEADER_FORMAT

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

Referenced by meetme_show_cmd().

◆ MEETME_DELAYDETECTENDTALK

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 662 of file app_meetme.c.

Referenced by conf_run().

◆ MEETME_DELAYDETECTTALK

#define MEETME_DELAYDETECTTALK   300

Definition at line 661 of file app_meetme.c.

Referenced by conf_run().

◆ OPTIONS_LEN

#define OPTIONS_LEN   100

Definition at line 821 of file app_meetme.c.

Referenced by find_conf_realtime().

◆ S

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

Referenced by P4(), P5(), sms_readfile(), and trunkstate2str().

◆ SLA_CONFIG_FILE

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 643 of file app_meetme.c.

Referenced by sla_build_station(), sla_build_trunk(), and sla_load_config().

◆ STR_CONCISE

#define STR_CONCISE   "concise"

Definition at line 644 of file app_meetme.c.

Referenced by complete_meetmecmd_list(), and meetme_show_cmd().

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

652  {
653  ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
654  ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
655  ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */
656  /*! User has requested to speak */
657  ADMINFLAG_T_REQUEST = (1 << 4),
658  ADMINFLAG_HANGUP = (1 << 5), /*!< User will be leaving the conference */
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 685 of file app_meetme.c.

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

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

◆ anonymous enum

anonymous enum
Enumerator
SLA_TRUNK_OPT_MOH 

Definition at line 7215 of file app_meetme.c.

7215  {
7216  SLA_TRUNK_OPT_MOH = (1 << 0),
7217 };

◆ anonymous enum

anonymous enum
Enumerator
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 7219 of file app_meetme.c.

◆ announcetypes

Enumerator
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 826 of file app_meetme.c.

826  {
827  CONF_HASJOIN,
829 };

◆ entrance_sound

Enumerator
ENTER 
LEAVE 

Definition at line 671 of file app_meetme.c.

671  {
672  ENTER,
673  LEAVE
674 };

◆ menu_modes

enum menu_modes
Enumerator
MENU_DISABLED 
MENU_NORMAL 
MENU_ADMIN 
MENU_ADMIN_EXTENDED 

Definition at line 2749 of file app_meetme.c.

◆ recording_state

Enumerator
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 676 of file app_meetme.c.

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

1038  {
1039  /*! A station has put the call on hold */
1041  /*! The state of a dial has changed */
1043  /*! The state of a ringing trunk has changed */
1045 };

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

931  {
932  /*! This means that any station can put it on hold, and any station
933  * can retrieve the call from hold. */
935  /*! This means that only the station that put the call on hold may
936  * retrieve it from hold. */
938 };

◆ sla_station_hangup

Enumerator
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 1071 of file app_meetme.c.

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

◆ sla_which_trunk_refs

Enumerator
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 918 of file app_meetme.c.

◆ volume_action

Enumerator
VOL_UP 
VOL_DOWN 

Definition at line 666 of file app_meetme.c.

666  {
667  VOL_UP,
668  VOL_DOWN
669 };

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 8085 of file app_meetme.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

References acf_meetme_info_eval(), 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_conference::confno, ast_conference::list, LOG_ERROR, LOG_NOTICE, parse(), and result.

7942 {
7943  struct ast_conference *conf;
7944  char *parse;
7945  int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
7947  AST_APP_ARG(keyword);
7949  );
7950 
7951  if (ast_strlen_zero(data)) {
7952  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
7953  return -1;
7954  }
7955 
7956  parse = ast_strdupa(data);
7957  AST_STANDARD_APP_ARGS(args, parse);
7958 
7959  if (ast_strlen_zero(args.keyword)) {
7960  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
7961  return -1;
7962  }
7963 
7964  if (ast_strlen_zero(args.confno)) {
7965  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
7966  return -1;
7967  }
7968 
7969  AST_LIST_LOCK(&confs);
7970  AST_LIST_TRAVERSE(&confs, conf, list) {
7971  if (!strcmp(args.confno, conf->confno)) {
7972  result = acf_meetme_info_eval(args.keyword, conf);
7973  break;
7974  }
7975  }
7977 
7978  if (result > -1) {
7979  snprintf(buf, len, "%d", result);
7980  } else if (result == -1) {
7981  ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
7982  snprintf(buf, len, "0");
7983  } else if (result == -2) {
7984  ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
7985  snprintf(buf, len, "0");
7986  }
7987 
7988  return 0;
7989 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
const char * args
#define ast_strlen_zero(foo)
Definition: strings.h:52
All configuration options for statsd client.
Definition: res_statsd.c:95
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int acf_meetme_info_eval(const char *keyword, const struct ast_conference *conf)
Definition: app_meetme.c:7923
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_NOTICE
Definition: logger.h:263
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
static PGresult * result
Definition: cel_pgsql.c:88
The MeetMe Conference object.
Definition: app_meetme.c:842
struct ast_conference::@39 list
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845

◆ acf_meetme_info_eval()

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

Definition at line 7923 of file app_meetme.c.

References ast_conference::isdynamic, ast_conference::locked, NULL, ast_conference::start, and ast_conference::users.

Referenced by acf_meetme_info().

7924 {
7925  if (!strcasecmp("lock", keyword)) {
7926  return conf->locked;
7927  } else if (!strcasecmp("parties", keyword)) {
7928  return conf->users;
7929  } else if (!strcasecmp("activity", keyword)) {
7930  time_t now;
7931  now = time(NULL);
7932  return (now - conf->start);
7933  } else if (!strcasecmp("dynamic", keyword)) {
7934  return conf->isdynamic;
7935  } else {
7936  return -1;
7937  }
7938 
7939 }
unsigned int isdynamic
Definition: app_meetme.c:857
#define NULL
Definition: resample.c:96
unsigned int locked
Definition: app_meetme.c:858

◆ action_meetmelist()

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

Definition at line 5521 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, 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(), ast_conf_user::chan, 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, ast_conf_user::talking, total, user, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_party_name::valid, and ast_party_number::valid.

Referenced by load_module().

5522 {
5523  const char *actionid = astman_get_header(m, "ActionID");
5524  const char *conference = astman_get_header(m, "Conference");
5525  char idText[80] = "";
5526  struct ast_conference *cnf;
5527  struct ast_conf_user *user;
5528  struct ao2_iterator user_iter;
5529  int total = 0;
5530 
5531  if (!ast_strlen_zero(actionid))
5532  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5533 
5534  if (AST_LIST_EMPTY(&confs)) {
5535  astman_send_error(s, m, "No active conferences.");
5536  return 0;
5537  }
5538 
5539  astman_send_listack(s, m, "Meetme user list will follow", "start");
5540 
5541  /* Find the right conference */
5542  AST_LIST_LOCK(&confs);
5543  AST_LIST_TRAVERSE(&confs, cnf, list) {
5544  /* If we ask for one particular, and this isn't it, skip it */
5545  if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
5546  continue;
5547 
5548  /* Show all the users */
5549  user_iter = ao2_iterator_init(cnf->usercontainer, 0);
5550  while ((user = ao2_iterator_next(&user_iter))) {
5551  total++;
5552  astman_append(s,
5553  "Event: MeetmeList\r\n"
5554  "%s"
5555  "Conference: %s\r\n"
5556  "UserNumber: %d\r\n"
5557  "CallerIDNum: %s\r\n"
5558  "CallerIDName: %s\r\n"
5559  "ConnectedLineNum: %s\r\n"
5560  "ConnectedLineName: %s\r\n"
5561  "Channel: %s\r\n"
5562  "Admin: %s\r\n"
5563  "Role: %s\r\n"
5564  "MarkedUser: %s\r\n"
5565  "Muted: %s\r\n"
5566  "Talking: %s\r\n"
5567  "\r\n",
5568  idText,
5569  cnf->confno,
5570  user->user_no,
5571  S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
5572  S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
5574  S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<no name>"),
5575  ast_channel_name(user->chan),
5576  ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
5577  ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
5578  ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
5579  user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
5580  user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
5581  ao2_ref(user, -1);
5582  }
5583  ao2_iterator_destroy(&user_iter);
5584  }
5586 
5587  /* Send final confirmation */
5588  astman_send_list_complete_start(s, m, "MeetmeListComplete", total);
5590  return 0;
5591 }
static char user[512]
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
struct ast_party_id id
Connected party ID.
Definition: channel.h:459
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
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:3237
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
char * str
Subscriber name (Malloced)
Definition: channel.h:265
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
The MeetMe User object.
Definition: app_meetme.c:896
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#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:85
struct ast_flags64 userflags
Definition: app_meetme.c:898
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ao2_container * usercontainer
Definition: app_meetme.c:875
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
const char * ast_channel_name(const struct ast_channel *chan)
static int total
Definition: res_adsi.c:968
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
The MeetMe Conference object.
Definition: app_meetme.c:842
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
struct ast_channel * chan
Definition: app_meetme.c:900
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845
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:3201
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343
#define ast_test_flag64(p, flag)
Definition: utils.h:120

◆ action_meetmelistrooms()

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

Definition at line 5593 of file app_meetme.c.

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().

5594 {
5595  const char *actionid = astman_get_header(m, "ActionID");
5596  char idText[80] = "";
5597  struct ast_conference *cnf;
5598  int totalitems = 0;
5599  int hr, min, sec;
5600  time_t now;
5601  char markedusers[5];
5602 
5603  if (!ast_strlen_zero(actionid)) {
5604  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5605  }
5606 
5607  if (AST_LIST_EMPTY(&confs)) {
5608  astman_send_error(s, m, "No active conferences.");
5609  return 0;
5610  }
5611 
5612  astman_send_listack(s, m, "Meetme conferences will follow", "start");
5613 
5614  now = time(NULL);
5615 
5616  /* Traverse the conference list */
5617  AST_LIST_LOCK(&confs);
5618  AST_LIST_TRAVERSE(&confs, cnf, list) {
5619  totalitems++;
5620 
5621  if (cnf->markedusers == 0) {
5622  strcpy(markedusers, "N/A");
5623  } else {
5624  sprintf(markedusers, "%.4d", cnf->markedusers);
5625  }
5626  hr = (now - cnf->start) / 3600;
5627  min = ((now - cnf->start) % 3600) / 60;
5628  sec = (now - cnf->start) % 60;
5629 
5630  astman_append(s,
5631  "Event: MeetmeListRooms\r\n"
5632  "%s"
5633  "Conference: %s\r\n"
5634  "Parties: %d\r\n"
5635  "Marked: %s\r\n"
5636  "Activity: %2.2d:%2.2d:%2.2d\r\n"
5637  "Creation: %s\r\n"
5638  "Locked: %s\r\n"
5639  "\r\n",
5640  idText,
5641  cnf->confno,
5642  cnf->users,
5643  markedusers,
5644  hr, min, sec,
5645  cnf->isdynamic ? "Dynamic" : "Static",
5646  cnf->locked ? "Yes" : "No");
5647  }
5649 
5650  /* Send final confirmation */
5651  astman_send_list_complete_start(s, m, "MeetmeListRoomsComplete", totalitems);
5653  return 0;
5654 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
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:3237
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
unsigned int isdynamic
Definition: app_meetme.c:857
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define NULL
Definition: resample.c:96
unsigned int locked
Definition: app_meetme.c:858
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
The MeetMe Conference object.
Definition: app_meetme.c:842
struct ast_conference::@39 list
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
#define min(a, b)
Definition: f2c.h:197
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845
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:3201

◆ action_meetmemute()

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

Definition at line 5511 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

5512 {
5513  return meetmemute(s, m, 1);
5514 }
static int meetmemute(struct mansession *s, const struct message *m, int mute)
Definition: app_meetme.c:5451

◆ action_meetmeunmute()

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

Definition at line 5516 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

5517 {
5518  return meetmemute(s, m, 0);
5519 }
static int meetmemute(struct mansession *s, const struct message *m, int mute)
Definition: app_meetme.c:5451

◆ admin_exec()

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 5225 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_callback, ao2_cleanup, ao2_find, ao2_ref, 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, 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 meetme_cmd_helper(), meetme_stasis_generate_msg(), run_station(), sla_station_exec(), and sla_stop_ringing_trunk().

5225  {
5226  char *params;
5227  struct ast_conference *cnf;
5228  struct ast_conf_user *user = NULL;
5230  AST_APP_ARG(confno);
5231  AST_APP_ARG(command);
5232  AST_APP_ARG(user);
5233  );
5234  int res = 0;
5235 
5236  if (ast_strlen_zero(data)) {
5237  ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
5238  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5239  return -1;
5240  }
5241 
5242  params = ast_strdupa(data);
5243  AST_STANDARD_APP_ARGS(args, params);
5244 
5245  if (!args.command) {
5246  ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
5247  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5248  return -1;
5249  }
5250 
5251  AST_LIST_LOCK(&confs);
5252  AST_LIST_TRAVERSE(&confs, cnf, list) {
5253  if (!strcmp(cnf->confno, args.confno))
5254  break;
5255  }
5256 
5257  if (!cnf) {
5258  ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
5260  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
5261  return 0;
5262  }
5263 
5265 
5266  if (args.user) {
5267  user = find_user(cnf, args.user);
5268  if (!user) {
5269  ast_log(LOG_NOTICE, "Specified User not found!\n");
5270  res = -2;
5271  goto usernotfound;
5272  }
5273  } else {
5274  /* fail for commands that require a user */
5275  switch (*args.command) {
5276  case 'm': /* Unmute */
5277  case 'M': /* Mute */
5278  case 't': /* Lower user's talk volume */
5279  case 'T': /* Raise user's talk volume */
5280  case 'u': /* Lower user's listen volume */
5281  case 'U': /* Raise user's listen volume */
5282  case 'r': /* Reset user's volume level */
5283  case 'k': /* Kick user */
5284  res = -2;
5285  ast_log(LOG_NOTICE, "No user specified!\n");
5286  goto usernotfound;
5287  default:
5288  break;
5289  }
5290  }
5291 
5292  switch (*args.command) {
5293  case 76: /* L: Lock */
5294  cnf->locked = 1;
5295  break;
5296  case 108: /* l: Unlock */
5297  cnf->locked = 0;
5298  break;
5299  case 75: /* K: kick all users */
5301  break;
5302  case 101: /* e: Eject last user*/
5303  {
5304  int max_no = 0;
5305  RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
5306 
5308  eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
5309  if (!eject_user) {
5310  res = -1;
5311  ast_log(LOG_NOTICE, "No last user to kick!\n");
5312  break;
5313  }
5314 
5315  if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
5316  eject_user->adminflags |= ADMINFLAG_KICKME;
5317  } else {
5318  res = -1;
5319  ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
5320  }
5321  break;
5322  }
5323  case 77: /* M: Mute */
5324  user->adminflags |= ADMINFLAG_MUTED;
5325  break;
5326  case 78: /* N: Mute all (non-admin) users */
5328  break;
5329  case 109: /* m: Unmute */
5331  break;
5332  case 110: /* n: Unmute all users */
5334  break;
5335  case 107: /* k: Kick user */
5336  user->adminflags |= ADMINFLAG_KICKME;
5337  break;
5338  case 118: /* v: Lower all users listen volume */
5340  break;
5341  case 86: /* V: Raise all users listen volume */
5343  break;
5344  case 115: /* s: Lower all users speaking volume */
5346  break;
5347  case 83: /* S: Raise all users speaking volume */
5349  break;
5350  case 82: /* R: Reset all volume levels */
5352  break;
5353  case 114: /* r: Reset user's volume level */
5354  reset_volumes(user);
5355  break;
5356  case 85: /* U: Raise user's listen volume */
5357  tweak_listen_volume(user, VOL_UP);
5358  break;
5359  case 117: /* u: Lower user's listen volume */
5361  break;
5362  case 84: /* T: Raise user's talk volume */
5363  tweak_talk_volume(user, VOL_UP);
5364  break;
5365  case 116: /* t: Lower user's talk volume */
5366  tweak_talk_volume(user, VOL_DOWN);
5367  break;
5368  case 'E': /* E: Extend conference */
5369  if (rt_extend_conf(args.confno)) {
5370  res = -1;
5371  }
5372  break;
5373  }
5374 
5375  if (args.user) {
5376  /* decrement reference from find_user */
5377  ao2_ref(user, -1);
5378  }
5379 usernotfound:
5381 
5382  dispose_conf(cnf);
5383  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
5384 
5385  return 0;
5386 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static struct ast_conf_user * find_user(struct ast_conference *conf, const char *callerident)
Definition: app_meetme.c:5162
static int dispose_conf(struct ast_conference *conf)
Decrement reference counts, as incremented by find_conf()
Definition: app_meetme.c:2504
static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1494
static int rt_extend_conf(const char *confno)
Definition: app_meetme.c:2523
static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2727
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static int user_listen_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5175
static int user_reset_vol_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5203
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
const char * args
#define NULL
Definition: resample.c:96
struct ast_conf_user::@41 list
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
unsigned int locked
Definition: app_meetme.c:858
static int user_max_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1579
#define ast_strlen_zero(foo)
Definition: strings.h:52
static int user_listen_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5182
static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2716
#define ast_log
Definition: astobj2.c:42
#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:911
The MeetMe User object.
Definition: app_meetme.c:896
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1506
static void reset_volumes(struct ast_conf_user *user)
Definition: app_meetme.c:1518
static int user_talk_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5189
#define LOG_NOTICE
Definition: logger.h:263
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * usercontainer
Definition: app_meetme.c:875
structure to hold users read from users.conf
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...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
The MeetMe Conference object.
Definition: app_meetme.c:842
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
static int user_talk_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5196
static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2738
#define AST_APP_ARG(name)
Define an application argument.
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845
#define ast_test_flag64(p, flag)
Definition: utils.h:120

◆ announce_thread()

static void* announce_thread ( void *  data)
static

Definition at line 2615 of file app_meetme.c.

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread_stop, announce_listitem::announcetype, 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, announce_listitem::confchan, announce_listitem::confusers, get_announce_filename(), announce_listitem::language, announce_listitem::namerecloc, NULL, PATH_MAX, and announce_listitem::vmrec.

Referenced by conf_run().

2616 {
2617  struct announce_listitem *current;
2618  struct ast_conference *conf = data;
2619  int res;
2620  char filename[PATH_MAX] = "";
2622  AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2623 
2624  while (!conf->announcethread_stop) {
2626  if (conf->announcethread_stop) {
2628  break;
2629  }
2630  if (AST_LIST_EMPTY(&conf->announcelist))
2632 
2633  AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2635 
2637  if (conf->announcethread_stop) {
2638  break;
2639  }
2640 
2641  for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2642  ast_debug(1, "About to play %s\n", current->namerecloc);
2643  if (!ast_fileexists(current->namerecloc, NULL, NULL))
2644  continue;
2645  if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2646  if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2647  res = ast_waitstream(current->confchan, "");
2648  if (!res) {
2649  ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2650  if (!ast_streamfile(current->confchan, filename, current->language))
2651  ast_waitstream(current->confchan, "");
2652  }
2653  }
2654  if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2655  /* only remove it if it isn't a VM recording file */
2656  ast_filedelete(current->namerecloc, NULL);
2657  }
2658  }
2659  }
2660 
2661  /* thread marked to stop, clean up */
2662  while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2663  /* only delete if it's a vm rec */
2664  if (!current->vmrec) {
2665  ast_filedelete(current->namerecloc, NULL);
2666  }
2667  ao2_ref(current, -1);
2668  }
2669  return NULL;
2670 }
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
static const char * get_announce_filename(enum announcetypes type)
Definition: app_meetme.c:2601
struct ast_channel * confchan
Definition: app_meetme.c:835
struct ast_conference::@40 announcelist
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1098
All configuration options for statsd client.
Definition: res_statsd.c:95
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
ast_mutex_t announcelistlock
Definition: app_meetme.c:883
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
char namerecloc[PATH_MAX]
Definition: app_meetme.c:833
char language[MAX_LANGUAGE]
Definition: app_meetme.c:834
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
ast_cond_t announcelist_addition
Definition: app_meetme.c:881
unsigned int announcethread_stop
Definition: app_meetme.c:880
Definition: search.h:40
enum announcetypes announcetype
Definition: app_meetme.c:838
#define PATH_MAX
Definition: asterisk.h:40
The MeetMe Conference object.
Definition: app_meetme.c:842
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:782

◆ answer_trunk_chan()

static void answer_trunk_chan ( struct ast_channel chan)
static

Definition at line 6062 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

6063 {
6064  ast_answer(chan);
6065  ast_indicate(chan, -1);
6066 }
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

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

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, 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_station_exec(), and sla_trunk_exec().

1609 {
1610  struct ast_conference *cnf;
1611  struct dahdi_confinfo dahdic = { 0, };
1612  int confno_int = 0;
1614 
1615  AST_LIST_LOCK(&confs);
1616 
1617  AST_LIST_TRAVERSE(&confs, cnf, list) {
1618  if (!strcmp(confno, cnf->confno))
1619  break;
1620  }
1621 
1622  if (cnf || (!make && !dynamic) || !cap_slin)
1623  goto cnfout;
1624 
1625  ast_format_cap_append(cap_slin, ast_format_slin, 0);
1626  /* Make a new one */
1627  cnf = ast_calloc(1, sizeof(*cnf));
1628  if (!cnf) {
1629  goto cnfout;
1630  }
1631 
1633  NULL, user_no_cmp);
1634  if (!cnf->usercontainer) {
1635  goto cnfout;
1636  }
1637 
1638  ast_mutex_init(&cnf->playlock);
1639  ast_mutex_init(&cnf->listenlock);
1644  ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1645  ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1646  ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1647  ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
1648 
1649  /* Setup a new dahdi conference */
1650  dahdic.confno = -1;
1651  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1652  cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1653  if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1654  if (test) {
1655  /* if we are creating a conference for a unit test, it is not neccesary
1656  * to open a pseudo channel, so, if we fail continue creating
1657  * the conference. */
1658  ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1659  } else {
1660  ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1661  if (cnf->fd >= 0)
1662  close(cnf->fd);
1663  ao2_ref(cnf->usercontainer, -1);
1664  ast_mutex_destroy(&cnf->playlock);
1668  ast_free(cnf);
1669  cnf = NULL;
1670  goto cnfout;
1671  }
1672  }
1673 
1674  cnf->dahdiconf = dahdic.confno;
1675 
1676  /* Setup a new channel for playback of audio files */
1677  cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
1678  if (cnf->chan) {
1681  dahdic.chan = 0;
1682  dahdic.confno = cnf->dahdiconf;
1683  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1684  if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
1685  if (test) {
1686  ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1687  }
1688  ast_log(LOG_WARNING, "Error setting conference\n");
1689  if (cnf->chan)
1690  ast_hangup(cnf->chan);
1691  else
1692  close(cnf->fd);
1693  ao2_ref(cnf->usercontainer, -1);
1694  ast_mutex_destroy(&cnf->playlock);
1698  ast_free(cnf);
1699  cnf = NULL;
1700  goto cnfout;
1701  }
1702  }
1703 
1704  /* Fill the conference struct */
1705  cnf->start = time(NULL);
1706  cnf->maxusers = 0x7fffffff;
1707  cnf->isdynamic = dynamic ? 1 : 0;
1708  ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1709  AST_LIST_INSERT_HEAD(&confs, cnf, list);
1710 
1711  /* Reserve conference number in map */
1712  if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1713  conf_map[confno_int] = 1;
1714 
1715 cnfout:
1716  ao2_cleanup(cap_slin);
1717  if (cnf)
1718  ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1719 
1721 
1722  return cnf;
1723 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
struct ast_channel * chan
Definition: app_meetme.c:846
ast_mutex_t playlock
Definition: app_meetme.c:843
pthread_t recordthread
Definition: app_meetme.c:860
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
unsigned int isdynamic
Definition: app_meetme.c:857
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
ast_mutex_t listenlock
Definition: app_meetme.c:844
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
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
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:6444
static int user_no_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1567
#define ast_log
Definition: astobj2.c:42
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
const char * ast_channel_uniqueid(const struct ast_channel *chan)
char uniqueid[32]
Definition: app_meetme.c:867
char pin[MAX_PIN]
Definition: app_meetme.c:865
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
pthread_t announcethread
Definition: app_meetme.c:878
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
struct ao2_container * usercontainer
Definition: app_meetme.c:875
int ast_channel_fd(const struct ast_channel *chan, int which)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char pinadmin[MAX_PIN]
Definition: app_meetme.c:866
static unsigned int conf_map[1024]
Definition: app_meetme.c:888
#define ast_mutex_init(pmutex)
Definition: lock.h:184
#define ast_mutex_destroy(a)
Definition: lock.h:186
The MeetMe Conference object.
Definition: app_meetme.c:842
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
ast_mutex_t recordthreadlock
Definition: app_meetme.c:861
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845
ast_mutex_t announcethreadlock
Definition: app_meetme.c:879

◆ can_write()

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

Definition at line 2672 of file app_meetme.c.

References AST_STATE_UP, ast_test_flag64, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

2673 {
2674  if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
2675  return 1;
2676  }
2677 
2678  return (ast_channel_state(chan) == AST_STATE_UP);
2679 }
ast_channel_state
ast_channel states
Definition: channelstate.h:35
#define CONFFLAG_NO_AUDIO_UNTIL_UP
Definition: app_meetme.c:747
#define ast_test_flag64(p, flag)
Definition: utils.h:120

◆ careful_write()

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

Definition at line 1408 of file app_meetme.c.

References ast_log, errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

1409 {
1410  int res;
1411  int x;
1412 
1413  while (len) {
1414  if (block) {
1415  x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
1416  res = ioctl(fd, DAHDI_IOMUX, &x);
1417  } else
1418  res = 0;
1419  if (res >= 0)
1420  res = write(fd, data, len);
1421  if (res < 1) {
1422  if (errno != EAGAIN) {
1423  ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
1424  return -1;
1425  } else
1426  return 0;
1427  }
1428  len -= res;
1429  data += res;
1430  }
1431 
1432  return 0;
1433 }
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno

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

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, ao2_callback, ao2_ref, 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, user_chan_cb(), and ast_conference::usercontainer.

Referenced by load_module().

5390  {
5391  char *params;
5392  struct ast_conference *conf = NULL;
5393  struct ast_conf_user *user = NULL;
5396  AST_APP_ARG(command);
5397  );
5398 
5399  if (ast_strlen_zero(data)) {
5400  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
5401  return -1;
5402  }
5403 
5404  params = ast_strdupa(data);
5405  AST_STANDARD_APP_ARGS(args, params);
5406 
5407  if (!args.channel) {
5408  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
5409  return -1;
5410  }
5411 
5412  if (!args.command) {
5413  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
5414  return -1;
5415  }
5416 
5417  AST_LIST_LOCK(&confs);
5418  AST_LIST_TRAVERSE(&confs, conf, list) {
5419  if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
5420  break;
5421  }
5422  }
5423 
5424  if (!user) {
5425  ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
5427  return 0;
5428  }
5429 
5430  /* perform the specified action */
5431  switch (*args.command) {
5432  case 77: /* M: Mute */
5433  user->adminflags |= ADMINFLAG_MUTED;
5434  break;
5435  case 109: /* m: Unmute */
5436  user->adminflags &= ~ADMINFLAG_MUTED;
5437  break;
5438  case 107: /* k: Kick user */
5439  user->adminflags |= ADMINFLAG_KICKME;
5440  break;
5441  default: /* unknown command */
5442  ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
5443  break;
5444  }
5445  ao2_ref(user, -1);
5447 
5448  return 0;
5449 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static int user_chan_cb(void *obj, void *args, int flags)
Definition: app_meetme.c:5210
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Definition: muted.c:95
const char * args
#define NULL
Definition: resample.c:96
struct ast_conf_user::@41 list
#define ast_strlen_zero(foo)
Definition: strings.h:52
All configuration options for statsd client.
Definition: res_statsd.c:95
#define ast_log
Definition: astobj2.c:42
The MeetMe User object.
Definition: app_meetme.c:896
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define LOG_NOTICE
Definition: logger.h:263
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ao2_container * usercontainer
Definition: app_meetme.c:875
structure to hold users read from users.conf
The MeetMe Conference object.
Definition: app_meetme.c:842
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ complete_confno()

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

Definition at line 1725 of file app_meetme.c.

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().

1726 {
1727  struct ast_conference *cnf;
1728  char *ret = NULL;
1729  int which = 0;
1730  int len = strlen(word);
1731 
1732  AST_LIST_LOCK(&confs);
1733  AST_LIST_TRAVERSE(&confs, cnf, list) {
1734  if (!strncmp(word, cnf->confno, len) && ++which > state) {
1735  /* dup before releasing the lock */
1736  ret = ast_strdup(cnf->confno);
1737  break;
1738  }
1739  }
1741  return ret;
1742 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
The MeetMe Conference object.
Definition: app_meetme.c:842
struct ast_conference::@39 list
short word
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845

◆ complete_meetmecmd_list()

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

Definition at line 1814 of file app_meetme.c.

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

Referenced by meetme_show_cmd().

1815 {
1816  int len;
1817 
1818  if (pos == 2) {
1819  len = strlen(word);
1820  if (!strncasecmp(word, STR_CONCISE, len)) {
1821  if (state == 0) {
1822  return ast_strdup(STR_CONCISE);
1823  }
1824  --state;
1825  }
1826 
1827  return complete_confno(word, state);
1828  }
1829  if (pos == 3 && state == 0) {
1830  char *saved = NULL;
1831  char *myline;
1832  char *confno;
1833 
1834  /* Extract the confno from the command line. */
1835  myline = ast_strdupa(line);
1836  strtok_r(myline, " ", &saved);
1837  strtok_r(NULL, " ", &saved);
1838  confno = strtok_r(NULL, " ", &saved);
1839 
1840  if (!strcasecmp(confno, STR_CONCISE)) {
1841  /* There is nothing valid in this position now. */
1842  return NULL;
1843  }
1844 
1845  len = strlen(word);
1846  if (!strncasecmp(word, STR_CONCISE, len)) {
1847  return ast_strdup(STR_CONCISE);
1848  }
1849  }
1850  return NULL;
1851 }
enum sip_cc_notify_state state
Definition: chan_sip.c:959
#define STR_CONCISE
Definition: app_meetme.c:644
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
short word
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1725
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845

◆ complete_meetmecmd_lock()

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

Definition at line 1806 of file app_meetme.c.

References complete_confno(), and NULL.

Referenced by meetme_lock_cmd().

1807 {
1808  if (pos == 2) {
1809  return complete_confno(word, state);
1810  }
1811  return NULL;
1812 }
#define NULL
Definition: resample.c:96
short word
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1725

◆ complete_meetmecmd_mute_kick()

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

Definition at line 1766 of file app_meetme.c.

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().

1767 {
1768  if (pos == 2) {
1769  return complete_confno(word, state);
1770  }
1771  if (pos == 3) {
1772  int len = strlen(word);
1773  char *ret = NULL;
1774  char *saved = NULL;
1775  char *myline;
1776  char *confno;
1777  struct ast_conference *cnf;
1778 
1779  if (!strncasecmp(word, "all", len)) {
1780  if (state == 0) {
1781  return ast_strdup("all");
1782  }
1783  --state;
1784  }
1785 
1786  /* Extract the confno from the command line. */
1787  myline = ast_strdupa(line);
1788  strtok_r(myline, " ", &saved);
1789  strtok_r(NULL, " ", &saved);
1790  confno = strtok_r(NULL, " ", &saved);
1791 
1792  AST_LIST_LOCK(&confs);
1793  AST_LIST_TRAVERSE(&confs, cnf, list) {
1794  if (!strcmp(confno, cnf->confno)) {
1795  ret = complete_userno(cnf, word, state);
1796  break;
1797  }
1798  }
1800 
1801  return ret;
1802  }
1803  return NULL;
1804 }
enum sip_cc_notify_state state
Definition: chan_sip.c:959
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static char * complete_userno(struct ast_conference *cnf, const char *word, int state)
Definition: app_meetme.c:1744
The MeetMe Conference object.
Definition: app_meetme.c:842
struct ast_conference::@39 list
short word
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1725
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845

◆ complete_userno()

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

Definition at line 1744 of file app_meetme.c.

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().

1745 {
1746  char usrno[50];
1747  struct ao2_iterator iter;
1748  struct ast_conf_user *usr;
1749  char *ret = NULL;
1750  int which = 0;
1751  int len = strlen(word);
1752 
1753  iter = ao2_iterator_init(cnf->usercontainer, 0);
1754  for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
1755  snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1756  if (!strncmp(word, usrno, len) && ++which > state) {
1757  ao2_ref(usr, -1);
1758  ret = ast_strdup(usrno);
1759  break;
1760  }
1761  }
1762  ao2_iterator_destroy(&iter);
1763  return ret;
1764 }
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
The MeetMe User object.
Definition: app_meetme.c:896
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
struct ao2_container * usercontainer
Definition: app_meetme.c:875
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
short word

◆ conf_exec()

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

The meetme() application.

Definition at line 4837 of file app_meetme.c.

References ast_conference::adminopts, 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_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, ast_variable::name, ast_variable::next, NULL, OPT_ARG_ARRAY_SIZE, options, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, SENTINEL, strsep(), ast_conference::useropts, ast_conference::users, ast_variable::value, and var.

Referenced by load_module().

4838 {
4839  int res = -1;
4840  char confno[MAX_CONFNUM] = "";
4841  int allowretry = 0;
4842  int retrycnt = 0;
4843  struct ast_conference *cnf = NULL;
4844  struct ast_flags64 confflags = {0};
4845  struct ast_flags config_flags = { 0 };
4846  int dynamic = 0;
4847  int empty = 0, empty_no_pin = 0;
4848  int always_prompt = 0;
4849  const char *notdata;
4850  char *info, the_pin[MAX_PIN] = "";
4852  AST_APP_ARG(confno);
4854  AST_APP_ARG(pin);
4855  );
4856  char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
4857 
4858  if (ast_strlen_zero(data)) {
4859  allowretry = 1;
4860  notdata = "";
4861  } else {
4862  notdata = data;
4863  }
4864 
4865  if (ast_channel_state(chan) != AST_STATE_UP)
4866  ast_answer(chan);
4867 
4868  info = ast_strdupa(notdata);
4869 
4870  AST_STANDARD_APP_ARGS(args, info);
4871 
4872  if (args.confno) {
4873  ast_copy_string(confno, args.confno, sizeof(confno));
4874  if (ast_strlen_zero(confno)) {
4875  allowretry = 1;
4876  }
4877  }
4878 
4879  if (args.pin)
4880  ast_copy_string(the_pin, args.pin, sizeof(the_pin));
4881 
4882  if (args.options) {
4883  ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
4884  dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
4885  if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
4886  strcpy(the_pin, "q");
4887 
4888  empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
4889  empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
4890  always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
4891  }
4892 
4893  do {
4894  if (retrycnt > 3)
4895  allowretry = 0;
4896  if (empty) {
4897  int i;
4898  struct ast_config *cfg;
4899  struct ast_variable *var;
4900  int confno_int;
4901 
4902  /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
4903  if ((empty_no_pin) || (!dynamic)) {
4904  cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4905  if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
4906  var = ast_variable_browse(cfg, "rooms");
4907  while (var) {
4908  char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
4909  if (!strcasecmp(var->name, "conf")) {
4910  int found = 0;
4911  ast_copy_string(parse, var->value, sizeof(parse));
4912  confno_tmp = strsep(&stringp, "|,");
4913  if (!dynamic) {
4914  /* For static: run through the list and see if this conference is empty */
4915  AST_LIST_LOCK(&confs);
4916  AST_LIST_TRAVERSE(&confs, cnf, list) {
4917  if (!strcmp(confno_tmp, cnf->confno)) {
4918  /* The conference exists, therefore it's not empty */
4919  found = 1;
4920  break;
4921  }
4922  }
4924  cnf = NULL;
4925  if (!found) {
4926  /* At this point, we have a confno_tmp (static conference) that is empty */
4927  if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
4928  /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4929  * Case 2: empty_no_pin and pin is blank (but not NULL)
4930  * Case 3: not empty_no_pin
4931  */
4932  ast_copy_string(confno, confno_tmp, sizeof(confno));
4933  break;
4934  }
4935  }
4936  }
4937  }
4938  var = var->next;
4939  }
4940  ast_config_destroy(cfg);
4941  }
4942 
4943  if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
4944  const char *catg;
4945  for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
4946  const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
4947  const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
4948  if (ast_strlen_zero(confno_tmp)) {
4949  continue;
4950  }
4951  if (!dynamic) {
4952  int found = 0;
4953  /* For static: run through the list and see if this conference is empty */
4954  AST_LIST_LOCK(&confs);
4955  AST_LIST_TRAVERSE(&confs, cnf, list) {
4956  if (!strcmp(confno_tmp, cnf->confno)) {
4957  /* The conference exists, therefore it's not empty */
4958  found = 1;
4959  break;
4960  }
4961  }
4963  if (!found) {
4964  /* At this point, we have a confno_tmp (realtime conference) that is empty */
4965  if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
4966  /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4967  * Case 2: empty_no_pin and pin is blank (but not NULL)
4968  * Case 3: not empty_no_pin
4969  */
4970  ast_copy_string(confno, confno_tmp, sizeof(confno));
4971  break;
4972  }
4973  }
4974  }
4975  }
4976  ast_config_destroy(cfg);
4977  }
4978  }
4979 
4980  /* Select first conference number not in use */
4981  if (ast_strlen_zero(confno) && dynamic) {
4982  AST_LIST_LOCK(&confs);
4983  for (i = 0; i < ARRAY_LEN(conf_map); i++) {
4984  if (!conf_map[i]) {
4985  snprintf(confno, sizeof(confno), "%d", i);
4986  conf_map[i] = 1;
4987  break;
4988  }
4989  }
4991  }
4992 
4993  /* Not found? */
4994  if (ast_strlen_zero(confno)) {
4995  res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
4996  ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
4997  if (!res)
4998  ast_waitstream(chan, "");
4999  } else {
5000  if (sscanf(confno, "%30d", &confno_int) == 1) {
5001  if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
5002  res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
5003  if (!res) {
5004  ast_waitstream(chan, "");
5005  res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
5006  }
5007  }
5008  } else {
5009  ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
5010  }
5011  }
5012  }
5013 
5014  while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
5015  /* Prompt user for conference number */
5016  res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
5017  if (res < 0) {
5018  /* Don't try to validate when we catch an error */
5019  confno[0] = '\0';
5020  allowretry = 0;
5021  break;
5022  }
5023  }
5024  if (!ast_strlen_zero(confno)) {
5025  /* Check the validity of the conference */
5026  cnf = find_conf(chan, confno, 1, dynamic, the_pin,
5027  sizeof(the_pin), 1, &confflags);
5028  if (!cnf) {
5029  int too_early = 0;
5030 
5031  cnf = find_conf_realtime(chan, confno, 1, dynamic,
5032  the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
5033  if (rt_schedule && too_early)
5034  allowretry = 0;
5035  }
5036 
5037  if (!cnf) {
5038  if (allowretry) {
5039  confno[0] = '\0';
5040  res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
5041  if (!res)
5042  ast_waitstream(chan, "");
5043  res = -1;
5044  }
5045  } else {
5046  /* Conference requires a pin for specified access level */
5047  int req_pin = !ast_strlen_zero(cnf->pin) ||
5048  (!ast_strlen_zero(cnf->pinadmin) &&
5049  ast_test_flag64(&confflags, CONFFLAG_ADMIN));
5050  /* The following logic was derived from a
5051  * 4 variable truth table and defines which
5052  * circumstances are not exempt from pin
5053  * checking.
5054  * If this needs to be modified, write the
5055  * truth table back out from the boolean
5056  * expression AB+A'D+C', change the erroneous
5057  * result, and rederive the expression.
5058  * Variables:
5059  * A: pin provided?
5060  * B: always prompt?
5061  * C: dynamic?
5062  * D: has users? */
5063  int not_exempt = !cnf->isdynamic;
5064  not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
5065  not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
5066  if (req_pin && not_exempt) {
5067  char pin[MAX_PIN] = "";
5068  int j;
5069 
5070  /* Allow the pin to be retried up to 3 times */
5071  for (j = 0; j < 3; j++) {
5072  if (*the_pin && (always_prompt == 0)) {
5073  ast_copy_string(pin, the_pin, sizeof(pin));
5074  res = 0;
5075  } else {
5076  /* Prompt user for pin if pin is required */
5077  ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
5078  "Channel: %s",
5079  ast_channel_name(chan));
5080  res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
5081  }
5082  if (res >= 0) {
5083  if ((!strcasecmp(pin, cnf->pin) &&
5084  (ast_strlen_zero(cnf->pinadmin) ||
5085  !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
5086  (!ast_strlen_zero(cnf->pinadmin) &&
5087  !strcasecmp(pin, cnf->pinadmin))) {
5088  /* Pin correct */
5089  allowretry = 0;
5090  if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
5091  if (!ast_strlen_zero(cnf->adminopts)) {
5092  char *opts = ast_strdupa(cnf->adminopts);
5093  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5094  }
5095  } else {
5096  if (!ast_strlen_zero(cnf->useropts)) {
5097  char *opts = ast_strdupa(cnf->useropts);
5098  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5099  }
5100  }
5101  /* Run the conference */
5102  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
5103  res = conf_run(chan, cnf, &confflags, optargs);
5104  break;
5105  } else {
5106  /* Pin invalid */
5107  if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
5108  res = ast_waitstream(chan, AST_DIGIT_ANY);
5109  ast_stopstream(chan);
5110  } else {
5111  ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
5112  break;
5113  }
5114  if (res < 0)
5115  break;
5116  pin[0] = res;
5117  pin[1] = '\0';
5118  res = -1;
5119  if (allowretry)
5120  confno[0] = '\0';
5121  }
5122  } else {
5123  /* failed when getting the pin */
5124  res = -1;
5125  allowretry = 0;
5126  /* see if we need to get rid of the conference */
5127  break;
5128  }
5129 
5130  /* Don't retry pin with a static pin */
5131  if (*the_pin && (always_prompt == 0)) {
5132  break;
5133  }
5134  }
5135  } else {
5136  /* No pin required */
5137  allowretry = 0;
5138 
5139  /* For RealTime conferences without a pin
5140  * should still support loading options
5141  */
5142  if (!ast_strlen_zero(cnf->useropts)) {
5143  char *opts = ast_strdupa(cnf->useropts);
5144  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5145  }
5146 
5147  /* Run the conference */
5148  res = conf_run(chan, cnf, &confflags, optargs);
5149  }
5150  dispose_conf(cnf);
5151  cnf = NULL;
5152  }
5153  }
5154  } while (allowretry);
5155 
5156  if (cnf)
5157  dispose_conf(cnf);
5158 
5159  return res;
5160 }
struct ast_variable * next
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static int dispose_conf(struct ast_conference *conf)
Decrement reference counts, as incremented by find_conf()
Definition: app_meetme.c:2504
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
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:4688
#define AST_DIGIT_ANY
Definition: file.h:48
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
unsigned int isdynamic
Definition: app_meetme.c:857
char * recordingformat
Definition: app_meetme.c:864
#define CONFIG_STATUS_FILEINVALID
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
static const struct ast_app_option meetme_opts[128]
Definition: app_meetme.c:800
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8349
const char * useropts
Definition: app_meetme.c:869
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
const char * args
#define NULL
Definition: resample.c:96
Structure used to handle a large number of boolean flags == used only in app_dial?
Definition: utils.h:204
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_strlen_zero(foo)
Definition: strings.h:52
static int rt_schedule
Definition: app_meetme.c:810
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
Definition: app_meetme.c:3177
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
#define ast_config_load(filename, flags)
Load a config file.
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:2911
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
char pin[MAX_PIN]
Definition: app_meetme.c:865
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
#define LOG_ERROR
Definition: logger.h:285
def info(msg)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
const char * adminopts
Definition: app_meetme.c:870
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:197
Structure used to handle boolean flags.
Definition: utils.h:199
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
char * strsep(char **str, const char *delims)
#define MAX_CONFNUM
Definition: app_meetme.c:819
#define MAX_SETTINGS
Definition: app_meetme.c:824
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
char pinadmin[MAX_PIN]
Definition: app_meetme.c:866
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
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:4500
const char * ast_channel_language(const struct ast_channel *chan)
static unsigned int conf_map[1024]
Definition: app_meetme.c:888
char * recordingfilename
Definition: app_meetme.c:863
#define MAX_PIN
Definition: app_meetme.c:820
static struct test_options options
The MeetMe Conference object.
Definition: app_meetme.c:842
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define CONFIG_FILE_NAME
Definition: app_meetme.c:642
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
#define AST_APP_ARG(name)
Define an application argument.
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845
#define ast_test_flag64(p, flag)
Definition: utils.h:120

◆ conf_flush()

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

Definition at line 2299 of file app_meetme.c.

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

Referenced by conf_run().

2300 {
2301  int x;
2302 
2303  /* read any frames that may be waiting on the channel
2304  and throw them away
2305  */
2306  if (chan) {
2307  struct ast_frame *f;
2308 
2309  /* when no frames are available, this will wait
2310  for 1 millisecond maximum
2311  */
2312  while (ast_waitfor(chan, 1) > 0) {
2313  f = ast_read(chan);
2314  if (f)
2315  ast_frfree(f);
2316  else /* channel was hung up or something else happened */
2317  break;
2318  }
2319  }
2320 
2321  /* flush any data sitting in the pseudo channel */
2322  x = DAHDI_FLUSH_ALL;
2323  if (ioctl(fd, DAHDI_FLUSH, &x))
2324  ast_log(LOG_WARNING, "Error flushing channel\n");
2325 
2326 }
#define LOG_WARNING
Definition: logger.h:274
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
#define ast_log
Definition: astobj2.c:42
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
#define ast_frfree(fr)
Data structure associated with a single frame of data.

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

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethread_stop, ast_conference::announcethreadlock, 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(), ast_conference::chan, ast_conference::fd, item, ast_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, meetme_stasis_generate_msg(), announce_listitem::namerecloc, NULL, ast_conference::origframe, ast_conference::playlock, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthreadlock, ast_conference::transframe, ast_conference::transpath, ast_conference::usercontainer, and announce_listitem::vmrec.

Referenced by dispose_conf().

2332 {
2333  int x;
2334  struct announce_listitem *item;
2335 
2336  AST_LIST_REMOVE(&confs, conf, list);
2337 
2338  meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
2339 
2340  if (conf->recording == MEETME_RECORD_ACTIVE) {
2343  while (1) {
2344  usleep(1);
2345  AST_LIST_LOCK(&confs);
2346  if (conf->recording == MEETME_RECORD_OFF)
2347  break;
2349  }
2350  }
2351 
2352  for (x = 0; x < AST_FRAME_BITS; x++) {
2353  if (conf->transframe[x])
2354  ast_frfree(conf->transframe[x]);
2355  if (conf->transpath[x])
2357  }
2358  if (conf->announcethread != AST_PTHREADT_NULL) {
2360  conf->announcethread_stop = 1;
2364  pthread_join(conf->announcethread, NULL);
2365 
2366  while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2367  /* If it's a voicemail greeting file we don't want to remove it */
2368  if (!item->vmrec){
2369  ast_filedelete(item->namerecloc, NULL);
2370  }
2371  ao2_ref(item, -1);
2372  }
2374  }
2375 
2376  if (conf->origframe)
2377  ast_frfree(conf->origframe);
2378  ast_hangup(conf->lchan);
2379  ast_hangup(conf->chan);
2380  if (conf->fd >= 0)
2381  close(conf->fd);
2382  if (conf->recordingfilename) {
2383  ast_free(conf->recordingfilename);
2384  }
2385  if (conf->usercontainer) {
2386  ao2_ref(conf->usercontainer, -1);
2387  }
2388  if (conf->recordingformat) {
2389  ast_free(conf->recordingformat);
2390  }
2391  ast_mutex_destroy(&conf->playlock);
2392  ast_mutex_destroy(&conf->listenlock);
2395  ast_free(conf);
2396 
2397  return 0;
2398 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
struct ast_channel * chan
Definition: app_meetme.c:846
ast_mutex_t playlock
Definition: app_meetme.c:843
#define AST_FRAME_BITS
Definition: app_meetme.c:664
struct ast_frame * origframe
Definition: app_meetme.c:873
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
char * recordingformat
Definition: app_meetme.c:864
struct ast_conference::@40 announcelist
struct ast_frame * transframe[32]
Definition: app_meetme.c:872
ast_mutex_t listenlock
Definition: app_meetme.c:844
static struct aco_type item
Definition: test_config.c:1463
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1098
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:855
#define ast_cond_signal(cond)
Definition: lock.h:201
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:1343
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2476
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
ast_mutex_t announcelistlock
Definition: app_meetme.c:883
enum recording_state recording
Definition: app_meetme.c:856
char namerecloc[PATH_MAX]
Definition: app_meetme.c:833
pthread_t announcethread
Definition: app_meetme.c:878
#define ast_free(a)
Definition: astmm.h:182
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
struct ao2_container * usercontainer
Definition: app_meetme.c:875
struct ast_trans_pvt * transpath[32]
Definition: app_meetme.c:874
#define ast_frfree(fr)
ast_cond_t announcelist_addition
Definition: app_meetme.c:881
unsigned int announcethread_stop
Definition: app_meetme.c:880
Definition: search.h:40
char * recordingfilename
Definition: app_meetme.c:863
struct ast_channel * lchan
Definition: app_meetme.c:847
#define ast_mutex_destroy(a)
Definition: lock.h:186
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:475
#define ast_mutex_unlock(a)
Definition: lock.h:188
ast_mutex_t recordthreadlock
Definition: app_meetme.c:861
ast_mutex_t announcethreadlock
Definition: app_meetme.c:879

◆ conf_play()

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

Definition at line 1526 of file app_meetme.c.

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(), ast_conference::confno, enter, ENTER, ast_conference::fd, leave, LEAVE, len(), ast_conference::markedusers, and NULL.

Referenced by conf_run().

1527 {
1528  unsigned char *data;
1529  int len;
1530  int res = -1;
1531 
1532  ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
1533  "Conference: %s\r\n"
1534  "Marked: %d",
1535  ast_channel_name(chan),
1536  conf->confno,
1537  conf->markedusers);
1538 
1539  if (!ast_check_hangup(chan))
1540  res = ast_autoservice_start(chan);
1541 
1542  AST_LIST_LOCK(&confs);
1543 
1544  switch(sound) {
1545  case ENTER:
1546  data = enter;
1547  len = sizeof(enter);
1548  break;
1549  case LEAVE:
1550  data = leave;
1551  len = sizeof(leave);
1552  break;
1553  default:
1554  data = NULL;
1555  len = 0;
1556  }
1557  if (data) {
1558  careful_write(conf->fd, data, len, 1);
1559  }
1560 
1562 
1563  if (!res)
1564  ast_autoservice_stop(chan);
1565 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
static int careful_write(int fd, unsigned char *data, int len, int block)
Definition: app_meetme.c:1408
static unsigned char leave[]
Definition: leave.h:12
static unsigned char enter[]
Definition: enter.h:12
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define NULL
Definition: resample.c:96
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const char * ast_channel_name(const struct ast_channel *chan)
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_name(), ast_log, ast_write(), ast_conf_user::chan, LOG_WARNING, user, and ast_conference::usercontainer.

Referenced by conf_run().

2402 {
2403  struct ast_conf_user *user;
2404  struct ao2_iterator user_iter;
2405 
2406  user_iter = ao2_iterator_init(conf->usercontainer, 0);
2407  while ((user = ao2_iterator_next(&user_iter))) {
2408  if (user == sender) {
2409  ao2_ref(user, -1);
2410  continue;
2411  }
2412  if (ast_write(user->chan, f) < 0)
2413  ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
2414  ao2_ref(user, -1);
2415  }
2416  ao2_iterator_destroy(&user_iter);
2417 }
static char user[512]
#define LOG_WARNING
Definition: logger.h:274
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_log
Definition: astobj2.c:42
The MeetMe User object.
Definition: app_meetme.c:896
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
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:5189
struct ao2_container * usercontainer
Definition: app_meetme.c:875
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_channel * chan
Definition: app_meetme.c:900
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ conf_run()

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

Definition at line 3177 of file app_meetme.c.

References volume::actual, ADMINFLAG_HANGUP, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, announce_thread(), ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethreadlock, announce_listitem::announcetype, ao2_alloc, ao2_callback, ao2_cleanup, ao2_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_audiohooks(), ast_channel_context(), ast_channel_fd(), ast_channel_language(), ast_channel_lock, ast_channel_macrocontext(), ast_channel_monitor(), ast_channel_name(), ast_channel_rawwriteformat(), ast_channel_setoption(), ast_channel_tech(), ast_channel_uniqueid(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag64, ast_cond_signal, ast_config_AST_SPOOL_DIR, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_DEVSTATE_NOT_CACHABLE, AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), ast_fileexists(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_compatibility_format2bitfield(), ast_format_slin, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_json_unref(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_moh_stop(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero, ast_strptime(), ast_test_flag64, ast_test_suite_event_notify, ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_variables_destroy(), ast_verb, ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), audio_buffers, ast_conference::bookid, buf, c, can_write(), careful_write(), ast_conference::chan, ast_conf_user::chan, conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), announce_listitem::confchan, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DONT_DENOISE, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROMSG, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_KILL_LAST_MAN_STANDING, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, announce_listitem::confusers, context, ast_conf_user::dahdichannel, ast_conference::dahdiconf, ast_frame::data, ast_frame::datalen, DATE_FORMAT, volume::desired, dtmfstr, ast_conf_user::end_sound, ast_conference::endalert, ast_conference::endtime, ENTER, errno, exitcontext, ast_frame_subclass::format, ast_frame::frametype, ast_conference::gmuted, ast_frame_subclass::integer, ast_conference::isdynamic, item, ast_conf_user::jointime, ast_conf_user::kicktime, announce_listitem::language, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, mailbox, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, meetme_menu(), meetme_stasis_generate_msg(), MENU_ADMIN, MENU_DISABLED, MENU_NORMAL, ast_variable::name, announce_listitem::namerecloc, ast_conf_user::namerecloc, ast_variable::next, NULL, OBJ_NODATA, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_INTROMSG, OPT_ARG_INTROUSER_VMREC, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, ast_conference::origframe, parse(), PATH_MAX, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conf_user::play_warning, ast_conference::playlock, ast_frame::ptr, RAII_VAR, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, ast_frame::samples, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, status_to_json(), strsep(), ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, THRESHOLD_SILENCE, ast_conf_user::timelimit, timeout, ast_conference::transframe, ast_conference::transpath, type, ast_conference::uniqueid, user_max_cmp(), ast_conf_user::user_no, user_set_hangup_cb(), ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, ast_variable::value, var, announce_listitem::vmrec, ast_conf_user::warning_freq, and ast_conf_user::warning_sound.

Referenced by conf_exec(), dial_trunk(), run_station(), sla_station_exec(), and sla_trunk_exec().

3178 {
3179  struct ast_conf_user *user = NULL;
3180  int fd;
3181  struct dahdi_confinfo dahdic, dahdic_empty;
3182  struct ast_frame *f;
3183  struct ast_channel *c;
3184  struct ast_frame fr;
3185  int outfd;
3186  int ms;
3187  int nfds;
3188  int res;
3189  int retrydahdi;
3190  int origfd;
3191  int musiconhold = 0, mohtempstopped = 0;
3192  int firstpass = 0;
3193  int lastmarked = 0;
3194  int currentmarked = 0;
3195  int ret = -1;
3196  int x;
3197  enum menu_modes menu_mode = MENU_DISABLED;
3198  int talkreq_manager = 0;
3199  int using_pseudo = 0;
3200  int duration = 20;
3201  int sent_event = 0;
3202  int checked = 0;
3203  int announcement_played = 0;
3204  struct timeval now;
3205  struct ast_dsp *dsp = NULL;
3206  struct ast_app *agi_app;
3207  char *agifile;
3208  const char *agifiledefault = "conf-background.agi", *tmpvar;
3209  char meetmesecs[30] = "";
3210  char exitcontext[AST_MAX_CONTEXT] = "";
3211  char recordingtmp[AST_MAX_EXTENSION * 2] = "";
3212  char members[10] = "";
3213  int dtmf = 0, opt_waitmarked_timeout = 0;
3214  time_t timeout = 0;
3215  struct dahdi_bufferinfo bi;
3216  char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
3217  char *buf = __buf + AST_FRIENDLY_OFFSET;
3218  char *exitkeys = NULL;
3219  unsigned int calldurationlimit = 0;
3220  long timelimit = 0;
3221  long play_warning = 0;
3222  long warning_freq = 0;
3223  const char *warning_sound = NULL;
3224  const char *end_sound = NULL;
3225  char *parse;
3226  long time_left_ms = 0;
3227  struct timeval nexteventts = { 0, };
3228  int to;
3229  int setusercount = 0;
3230  int confsilence = 0, totalsilence = 0;
3231  char *mailbox, *context;
3233 
3234  if (!cap_slin) {
3235  goto conf_run_cleanup;
3236  }
3237  ast_format_cap_append(cap_slin, ast_format_slin, 0);
3238 
3239  if (!(user = ao2_alloc(sizeof(*user), NULL))) {
3240  goto conf_run_cleanup;
3241  }
3242 
3243  /* Possible timeout waiting for marked user */
3244  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3245  !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
3246  (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
3247  (opt_waitmarked_timeout > 0)) {
3248  timeout = time(NULL) + opt_waitmarked_timeout;
3249  }
3250 
3252  calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
3253  ast_verb(3, "Setting call duration limit to %u seconds.\n", calldurationlimit);
3254  }
3255 
3257  char *limit_str, *warning_str, *warnfreq_str;
3258  const char *var;
3259 
3260  parse = optargs[OPT_ARG_DURATION_LIMIT];
3261  limit_str = strsep(&parse, ":");
3262  warning_str = strsep(&parse, ":");
3263  warnfreq_str = parse;
3264 
3265  timelimit = atol(limit_str);
3266  if (warning_str)
3267  play_warning = atol(warning_str);
3268  if (warnfreq_str)
3269  warning_freq = atol(warnfreq_str);
3270 
3271  if (!timelimit) {
3272  timelimit = play_warning = warning_freq = 0;
3273  warning_sound = NULL;
3274  } else if (play_warning > timelimit) {
3275  if (!warning_freq) {
3276  play_warning = 0;
3277  } else {
3278  while (play_warning > timelimit)
3279  play_warning -= warning_freq;
3280  if (play_warning < 1)
3281  play_warning = warning_freq = 0;
3282  }
3283  }
3284 
3285  ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
3286  if (play_warning) {
3287  ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
3288  }
3289  if (warning_freq) {
3290  ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
3291  }
3292 
3293  ast_channel_lock(chan);
3294  if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
3295  var = ast_strdupa(var);
3296  }
3297  ast_channel_unlock(chan);
3298 
3299  warning_sound = var ? var : "timeleft";
3300 
3301  ast_channel_lock(chan);
3302  if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
3303  var = ast_strdupa(var);
3304  }
3305  ast_channel_unlock(chan);
3306 
3307  end_sound = var ? var : NULL;
3308 
3309  /* undo effect of S(x) in case they are both used */
3310  calldurationlimit = 0;
3311  /* more efficient do it like S(x) does since no advanced opts */
3312  if (!play_warning && !end_sound && timelimit) {
3313  calldurationlimit = timelimit / 1000;
3314  timelimit = play_warning = warning_freq = 0;
3315  } else {
3316  ast_debug(2, "Limit Data for this call:\n");
3317  ast_debug(2, "- timelimit = %ld\n", timelimit);
3318  ast_debug(2, "- play_warning = %ld\n", play_warning);
3319  ast_debug(2, "- warning_freq = %ld\n", warning_freq);
3320  ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
3321  ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
3322  }
3323  }
3324 
3325  /* Get exit keys */
3326  if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
3327  if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
3328  exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
3329  else
3330  exitkeys = ast_strdupa("#"); /* Default */
3331  }
3332 
3333  if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
3334  if (!conf->recordingfilename) {
3335  const char *var;
3336  ast_channel_lock(chan);
3337  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3338  conf->recordingfilename = ast_strdup(var);
3339  }
3340  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3341  conf->recordingformat = ast_strdup(var);
3342  }
3343  ast_channel_unlock(chan);
3344  if (!conf->recordingfilename) {
3345  snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3346  conf->recordingfilename = ast_strdup(recordingtmp);
3347  }
3348  if (!conf->recordingformat) {
3349  conf->recordingformat = ast_strdup("wav");
3350  }
3351  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3352  conf->confno, conf->recordingfilename, conf->recordingformat);
3353  }
3354  }
3355 
3357  if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
3358  ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3361  dahdic.chan = 0;
3362  dahdic.confno = conf->dahdiconf;
3363  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
3364  if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
3365  ast_log(LOG_WARNING, "Error starting listen channel\n");
3366  ast_hangup(conf->lchan);
3367  conf->lchan = NULL;
3368  } else {
3370  }
3371  }
3373 
3375  if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3380  }
3382 
3383  time(&user->jointime);
3384 
3385  user->timelimit = timelimit;
3386  user->play_warning = play_warning;
3387  user->warning_freq = warning_freq;
3388  user->warning_sound = warning_sound;
3389  user->end_sound = end_sound;
3390 
3391  if (calldurationlimit > 0) {
3392  time(&user->kicktime);
3393  user->kicktime = user->kicktime + calldurationlimit;
3394  }
3395 
3396  if (ast_tvzero(user->start_time))
3397  user->start_time = ast_tvnow();
3398  time_left_ms = user->timelimit;
3399 
3400  if (user->timelimit) {
3401  nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3402  nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
3403  }
3404 
3405  if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
3406  /* Sorry, but this conference is locked! */
3407  if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
3408  ast_waitstream(chan, "");
3409  goto outrun;
3410  }
3411 
3412  ast_mutex_lock(&conf->playlock);
3413 
3414  if (rt_schedule && conf->maxusers) {
3415  if (conf->users >= conf->maxusers) {
3416  /* Sorry, but this confernce has reached the participant limit! */
3417  ast_mutex_unlock(&conf->playlock);
3418  if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
3419  ast_waitstream(chan, "");
3420  goto outrun;
3421  }
3422  }
3423 
3424  ao2_lock(conf->usercontainer);
3426  user->user_no++;
3427  ao2_link(conf->usercontainer, user);
3428  ao2_unlock(conf->usercontainer);
3429 
3430  user->chan = chan;
3431  user->userflags = *confflags;
3433  if (!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3434  user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
3435  }
3436  user->talking = -1;
3437 
3438  ast_mutex_unlock(&conf->playlock);
3439 
3441  char destdir[PATH_MAX];
3442 
3443  snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
3444 
3445  if (ast_mkdir(destdir, 0777) != 0) {
3446  ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
3447  goto outrun;
3448  }
3449 
3450  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
3451  context = ast_strdupa(optargs[OPT_ARG_INTROUSER_VMREC]);
3452  mailbox = strsep(&context, "@");
3453 
3454  if (ast_strlen_zero(mailbox)) {
3455  /* invalid input, clear the v flag*/
3457  ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
3458  } else {
3459  if (ast_strlen_zero(context)) {
3460  context = "default";
3461  }
3462  /* if there is no mailbox we don't need to do this logic */
3463  snprintf(user->namerecloc, sizeof(user->namerecloc),
3464  "%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
3465 
3466  /* if the greeting doesn't exist then use the temp file method instead, clear flag v */
3467  if (!ast_fileexists(user->namerecloc, NULL, NULL)){
3468  snprintf(user->namerecloc, sizeof(user->namerecloc),
3469  "%s/meetme-username-%s-%d", destdir,
3470  conf->confno, user->user_no);
3472  }
3473  }
3474  } else {
3475  snprintf(user->namerecloc, sizeof(user->namerecloc),
3476  "%s/meetme-username-%s-%d", destdir,
3477  conf->confno, user->user_no);
3478  }
3479 
3480  res = 0;
3482  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);
3483  else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
3484  res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
3485  if (res == -1)
3486  goto outrun;
3487 
3488  }
3489 
3490  ast_mutex_lock(&conf->playlock);
3491 
3492  if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
3493  conf->markedusers++;
3494  conf->users++;
3495  if (rt_log_members) {
3496  /* Update table */
3497  snprintf(members, sizeof(members), "%d", conf->users);
3498  ast_realtime_require_field("meetme",
3499  "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
3500  "members", RQ_UINTEGER1, strlen(members),
3501  NULL);
3502  ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
3503  }
3504  setusercount = 1;
3505 
3506  /* This device changed state now - if this is the first user */
3507  if (conf->users == 1)
3509 
3510  ast_mutex_unlock(&conf->playlock);
3511 
3512  /* return the unique ID of the conference */
3513  pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
3514 
3515  if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
3516  ast_channel_lock(chan);
3517  if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
3518  ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
3519  } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
3520  ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
3521  } else {
3522  ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
3523  }
3524  ast_channel_unlock(chan);
3525  }
3526 
3527  /* Play an arbitrary intro message */
3528  if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
3529  !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
3530  if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
3531  ast_waitstream(chan, "");
3532  }
3533  }
3534 
3535  if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
3536  if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
3537  if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
3538  ast_waitstream(chan, "");
3539  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
3540  if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
3541  ast_waitstream(chan, "");
3542  }
3543 
3544  if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
3545  int keepplaying = 1;
3546 
3547  if (conf->users == 2) {
3548  if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
3549  res = ast_waitstream(chan, AST_DIGIT_ANY);
3550  ast_stopstream(chan);
3551  if (res > 0)
3552  keepplaying = 0;
3553  else if (res == -1)
3554  goto outrun;
3555  }
3556  } else {
3557  if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
3558  res = ast_waitstream(chan, AST_DIGIT_ANY);
3559  ast_stopstream(chan);
3560  if (res > 0)
3561  keepplaying = 0;
3562  else if (res == -1)
3563  goto outrun;
3564  }
3565  if (keepplaying) {
3566  res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3567  if (res > 0)
3568  keepplaying = 0;
3569  else if (res == -1)
3570  goto outrun;
3571  }
3572  if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3573  res = ast_waitstream(chan, AST_DIGIT_ANY);
3574  ast_stopstream(chan);
3575  if (res > 0)
3576  keepplaying = 0;
3577  else if (res == -1)
3578  goto outrun;
3579  }
3580  }
3581  }
3582 
3583  if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
3584  /* We're leaving this alone until the state gets changed to up */
3585  ast_indicate(chan, -1);
3586  }
3587 
3588  if (ast_set_write_format(chan, ast_format_slin) < 0) {
3589  ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
3590  goto outrun;
3591  }
3592 
3593  if (ast_set_read_format(chan, ast_format_slin) < 0) {
3594  ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
3595  goto outrun;
3596  }
3597 
3598  /* Reduce background noise from each participant */
3599  if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE)) {
3600  ast_func_write(chan, "DENOISE(rx)", "on");
3601  }
3602 
3603  retrydahdi = (strcasecmp(ast_channel_tech(chan)->type, "DAHDI") || (ast_channel_audiohooks(chan) || ast_channel_monitor(chan)) ? 1 : 0);
3604  user->dahdichannel = !retrydahdi;
3605 
3606  dahdiretry:
3607  origfd = ast_channel_fd(chan, 0);
3608  if (retrydahdi) {
3609  /* open pseudo in non-blocking mode */
3610  fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
3611  if (fd < 0) {
3612  ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
3613  goto outrun;
3614  }
3615  using_pseudo = 1;
3616  /* Setup buffering information */
3617  memset(&bi, 0, sizeof(bi));
3618  bi.bufsize = CONF_SIZE / 2;
3619  bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
3620  bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
3621  bi.numbufs = audio_buffers;
3622  if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
3623  ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
3624  close(fd);
3625  goto outrun;
3626  }
3627  x = 1;
3628  if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
3629  ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
3630  close(fd);
3631  goto outrun;
3632  }
3633  nfds = 1;
3634  } else {
3635  /* XXX Make sure we're not running on a pseudo channel XXX */
3636  fd = ast_channel_fd(chan, 0);
3637  nfds = 0;
3638  }
3639  memset(&dahdic, 0, sizeof(dahdic));
3640  memset(&dahdic_empty, 0, sizeof(dahdic_empty));
3641  /* Check to see if we're in a conference... */
3642  dahdic.chan = 0;
3643  if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
3644  ast_log(LOG_WARNING, "Error getting conference\n");
3645  close(fd);
3646  goto outrun;
3647  }
3648  if (dahdic.confmode) {
3649  /* Whoa, already in a conference... Retry... */
3650  if (!retrydahdi) {
3651  ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
3652  retrydahdi = 1;
3653  goto dahdiretry;
3654  }
3655  }
3656  memset(&dahdic, 0, sizeof(dahdic));
3657  /* Add us to the conference */
3658  dahdic.chan = 0;
3659  dahdic.confno = conf->dahdiconf;
3660 
3661  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
3663  struct announce_listitem *item;
3664  if (!(item = ao2_alloc(sizeof(*item), NULL)))
3665  goto outrun;
3666  ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
3667  ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
3668  item->confchan = conf->chan;
3669  item->confusers = conf->users;
3670  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
3671  item->vmrec = 1;
3672  }
3673  item->announcetype = CONF_HASJOIN;
3675  ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
3676  AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
3679 
3680  while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
3681  ;
3682  }
3683  ao2_ref(item, -1);
3684  }
3685 
3686  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
3687  dahdic.confmode = DAHDI_CONF_CONF;
3688  else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
3689  dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3690  else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
3691  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3692  else
3693  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3694 
3695  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3696  ast_log(LOG_WARNING, "Error setting conference\n");
3697  close(fd);
3698  goto outrun;
3699  }
3700  ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
3701 
3702  if (!sent_event) {
3703  meetme_stasis_generate_msg(conf, chan, user, meetme_join_type(), NULL);
3704  sent_event = 1;
3705  }
3706 
3707  if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
3708  !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3709  firstpass = 1;
3710  if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
3711  if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
3712  (conf->markedusers >= 1))) {
3713  conf_play(chan, conf, ENTER);
3714  }
3715  }
3716 
3717  conf_flush(fd, chan);
3718 
3719  if (dsp)
3720  ast_dsp_free(dsp);
3721 
3722  if (!(dsp = ast_dsp_new())) {
3723  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
3724  res = -1;
3725  }
3726 
3727  if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
3728  /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
3729  or use default filename of conf-background.agi */
3730 
3731  ast_channel_lock(chan);
3732  if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
3733  agifile = ast_strdupa(tmpvar);
3734  } else {
3735  agifile = ast_strdupa(agifiledefault);
3736  }
3737  ast_channel_unlock(chan);
3738 
3739  if (user->dahdichannel) {
3740  /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
3741  x = 1;
3742  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3743  }
3744  /* Find a pointer to the agi app and execute the script */
3745  agi_app = pbx_findapp("agi");
3746  if (agi_app) {
3747  ret = pbx_exec(chan, agi_app, agifile);
3748  } else {
3749  ast_log(LOG_WARNING, "Could not find application (agi)\n");
3750  ret = -2;
3751  }
3752  if (user->dahdichannel) {
3753  /* Remove CONFMUTE mode on DAHDI channel */
3754  x = 0;
3755  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3756  }
3757  } else {
3758  int lastusers = conf->users;
3759  if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
3760  /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
3761  x = 1;
3762  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3763  }
3764 
3765  for (;;) {
3766  int menu_was_active = 0;
3767 
3768  outfd = -1;
3769  ms = -1;
3770  now = ast_tvnow();
3771 
3772  if (rt_schedule && conf->endtime) {
3773  char currenttime[32];
3774  long localendtime = 0;
3775  int extended = 0;
3776  struct ast_tm tm;
3777  struct ast_variable *var, *origvar;
3778  struct timeval tmp;
3779 
3780  if (now.tv_sec % 60 == 0) {
3781  if (!checked) {
3782  ast_localtime(&now, &tm, NULL);
3783  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
3784  var = origvar = ast_load_realtime("meetme", "confno",
3785  conf->confno, "starttime <=", currenttime,
3786  "endtime >=", currenttime, NULL);
3787 
3788  for ( ; var; var = var->next) {
3789  if (!strcasecmp(var->name, "endtime")) {
3790  struct ast_tm endtime_tm;
3791  ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
3792  tmp = ast_mktime(&endtime_tm, NULL);
3793  localendtime = tmp.tv_sec;
3794  }
3795  }
3796  ast_variables_destroy(origvar);
3797 
3798  /* A conference can be extended from the
3799  Admin/User menu or by an external source */
3800  if (localendtime > conf->endtime){
3801  conf->endtime = localendtime;
3802  extended = 1;
3803  }
3804 
3805  if (conf->endtime && (now.tv_sec >= conf->endtime)) {
3806  ast_verbose("Quitting time...\n");
3807  goto outrun;
3808  }
3809 
3810  if (!announcement_played && conf->endalert) {
3811  if (now.tv_sec + conf->endalert >= conf->endtime) {
3812  if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
3813  ast_waitstream(chan, "");
3814  ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
3815  if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
3816  ast_waitstream(chan, "");
3817  if (musiconhold) {
3818  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3819  }
3820  announcement_played = 1;
3821  }
3822  }
3823 
3824  if (extended) {
3825  announcement_played = 0;
3826  }
3827 
3828  checked = 1;
3829  }
3830  } else {
3831  checked = 0;
3832  }
3833  }
3834 
3835  if (user->kicktime && (user->kicktime <= now.tv_sec)) {
3836  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3837  ret = 0;
3838  } else {
3839  ret = -1;
3840  }
3841  break;
3842  }
3843 
3844  to = -1;
3845  if (user->timelimit) {
3846  int minutes = 0, seconds = 0, remain = 0;
3847 
3848  to = ast_tvdiff_ms(nexteventts, now);
3849  if (to < 0) {
3850  to = 0;
3851  }
3852  time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
3853  if (time_left_ms < to) {
3854  to = time_left_ms;
3855  }
3856 
3857  if (time_left_ms <= 0) {
3858  if (user->end_sound) {
3859  res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
3860  res = ast_waitstream(chan, "");
3861  }
3862  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3863  ret = 0;
3864  } else {
3865  ret = -1;
3866  }
3867  break;
3868  }
3869 
3870  if (!to) {
3871  if (time_left_ms >= 5000) {
3872 
3873  remain = (time_left_ms + 500) / 1000;
3874  if (remain / 60 >= 1) {
3875  minutes = remain / 60;
3876  seconds = remain % 60;
3877  } else {
3878  seconds = remain;
3879  }
3880 
3881  /* force the time left to round up if appropriate */
3882  if (user->warning_sound && user->play_warning) {
3883  if (!strcmp(user->warning_sound, "timeleft")) {
3884 
3885  res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
3886  res = ast_waitstream(chan, "");
3887  if (minutes) {
3888  res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3889  res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
3890  res = ast_waitstream(chan, "");
3891  }
3892  if (seconds) {
3893  res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3894  res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
3895  res = ast_waitstream(chan, "");
3896  }
3897  } else {
3898  res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
3899  res = ast_waitstream(chan, "");
3900  }
3901  if (musiconhold) {
3902  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3903  }
3904  }
3905  }
3906  if (user->warning_freq) {
3907  nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
3908  } else {
3909  nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3910  }
3911  }
3912  }
3913 
3914  now = ast_tvnow();
3915  if (timeout && now.tv_sec >= timeout) {
3916  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3917  ret = 0;
3918  } else {
3919  ret = -1;
3920  }
3921  break;
3922  }
3923 
3924  /* if we have just exited from the menu, and the user had a channel-driver
3925  volume adjustment, restore it
3926  */
3927  if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
3928  set_talk_volume(user, user->listen.desired);
3929  }
3930 
3931  menu_was_active = menu_mode;
3932 
3933  currentmarked = conf->markedusers;
3934  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3935  ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
3936  ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3937  lastmarked == 0) {
3938  if (currentmarked == 1 && conf->users > 1) {
3939  ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3940  if (conf->users - 1 == 1) {
3941  if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
3942  ast_waitstream(chan, "");
3943  }
3944  } else {
3945  if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
3946  ast_waitstream(chan, "");
3947  }
3948  }
3949  }
3950  if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
3951  if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
3952  ast_waitstream(chan, "");
3953  }
3954  }
3955  }
3956 
3957  /* Update the struct with the actual confflags */
3958  user->userflags = *confflags;
3959 
3960  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
3961  if (currentmarked == 0) {
3962  if (lastmarked != 0) {
3963  if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
3964  if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
3965  ast_waitstream(chan, "");
3966  }
3967  }
3968  if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
3969  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3970  ret = 0;
3971  }
3972  break;
3973  } else {
3974  dahdic.confmode = DAHDI_CONF_CONF;
3975  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3976  ast_log(LOG_WARNING, "Error setting conference\n");
3977  close(fd);
3978  goto outrun;
3979  }
3980  }
3981  }
3982  if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
3983  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3984  musiconhold = 1;
3985  }
3986  } else if (currentmarked >= 1 && lastmarked == 0) {
3987  /* Marked user entered, so cancel timeout */
3988  timeout = 0;
3989  if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
3990  dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3991  } else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
3992  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3993  } else {
3994  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3995  }
3996  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3997  ast_log(LOG_WARNING, "Error setting conference\n");
3998  close(fd);
3999  goto outrun;
4000  }
4001  if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
4002  ast_moh_stop(chan);
4003  musiconhold = 0;
4004  }
4005  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4006  !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
4007  if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
4008  ast_waitstream(chan, "");
4009  }
4010  conf_play(chan, conf, ENTER);
4011  }
4012  }
4013  }
4014 
4015  /* trying to add moh for single person conf */
4016  if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
4017  if (conf->users == 1) {
4018  if (!musiconhold) {
4019  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4020  musiconhold = 1;
4021  }
4022  } else {
4023  if (musiconhold) {
4024  ast_moh_stop(chan);
4025  musiconhold = 0;
4026  }
4027  }
4028  }
4029 
4030  /* Leave if the last marked user left */
4031  if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
4032  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
4033  ret = 0;
4034  } else {
4035  ret = -1;
4036  }
4037  break;
4038  }
4039 
4040  /* Throw a TestEvent if a user exit did not cause this user to leave the conference */
4041  if (conf->users != lastusers) {
4042  if (conf->users < lastusers) {
4043  ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
4044  }
4045  lastusers = conf->users;
4046  }
4047 
4048  /* Check if my modes have changed */
4049 
4050  /* If I should be muted but am still talker, mute me */
4051  if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
4052  RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
4053  dahdic.confmode ^= DAHDI_CONF_TALKER;
4054  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4055  ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
4056  ret = -1;
4057  break;
4058  }
4059 
4060  /* Indicate user is not talking anymore - change him to unmonitored state */
4062  set_user_talking(chan, conf, user, -1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
4063  }
4064  meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
4065  }
4066 
4067  /* If I should be un-muted but am not talker, un-mute me */
4068  if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
4069  RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
4070  dahdic.confmode |= DAHDI_CONF_TALKER;
4071  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4072  ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
4073  ret = -1;
4074  break;
4075  }
4076  meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
4077  }
4078 
4079  if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
4080  (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
4081 
4082  RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
4083  talkreq_manager = 1;
4084  meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
4085  }
4086 
4087  if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
4088  !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
4089  RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
4090  talkreq_manager = 0;
4091  meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
4092  }
4093 
4094  /* If user have been hung up, exit the conference */
4095  if (user->adminflags & ADMINFLAG_HANGUP) {
4096  ret = 0;
4097  break;
4098  }
4099 
4100  /* If I have been kicked, exit the conference */
4101  if (user->adminflags & ADMINFLAG_KICKME) {
4102  /* You have been kicked. */
4103  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4104  !ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
4105  ast_waitstream(chan, "");
4106  }
4107  ret = 0;
4108  break;
4109  }
4110 
4111  /* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
4112  if (ast_check_hangup(chan)) {
4113  break;
4114  }
4115 
4116  c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
4117 
4118  if (c) {
4119  char dtmfstr[2] = "";
4120 
4121  if (ast_channel_fd(c, 0) != origfd || (user->dahdichannel && (ast_channel_audiohooks(c) || ast_channel_monitor(c)))) {
4122  if (using_pseudo) {
4123  /* Kill old pseudo */
4124  close(fd);
4125  using_pseudo = 0;
4126  }
4127  ast_debug(1, "Ooh, something swapped out under us, starting over\n");
4128  retrydahdi = (strcasecmp(ast_channel_tech(c)->type, "DAHDI") || (ast_channel_audiohooks(c) || ast_channel_monitor(c)) ? 1 : 0);
4129  user->dahdichannel = !retrydahdi;
4130  goto dahdiretry;
4131  }
4133  f = ast_read_noaudio(c);
4134  } else {
4135  f = ast_read(c);
4136  }
4137  if (!f) {
4138  break;
4139  }
4140  if (f->frametype == AST_FRAME_DTMF) {
4141  dtmfstr[0] = f->subclass.integer;
4142  dtmfstr[1] = '\0';
4143  }
4144 
4146  if (user->talk.actual) {
4148  }
4149 
4151  if (user->talking == -1) {
4152  user->talking = 0;
4153  }
4154 
4155  res = ast_dsp_silence(dsp, f, &totalsilence);
4156  if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
4157  set_user_talking(chan, conf, user, 1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
4158  }
4159 
4160  if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
4161  set_user_talking(chan, conf, user, 0, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
4162  }
4163  }
4164  if (using_pseudo) {
4165  /* Absolutely do _not_ use careful_write here...
4166  it is important that we read data from the channel
4167  as fast as it arrives, and feed it into the conference.
4168  The buffering in the pseudo channel will take care of any
4169  timing differences, unless they are so drastic as to lose
4170  audio frames (in which case carefully writing would only
4171  have delayed the audio even further).
4172  */
4173  /* As it turns out, we do want to use careful write. We just
4174  don't want to block, but we do want to at least *try*
4175  to write out all the samples.
4176  */
4177  if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
4178  careful_write(fd, f->data.ptr, f->datalen, 0);
4179  }
4180  }
4181  } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
4182  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4183  conf_queue_dtmf(conf, user, f);
4184  }
4185  /* Take out of conference */
4186  if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
4187  ast_log(LOG_WARNING, "Error setting conference\n");
4188  close(fd);
4189  ast_frfree(f);
4190  goto outrun;
4191  }
4192 
4193  /* if we are entering the menu, and the user has a channel-driver
4194  volume adjustment, clear it
4195  */
4196  if (!menu_mode && user->talk.desired && !user->talk.actual) {
4197  set_talk_volume(user, 0);
4198  }
4199 
4200  if (musiconhold) {
4201  ast_moh_stop(chan);
4202  } else if (!menu_mode) {
4203  char *menu_to_play;
4204  if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
4205  menu_mode = MENU_ADMIN;
4206  menu_to_play = "conf-adminmenu-18";
4207  } else {
4208  menu_mode = MENU_NORMAL;
4209  menu_to_play = "conf-usermenu-162";
4210  }
4211 
4212  if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
4213  dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
4214  ast_stopstream(chan);
4215  } else {
4216  dtmf = 0;
4217  }
4218  } else {
4219  dtmf = f->subclass.integer;
4220  }
4221 
4222  if (dtmf > 0) {
4223  meetme_menu(&menu_mode, &dtmf, conf, confflags,
4224  chan, user, recordingtmp, sizeof(recordingtmp), cap_slin);
4225  }
4226 
4227  if (musiconhold && !menu_mode) {
4228  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4229  }
4230 
4231  /* Put back into conference */
4232  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4233  ast_log(LOG_WARNING, "Error setting conference\n");
4234  close(fd);
4235  ast_frfree(f);
4236  goto outrun;
4237  }
4238 
4239  conf_flush(fd, chan);
4240  /*
4241  * Since options using DTMF could absorb DTMF meant for the
4242  * conference menu, we have to check them after the menu.
4243  */
4244  } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
4245  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4246  conf_queue_dtmf(conf, user, f);
4247  }
4248 
4249  if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
4250  ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
4251  ret = 0;
4252  ast_frfree(f);
4253  break;
4254  } else {
4255  ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
4256  }
4257  } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
4258  (strchr(exitkeys, f->subclass.integer))) {
4259  pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
4260 
4261  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4262  conf_queue_dtmf(conf, user, f);