Asterisk - The Open Source Telephony Project  GIT-master-a1fa8df
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"

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, .optional_modules = "func_speex", }
 
static const char *const app = "MeetMe"
 
static const char *const app2 = "MeetMeCount"
 
static const char *const app3 = "MeetMeAdmin"
 
static const char *const app4 = "MeetMeChannelAdmin"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int audio_buffers
 The number of audio buffers to be allocated on pseudo channels when in a conference. More...
 
static struct ast_cli_entry cli_meetme []
 
static unsigned int conf_map [1024] = {0, }
 
static struct confs confs = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int earlyalert
 
static int endalert
 
static int extendby
 
static int fuzzystart
 
static const char gain_map []
 Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers. More...
 
static struct stasis_message_routermeetme_event_message_router
 
static struct ast_custom_function meetme_info_acf
 
static const struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'G' ] = { .flag = (1ULL << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'v' ] = { .flag = (1ULL << 33) , .arg_index = OPT_ARG_INTROUSER_VMREC + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'k' ] = { .flag = (1ULL << 34) }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'n' ] = { .flag = (1ULL << 35) }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
 
static int rt_log_members
 
static int rt_schedule
 
struct {
   unsigned int   attempt_callerid:1
 
   ast_cond_t   cond
 
   struct {
      struct sla_event *   first
 
      struct sla_event *   last
 
   }   event_q
 
   struct {
      struct sla_failed_station *   first
 
      struct sla_failed_station *   last
 
   }   failed_stations
 
   ast_mutex_t   lock
 
   struct {
      struct sla_ringing_station *   first
 
      struct sla_ringing_station *   last
 
   }   ringing_stations
 
   struct {
      struct sla_ringing_trunk *   first
 
      struct sla_ringing_trunk *   last
 
   }   ringing_trunks
 
   unsigned int   stop:1
 
   pthread_t   thread
 
sla
 A structure for data used by the sla thread. More...
 
static const char sla_registrar [] = "SLA"
 
static struct ao2_containersla_stations
 
static const struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
 
static struct ao2_containersla_trunks
 
static const char *const slastation_app = "SLAStation"
 
static const char *const slatrunk_app = "SLATrunk"
 

Detailed Description

Meet me conference bridge and Shared Line Appearances.

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

Definition in file app_meetme.c.

Macro Definition Documentation

◆ AST_FRAME_BITS

#define AST_FRAME_BITS   32

Definition at line 666 of file app_meetme.c.

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

◆ CONF_SIZE

#define CONF_SIZE   320

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

Referenced by conf_run().

◆ CONFFLAG_INTROUSER_VMREC

#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)

Definition at line 751 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 753 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 749 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 644 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 652 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 649 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 822 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 826 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 664 of file app_meetme.c.

Referenced by conf_run().

◆ MEETME_DELAYDETECTTALK

#define MEETME_DELAYDETECTTALK   300

Definition at line 663 of file app_meetme.c.

Referenced by conf_run().

◆ OPTIONS_LEN

#define OPTIONS_LEN   100

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

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

◆ anonymous enum

anonymous enum
Enumerator
CONFFLAG_ADMIN 

user has admin access on the conference

CONFFLAG_MONITOR 

If set the user can only receive audio from the conference

CONFFLAG_KEYEXIT 

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

CONFFLAG_STARMENU 

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

CONFFLAG_TALKER 

If set the use can only send audio to the conference

CONFFLAG_QUIET 

If set there will be no enter or leave sounds

CONFFLAG_ANNOUNCEUSERCOUNT 

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

CONFFLAG_AGI 

Set to run AGI Script in Background

CONFFLAG_MOH 

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

CONFFLAG_MARKEDEXIT 

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

CONFFLAG_WAITMARKED 

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

CONFFLAG_EXIT_CONTEXT 

If set, the MeetMe will exit to the specified context

CONFFLAG_MARKEDUSER 

If set, the user will be marked

CONFFLAG_INTROUSER 

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

CONFFLAG_RECORDCONF 

If set, the MeetMe will be recorded

CONFFLAG_MONITORTALKER 

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

CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER 

If set, treat talking users as muted users

CONFFLAG_NOONLYPERSON 

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

CONFFLAG_INTROUSERNOREVIEW 

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

CONFFLAG_STARTMUTED 

If set, the user will be initially self-muted

CONFFLAG_PASS_DTMF 

Pass DTMF through the conference

CONFFLAG_SLA_STATION 
CONFFLAG_SLA_TRUNK 
CONFFLAG_KICK_CONTINUE 

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

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 

Definition at line 687 of file app_meetme.c.

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

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_INTROMSG 
OPT_ARG_INTROUSER_VMREC 
OPT_ARG_ARRAY_SIZE 

Definition at line 757 of file app_meetme.c.

◆ anonymous enum

anonymous enum
Enumerator
SLA_TRUNK_OPT_MOH 

Definition at line 7217 of file app_meetme.c.

7217  {
7218  SLA_TRUNK_OPT_MOH = (1 << 0),
7219 };

◆ anonymous enum

anonymous enum
Enumerator
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 7221 of file app_meetme.c.

◆ announcetypes

Enumerator
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 828 of file app_meetme.c.

828  {
829  CONF_HASJOIN,
831 };

◆ entrance_sound

Enumerator
ENTER 
LEAVE 

Definition at line 673 of file app_meetme.c.

673  {
674  ENTER,
675  LEAVE
676 };

◆ menu_modes

enum menu_modes
Enumerator
MENU_DISABLED 
MENU_NORMAL 
MENU_ADMIN 
MENU_ADMIN_EXTENDED 

Definition at line 2751 of file app_meetme.c.

◆ recording_state

Enumerator
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

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

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

◆ sla_hold_access

Enumerator
SLA_HOLD_OPEN 

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

SLA_HOLD_PRIVATE 

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

Definition at line 933 of file app_meetme.c.

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

◆ sla_station_hangup

Enumerator
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

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

◆ sla_which_trunk_refs

Enumerator
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 920 of file app_meetme.c.

◆ volume_action

Enumerator
VOL_UP 
VOL_DOWN 

Definition at line 668 of file app_meetme.c.

668  {
669  VOL_UP,
670  VOL_DOWN
671 };

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 8087 of file app_meetme.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 8087 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 7943 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.

7944 {
7945  struct ast_conference *conf;
7946  char *parse;
7947  int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
7949  AST_APP_ARG(keyword);
7951  );
7952 
7953  if (ast_strlen_zero(data)) {
7954  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
7955  return -1;
7956  }
7957 
7958  parse = ast_strdupa(data);
7959  AST_STANDARD_APP_ARGS(args, parse);
7960 
7961  if (ast_strlen_zero(args.keyword)) {
7962  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
7963  return -1;
7964  }
7965 
7966  if (ast_strlen_zero(args.confno)) {
7967  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
7968  return -1;
7969  }
7970 
7971  AST_LIST_LOCK(&confs);
7972  AST_LIST_TRAVERSE(&confs, conf, list) {
7973  if (!strcmp(args.confno, conf->confno)) {
7974  result = acf_meetme_info_eval(args.keyword, conf);
7975  break;
7976  }
7977  }
7979 
7980  if (result > -1) {
7981  snprintf(buf, len, "%d", result);
7982  } else if (result == -1) {
7983  ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
7984  snprintf(buf, len, "0");
7985  } else if (result == -2) {
7986  ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
7987  snprintf(buf, len, "0");
7988  }
7989 
7990  return 0;
7991 }
#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.
struct ast_conference::@35 list
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
const char * args
All configuration options for statsd client.
Definition: res_statsd.c:101
#define ast_log
Definition: astobj2.c:42
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#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:7925
#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:1844
static PGresult * result
Definition: cel_pgsql.c:88
The MeetMe Conference object.
Definition: app_meetme.c:844
#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:847

◆ acf_meetme_info_eval()

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

Definition at line 7925 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().

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

◆ action_meetmelist()

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

Definition at line 5523 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().

5524 {
5525  const char *actionid = astman_get_header(m, "ActionID");
5526  const char *conference = astman_get_header(m, "Conference");
5527  char idText[80] = "";
5528  struct ast_conference *cnf;
5529  struct ast_conf_user *user;
5530  struct ao2_iterator user_iter;
5531  int total = 0;
5532 
5533  if (!ast_strlen_zero(actionid))
5534  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5535 
5536  if (AST_LIST_EMPTY(&confs)) {
5537  astman_send_error(s, m, "No active conferences.");
5538  return 0;
5539  }
5540 
5541  astman_send_listack(s, m, "Meetme user list will follow", "start");
5542 
5543  /* Find the right conference */
5544  AST_LIST_LOCK(&confs);
5545  AST_LIST_TRAVERSE(&confs, cnf, list) {
5546  /* If we ask for one particular, and this isn't it, skip it */
5547  if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
5548  continue;
5549 
5550  /* Show all the users */
5551  user_iter = ao2_iterator_init(cnf->usercontainer, 0);
5552  while ((user = ao2_iterator_next(&user_iter))) {
5553  total++;
5554  astman_append(s,
5555  "Event: MeetmeList\r\n"
5556  "%s"
5557  "Conference: %s\r\n"
5558  "UserNumber: %d\r\n"
5559  "CallerIDNum: %s\r\n"
5560  "CallerIDName: %s\r\n"
5561  "ConnectedLineNum: %s\r\n"
5562  "ConnectedLineName: %s\r\n"
5563  "Channel: %s\r\n"
5564  "Admin: %s\r\n"
5565  "Role: %s\r\n"
5566  "MarkedUser: %s\r\n"
5567  "Muted: %s\r\n"
5568  "Talking: %s\r\n"
5569  "\r\n",
5570  idText,
5571  cnf->confno,
5572  user->user_no,
5573  S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
5574  S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
5576  S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<no name>"),
5577  ast_channel_name(user->chan),
5578  ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
5579  ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
5580  ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
5581  user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
5582  user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
5583  ao2_ref(user, -1);
5584  }
5585  ao2_iterator_destroy(&user_iter);
5586  }
5588 
5589  /* Send final confirmation */
5590  astman_send_list_complete_start(s, m, "MeetmeListComplete", total);
5592  return 0;
5593 }
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
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)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
The MeetMe User object.
Definition: app_meetme.c:898
#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:900
#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:877
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:844
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:902
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:847
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 5595 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().

5596 {
5597  const char *actionid = astman_get_header(m, "ActionID");
5598  char idText[80] = "";
5599  struct ast_conference *cnf;
5600  int totalitems = 0;
5601  int hr, min, sec;
5602  time_t now;
5603  char markedusers[5];
5604 
5605  if (!ast_strlen_zero(actionid)) {
5606  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5607  }
5608 
5609  if (AST_LIST_EMPTY(&confs)) {
5610  astman_send_error(s, m, "No active conferences.");
5611  return 0;
5612  }
5613 
5614  astman_send_listack(s, m, "Meetme conferences will follow", "start");
5615 
5616  now = time(NULL);
5617 
5618  /* Traverse the conference list */
5619  AST_LIST_LOCK(&confs);
5620  AST_LIST_TRAVERSE(&confs, cnf, list) {
5621  totalitems++;
5622 
5623  if (cnf->markedusers == 0) {
5624  strcpy(markedusers, "N/A");
5625  } else {
5626  sprintf(markedusers, "%.4d", cnf->markedusers);
5627  }
5628  hr = (now - cnf->start) / 3600;
5629  min = ((now - cnf->start) % 3600) / 60;
5630  sec = (now - cnf->start) % 60;
5631 
5632  astman_append(s,
5633  "Event: MeetmeListRooms\r\n"
5634  "%s"
5635  "Conference: %s\r\n"
5636  "Parties: %d\r\n"
5637  "Marked: %s\r\n"
5638  "Activity: %2.2d:%2.2d:%2.2d\r\n"
5639  "Creation: %s\r\n"
5640  "Locked: %s\r\n"
5641  "\r\n",
5642  idText,
5643  cnf->confno,
5644  cnf->users,
5645  markedusers,
5646  hr, min, sec,
5647  cnf->isdynamic ? "Dynamic" : "Static",
5648  cnf->locked ? "Yes" : "No");
5649  }
5651 
5652  /* Send final confirmation */
5653  astman_send_list_complete_start(s, m, "MeetmeListRoomsComplete", totalitems);
5655  return 0;
5656 }
#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_conference::@35 list
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:859
#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:860
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#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:844
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:847
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 5513 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

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

◆ action_meetmeunmute()

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

Definition at line 5518 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

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

◆ admin_exec()

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 5227 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().

5227  {
5228  char *params;
5229  struct ast_conference *cnf;
5230  struct ast_conf_user *user = NULL;
5232  AST_APP_ARG(confno);
5233  AST_APP_ARG(command);
5234  AST_APP_ARG(user);
5235  );
5236  int res = 0;
5237 
5238  if (ast_strlen_zero(data)) {
5239  ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
5240  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5241  return -1;
5242  }
5243 
5244  params = ast_strdupa(data);
5245  AST_STANDARD_APP_ARGS(args, params);
5246 
5247  if (!args.command) {
5248  ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
5249  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5250  return -1;
5251  }
5252 
5253  AST_LIST_LOCK(&confs);
5254  AST_LIST_TRAVERSE(&confs, cnf, list) {
5255  if (!strcmp(cnf->confno, args.confno))
5256  break;
5257  }
5258 
5259  if (!cnf) {
5260  ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
5262  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
5263  return 0;
5264  }
5265 
5267 
5268  if (args.user) {
5269  user = find_user(cnf, args.user);
5270  if (!user) {
5271  ast_log(LOG_NOTICE, "Specified User not found!\n");
5272  res = -2;
5273  goto usernotfound;
5274  }
5275  } else {
5276  /* fail for commands that require a user */
5277  switch (*args.command) {
5278  case 'm': /* Unmute */
5279  case 'M': /* Mute */
5280  case 't': /* Lower user's talk volume */
5281  case 'T': /* Raise user's talk volume */
5282  case 'u': /* Lower user's listen volume */
5283  case 'U': /* Raise user's listen volume */
5284  case 'r': /* Reset user's volume level */
5285  case 'k': /* Kick user */
5286  res = -2;
5287  ast_log(LOG_NOTICE, "No user specified!\n");
5288  goto usernotfound;
5289  default:
5290  break;
5291  }
5292  }
5293 
5294  switch (*args.command) {
5295  case 76: /* L: Lock */
5296  cnf->locked = 1;
5297  break;
5298  case 108: /* l: Unlock */
5299  cnf->locked = 0;
5300  break;
5301  case 75: /* K: kick all users */
5303  break;
5304  case 101: /* e: Eject last user*/
5305  {
5306  int max_no = 0;
5307  RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
5308 
5310  eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
5311  if (!eject_user) {
5312  res = -1;
5313  ast_log(LOG_NOTICE, "No last user to kick!\n");
5314  break;
5315  }
5316 
5317  if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
5318  eject_user->adminflags |= ADMINFLAG_KICKME;
5319  } else {
5320  res = -1;
5321  ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
5322  }
5323  break;
5324  }
5325  case 77: /* M: Mute */
5326  user->adminflags |= ADMINFLAG_MUTED;
5327  break;
5328  case 78: /* N: Mute all (non-admin) users */
5330  break;
5331  case 109: /* m: Unmute */
5333  break;
5334  case 110: /* n: Unmute all users */
5336  break;
5337  case 107: /* k: Kick user */
5338  user->adminflags |= ADMINFLAG_KICKME;
5339  break;
5340  case 118: /* v: Lower all users listen volume */
5342  break;
5343  case 86: /* V: Raise all users listen volume */
5345  break;
5346  case 115: /* s: Lower all users speaking volume */
5348  break;
5349  case 83: /* S: Raise all users speaking volume */
5351  break;
5352  case 82: /* R: Reset all volume levels */
5354  break;
5355  case 114: /* r: Reset user's volume level */
5356  reset_volumes(user);
5357  break;
5358  case 85: /* U: Raise user's listen volume */
5359  tweak_listen_volume(user, VOL_UP);
5360  break;
5361  case 117: /* u: Lower user's listen volume */
5363  break;
5364  case 84: /* T: Raise user's talk volume */
5365  tweak_talk_volume(user, VOL_UP);
5366  break;
5367  case 116: /* t: Lower user's talk volume */
5368  tweak_talk_volume(user, VOL_DOWN);
5369  break;
5370  case 'E': /* E: Extend conference */
5371  if (rt_extend_conf(args.confno)) {
5372  res = -1;
5373  }
5374  break;
5375  }
5376 
5377  if (args.user) {
5378  /* decrement reference from find_user */
5379  ao2_ref(user, -1);
5380  }
5381 usernotfound:
5383 
5384  dispose_conf(cnf);
5385  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
5386 
5387  return 0;
5388 }
struct ast_conf_user::@37 list
#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:5164
static int dispose_conf(struct ast_conference *conf)
Decrement reference counts, as incremented by find_conf()
Definition: app_meetme.c:2506
static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1496
static int rt_extend_conf(const char *confno)
Definition: app_meetme.c:2525
static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2729
#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:5177
static int user_reset_vol_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5205
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
const char * args
#define NULL
Definition: resample.c:96
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:860
static int user_max_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1581
static int user_listen_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5184
static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2718
#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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
The MeetMe User object.
Definition: app_meetme.c:898
#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:1508
static void reset_volumes(struct ast_conf_user *user)
Definition: app_meetme.c:1520
static int user_talk_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5191
#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:877
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:844
#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:5198
static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2740
#define AST_APP_ARG(name)
Define an application argument.
char confno[MAX_CONFNUM]
Definition: app_meetme.c:847
#define ast_test_flag64(p, flag)
Definition: utils.h:120

◆ announce_thread()

static void* announce_thread ( void *  data)
static

Definition at line 2617 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().

2618 {
2619  struct announce_listitem *current;
2620  struct ast_conference *conf = data;
2621  int res;
2622  char filename[PATH_MAX] = "";
2624  AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2625 
2626  while (!conf->announcethread_stop) {
2628  if (conf->announcethread_stop) {
2630  break;
2631  }
2632  if (AST_LIST_EMPTY(&conf->announcelist))
2634 
2635  AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2637 
2639  if (conf->announcethread_stop) {
2640  break;
2641  }
2642 
2643  for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2644  ast_debug(1, "About to play %s\n", current->namerecloc);
2645  if (!ast_fileexists(current->namerecloc, NULL, NULL))
2646  continue;
2647  if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2648  if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2649  res = ast_waitstream(current->confchan, "");
2650  if (!res) {
2651  ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2652  if (!ast_streamfile(current->confchan, filename, current->language))
2653  ast_waitstream(current->confchan, "");
2654  }
2655  }
2656  if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2657  /* only remove it if it isn't a VM recording file */
2658  ast_filedelete(current->namerecloc, NULL);
2659  }
2660  }
2661  }
2662 
2663  /* thread marked to stop, clean up */
2664  while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2665  /* only delete if it's a vm rec */
2666  if (!current->vmrec) {
2667  ast_filedelete(current->namerecloc, NULL);
2668  }
2669  ao2_ref(current, -1);
2670  }
2671  return NULL;
2672 }
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:2603
struct ast_channel * confchan
Definition: app_meetme.c:837
#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:101
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#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:885
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:441
char namerecloc[PATH_MAX]
Definition: app_meetme.c:835
char language[MAX_LANGUAGE]
Definition: app_meetme.c:836
#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
struct ast_conference::@36 announcelist
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:883
unsigned int announcethread_stop
Definition: app_meetme.c:882
Definition: search.h:40
enum announcetypes announcetype
Definition: app_meetme.c:840
#define PATH_MAX
Definition: asterisk.h:40
The MeetMe Conference object.
Definition: app_meetme.c:844
#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 6064 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

6065 {
6066  ast_answer(chan);
6067  ast_indicate(chan, -1);
6068 }
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4309
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2810

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 8087 of file app_meetme.c.

◆ build_conf()

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

Find or create a conference.

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

Definition at line 1608 of file app_meetme.c.

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

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

◆ can_write()

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

Definition at line 2674 of file app_meetme.c.

References AST_STATE_UP, ast_test_flag64, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

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

References ast_log, errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

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

5392  {
5393  char *params;
5394  struct ast_conference *conf = NULL;
5395  struct ast_conf_user *user = NULL;
5397  AST_APP_ARG(channel);
5398  AST_APP_ARG(command);
5399  );
5400 
5401  if (ast_strlen_zero(data)) {
5402  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
5403  return -1;
5404  }
5405 
5406  params = ast_strdupa(data);
5407  AST_STANDARD_APP_ARGS(args, params);
5408 
5409  if (!args.channel) {
5410  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
5411  return -1;
5412  }
5413 
5414  if (!args.command) {
5415  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
5416  return -1;
5417  }
5418 
5419  AST_LIST_LOCK(&confs);
5420  AST_LIST_TRAVERSE(&confs, conf, list) {
5421  if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
5422  break;
5423  }
5424  }
5425 
5426  if (!user) {
5427  ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
5429  return 0;
5430  }
5431 
5432  /* perform the specified action */
5433  switch (*args.command) {
5434  case 77: /* M: Mute */
5435  user->adminflags |= ADMINFLAG_MUTED;
5436  break;
5437  case 109: /* m: Unmute */
5438  user->adminflags &= ~ADMINFLAG_MUTED;
5439  break;
5440  case 107: /* k: Kick user */
5441  user->adminflags |= ADMINFLAG_KICKME;
5442  break;
5443  default: /* unknown command */
5444  ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
5445  break;
5446  }
5447  ao2_ref(user, -1);
5449 
5450  return 0;
5451 }
struct ast_conf_user::@37 list
#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:5212
#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
const char * args
#define NULL
Definition: resample.c:96
All configuration options for statsd client.
Definition: res_statsd.c:101
#define ast_log
Definition: astobj2.c:42
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
The MeetMe User object.
Definition: app_meetme.c:898
#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:877
structure to hold users read from users.conf
The MeetMe Conference object.
Definition: app_meetme.c:844
#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 1727 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().

1728 {
1729  struct ast_conference *cnf;
1730  char *ret = NULL;
1731  int which = 0;
1732  int len = strlen(word);
1733 
1734  AST_LIST_LOCK(&confs);
1735  AST_LIST_TRAVERSE(&confs, cnf, list) {
1736  if (!strncmp(word, cnf->confno, len) && ++which > state) {
1737  /* dup before releasing the lock */
1738  ret = ast_strdup(cnf->confno);
1739  break;
1740  }
1741  }
1743  return ret;
1744 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
struct ast_conference::@35 list
#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:844
short word
char confno[MAX_CONFNUM]
Definition: app_meetme.c:847

◆ complete_meetmecmd_list()

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

Definition at line 1816 of file app_meetme.c.

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

Referenced by meetme_show_cmd().

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

◆ complete_meetmecmd_lock()

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

Definition at line 1808 of file app_meetme.c.

References complete_confno(), and NULL.

Referenced by meetme_lock_cmd().

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

◆ complete_meetmecmd_mute_kick()

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

Definition at line 1768 of file app_meetme.c.

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

1769 {
1770  if (pos == 2) {
1771  return complete_confno(word, state);
1772  }
1773  if (pos == 3) {
1774  int len = strlen(word);
1775  char *ret = NULL;
1776  char *saved = NULL;
1777  char *myline;
1778  char *confno;
1779  struct ast_conference *cnf;
1780 
1781  if (!strncasecmp(word, "all", len)) {
1782  if (state == 0) {
1783  return ast_strdup("all");
1784  }
1785  --state;
1786  }
1787 
1788  /* Extract the confno from the command line. */
1789  myline = ast_strdupa(line);
1790  strtok_r(myline, " ", &saved);
1791  strtok_r(NULL, " ", &saved);
1792  confno = strtok_r(NULL, " ", &saved);
1793 
1794  AST_LIST_LOCK(&confs);
1795  AST_LIST_TRAVERSE(&confs, cnf, list) {
1796  if (!strcmp(confno, cnf->confno)) {
1797  ret = complete_userno(cnf, word, state);
1798  break;
1799  }
1800  }
1802 
1803  return ret;
1804  }
1805  return NULL;
1806 }
enum sip_cc_notify_state state
Definition: chan_sip.c:963
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
struct ast_conference::@35 list
#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:1746
The MeetMe Conference object.
Definition: app_meetme.c:844
short word
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1727
char confno[MAX_CONFNUM]
Definition: app_meetme.c:847

◆ complete_userno()

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

Definition at line 1746 of file app_meetme.c.

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

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

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

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

Referenced by conf_run().

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

2334 {
2335  int x;
2336  struct announce_listitem *item;
2337 
2338  AST_LIST_REMOVE(&confs, conf, list);
2339 
2340  meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
2341 
2342  if (conf->recording == MEETME_RECORD_ACTIVE) {
2345  while (1) {
2346  usleep(1);
2347  AST_LIST_LOCK(&confs);
2348  if (conf->recording == MEETME_RECORD_OFF)
2349  break;
2351  }
2352  }
2353 
2354  for (x = 0; x < AST_FRAME_BITS; x++) {
2355  if (conf->transframe[x])
2356  ast_frfree(conf->transframe[x]);
2357  if (conf->transpath[x])
2359  }
2360  if (conf->announcethread != AST_PTHREADT_NULL) {
2362  conf->announcethread_stop = 1;
2366  pthread_join(conf->announcethread, NULL);
2367 
2368  while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2369  /* If it's a voicemail greeting file we don't want to remove it */
2370  if (!item->vmrec){
2371  ast_filedelete(item->namerecloc, NULL);
2372  }
2373  ao2_ref(item, -1);
2374  }
2376  }
2377 
2378  if (conf->origframe)
2379  ast_frfree(conf->origframe);
2380  ast_hangup(conf->lchan);
2381  ast_hangup(conf->chan);
2382  if (conf->fd >= 0)
2383  close(conf->fd);
2384  if (conf->recordingfilename) {
2385  ast_free(conf->recordingfilename);
2386  }
2387  if (conf->usercontainer) {
2388  ao2_ref(conf->usercontainer, -1);
2389  }
2390  if (conf->recordingformat) {
2391  ast_free(conf->recordingformat);
2392  }
2393  ast_mutex_destroy(&conf->playlock);
2394  ast_mutex_destroy(&conf->listenlock);
2397  ast_free(conf);
2398 
2399  return 0;
2400 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
struct ast_channel * chan
Definition: app_meetme.c:848
ast_mutex_t playlock
Definition: app_meetme.c:845
#define AST_FRAME_BITS
Definition: app_meetme.c:666
struct ast_frame * origframe
Definition: app_meetme.c:875
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
char * recordingformat
Definition: app_meetme.c:866
struct ast_frame * transframe[32]
Definition: app_meetme.c:874
ast_mutex_t listenlock
Definition: app_meetme.c:846
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:1345
#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:2472
#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:885
enum recording_state recording
Definition: app_meetme.c:858
char namerecloc[PATH_MAX]
Definition: app_meetme.c:835
pthread_t announcethread
Definition: app_meetme.c:880
#define ast_free(a)
Definition: astmm.h:182
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2544
struct ao2_container * usercontainer
Definition: app_meetme.c:877
struct ast_conference::@36 announcelist
struct ast_trans_pvt * transpath[32]
Definition: app_meetme.c:876
#define ast_frfree(fr)
ast_cond_t announcelist_addition
Definition: app_meetme.c:883
unsigned int announcethread_stop
Definition: app_meetme.c:882
Definition: search.h:40
char * recordingfilename
Definition: app_meetme.c:865
struct ast_channel * lchan
Definition: app_meetme.c:849
#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:863
ast_mutex_t announcethreadlock
Definition: app_meetme.c:881

◆ conf_play()

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

Definition at line 1528 of file app_meetme.c.

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

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

◆ conf_queue_dtmf()

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

Definition at line 2402 of file app_meetme.c.

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

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

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