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/data.h"#include "asterisk/test.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 |
Defines | |
| #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_DATA_EXPORT(MEMBER) |
| #define | MEETME_DELAYDETECTENDTALK 1000 |
| #define | MEETME_DELAYDETECTTALK 300 |
| #define | MEETME_USER_DATA_EXPORT(MEMBER) |
| #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. | |
| static void * | announce_thread (void *data) |
| static void | answer_trunk_chan (struct ast_channel *chan) |
| AST_DATA_STRUCTURE (ast_conference, MEETME_DATA_EXPORT) | |
| AST_DATA_STRUCTURE (ast_conf_user, MEETME_USER_DATA_EXPORT) | |
| static struct ast_conference * | build_conf (const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test) |
| Find or create a conference. | |
| 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) | |
| 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. | |
| 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. | |
| 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. | |
| static struct sla_trunk_ref * | create_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() | |
| static void | filename_parse (char *filename, char *buffer) |
| static struct ast_conference * | find_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags) |
| static struct ast_conference * | find_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs) |
| static struct ast_conf_user * | find_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 (void) |
| static int | load_module (void) |
| static char * | meetme_cmd_helper (struct ast_cli_args *a) |
| static int | meetme_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root) |
| 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 dahdi_confinfo *dahdic, 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 dahdi_confinfo *dahdic, 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 char * | meetme_show_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| 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. | |
| static struct sla_ringing_trunk * | queue_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. | |
| static int | sla_calc_station_timeouts (unsigned int *timeout) |
| Process station ring timeouts. | |
| static int | sla_calc_trunk_timeouts (unsigned int *timeout) |
| Process trunk ring timeouts. | |
| 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. | |
| static int | sla_check_inuse_station (const struct sla_station *station) |
| Check to see if a station is in use. | |
| static int | sla_check_ringing_station (const struct sla_station *station) |
| Check to see if this station is already ringing. | |
| 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. | |
| 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. | |
| static struct sla_trunk_ref * | sla_choose_idle_trunk (const struct sla_station *station) |
| For a given station, choose the highest priority idle trunk. | |
| static struct sla_ringing_trunk * | sla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm) |
| Choose the highest priority ringing trunk for a station. | |
| static struct sla_failed_station * | sla_create_failed_station (struct sla_station *station) |
| static struct sla_ringing_station * | sla_create_ringing_station (struct sla_station *station) |
| static struct sla_station_ref * | sla_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_station * | sla_find_station (const char *name) |
| static struct sla_trunk * | sla_find_trunk (const char *name) |
| static struct sla_trunk_ref * | sla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk) |
| static struct sla_trunk_ref * | sla_find_trunk_ref_byname (const struct sla_station *station, const char *name) |
| Find a trunk reference on a station by name. | |
| 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. | |
| 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. | |
| 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. | |
| static void | sla_ring_stations (void) |
| Ring stations based on current set of ringing trunks. | |
| 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_hash (const void *obj, const int flags) |
| 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_hash (const void *obj, const int flags) |
| 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) |
| 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_add_provider_cb (void *obj, void *arg, int flags) |
| 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, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, } |
| 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 struct ast_module_info * | ast_module_info = &__mod_info |
| static int | audio_buffers |
| The number of audio buffers to be allocated on pseudo channels when in a conference. | |
| static struct ast_cli_entry | cli_meetme [] |
| static unsigned int | conf_map [1024] = {0, } |
| static struct confs | confs |
| 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. | |
| static struct ast_data_handler | meetme_data_provider |
| static struct ast_data_entry | meetme_data_providers [] |
| static struct ast_custom_function | meetme_info_acf |
| static 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. | |
| static const char | sla_registrar [] = "SLA" |
| static struct ao2_container * | sla_stations |
| static 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_container * | sla_trunks |
| static const char *const | slastation_app = "SLAStation" |
| static const char *const | slatrunk_app = "SLATrunk" |
Meet me conference bridge and Shared Line Appearances.
Definition in file app_meetme.c.
| #define AST_FRAME_BITS 32 |
Definition at line 571 of file app_meetme.c.
Referenced by conf_free(), conf_run(), and recordthread().
| #define CONF_SIZE 320 |
Definition at line 590 of file app_meetme.c.
Referenced by conf_run().
| #define CONFFLAG_DONT_DENOISE (1ULL << 35) |
If set, don't enable a denoiser for the channel
Definition at line 660 of file app_meetme.c.
Referenced by conf_run().
| #define CONFFLAG_INTROMSG (1ULL << 32) |
If set play an intro announcement at start of conference
Definition at line 655 of file app_meetme.c.
Referenced by conf_run().
| #define CONFFLAG_INTROUSER_VMREC (1ULL << 33) |
Definition at line 656 of file app_meetme.c.
Referenced by conf_run(), find_conf(), and find_conf_realtime().
| #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 658 of file app_meetme.c.
Referenced by conf_run().
| #define CONFFLAG_NO_AUDIO_UNTIL_UP (1ULL << 31) |
Do not write any audio to this channel until the state is up.
Definition at line 654 of file app_meetme.c.
Referenced by can_write(), conf_run(), and sla_trunk_exec().
| #define CONFIG_FILE_NAME "meetme.conf" |
Definition at line 549 of file app_meetme.c.
Referenced by conf_exec(), find_conf(), and load_config_meetme().
| #define DATE_FORMAT "%Y-%m-%d %H:%M:%S" |
String format for scheduled conferences
Definition at line 557 of file app_meetme.c.
Referenced by conf_run(), find_conf_realtime(), and rt_extend_conf().
| #define DEFAULT_AUDIO_BUFFERS 32 |
each buffer is 20ms, so this is 640ms total
Definition at line 554 of file app_meetme.c.
Referenced by load_config_meetme().
| #define MAX_CONFNUM 80 |
Definition at line 726 of file app_meetme.c.
Referenced by conf_exec(), dial_trunk(), meetme_cmd_helper(), sla_station_exec(), and sla_trunk_exec().
| #define MAX_PIN 80 |
Definition at line 727 of file app_meetme.c.
Referenced by conf_exec(), and conf_get_pin().
| #define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3) |
Definition at line 731 of file app_meetme.c.
Referenced by conf_exec(), and find_conf().
| #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n" |
Referenced by meetme_show_cmd().
| #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n" |
Referenced by meetme_show_cmd().
| #define MEETME_DATA_EXPORT | ( | MEMBER | ) |
Definition at line 7794 of file app_meetme.c.
| #define MEETME_DELAYDETECTENDTALK 1000 |
Definition at line 569 of file app_meetme.c.
Referenced by conf_run().
| #define MEETME_DELAYDETECTTALK 300 |
Definition at line 568 of file app_meetme.c.
Referenced by conf_run().
| #define MEETME_USER_DATA_EXPORT | ( | MEMBER | ) |
Definition at line 7811 of file app_meetme.c.
| #define OPTIONS_LEN 100 |
Definition at line 728 of file app_meetme.c.
Referenced by find_conf_realtime().
| #define S | ( | e | ) | case e: return # e; |
Referenced by sms_readfile(), and trunkstate2str().
| #define SLA_CONFIG_FILE "sla.conf" |
Definition at line 550 of file app_meetme.c.
Referenced by sla_build_station(), sla_build_trunk(), and sla_load_config().
| #define STR_CONCISE "concise" |
Definition at line 551 of file app_meetme.c.
Referenced by complete_meetmecmd_list(), and meetme_show_cmd().
| anonymous enum |
Definition at line 559 of file app_meetme.c.
{
ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */
/*! User has requested to speak */
ADMINFLAG_T_REQUEST = (1 << 4),
ADMINFLAG_HANGUP = (1 << 5), /*!< User will be leaving the conference */
};
| anonymous enum |
Definition at line 592 of file app_meetme.c.
{
/*! user has admin access on the conference */
CONFFLAG_ADMIN = (1 << 0),
/*! If set the user can only receive audio from the conference */
CONFFLAG_MONITOR = (1 << 1),
/*! If set asterisk will exit conference when key defined in p() option is pressed */
CONFFLAG_KEYEXIT = (1 << 2),
/*! If set asterisk will provide a menu to the user when '*' is pressed */
CONFFLAG_STARMENU = (1 << 3),
/*! If set the use can only send audio to the conference */
CONFFLAG_TALKER = (1 << 4),
/*! If set there will be no enter or leave sounds */
CONFFLAG_QUIET = (1 << 5),
/*! If set, when user joins the conference, they will be told the number
* of users that are already in */
CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
/*! Set to run AGI Script in Background */
CONFFLAG_AGI = (1 << 7),
/*! Set to have music on hold when user is alone in conference */
CONFFLAG_MOH = (1 << 8),
/*! If set, the channel will leave the conference if all marked users leave */
CONFFLAG_MARKEDEXIT = (1 << 9),
/*! If set, the MeetMe will wait until a marked user enters */
CONFFLAG_WAITMARKED = (1 << 10),
/*! If set, the MeetMe will exit to the specified context */
CONFFLAG_EXIT_CONTEXT = (1 << 11),
/*! If set, the user will be marked */
CONFFLAG_MARKEDUSER = (1 << 12),
/*! If set, user will be ask record name on entry of conference */
CONFFLAG_INTROUSER = (1 << 13),
/*! If set, the MeetMe will be recorded */
CONFFLAG_RECORDCONF = (1<< 14),
/*! If set, the user will be monitored if the user is talking or not */
CONFFLAG_MONITORTALKER = (1 << 15),
CONFFLAG_DYNAMIC = (1 << 16),
CONFFLAG_DYNAMICPIN = (1 << 17),
CONFFLAG_EMPTY = (1 << 18),
CONFFLAG_EMPTYNOPIN = (1 << 19),
CONFFLAG_ALWAYSPROMPT = (1 << 20),
/*! If set, treat talking users as muted users */
CONFFLAG_OPTIMIZETALKER = (1 << 21),
/*! If set, won't speak the extra prompt when the first person
* enters the conference */
CONFFLAG_NOONLYPERSON = (1 << 22),
/*! If set, user will be asked to record name on entry of conference
* without review */
CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
/*! If set, the user will be initially self-muted */
CONFFLAG_STARTMUTED = (1 << 24),
/*! Pass DTMF through the conference */
CONFFLAG_PASS_DTMF = (1 << 25),
CONFFLAG_SLA_STATION = (1 << 26),
CONFFLAG_SLA_TRUNK = (1 << 27),
/*! If set, the user should continue in the dialplan if kicked out */
CONFFLAG_KICK_CONTINUE = (1 << 28),
CONFFLAG_DURATION_STOP = (1 << 29),
CONFFLAG_DURATION_LIMIT = (1 << 30),
};
| anonymous enum |
| 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 662 of file app_meetme.c.
{
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,
};
| anonymous enum |
Definition at line 6991 of file app_meetme.c.
{
SLA_TRUNK_OPT_MOH = (1 << 0),
};
| anonymous enum |
Definition at line 6995 of file app_meetme.c.
{
SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
};
| enum announcetypes |
Definition at line 733 of file app_meetme.c.
{
CONF_HASJOIN,
CONF_HASLEFT
};
| enum entrance_sound |
| enum menu_modes |
Definition at line 2416 of file app_meetme.c.
{
MENU_DISABLED = 0,
MENU_NORMAL,
MENU_ADMIN,
MENU_ADMIN_EXTENDED,
};
| enum recording_state |
Definition at line 583 of file app_meetme.c.
| enum sla_event_type |
Event types that can be queued up for the SLA thread.
| 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 945 of file app_meetme.c.
{
/*! A station has put the call on hold */
SLA_EVENT_HOLD,
/*! The state of a dial has changed */
SLA_EVENT_DIAL_STATE,
/*! The state of a ringing trunk has changed */
SLA_EVENT_RINGING_TRUNK,
};
| enum sla_hold_access |
Definition at line 838 of file app_meetme.c.
{
/*! This means that any station can put it on hold, and any station
* can retrieve the call from hold. */
SLA_HOLD_OPEN,
/*! This means that only the station that put the call on hold may
* retrieve it from hold. */
SLA_HOLD_PRIVATE,
};
| enum sla_station_hangup |
Definition at line 978 of file app_meetme.c.
| 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 |
Definition at line 830 of file app_meetme.c.
| enum sla_which_trunk_refs |
Definition at line 825 of file app_meetme.c.
| enum volume_action |
| static void __reg_module | ( | void | ) | [static] |
Definition at line 8047 of file app_meetme.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 8047 of file app_meetme.c.
| static int acf_meetme_info | ( | struct ast_channel * | chan, |
| const char * | cmd, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | len | ||
| ) | [static] |
Definition at line 7731 of file app_meetme.c.
References acf_meetme_info_eval(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_conference::confno, ast_conference::list, LOG_ERROR, LOG_NOTICE, and parse().
{
struct ast_conference *conf;
char *parse;
int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(keyword);
AST_APP_ARG(confno);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.keyword)) {
ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
return -1;
}
if (ast_strlen_zero(args.confno)) {
ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
return -1;
}
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, conf, list) {
if (!strcmp(args.confno, conf->confno)) {
result = acf_meetme_info_eval(args.keyword, conf);
break;
}
}
AST_LIST_UNLOCK(&confs);
if (result > -1) {
snprintf(buf, len, "%d", result);
} else if (result == -1) {
ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
snprintf(buf, len, "0");
} else if (result == -2) {
ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
snprintf(buf, len, "0");
}
return 0;
}
| static int acf_meetme_info_eval | ( | const char * | keyword, |
| const struct ast_conference * | conf | ||
| ) | [static] |
Definition at line 7713 of file app_meetme.c.
References ast_conference::isdynamic, ast_conference::locked, ast_conference::start, and ast_conference::users.
Referenced by acf_meetme_info().
{
if (!strcasecmp("lock", keyword)) {
return conf->locked;
} else if (!strcasecmp("parties", keyword)) {
return conf->users;
} else if (!strcasecmp("activity", keyword)) {
time_t now;
now = time(NULL);
return (now - conf->start);
} else if (!strcasecmp("dynamic", keyword)) {
return conf->isdynamic;
} else {
return -1;
}
}
| static int action_meetmelist | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 5302 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_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().
{
const char *actionid = astman_get_header(m, "ActionID");
const char *conference = astman_get_header(m, "Conference");
char idText[80] = "";
struct ast_conference *cnf;
struct ast_conf_user *user;
struct ao2_iterator user_iter;
int total = 0;
if (!ast_strlen_zero(actionid))
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
if (AST_LIST_EMPTY(&confs)) {
astman_send_error(s, m, "No active conferences.");
return 0;
}
astman_send_listack(s, m, "Meetme user list will follow", "start");
/* Find the right conference */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
/* If we ask for one particular, and this isn't it, skip it */
if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
continue;
/* Show all the users */
user_iter = ao2_iterator_init(cnf->usercontainer, 0);
while ((user = ao2_iterator_next(&user_iter))) {
total++;
astman_append(s,
"Event: MeetmeList\r\n"
"%s"
"Conference: %s\r\n"
"UserNumber: %d\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Channel: %s\r\n"
"Admin: %s\r\n"
"Role: %s\r\n"
"MarkedUser: %s\r\n"
"Muted: %s\r\n"
"Talking: %s\r\n"
"\r\n",
idText,
cnf->confno,
user->user_no,
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
S_COR(ast_channel_connected(user->chan)->id.number.valid, ast_channel_connected(user->chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<no name>"),
ast_channel_name(user->chan),
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
ao2_ref(user, -1);
}
ao2_iterator_destroy(&user_iter);
}
AST_LIST_UNLOCK(&confs);
/* Send final confirmation */
astman_append(s,
"Event: MeetmeListComplete\r\n"
"EventList: Complete\r\n"
"ListItems: %d\r\n"
"%s"
"\r\n", total, idText);
return 0;
}
| static int action_meetmelistrooms | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 5377 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_listack(), ast_conference::confno, ast_conference::isdynamic, ast_conference::list, ast_conference::locked, ast_conference::markedusers, ast_conference::start, and ast_conference::users.
Referenced by load_module().
{
const char *actionid = astman_get_header(m, "ActionID");
char idText[80] = "";
struct ast_conference *cnf;
int totalitems = 0;
int hr, min, sec;
time_t now;
char markedusers[5];
if (!ast_strlen_zero(actionid)) {
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
}
if (AST_LIST_EMPTY(&confs)) {
astman_send_error(s, m, "No active conferences.");
return 0;
}
astman_send_listack(s, m, "Meetme conferences will follow", "start");
now = time(NULL);
/* Traverse the conference list */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
totalitems++;
if (cnf->markedusers == 0) {
strcpy(markedusers, "N/A");
} else {
sprintf(markedusers, "%.4d", cnf->markedusers);
}
hr = (now - cnf->start) / 3600;
min = ((now - cnf->start) % 3600) / 60;
sec = (now - cnf->start) % 60;
astman_append(s,
"Event: MeetmeListRooms\r\n"
"%s"
"Conference: %s\r\n"
"Parties: %d\r\n"
"Marked: %s\r\n"
"Activity: %2.2d:%2.2d:%2.2d\r\n"
"Creation: %s\r\n"
"Locked: %s\r\n"
"\r\n",
idText,
cnf->confno,
cnf->users,
markedusers,
hr, min, sec,
cnf->isdynamic ? "Dynamic" : "Static",
cnf->locked ? "Yes" : "No");
}
AST_LIST_UNLOCK(&confs);
/* Send final confirmation */
astman_append(s,
"Event: MeetmeListRoomsComplete\r\n"
"EventList: Complete\r\n"
"ListItems: %d\r\n"
"%s"
"\r\n", totalitems, idText);
return 0;
}
| static int action_meetmemute | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 5292 of file app_meetme.c.
References meetmemute().
Referenced by load_module().
{
return meetmemute(s, m, 1);
}
| static int action_meetmeunmute | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 5297 of file app_meetme.c.
References meetmemute().
Referenced by load_module().
{
return meetmemute(s, m, 0);
}
| static int admin_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
The MeetMeadmin application.
MeetMeAdmin(confno, command, caller)
Definition at line 5006 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, args, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_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, OBJ_NODATA, pbx_builtin_setvar_helper(), ast_conference::refcount, reset_volumes(), rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), user_listen_voldown_cb(), user_listen_volup_cb(), user_max_cmp(), user_reset_vol_cb(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), user_talk_voldown_cb(), user_talk_volup_cb(), ast_conference::usercontainer, VOL_DOWN, and VOL_UP.
Referenced by load_module(), meetme_cmd_helper(), run_station(), sla_station_exec(), and sla_stop_ringing_trunk().
{
char *params;
struct ast_conference *cnf;
struct ast_conf_user *user = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(confno);
AST_APP_ARG(command);
AST_APP_ARG(user);
);
int res = 0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
return -1;
}
params = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, params);
if (!args.command) {
ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
return -1;
}
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(cnf->confno, args.confno))
break;
}
if (!cnf) {
ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
AST_LIST_UNLOCK(&confs);
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
return 0;
}
ast_atomic_fetchadd_int(&cnf->refcount, 1);
if (args.user) {
user = find_user(cnf, args.user);
if (!user) {
ast_log(LOG_NOTICE, "Specified User not found!\n");
res = -2;
goto usernotfound;
}
} else {
/* fail for commands that require a user */
switch (*args.command) {
case 'm': /* Unmute */
case 'M': /* Mute */
case 't': /* Lower user's talk volume */
case 'T': /* Raise user's talk volume */
case 'u': /* Lower user's listen volume */
case 'U': /* Raise user's listen volume */
case 'r': /* Reset user's volume level */
case 'k': /* Kick user */
res = -2;
ast_log(LOG_NOTICE, "No user specified!\n");
goto usernotfound;
default:
break;
}
}
switch (*args.command) {
case 76: /* L: Lock */
cnf->locked = 1;
break;
case 108: /* l: Unlock */
cnf->locked = 0;
break;
case 75: /* K: kick all users */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
break;
case 101: /* e: Eject last user*/
{
int max_no = 0;
RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
if (!eject_user) {
res = -1;
ast_log(LOG_NOTICE, "No last user to kick!\n");
break;
}
if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
eject_user->adminflags |= ADMINFLAG_KICKME;
} else {
res = -1;
ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
}
break;
}
case 77: /* M: Mute */
user->adminflags |= ADMINFLAG_MUTED;
break;
case 78: /* N: Mute all (non-admin) users */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, &cnf);
break;
case 109: /* m: Unmute */
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
break;
case 110: /* n: Unmute all users */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
break;
case 107: /* k: Kick user */
user->adminflags |= ADMINFLAG_KICKME;
break;
case 118: /* v: Lower all users listen volume */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
break;
case 86: /* V: Raise all users listen volume */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
break;
case 115: /* s: Lower all users speaking volume */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
break;
case 83: /* S: Raise all users speaking volume */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
break;
case 82: /* R: Reset all volume levels */
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
break;
case 114: /* r: Reset user's volume level */
reset_volumes(user);
break;
case 85: /* U: Raise user's listen volume */
tweak_listen_volume(user, VOL_UP);
break;
case 117: /* u: Lower user's listen volume */
tweak_listen_volume(user, VOL_DOWN);
break;
case 84: /* T: Raise user's talk volume */
tweak_talk_volume(user, VOL_UP);
break;
case 116: /* t: Lower user's talk volume */
tweak_talk_volume(user, VOL_DOWN);
break;
case 'E': /* E: Extend conference */
if (rt_extend_conf(args.confno)) {
res = -1;
}
break;
}
if (args.user) {
/* decrement reference from find_user */
ao2_ref(user, -1);
}
usernotfound:
AST_LIST_UNLOCK(&confs);
dispose_conf(cnf);
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
return 0;
}
| static void* announce_thread | ( | void * | data | ) | [static] |
Definition at line 2260 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, and announce_listitem::vmrec.
Referenced by conf_run().
{
struct announce_listitem *current;
struct ast_conference *conf = data;
int res;
char filename[PATH_MAX] = "";
AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
AST_LIST_HEAD_INIT_NOLOCK(&local_list);
while (!conf->announcethread_stop) {
ast_mutex_lock(&conf->announcelistlock);
if (conf->announcethread_stop) {
ast_mutex_unlock(&conf->announcelistlock);
break;
}
if (AST_LIST_EMPTY(&conf->announcelist))
ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
ast_mutex_unlock(&conf->announcelistlock);
if (conf->announcethread_stop) {
break;
}
for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
ast_debug(1, "About to play %s\n", current->namerecloc);
if (!ast_fileexists(current->namerecloc, NULL, NULL))
continue;
if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
res = ast_waitstream(current->confchan, "");
if (!res) {
ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
if (!ast_streamfile(current->confchan, filename, current->language))
ast_waitstream(current->confchan, "");
}
}
if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
/* only remove it if it isn't a VM recording file */
ast_filedelete(current->namerecloc, NULL);
}
}
}
/* thread marked to stop, clean up */
while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
/* only delete if it's a vm rec */
if (!current->vmrec) {
ast_filedelete(current->namerecloc, NULL);
}
ao2_ref(current, -1);
}
return NULL;
}
| static void answer_trunk_chan | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 5838 of file app_meetme.c.
References ast_answer(), and ast_indicate().
Referenced by run_station(), sla_handle_dial_state_event(), and sla_station_exec().
{
ast_answer(chan);
ast_indicate(chan, -1);
}
| 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, read] |
Find or create a conference.
| confno | The conference name/number |
| pin | The regular user pin |
| pinadmin | The admin pin |
| make | Make the conf if it doesn't exist |
| dynamic | Mark the newly created conference as dynamic |
| refcount | How many references to mark on the conference |
| chan | The asterisk channel |
Definition at line 1247 of file app_meetme.c.
References ast_conference::announcethread, ast_conference::announcethreadlock, ao2_container_alloc, ao2_ref, ast_atomic_fetchadd_int(), ast_calloc, ast_channel_fd(), ast_channel_uniqueid(), ast_copy_string(), ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), ast_format_set(), AST_FORMAT_SLINEAR, 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_by_id(), ast_set_write_format_by_id(), ast_test_status_update, ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, 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().
{
struct ast_conference *cnf;
struct dahdi_confinfo dahdic = { 0, };
int confno_int = 0;
struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
struct ast_format tmp_fmt;
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno))
break;
}
if (cnf || (!make && !dynamic) || !cap_slin)
goto cnfout;
ast_format_cap_add(cap_slin, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
/* Make a new one */
if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
!(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
goto cnfout;
}
ast_mutex_init(&cnf->playlock);
ast_mutex_init(&cnf->listenlock);
cnf->recordthread = AST_PTHREADT_NULL;
ast_mutex_init(&cnf->recordthreadlock);
cnf->announcethread = AST_PTHREADT_NULL;
ast_mutex_init(&cnf->announcethreadlock);
ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
/* Setup a new dahdi conference */
dahdic.confno = -1;
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
if (test) {
/* if we are creating a conference for a unit test, it is not neccesary
* to open a pseudo channel, so, if we fail continue creating
* the conference. */
ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
} else {
ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
if (cnf->fd >= 0)
close(cnf->fd);
ao2_ref(cnf->usercontainer, -1);
ast_mutex_destroy(&cnf->playlock);
ast_mutex_destroy(&cnf->listenlock);
ast_mutex_destroy(&cnf->recordthreadlock);
ast_mutex_destroy(&cnf->announcethreadlock);
ast_free(cnf);
cnf = NULL;
goto cnfout;
}
}
cnf->dahdiconf = dahdic.confno;
/* Setup a new channel for playback of audio files */
cnf->chan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL);
if (cnf->chan) {
ast_set_read_format_by_id(cnf->chan, AST_FORMAT_SLINEAR);
ast_set_write_format_by_id(cnf->chan, AST_FORMAT_SLINEAR);
dahdic.chan = 0;
dahdic.confno = cnf->dahdiconf;
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
if (test) {
ast_test_status_update(test, "Error setting conference on pseudo channel\n");
}
ast_log(LOG_WARNING, "Error setting conference\n");
if (cnf->chan)
ast_hangup(cnf->chan);
else
close(cnf->fd);
ao2_ref(cnf->usercontainer, -1);
ast_mutex_destroy(&cnf->playlock);
ast_mutex_destroy(&cnf->listenlock);
ast_mutex_destroy(&cnf->recordthreadlock);
ast_mutex_destroy(&cnf->announcethreadlock);
ast_free(cnf);
cnf = NULL;
goto cnfout;
}
}
/* Fill the conference struct */
cnf->start = time(NULL);
cnf->maxusers = 0x7fffffff;
cnf->isdynamic = dynamic ? 1 : 0;
ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
AST_LIST_INSERT_HEAD(&confs, cnf, list);
/* Reserve conference number in map */
if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
conf_map[confno_int] = 1;
cnfout:
cap_slin = ast_format_cap_destroy(cap_slin);
if (cnf)
ast_atomic_fetchadd_int(&cnf->refcount, refcount);
AST_LIST_UNLOCK(&confs);
return cnf;
}
| static int can_write | ( | struct ast_channel * | chan, |
| struct ast_flags64 * | confflags | ||
| ) | [static] |
Definition at line 2317 of file app_meetme.c.
References AST_STATE_UP, ast_test_flag64, and CONFFLAG_NO_AUDIO_UNTIL_UP.
Referenced by conf_run().
{
if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
return 1;
}
return (ast_channel_state(chan) == AST_STATE_UP);
}
| static int careful_write | ( | int | fd, |
| unsigned char * | data, | ||
| int | len, | ||
| int | block | ||
| ) | [static] |
Definition at line 1050 of file app_meetme.c.
References ast_log(), errno, and LOG_WARNING.
Referenced by conf_play(), and conf_run().
{
int res;
int x;
while (len) {
if (block) {
x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
res = ioctl(fd, DAHDI_IOMUX, &x);
} else
res = 0;
if (res >= 0)
res = write(fd, data, len);
if (res < 1) {
if (errno != EAGAIN) {
ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
return -1;
} else
return 0;
}
len -= res;
data += res;
}
return 0;
}
| static int channel_admin_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command)
Definition at line 5171 of file app_meetme.c.
References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, ao2_callback, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_conf_user::list, LOG_NOTICE, LOG_WARNING, user_chan_cb(), and ast_conference::usercontainer.
Referenced by load_module().
{
char *params;
struct ast_conference *conf = NULL;
struct ast_conf_user *user = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(channel);
AST_APP_ARG(command);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
return -1;
}
params = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, params);
if (!args.channel) {
ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
return -1;
}
if (!args.command) {
ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
return -1;
}
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, conf, list) {
if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
break;
}
}
if (!user) {
ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
AST_LIST_UNLOCK(&confs);
return 0;
}
/* perform the specified action */
switch (*args.command) {
case 77: /* M: Mute */
user->adminflags |= ADMINFLAG_MUTED;
break;
case 109: /* m: Unmute */
user->adminflags &= ~ADMINFLAG_MUTED;
break;
case 107: /* k: Kick user */
user->adminflags |= ADMINFLAG_KICKME;
break;
default: /* unknown command */
ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
break;
}
ao2_ref(user, -1);
AST_LIST_UNLOCK(&confs);
return 0;
}
| static char* complete_confno | ( | const char * | word, |
| int | state | ||
| ) | [static] |
Definition at line 1361 of file app_meetme.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_conference::confno, len(), and ast_conference::list.
Referenced by complete_meetmecmd_list(), complete_meetmecmd_lock(), and complete_meetmecmd_mute_kick().
{
struct ast_conference *cnf;
char *ret = NULL;
int which = 0;
int len = strlen(word);
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strncmp(word, cnf->confno, len) && ++which > state) {
/* dup before releasing the lock */
ret = ast_strdup(cnf->confno);
break;
}
}
AST_LIST_UNLOCK(&confs);
return ret;
}
| static char* complete_meetmecmd_list | ( | const char * | line, |
| const char * | word, | ||
| int | pos, | ||
| int | state | ||
| ) | [static] |
Definition at line 1450 of file app_meetme.c.
References ast_strdup, complete_confno(), ast_conference::confno, len(), state, and STR_CONCISE.
Referenced by meetme_show_cmd().
{
int len;
if (pos == 2) {
len = strlen(word);
if (!strncasecmp(word, STR_CONCISE, len)) {
if (state == 0) {
return ast_strdup(STR_CONCISE);
}
--state;
}
return complete_confno(word, state);
}
if (pos == 3 && state == 0) {
char *saved = NULL;
char *myline;
char *confno;
/* Extract the confno from the command line. */
myline = ast_strdupa(line);
strtok_r(myline, " ", &saved);
strtok_r(NULL, " ", &saved);
confno = strtok_r(NULL, " ", &saved);
if (!strcasecmp(confno, STR_CONCISE)) {
/* There is nothing valid in this position now. */
return NULL;
}
len = strlen(word);
if (!strncasecmp(word, STR_CONCISE, len)) {
return ast_strdup(STR_CONCISE);
}
}
return NULL;
}
| static char* complete_meetmecmd_lock | ( | const char * | word, |
| int | pos, | ||
| int | state | ||
| ) | [static] |
Definition at line 1442 of file app_meetme.c.
References complete_confno().
Referenced by meetme_lock_cmd().
{
if (pos == 2) {
return complete_confno(word, state);
}
return NULL;
}
| static char* complete_meetmecmd_mute_kick | ( | const char * | line, |
| const char * | word, | ||
| int | pos, | ||
| int | state | ||
| ) | [static] |
Definition at line 1402 of file app_meetme.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, complete_confno(), complete_userno(), ast_conference::confno, len(), ast_conference::list, and state.
Referenced by meetme_kick_cmd(), and meetme_mute_cmd().
{
if (pos == 2) {
return complete_confno(word, state);
}
if (pos == 3) {
int len = strlen(word);
char *ret = NULL;
char *saved = NULL;
char *myline;
char *confno;
struct ast_conference *cnf;
if (!strncasecmp(word, "all", len)) {
if (state == 0) {
return ast_strdup("all");
}
--state;
}
/* Extract the confno from the command line. */
myline = ast_strdupa(line);
strtok_r(myline, " ", &saved);
strtok_r(NULL, " ", &saved);
confno = strtok_r(NULL, " ", &saved);
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno)) {
ret = complete_userno(cnf, word, state);
break;
}
}
AST_LIST_UNLOCK(&confs);
return ret;
}
return NULL;
}
| static char* complete_userno | ( | struct ast_conference * | cnf, |
| const char * | word, | ||
| int | state | ||
| ) | [static] |
Definition at line 1380 of file app_meetme.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, len(), ast_conf_user::user_no, and ast_conference::usercontainer.
Referenced by complete_meetmecmd_mute_kick().
{
char usrno[50];
struct ao2_iterator iter;
struct ast_conf_user *usr;
char *ret = NULL;
int which = 0;
int len = strlen(word);
iter = ao2_iterator_init(cnf->usercontainer, 0);
for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
if (!strncmp(word, usrno, len) && ++which > state) {
ao2_ref(usr, -1);
ret = ast_strdup(usrno);
break;
}
}
ao2_iterator_destroy(&iter);
return ret;
}
| static int conf_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
The meetme() application.
Definition at line 4618 of file app_meetme.c.
References ast_conference::adminopts, args, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options64(), ast_category_browse(), ast_channel_language(), ast_channel_name(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime_multientry(), ast_log(), ast_say_digits(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_test_suite_event_notify, ast_variable_browse(), ast_variable_retrieve(), ast_verb, ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_conference::isdynamic, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, SENTINEL, ast_conference::useropts, ast_conference::users, ast_variable::value, and var.
Referenced by load_module().
{
int res = -1;
char confno[MAX_CONFNUM] = "";
int allowretry = 0;
int retrycnt = 0;
struct ast_conference *cnf = NULL;
struct ast_flags64 confflags = {0};
struct ast_flags config_flags = { 0 };
int dynamic = 0;
int empty = 0, empty_no_pin = 0;
int always_prompt = 0;
const char *notdata;
char *info, the_pin[MAX_PIN] = "";
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(confno);
AST_APP_ARG(options);
AST_APP_ARG(pin);
);
char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
if (ast_strlen_zero(data)) {
allowretry = 1;
notdata = "";
} else {
notdata = data;
}
if (ast_channel_state(chan) != AST_STATE_UP)
ast_answer(chan);
info = ast_strdupa(notdata);
AST_STANDARD_APP_ARGS(args, info);
if (args.confno) {
ast_copy_string(confno, args.confno, sizeof(confno));
if (ast_strlen_zero(confno)) {
allowretry = 1;
}
}
if (args.pin)
ast_copy_string(the_pin, args.pin, sizeof(the_pin));
if (args.options) {
ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
strcpy(the_pin, "q");
empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
}
do {
if (retrycnt > 3)
allowretry = 0;
if (empty) {
int i;
struct ast_config *cfg;
struct ast_variable *var;
int confno_int;
/* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
if ((empty_no_pin) || (!dynamic)) {
cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
var = ast_variable_browse(cfg, "rooms");
while (var) {
char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
if (!strcasecmp(var->name, "conf")) {
int found = 0;
ast_copy_string(parse, var->value, sizeof(parse));
confno_tmp = strsep(&stringp, "|,");
if (!dynamic) {
/* For static: run through the list and see if this conference is empty */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno_tmp, cnf->confno)) {
/* The conference exists, therefore it's not empty */
found = 1;
break;
}
}
AST_LIST_UNLOCK(&confs);
cnf = NULL;
if (!found) {
/* At this point, we have a confno_tmp (static conference) that is empty */
if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
/* Case 1: empty_no_pin and pin is nonexistent (NULL)
* Case 2: empty_no_pin and pin is blank (but not NULL)
* Case 3: not empty_no_pin
*/
ast_copy_string(confno, confno_tmp, sizeof(confno));
break;
}
}
}
}
var = var->next;
}
ast_config_destroy(cfg);
}
if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
const char *catg;
for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
if (ast_strlen_zero(confno_tmp)) {
continue;
}
if (!dynamic) {
int found = 0;
/* For static: run through the list and see if this conference is empty */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno_tmp, cnf->confno)) {
/* The conference exists, therefore it's not empty */
found = 1;
break;
}
}
AST_LIST_UNLOCK(&confs);
if (!found) {
/* At this point, we have a confno_tmp (realtime conference) that is empty */
if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
/* Case 1: empty_no_pin and pin is nonexistent (NULL)
* Case 2: empty_no_pin and pin is blank (but not NULL)
* Case 3: not empty_no_pin
*/
ast_copy_string(confno, confno_tmp, sizeof(confno));
break;
}
}
}
}
ast_config_destroy(cfg);
}
}
/* Select first conference number not in use */
if (ast_strlen_zero(confno) && dynamic) {
AST_LIST_LOCK(&confs);
for (i = 0; i < ARRAY_LEN(conf_map); i++) {
if (!conf_map[i]) {
snprintf(confno, sizeof(confno), "%d", i);
conf_map[i] = 1;
break;
}
}
AST_LIST_UNLOCK(&confs);
}
/* Not found? */
if (ast_strlen_zero(confno)) {
res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
if (!res)
ast_waitstream(chan, "");
} else {
if (sscanf(confno, "%30d", &confno_int) == 1) {
if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
if (!res) {
ast_waitstream(chan, "");
res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
}
}
} else {
ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
}
}
}
while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
/* Prompt user for conference number */
res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
if (res < 0) {
/* Don't try to validate when we catch an error */
confno[0] = '\0';
allowretry = 0;
break;
}
}
if (!ast_strlen_zero(confno)) {
/* Check the validity of the conference */
cnf = find_conf(chan, confno, 1, dynamic, the_pin,
sizeof(the_pin), 1, &confflags);
if (!cnf) {
int too_early = 0;
cnf = find_conf_realtime(chan, confno, 1, dynamic,
the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
if (rt_schedule && too_early)
allowretry = 0;
}
if (!cnf) {
if (allowretry) {
confno[0] = '\0';
res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
if (!res)
ast_waitstream(chan, "");
res = -1;
}
} else {
/* Conference requires a pin for specified access level */
int req_pin = !ast_strlen_zero(cnf->pin) ||
(!ast_strlen_zero(cnf->pinadmin) &&
ast_test_flag64(&confflags, CONFFLAG_ADMIN));
/* The following logic was derived from a
* 4 variable truth table and defines which
* circumstances are not exempt from pin
* checking.
* If this needs to be modified, write the
* truth table back out from the boolean
* expression AB+A'D+C', change the erroneous
* result, and rederive the expression.
* Variables:
* A: pin provided?
* B: always prompt?
* C: dynamic?
* D: has users? */
int not_exempt = !cnf->isdynamic;
not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
if (req_pin && not_exempt) {
char pin[MAX_PIN] = "";
int j;
/* Allow the pin to be retried up to 3 times */
for (j = 0; j < 3; j++) {
if (*the_pin && (always_prompt == 0)) {
ast_copy_string(pin, the_pin, sizeof(pin));
res = 0;
} else {
/* Prompt user for pin if pin is required */
ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
"Channel: %s",
ast_channel_name(chan));
res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
}
if (res >= 0) {
if ((!strcasecmp(pin, cnf->pin) &&
(ast_strlen_zero(cnf->pinadmin) ||
!ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
(!ast_strlen_zero(cnf->pinadmin) &&
!strcasecmp(pin, cnf->pinadmin))) {
/* Pin correct */
allowretry = 0;
if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
if (!ast_strlen_zero(cnf->adminopts)) {
char *opts = ast_strdupa(cnf->adminopts);
ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
}
} else {
if (!ast_strlen_zero(cnf->useropts)) {
char *opts = ast_strdupa(cnf->useropts);
ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
}
}
/* Run the conference */
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
res = conf_run(chan, cnf, &confflags, optargs);
break;
} else {
/* Pin invalid */
if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
} else {
ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
break;
}
if (res < 0)
break;
pin[0] = res;
pin[1] = '\0';
res = -1;
if (allowretry)
confno[0] = '\0';
}
} else {
/* failed when getting the pin */
res = -1;
allowretry = 0;
/* see if we need to get rid of the conference */
break;
}
/* Don't retry pin with a static pin */
if (*the_pin && (always_prompt == 0)) {
break;
}
}
} else {
/* No pin required */
allowretry = 0;
/* For RealTime conferences without a pin
* should still support loading options
*/
if (!ast_strlen_zero(cnf->useropts)) {
char *opts = ast_strdupa(cnf->useropts);
ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
}
/* Run the conference */
res = conf_run(chan, cnf, &confflags, optargs);
}
dispose_conf(cnf);
cnf = NULL;
}
}
} while (allowretry);
if (cnf)
dispose_conf(cnf);
return res;
}
| static void conf_flush | ( | int | fd, |
| struct ast_channel * | chan | ||
| ) | [static] |
Definition at line 1932 of file app_meetme.c.
References ast_frfree, ast_log(), ast_read(), ast_waitfor(), f, and LOG_WARNING.
Referenced by conf_run().
{
int x;
/* read any frames that may be waiting on the channel
and throw them away
*/
if (chan) {
struct ast_frame *f;
/* when no frames are available, this will wait
for 1 millisecond maximum
*/
while (ast_waitfor(chan, 1) > 0) {
f = ast_read(chan);
if (f)
ast_frfree(f);
else /* channel was hung up or something else happened */
break;
}
}
/* flush any data sitting in the pseudo channel */
x = DAHDI_FLUSH_ALL;
if (ioctl(fd, DAHDI_FLUSH, &x))
ast_log(LOG_WARNING, "Error flushing channel\n");
}
| 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 1964 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::confno, EVENT_FLAG_CALL, ast_conference::fd, ast_conference::lchan, ast_conference::listenlock, manager_event, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, announce_listitem::namerecloc, 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().
{
int x;
struct announce_listitem *item;
AST_LIST_REMOVE(&confs, conf, list);
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a MeetMe conference ends.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
</syntax>
<see-also>
<ref type="managerEvent">MeetmeJoin</ref>
</see-also>
</managerEventInstance>
***/
manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
if (conf->recording == MEETME_RECORD_ACTIVE) {
conf->recording = MEETME_RECORD_TERMINATE;
AST_LIST_UNLOCK(&confs);
while (1) {
usleep(1);
AST_LIST_LOCK(&confs);
if (conf->recording == MEETME_RECORD_OFF)
break;
AST_LIST_UNLOCK(&confs);
}
}
for (x = 0; x < AST_FRAME_BITS; x++) {
if (conf->transframe[x])
ast_frfree(conf->transframe[x]);
if (conf->transpath[x])
ast_translator_free_path(conf->transpath[x]);
}
if (conf->announcethread != AST_PTHREADT_NULL) {
ast_mutex_lock(&conf->announcelistlock);
conf->announcethread_stop = 1;
ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
ast_cond_signal(&conf->announcelist_addition);
ast_mutex_unlock(&conf->announcelistlock);
pthread_join(conf->announcethread, NULL);
while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
/* If it's a voicemail greeting file we don't want to remove it */
if (!item->vmrec){
ast_filedelete(item->namerecloc, NULL);
}
ao2_ref(item, -1);
}
ast_mutex_destroy(&conf->announcelistlock);
}
if (conf->origframe)
ast_frfree(conf->origframe);
if (conf->lchan)
ast_hangup(conf->lchan);
if (conf->chan)
ast_hangup(conf->chan);
if (conf->fd >= 0)
close(conf->fd);
if (conf->recordingfilename) {
ast_free(conf->recordingfilename);
}
if (conf->usercontainer) {
ao2_ref(conf->usercontainer, -1);
}
if (conf->recordingformat) {
ast_free(conf->recordingformat);
}
ast_mutex_destroy(&conf->playlock);
ast_mutex_destroy(&conf->listenlock);
ast_mutex_destroy(&conf->recordthreadlock);
ast_mutex_destroy(&conf->announcethreadlock);
ast_free(conf);
return 0;
}
| static void conf_play | ( | struct ast_channel * | chan, |
| struct ast_conference * | conf, | ||
| enum entrance_sound | sound | ||
| ) | [static] |
Definition at line 1168 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(), and ast_conference::markedusers.
Referenced by conf_run().
{
unsigned char *data;
int len;
int res = -1;
ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
"Conference: %s\r\n"
"Marked: %d",
ast_channel_name(chan),
conf->confno,
conf->markedusers);
if (!ast_check_hangup(chan))
res = ast_autoservice_start(chan);
AST_LIST_LOCK(&confs);
switch(sound) {
case ENTER:
data = enter;
len = sizeof(enter);
break;
case LEAVE:
data = leave;
len = sizeof(leave);
break;
default:
data = NULL;
len = 0;
}
if (data) {
careful_write(conf->fd, data, len, 1);
}
AST_LIST_UNLOCK(&confs);
if (!res)
ast_autoservice_stop(chan);
}
| static void conf_queue_dtmf | ( | const struct ast_conference * | conf, |
| const struct ast_conf_user * | sender, | ||
| struct ast_frame * | f | ||
| ) | [static] |
Definition at line 2045 of file app_meetme.c.
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().
{
struct ast_conf_user *user;
struct ao2_iterator user_iter;
user_iter = ao2_iterator_init(conf->usercontainer, 0);
while ((user = ao2_iterator_next(&user_iter))) {
if (user == sender) {
ao2_ref(user, -1);
continue;
}
if (ast_write(user->chan, f) < 0)
ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
ao2_ref(user, -1);
}
ao2_iterator_destroy(&user_iter);
}
| static int conf_run | ( | struct ast_channel * | chan, |
| struct ast_conference * | conf, | ||
| struct ast_flags64 * | confflags, | ||
| char * | optargs[] | ||
| ) | [static] |
Definition at line 2839 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_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_audiohooks(), ast_channel_caller(), ast_channel_connected(), 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_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), ast_format_from_old_bitfield(), ast_format_set(), AST_FORMAT_SLINEAR, ast_format_to_old_bitfield(), 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_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), 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_manager_event, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_module_helper(), 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_by_id(), ast_set_write_format_by_id(), ast_stopstream(), ast_strdup, 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, 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, EVENT_FLAG_CALL, exitcontext, f, ast_frame_subclass::format, ast_frame::frametype, ast_conference::gmuted, ast_format::id, ast_party_caller::id, ast_party_connected_line::id, ast_frame_subclass::integer, ast_conference::isdynamic, 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(), MENU_ADMIN, MENU_DISABLED, MENU_NORMAL, ast_variable::name, ast_party_id::name, announce_listitem::namerecloc, ast_conf_user::namerecloc, ast_variable::next, ast_party_id::number, 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(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conf_user::play_warning, ast_conference::playlock, ast_frame::ptr, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, S_COR, ast_frame::samples, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, ast_party_name::str, ast_party_number::str, 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_party_name::valid, ast_party_number::valid, 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().
{
struct ast_conf_user *user = NULL;
int fd;
struct dahdi_confinfo dahdic, dahdic_empty;
struct ast_frame *f;
struct ast_channel *c;
struct ast_frame fr;
int outfd;
int ms;
int nfds;
int res;
int retrydahdi;
int origfd;
int musiconhold = 0, mohtempstopped = 0;
int firstpass = 0;
int lastmarked = 0;
int currentmarked = 0;
int ret = -1;
int x;
enum menu_modes menu_mode = MENU_DISABLED;
int talkreq_manager = 0;
int using_pseudo = 0;
int duration = 20;
int sent_event = 0;
int checked = 0;
int announcement_played = 0;
struct timeval now;
struct ast_dsp *dsp = NULL;
struct ast_app *agi_app;
char *agifile, *mod_speex;
const char *agifiledefault = "conf-background.agi", *tmpvar;
char meetmesecs[30] = "";
char exitcontext[AST_MAX_CONTEXT] = "";
char recordingtmp[AST_MAX_EXTENSION] = "";
char members[10] = "";
int dtmf = 0, opt_waitmarked_timeout = 0;
time_t timeout = 0;
struct dahdi_bufferinfo bi;
char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
char *buf = __buf + AST_FRIENDLY_OFFSET;
char *exitkeys = NULL;
unsigned int calldurationlimit = 0;
long timelimit = 0;
long play_warning = 0;
long warning_freq = 0;
const char *warning_sound = NULL;
const char *end_sound = NULL;
char *parse;
long time_left_ms = 0;
struct timeval nexteventts = { 0, };
int to;
int setusercount = 0;
int confsilence = 0, totalsilence = 0;
char *mailbox, *context;
struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
struct ast_format tmpfmt;
if (!cap_slin) {
goto conf_run_cleanup;
}
ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
if (!(user = ao2_alloc(sizeof(*user), NULL))) {
goto conf_run_cleanup;
}
/* Possible timeout waiting for marked user */
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
!ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
(sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
(opt_waitmarked_timeout > 0)) {
timeout = time(NULL) + opt_waitmarked_timeout;
}
if (ast_test_flag64(confflags, CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
}
if (ast_test_flag64(confflags, CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
char *limit_str, *warning_str, *warnfreq_str;
const char *var;
parse = optargs[OPT_ARG_DURATION_LIMIT];
limit_str = strsep(&parse, ":");
warning_str = strsep(&parse, ":");
warnfreq_str = parse;
timelimit = atol(limit_str);
if (warning_str)
play_warning = atol(warning_str);
if (warnfreq_str)
warning_freq = atol(warnfreq_str);
if (!timelimit) {
timelimit = play_warning = warning_freq = 0;
warning_sound = NULL;
} else if (play_warning > timelimit) {
if (!warning_freq) {
play_warning = 0;
} else {
while (play_warning > timelimit)
play_warning -= warning_freq;
if (play_warning < 1)
play_warning = warning_freq = 0;
}
}
ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
if (play_warning) {
ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
}
if (warning_freq) {
ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
}
ast_channel_lock(chan);
if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
var = ast_strdupa(var);
}
ast_channel_unlock(chan);
warning_sound = var ? var : "timeleft";
ast_channel_lock(chan);
if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
var = ast_strdupa(var);
}
ast_channel_unlock(chan);
end_sound = var ? var : NULL;
/* undo effect of S(x) in case they are both used */
calldurationlimit = 0;
/* more efficient do it like S(x) does since no advanced opts */
if (!play_warning && !end_sound && timelimit) {
calldurationlimit = timelimit / 1000;
timelimit = play_warning = warning_freq = 0;
} else {
ast_debug(2, "Limit Data for this call:\n");
ast_debug(2, "- timelimit = %ld\n", timelimit);
ast_debug(2, "- play_warning = %ld\n", play_warning);
ast_debug(2, "- warning_freq = %ld\n", warning_freq);
ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
}
}
/* Get exit keys */
if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
else
exitkeys = ast_strdupa("#"); /* Default */
}
if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
if (!conf->recordingfilename) {
const char *var;
ast_channel_lock(chan);
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
conf->recordingfilename = ast_strdup(var);
}
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
conf->recordingformat = ast_strdup(var);
}
ast_channel_unlock(chan);
if (!conf->recordingfilename) {
snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
conf->recordingfilename = ast_strdup(recordingtmp);
}
if (!conf->recordingformat) {
conf->recordingformat = ast_strdup("wav");
}
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
conf->confno, conf->recordingfilename, conf->recordingformat);
}
}
ast_mutex_lock(&conf->recordthreadlock);
if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
dahdic.chan = 0;
dahdic.confno = conf->dahdiconf;
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error starting listen channel\n");
ast_hangup(conf->lchan);
conf->lchan = NULL;
} else {
ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
}
}
ast_mutex_unlock(&conf->recordthreadlock);
ast_mutex_lock(&conf->announcethreadlock);
if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
ast_mutex_init(&conf->announcelistlock);
AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
}
ast_mutex_unlock(&conf->announcethreadlock);
time(&user->jointime);
user->timelimit = timelimit;
user->play_warning = play_warning;
user->warning_freq = warning_freq;
user->warning_sound = warning_sound;
user->end_sound = end_sound;
if (calldurationlimit > 0) {
time(&user->kicktime);
user->kicktime = user->kicktime + calldurationlimit;
}
if (ast_tvzero(user->start_time))
user->start_time = ast_tvnow();
time_left_ms = user->timelimit;
if (user->timelimit) {
nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
}
if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
/* Sorry, but this conference is locked! */
if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
ast_waitstream(chan, "");
goto outrun;
}
ast_mutex_lock(&conf->playlock);
if (rt_schedule && conf->maxusers) {
if (conf->users >= conf->maxusers) {
/* Sorry, but this confernce has reached the participant limit! */
if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
ast_waitstream(chan, "");
ast_mutex_unlock(&conf->playlock);
goto outrun;
}
}
ao2_lock(conf->usercontainer);
ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
user->user_no++;
ao2_link(conf->usercontainer, user);
ao2_unlock(conf->usercontainer);
user->chan = chan;
user->userflags = *confflags;
user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
user->talking = -1;
ast_mutex_unlock(&conf->playlock);
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC))) {
char destdir[PATH_MAX];
snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
if (ast_mkdir(destdir, 0777) != 0) {
ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
goto outrun;
}
if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
context = ast_strdupa(optargs[OPT_ARG_INTROUSER_VMREC]);
mailbox = strsep(&context, "@");
if (ast_strlen_zero(mailbox)) {
/* invalid input, clear the v flag*/
ast_clear_flag64(confflags,CONFFLAG_INTROUSER_VMREC);
ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
} else {
if (ast_strlen_zero(context)) {
context = "default";
}
/* if there is no mailbox we don't need to do this logic */
snprintf(user->namerecloc, sizeof(user->namerecloc),
"%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
/* if the greeting doesn't exist then use the temp file method instead, clear flag v */
if (!ast_fileexists(user->namerecloc, NULL, NULL)){
snprintf(user->namerecloc, sizeof(user->namerecloc),
"%s/meetme-username-%s-%d", destdir,
conf->confno, user->user_no);
ast_clear_flag64(confflags, CONFFLAG_INTROUSER_VMREC);
}
}
} else {
snprintf(user->namerecloc, sizeof(user->namerecloc),
"%s/meetme-username-%s-%d", destdir,
conf->confno, user->user_no);
}
res = 0;
if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) && !ast_fileexists(user->namerecloc, NULL, NULL))
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);
else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
if (res == -1)
goto outrun;
}
ast_mutex_lock(&conf->playlock);
if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
conf->markedusers++;
conf->users++;
if (rt_log_members) {
/* Update table */
snprintf(members, sizeof(members), "%d", conf->users);
ast_realtime_require_field("meetme",
"confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
"members", RQ_UINTEGER1, strlen(members),
NULL);
ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
}
setusercount = 1;
/* This device changed state now - if this is the first user */
if (conf->users == 1)
ast_devstate_changed(AST_DEVICE_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
ast_mutex_unlock(&conf->playlock);
/* return the unique ID of the conference */
pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
ast_channel_lock(chan);
if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
} else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
} else {
ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
}
ast_channel_unlock(chan);
}
/* Play an arbitrary intro message */
if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
!ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
ast_waitstream(chan, "");
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
ast_waitstream(chan, "");
}
if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
int keepplaying = 1;
if (conf->users == 2) {
if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0)
keepplaying = 0;
else if (res == -1)
goto outrun;
}
} else {
if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0)
keepplaying = 0;
else if (res == -1)
goto outrun;
}
if (keepplaying) {
res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
if (res > 0)
keepplaying = 0;
else if (res == -1)
goto outrun;
}
if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0)
keepplaying = 0;
else if (res == -1)
goto outrun;
}
}
}
if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
/* We're leaving this alone until the state gets changed to up */
ast_indicate(chan, -1);
}
if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
goto outrun;
}
if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
goto outrun;
}
/* Reduce background noise from each participant */
if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE) &&
(mod_speex = ast_module_helper("", "func_speex", 0, 0, 0, 0))) {
ast_free(mod_speex);
ast_func_write(chan, "DENOISE(rx)", "on");
}
retrydahdi = (strcasecmp(ast_channel_tech(chan)->type, "DAHDI") || (ast_channel_audiohooks(chan) || ast_channel_monitor(chan)) ? 1 : 0);
user->dahdichannel = !retrydahdi;
dahdiretry:
origfd = ast_channel_fd(chan, 0);
if (retrydahdi) {
/* open pseudo in non-blocking mode */
fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
if (fd < 0) {
ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
goto outrun;
}
using_pseudo = 1;
/* Setup buffering information */
memset(&bi, 0, sizeof(bi));
bi.bufsize = CONF_SIZE / 2;
bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
bi.numbufs = audio_buffers;
if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
close(fd);
goto outrun;
}
x = 1;
if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
close(fd);
goto outrun;
}
nfds = 1;
} else {
/* XXX Make sure we're not running on a pseudo channel XXX */
fd = ast_channel_fd(chan, 0);
nfds = 0;
}
memset(&dahdic, 0, sizeof(dahdic));
memset(&dahdic_empty, 0, sizeof(dahdic_empty));
/* Check to see if we're in a conference... */
dahdic.chan = 0;
if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error getting conference\n");
close(fd);
goto outrun;
}
if (dahdic.confmode) {
/* Whoa, already in a conference... Retry... */
if (!retrydahdi) {
ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
retrydahdi = 1;
goto dahdiretry;
}
}
memset(&dahdic, 0, sizeof(dahdic));
/* Add us to the conference */
dahdic.chan = 0;
dahdic.confno = conf->dahdiconf;
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) || ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)) && conf->users > 1) {
struct announce_listitem *item;
if (!(item = ao2_alloc(sizeof(*item), NULL)))
goto outrun;
ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
item->confchan = conf->chan;
item->confusers = conf->users;
if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
item->vmrec = 1;
}
item->announcetype = CONF_HASJOIN;
ast_mutex_lock(&conf->announcelistlock);
ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
ast_cond_signal(&conf->announcelist_addition);
ast_mutex_unlock(&conf->announcelistlock);
while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
;
}
ao2_ref(item, -1);
}
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
dahdic.confmode = DAHDI_CONF_CONF;
else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
else
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error setting conference\n");
close(fd);
goto outrun;
}
ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
if (!sent_event) {
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a user joins a MeetMe conference.</synopsis>
<syntax>
<parameter name="Meetme">
<para>The identifier for the MeetMe conference.</para>
</parameter>
<parameter name="Usernum">
<para>The identifier of the MeetMe user who joined.</para>
</parameter>
</syntax>
<see-also>
<ref type="managerEvent">MeetmeLeave</ref>
<ref type="application">MeetMe</ref>
</see-also>
</managerEventInstance>
***/
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeJoin",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"CallerIDnum: %s\r\n"
"CallerIDname: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n",
ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno,
user->user_no,
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<unknown>"),
S_COR(ast_channel_connected(user->chan)->id.number.valid, ast_channel_connected(user->chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<unknown>")
);
sent_event = 1;
}
if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
firstpass = 1;
if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
(conf->markedusers >= 1))) {
conf_play(chan, conf, ENTER);
}
}
conf_flush(fd, chan);
if (dsp)
ast_dsp_free(dsp);
if (!(dsp = ast_dsp_new())) {
ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
res = -1;
}
if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
/* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
or use default filename of conf-background.agi */
ast_channel_lock(chan);
if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
agifile = ast_strdupa(tmpvar);
} else {
agifile = ast_strdupa(agifiledefault);
}
ast_channel_unlock(chan);
if (user->dahdichannel) {
/* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
x = 1;
ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
}
/* Find a pointer to the agi app and execute the script */
agi_app = pbx_findapp("agi");
if (agi_app) {
ret = pbx_exec(chan, agi_app, agifile);
} else {
ast_log(LOG_WARNING, "Could not find application (agi)\n");
ret = -2;
}
if (user->dahdichannel) {
/* Remove CONFMUTE mode on DAHDI channel */
x = 0;
ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
}
} else {
int lastusers = conf->users;
if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
/* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
x = 1;
ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
}
for (;;) {
int menu_was_active = 0;
outfd = -1;
ms = -1;
now = ast_tvnow();
if (rt_schedule && conf->endtime) {
char currenttime[32];
long localendtime = 0;
int extended = 0;
struct ast_tm tm;
struct ast_variable *var, *origvar;
struct timeval tmp;
if (now.tv_sec % 60 == 0) {
if (!checked) {
ast_localtime(&now, &tm, NULL);
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
var = origvar = ast_load_realtime("meetme", "confno",
conf->confno, "starttime <=", currenttime,
"endtime >=", currenttime, NULL);
for ( ; var; var = var->next) {
if (!strcasecmp(var->name, "endtime")) {
struct ast_tm endtime_tm;
ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
tmp = ast_mktime(&endtime_tm, NULL);
localendtime = tmp.tv_sec;
}
}
ast_variables_destroy(origvar);
/* A conference can be extended from the
Admin/User menu or by an external source */
if (localendtime > conf->endtime){
conf->endtime = localendtime;
extended = 1;
}
if (conf->endtime && (now.tv_sec >= conf->endtime)) {
ast_verbose("Quitting time...\n");
goto outrun;
}
if (!announcement_played && conf->endalert) {
if (now.tv_sec + conf->endalert >= conf->endtime) {
if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
ast_waitstream(chan, "");
ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
ast_waitstream(chan, "");
if (musiconhold) {
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
}
announcement_played = 1;
}
}
if (extended) {
announcement_played = 0;
}
checked = 1;
}
} else {
checked = 0;
}
}
if (user->kicktime && (user->kicktime <= now.tv_sec)) {
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
ret = 0;
} else {
ret = -1;
}
break;
}
to = -1;
if (user->timelimit) {
int minutes = 0, seconds = 0, remain = 0;
to = ast_tvdiff_ms(nexteventts, now);
if (to < 0) {
to = 0;
}
time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
if (time_left_ms < to) {
to = time_left_ms;
}
if (time_left_ms <= 0) {
if (user->end_sound) {
res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
res = ast_waitstream(chan, "");
}
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
ret = 0;
} else {
ret = -1;
}
break;
}
if (!to) {
if (time_left_ms >= 5000) {
remain = (time_left_ms + 500) / 1000;
if (remain / 60 >= 1) {
minutes = remain / 60;
seconds = remain % 60;
} else {
seconds = remain;
}
/* force the time left to round up if appropriate */
if (user->warning_sound && user->play_warning) {
if (!strcmp(user->warning_sound, "timeleft")) {
res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
res = ast_waitstream(chan, "");
if (minutes) {
res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
res = ast_waitstream(chan, "");
}
if (seconds) {
res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
res = ast_waitstream(chan, "");
}
} else {
res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
res = ast_waitstream(chan, "");
}
if (musiconhold) {
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
}
}
}
if (user->warning_freq) {
nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
} else {
nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
}
}
}
now = ast_tvnow();
if (timeout && now.tv_sec >= timeout) {
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
ret = 0;
} else {
ret = -1;
}
break;
}
/* if we have just exited from the menu, and the user had a channel-driver
volume adjustment, restore it
*/
if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
set_talk_volume(user, user->listen.desired);
}
menu_was_active = menu_mode;
currentmarked = conf->markedusers;
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
lastmarked == 0) {
if (currentmarked == 1 && conf->users > 1) {
ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
if (conf->users - 1 == 1) {
if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
}
if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
}
/* Update the struct with the actual confflags */
user->userflags = *confflags;
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
if (currentmarked == 0) {
if (lastmarked != 0) {
if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
ret = 0;
}
break;
} else {
dahdic.confmode = DAHDI_CONF_CONF;
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error setting conference\n");
close(fd);
goto outrun;
}
}
}
if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
musiconhold = 1;
}
} else if (currentmarked >= 1 && lastmarked == 0) {
/* Marked user entered, so cancel timeout */
timeout = 0;
if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
} else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
} else {
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
}
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error setting conference\n");
close(fd);
goto outrun;
}
if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
ast_moh_stop(chan);
musiconhold = 0;
}
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
!ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
conf_play(chan, conf, ENTER);
}
}
}
/* trying to add moh for single person conf */
if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
if (conf->users == 1) {
if (!musiconhold) {
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
musiconhold = 1;
}
} else {
if (musiconhold) {
ast_moh_stop(chan);
musiconhold = 0;
}
}
}
/* Leave if the last marked user left */
if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
ret = 0;
} else {
ret = -1;
}
break;
}
/* Throw a TestEvent if a user exit did not cause this user to leave the conference */
if (conf->users != lastusers) {
if (conf->users < lastusers) {
ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
}
lastusers = conf->users;
}
/* Check if my modes have changed */
/* If I should be muted but am still talker, mute me */
if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
dahdic.confmode ^= DAHDI_CONF_TALKER;
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
ret = -1;
break;
}
/* Indicate user is not talking anymore - change him to unmonitored state */
if (ast_test_flag64(confflags, (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
set_user_talking(chan, conf, user, -1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
}
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a MeetMe user is muted.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
<parameter name="Status">
<enumlist>
<enum name="on"/>
<enum name="off"/>
</enumlist>
</parameter>
</syntax>
</managerEventInstance>
***/
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"Status: on\r\n",
ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
}
/* If I should be un-muted but am not talker, un-mute me */
if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
dahdic.confmode |= DAHDI_CONF_TALKER;
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
ret = -1;
break;
}
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a MeetMe user is unmuted.</synopsis>
</managerEventInstance>
***/
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"Status: off\r\n",
ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
}
if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
(user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
talkreq_manager = 1;
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a MeetMe user has started talking.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
<parameter name="Status">
<enumlist>
<enum name="on"/>
<enum name="off"/>
</enumlist>
</parameter>
</syntax>
</managerEventInstance>
***/
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"Status: on\r\n",
ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
}
if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
!(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
talkreq_manager = 0;
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a MeetMe user has finished talking.</synopsis>
</managerEventInstance>
***/
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"Status: off\r\n",
ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
}
/* If user have been hung up, exit the conference */
if (user->adminflags & ADMINFLAG_HANGUP) {
ret = 0;
break;
}
/* If I have been kicked, exit the conference */
if (user->adminflags & ADMINFLAG_KICKME) {
/* You have been kicked. */
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
!ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
ret = 0;
break;
}
/* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
if (ast_check_hangup(chan)) {
break;
}
c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
if (c) {
char dtmfstr[2] = "";
if (ast_channel_fd(c, 0) != origfd || (user->dahdichannel && (ast_channel_audiohooks(c) || ast_channel_monitor(c)))) {
if (using_pseudo) {
/* Kill old pseudo */
close(fd);
using_pseudo = 0;
}
ast_debug(1, "Ooh, something swapped out under us, starting over\n");
retrydahdi = (strcasecmp(ast_channel_tech(c)->type, "DAHDI") || (ast_channel_audiohooks(c) || ast_channel_monitor(c)) ? 1 : 0);
user->dahdichannel = !retrydahdi;
goto dahdiretry;
}
if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
f = ast_read_noaudio(c);
} else {
f = ast_read(c);
}
if (!f) {
break;
}
if (f->frametype == AST_FRAME_DTMF) {
dtmfstr[0] = f->subclass.integer;
dtmfstr[1] = '\0';
}
if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
if (user->talk.actual) {
ast_frame_adjust_volume(f, user->talk.actual);
}
if (ast_test_flag64(confflags, (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER))) {
if (user->talking == -1) {
user->talking = 0;
}
res = ast_dsp_silence(dsp, f, &totalsilence);
if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
set_user_talking(chan, conf, user, 1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
}
if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
set_user_talking(chan, conf, user, 0, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
}
}
if (using_pseudo) {
/* Absolutely do _not_ use careful_write here...
it is important that we read data from the channel
as fast as it arrives, and feed it into the conference.
The buffering in the pseudo channel will take care of any
timing differences, unless they are so drastic as to lose
audio frames (in which case carefully writing would only
have delayed the audio even further).
*/
/* As it turns out, we do want to use careful write. We just
don't want to block, but we do want to at least *try*
to write out all the samples.
*/
if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
careful_write(fd, f->data.ptr, f->datalen, 0);
}
}
} else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
conf_queue_dtmf(conf, user, f);
}
if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
ast_log(LOG_WARNING, "Error setting conference\n");
close(fd);
ast_frfree(f);
goto outrun;
}
/* if we are entering the menu, and the user has a channel-driver
volume adjustment, clear it
*/
if (!menu_mode && user->talk.desired && !user->talk.actual) {
set_talk_volume(user, 0);
}
if (musiconhold) {
ast_moh_stop(chan);
} else if (!menu_mode) {
char *menu_to_play;
if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
menu_mode = MENU_ADMIN;
menu_to_play = "conf-adminmenu-18";
} else {
menu_mode = MENU_NORMAL;
menu_to_play = "conf-usermenu-162";
}
if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
} else {
dtmf = 0;
}
} else {
dtmf = f->subclass.integer;
}
if (dtmf > 0) {
meetme_menu(&menu_mode, &dtmf, conf, confflags, chan, user, recordingtmp, sizeof(recordingtmp), &dahdic, cap_slin);
}
if (musiconhold && !menu_mode) {
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
}
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error setting conference\n");
close(fd);
ast_frfree(f);
goto outrun;
}
conf_flush(fd, chan);
/*
* Since options using DTMF could absorb DTMF meant for the
* conference menu, we have to check them after the menu.
*/
} else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
conf_queue_dtmf(conf, user, f);
}
if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
ret = 0;
ast_frfree(f);
break;
} else {
ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
}
} else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
(strchr(exitkeys, f->subclass.integer))) {
pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
conf_queue_dtmf(conf, user, f);
}
ret = 0;
ast_frfree(f);
break;
} else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
&& ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
conf_queue_dtmf(conf, user, f);
} else if (ast_test_flag64(confflags, CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
switch (f->subclass.integer) {
case AST_CONTROL_HOLD:
sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
break;
default:
break;
}
} else if (f->frametype == AST_FRAME_NULL) {
/* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
} else if (f->frametype == AST_FRAME_CONTROL) {
switch (f->subclass.integer) {
case AST_CONTROL_BUSY:
case AST_CONTROL_CONGESTION:
ast_frfree(f);
goto outrun;
break;
default:
ast_debug(1,
"Got ignored control frame on channel %s, f->frametype=%d,f->subclass=%d\n",
ast_channel_name(chan), f->frametype, f->subclass.integer);
}
} else {
ast_debug(1,
"Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
ast_channel_name(chan), f->frametype, f->subclass.integer);
}
ast_frfree(f);
} else if (outfd > -1) {
res = read(outfd, buf, CONF_SIZE);
if (res > 0) {
memset(&fr, 0, sizeof(fr));
fr.frametype = AST_FRAME_VOICE;
ast_format_set(&fr.subclass.format, AST_FORMAT_SLINEAR, 0);
fr.datalen = res;
fr.samples = res / 2;
fr.data.ptr = buf;
fr.offset = AST_FRIENDLY_OFFSET;
if (!user->listen.actual &&
(ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
(!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
)) {
int idx;
for (idx = 0; idx < AST_FRAME_BITS; idx++) {
if (ast_format_to_old_bitfield(ast_channel_rawwriteformat(chan)) & (1 << idx)) {
break;
}
}
if (idx >= AST_FRAME_BITS) {
goto bailoutandtrynormal;
}
ast_mutex_lock(&conf->listenlock);
if (!conf->transframe[idx]) {
if (conf->origframe) {
if (musiconhold && !ast_dsp_silence(dsp, conf->origframe, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
ast_moh_stop(chan);
mohtempstopped = 1;
}
if (!conf->transpath[idx]) {
struct ast_format src;
struct ast_format dst;
ast_format_set(&src, AST_FORMAT_SLINEAR, 0);
ast_format_from_old_bitfield(&dst, (1 << idx));
conf->transpath[idx] = ast_translator_build_path(&dst, &src);
}
if (conf->transpath[idx]) {
conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
if (!conf->transframe[idx]) {
conf->transframe[idx] = &ast_null_frame;
}
}
}
}
if (conf->transframe[idx]) {
if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
can_write(chan, confflags)) {
struct ast_frame *cur;
/* the translator may have returned a list of frames, so
write each one onto the channel
*/
for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
if (ast_write(chan, cur)) {
ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
break;
}
}
if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
mohtempstopped = 0;
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
}
}
} else {
ast_mutex_unlock(&conf->listenlock);
goto bailoutandtrynormal;
}
ast_mutex_unlock(&conf->listenlock);
} else {
bailoutandtrynormal:
if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
ast_moh_stop(chan);
mohtempstopped = 1;
}
if (user->listen.actual) {
ast_frame_adjust_volume(&fr, user->listen.actual);
}
if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
}
if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
mohtempstopped = 0;
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
}
}
} else {
ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
}
}
lastmarked = currentmarked;
}
}
if (musiconhold) {
ast_moh_stop(chan);
}
if (using_pseudo) {
close(fd);
} else {
/* Take out of conference */
dahdic.chan = 0;
dahdic.confno = 0;
dahdic.confmode = 0;
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
ast_log(LOG_WARNING, "Error setting conference\n");
}
}
reset_volumes(user);
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
conf_play(chan, conf, LEAVE);
}
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER |CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC) && conf->users > 1) {
struct announce_listitem *item;
if (!(item = ao2_alloc(sizeof(*item), NULL)))
goto outrun;
ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
item->confchan = conf->chan;
item->confusers = conf->users;
item->announcetype = CONF_HASLEFT;
if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
item->vmrec = 1;
}
ast_mutex_lock(&conf->announcelistlock);
AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
ast_cond_signal(&conf->announcelist_addition);
ast_mutex_unlock(&conf->announcelistlock);
} else if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) && !ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC) && conf->users == 1) {
/* Last person is leaving, so no reason to try and announce, but should delete the name recording */
ast_filedelete(user->namerecloc, NULL);
}
outrun:
AST_LIST_LOCK(&confs);
if (dsp) {
ast_dsp_free(dsp);
}
if (user->user_no) {
/* Only cleanup users who really joined! */
now = ast_tvnow();
if (sent_event) {
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a user leaves a MeetMe conference.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
<parameter name="Duration">
<para>The length of time in seconds that the Meetme user was in the conference.</para>
</parameter>
</syntax>
<see-also>
<ref type="managerEvent">MeetmeJoin</ref>
</see-also>
</managerEventInstance>
***/
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeLeave",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Duration: %ld\r\n",
ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno,
user->user_no,
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<unknown>"),
S_COR(ast_channel_connected(user->chan)->id.number.valid, ast_channel_connected(user->chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<unknown>"),
(long)(now.tv_sec - user->jointime));
}
if (setusercount) {
conf->users--;
if (rt_log_members) {
/* Update table */
snprintf(members, sizeof(members), "%d", conf->users);
ast_realtime_require_field("meetme",
"confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
"members", RQ_UINTEGER1, strlen(members),
NULL);
ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
}
if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
conf->markedusers--;
}
}
/* Remove ourselves from the container */
ao2_unlink(conf->usercontainer, user);
/* Change any states */
if (!conf->users) {
ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
}
/* This flag is meant to kill a conference with only one participant remaining. */
if (conf->users == 1 && ast_test_flag64(confflags, CONFFLAG_KILL_LAST_MAN_STANDING)) {
ao2_callback(conf->usercontainer, 0, user_set_hangup_cb, NULL);
}
/* Return the number of seconds the user was in the conf */
snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
/* Return the RealTime bookid for CDR linking */
if (rt_schedule) {
pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
}
}
ao2_ref(user, -1);
AST_LIST_UNLOCK(&confs);
conf_run_cleanup:
cap_slin = ast_format_cap_destroy(cap_slin);
return ret;
}
| static void conf_start_moh | ( | struct ast_channel * | chan, |
| const char * | musicclass | ||
| ) | [static] |
Definition at line 2230 of file app_meetme.c.
References ast_channel_lock, ast_channel_musicclass(), ast_channel_unlock, and ast_moh_start().
Referenced by conf_run().
{
char *original_moh;
ast_channel_lock(chan);
original_moh = ast_strdupa(ast_channel_musicclass(chan));
ast_channel_musicclass_set(chan, musicclass);
ast_channel_unlock(chan);
ast_moh_start(chan, original_moh, NULL);
ast_channel_lock(chan);
ast_channel_musicclass_set(chan, original_moh);
ast_channel_unlock(chan);
}
| static int count_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
The MeetmeCount application.
Definition at line 4573 of file app_meetme.c.
References args, ast_answer(), AST_APP_ARG, ast_channel_language(), AST_DECLARE_APP_ARGS, ast_log(), ast_say_number(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strlen_zero(), dispose_conf(), find_conf(), LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.
Referenced by load_module().
{
int res = 0;
struct ast_conference *conf;
int count;
char *localdata;
char val[80] = "0";
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(confno);
AST_APP_ARG(varname);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
return -1;
}
localdata = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, localdata);
conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
if (conf) {
count = conf->users;
dispose_conf(conf);
conf = NULL;
} else
count = 0;
if (!ast_strlen_zero(args.varname)) {
/* have var so load it and exit */
snprintf(val, sizeof(val), "%d", count);
pbx_builtin_setvar_helper(chan, args.varname, val);
} else {
if (ast_channel_state(chan) != AST_STATE_UP) {
ast_answer(chan);
}
res = ast_say_number(chan, count, "", ast_channel_language(chan), (char *) NULL); /* Needs gender */
}
return res;
}
| static struct sla_trunk_ref* create_trunk_ref | ( | struct sla_trunk * | trunk | ) | [static, read] |
Definition at line 6944 of file app_meetme.c.
References ao2_alloc, ao2_ref, sla_trunk_ref_destructor(), and sla_trunk_ref::trunk.
Referenced by sla_add_trunk_to_station().
{
struct sla_trunk_ref *trunk_ref;
if (!(trunk_ref = ao2_alloc(sizeof(*trunk_ref), sla_trunk_ref_destructor))) {
return NULL;
}
ao2_ref(trunk, 1);
trunk_ref->trunk = trunk;
return trunk_ref;
}
| static void* dial_trunk | ( | void * | data | ) | [static] |
Definition at line 6628 of file app_meetme.c.
References ALL_TRUNK_REFS, ao2_cleanup, args, ast_channel_caller(), ast_channel_caller_set(), ast_channel_name(), ast_cond_signal, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, ast_debug, AST_DEVICE_NOT_INUSE, ast_dial_answered(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_run(), ast_dial_state(), ast_indicate(), ast_mutex_lock, ast_mutex_unlock, ast_party_caller_free(), ast_party_caller_init(), ast_safe_sleep(), ast_set_flag64, build_conf(), dial_trunk_args::cond, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_TRUNK, dispose_conf(), MAX_CONFNUM, sla, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, dial_trunk_args::station, and dial_trunk_args::trunk_ref.
Referenced by sla_station_exec().
{
struct dial_trunk_args *args = data;
struct ast_dial *dial;
char *tech, *tech_data;
enum ast_dial_result dial_res;
char conf_name[MAX_CONFNUM];
struct ast_conference *conf;
struct ast_flags64 conf_flags = { 0 };
RAII_VAR(struct sla_trunk_ref *, trunk_ref, args->trunk_ref, ao2_cleanup);
RAII_VAR(struct sla_station *, station, args->station, ao2_cleanup);
int caller_is_saved;
struct ast_party_caller caller;
int last_state = 0;
int current_state = 0;
if (!(dial = ast_dial_create())) {
ast_mutex_lock(args->cond_lock);
ast_cond_signal(args->cond);
ast_mutex_unlock(args->cond_lock);
return NULL;
}
tech_data = ast_strdupa(trunk_ref->trunk->device);
tech = strsep(&tech_data, "/");
if (ast_dial_append(dial, tech, tech_data) == -1) {
ast_mutex_lock(args->cond_lock);
ast_cond_signal(args->cond);
ast_mutex_unlock(args->cond_lock);
ast_dial_destroy(dial);
return NULL;
}
/* Do we need to save of the caller ID data? */
caller_is_saved = 0;
if (!sla.attempt_callerid) {
caller_is_saved = 1;
caller = *ast_channel_caller(trunk_ref->chan);
ast_party_caller_init(ast_channel_caller(trunk_ref->chan));
}
dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
/* Restore saved caller ID */
if (caller_is_saved) {
ast_party_caller_free(ast_channel_caller(trunk_ref->chan));
ast_channel_caller_set(trunk_ref->chan, &caller);
}
if (dial_res != AST_DIAL_RESULT_TRYING) {
ast_mutex_lock(args->cond_lock);
ast_cond_signal(args->cond);
ast_mutex_unlock(args->cond_lock);
ast_dial_destroy(dial);
return NULL;
}
for (;;) {
unsigned int done = 0;
switch ((dial_res = ast_dial_state(dial))) {
case AST_DIAL_RESULT_ANSWERED:
trunk_ref->trunk->chan = ast_dial_answered(dial);
case AST_DIAL_RESULT_HANGUP:
case AST_DIAL_RESULT_INVALID:
case AST_DIAL_RESULT_FAILED:
case AST_DIAL_RESULT_TIMEOUT:
case AST_DIAL_RESULT_UNANSWERED:
done = 1;
break;
case AST_DIAL_RESULT_TRYING:
current_state = AST_CONTROL_PROGRESS;
break;
case AST_DIAL_RESULT_RINGING:
case AST_DIAL_RESULT_PROGRESS:
case AST_DIAL_RESULT_PROCEEDING:
current_state = AST_CONTROL_RINGING;
break;
}
if (done)
break;
/* check that SLA station that originated trunk call is still alive */
if (station && ast_device_state(station->device) == AST_DEVICE_NOT_INUSE) {
ast_debug(3, "Originating station device %s no longer active\n", station->device);
trunk_ref->trunk->chan = NULL;
break;
}
/* If trunk line state changed, send indication back to originating SLA Station channel */
if (current_state != last_state) {
ast_debug(3, "Indicating State Change %d to channel %s\n", current_state, ast_channel_name(trunk_ref->chan));
ast_indicate(trunk_ref->chan, current_state);
last_state = current_state;
}
/* avoid tight loop... sleep for 1/10th second */
ast_safe_sleep(trunk_ref->chan, 100);
}
if (!trunk_ref->trunk->chan) {
ast_mutex_lock(args->cond_lock);
ast_cond_signal(args->cond);
ast_mutex_unlock(args->cond_lock);
ast_dial_join(dial);
ast_dial_destroy(dial);
return NULL;
}
snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
ast_set_flag64(&conf_flags,
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
ast_mutex_lock(args->cond_lock);
ast_cond_signal(args->cond);
ast_mutex_unlock(args->cond_lock);
if (conf) {
conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
dispose_conf(conf);
conf = NULL;
}
/* If the trunk is going away, it is definitely now IDLE. */
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
trunk_ref->trunk->chan = NULL;
trunk_ref->trunk->on_hold = 0;
ast_dial_join(dial);
ast_dial_destroy(dial);
return NULL;
}
| static int dispose_conf | ( | struct ast_conference * | conf | ) | [static] |
Decrement reference counts, as incremented by find_conf()
Definition at line 2149 of file app_meetme.c.
References ast_atomic_dec_and_test(), AST_LIST_LOCK, AST_LIST_UNLOCK, conf_free(), conf_map, ast_conference::confno, and ast_conference::refcount.
Referenced by admin_exec(), conf_exec(), count_exec(), dial_trunk(), run_station(), sla_station_exec(), and sla_trunk_exec().
{
int res = 0;
int confno_int = 0;
AST_LIST_LOCK(&confs);
if (ast_atomic_dec_and_test(&conf->refcount)) {
/* Take the conference room number out of an inuse state */
if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
conf_map[confno_int] = 0;
}
conf_free(conf);
res = 1;
}
AST_LIST_UNLOCK(&confs);
return res;
}
| static void filename_parse | ( | char * | filename, |
| char * | buffer | ||
| ) | [static] |
Definition at line 5450 of file app_meetme.c.
References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log(), ast_mkdir(), ast_strlen_zero(), and LOG_WARNING.
Referenced by recordthread().
{
char *slash;
if (ast_strlen_zero(filename)) {
ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
} else if (filename[0] != '/') {
snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
} else {
ast_copy_string(buffer, filename, PATH_MAX);
}
slash = buffer;
if ((slash = strrchr(slash, '/'))) {
*slash = '\0';
ast_mkdir(buffer, 0777);
*slash = '/';
}
}
| static struct ast_conference* find_conf | ( | struct ast_channel * | chan, |
| char * | confno, | ||
| int | make, | ||
| int | dynamic, | ||
| char * | dynamic_pin, | ||
| size_t | pin_buf_len, | ||
| int | refcount, | ||
| struct ast_flags64 * | confflags | ||
| ) | [static, read] |
Definition at line 4469 of file app_meetme.c.
References args, AST_APP_ARG, ast_app_getdata(), ast_clear_flag64, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_test_flag64, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, ast_conference::list, LOG_ERROR, LOG_WARNING, MAX_SETTINGS, ast_variable::name, ast_variable::next, parse(), ast_conference::refcount, S_OR, ast_variable::value, and var.
Referenced by conf_exec(), and count_exec().
{
struct ast_config *cfg;
struct ast_variable *var;
struct ast_flags config_flags = { 0 };
struct ast_conference *cnf;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(confno);
AST_APP_ARG(pin);
AST_APP_ARG(pinadmin);
);
/* Check first in the conference list */
ast_debug(1, "The requested confno is '%s'?\n", confno);
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
if (!strcmp(confno, cnf->confno))
break;
}
if (cnf) {
cnf->refcount += refcount;
}
AST_LIST_UNLOCK(&confs);
if (!cnf) {
if (dynamic) {
/* No need to parse meetme.conf */
ast_debug(1, "Building dynamic conference '%s'\n", confno);
if (dynamic_pin) {
if (dynamic_pin[0] == 'q') {
/* Query the user to enter a PIN */
if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
return NULL;
}
cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
} else {
cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
}
} else {
/* Check the config */
cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
if (!cfg) {
ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
return NULL;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
return NULL;
}
for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
char parse[MAX_SETTINGS];
if (strcasecmp(var->name, "conf"))
continue;
ast_copy_string(parse, var->value, sizeof(parse));
AST_STANDARD_APP_ARGS(args, parse);
ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
if (!strcasecmp(args.confno, confno)) {
/* Bingo it's a valid conference */
cnf = build_conf(args.confno,
S_OR(args.pin, ""),
S_OR(args.pinadmin, ""),
make, dynamic, refcount, chan, NULL);
break;
}
}
if (!var) {
ast_debug(1, "%s isn't a valid conference\n", confno);
}
ast_config_destroy(cfg);
}
} else if (dynamic_pin) {
/* Correct for the user selecting 'D' instead of 'd' to have
someone join into a conference that has already been created
with a pin. */
if (dynamic_pin[0] == 'q') {
dynamic_pin[0] = '\0';
}
}
if (cnf) {
if (confflags && !cnf->chan &&
!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC);
}
if (confflags && !cnf->chan &&
ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
}
}
return cnf;
}
| static struct ast_conference* find_conf_realtime | ( | struct ast_channel * | chan, |
| char * | confno, | ||
| int | make, | ||
| int | dynamic, | ||
| char * | dynamic_pin, | ||
| size_t | pin_buf_len, | ||
| int | refcount, | ||
| struct ast_flags64 * | confflags, | ||
| int * | too_early, | ||
| char ** | optargs | ||
| ) | [static, read] |
Definition at line 4281 of file app_meetme.c.
References ast_conference::adminopts, ast_app_parse_options64(), ast_channel_language(), ast_channel_lock, ast_channel_uniqueid(), ast_channel_unlock, ast_clear_flag64, ast_copy_flags64, ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), AST_MAX_EXTENSION, ast_mktime(), ast_strdup, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_tvnow(), ast_variables_destroy(), ast_verb, ast_waitstream(), ast_conference::bookid, build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, earlyalert, endalert, ast_conference::endalert, ast_conference::endtime, ast_flags64::flags, fuzzystart, ast_conference::list, LOG_WARNING, ast_conference::maxusers, meetme_opts, ast_variable::name, ast_variable::next, OPTIONS_LEN, pbx_builtin_getvar_helper(), ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::refcount, ast_conference::useropts, ast_variable::value, and var.
Referenced by conf_exec().
{
struct ast_variable *var, *origvar;
struct ast_conference *cnf;
*too_early = 0;
/* Check first in the conference list */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno)) {
break;
}
}
if (cnf) {
cnf->refcount += refcount;
}
AST_LIST_UNLOCK(&confs);
if (!cnf) {
char *pin = NULL, *pinadmin = NULL; /* For temp use */
int maxusers = 0;
struct timeval now;
char recordingfilename[256] = "";
char recordingformat[11] = "";
char currenttime[32] = "";
char eatime[32] = "";
char bookid[51] = "";
char recordingtmp[AST_MAX_EXTENSION] = "";
char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
char adminopts[OPTIONS_LEN + 1] = "";
struct ast_tm tm, etm;
struct timeval endtime = { .tv_sec = 0 };
const char *var2;
if (rt_schedule) {
now = ast_tvnow();
ast_localtime(&now, &tm, NULL);
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
var = ast_load_realtime("meetme", "confno",
confno, "starttime <= ", currenttime, "endtime >= ",
currenttime, NULL);
if (!var && fuzzystart) {
now = ast_tvnow();
now.tv_sec += fuzzystart;
ast_localtime(&now, &tm, NULL);
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
var = ast_load_realtime("meetme", "confno",
confno, "starttime <= ", currenttime, "endtime >= ",
currenttime, NULL);
}
if (!var && earlyalert) {
now = ast_tvnow();
now.tv_sec += earlyalert;
ast_localtime(&now, &etm, NULL);
ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
var = ast_load_realtime("meetme", "confno",
confno, "starttime <= ", eatime, "endtime >= ",
currenttime, NULL);
if (var) {
*too_early = 1;
}
}
} else {
var = ast_load_realtime("meetme", "confno", confno, NULL);
}
if (!var) {
return NULL;
}
if (rt_schedule && *too_early) {
/* Announce that the caller is early and exit */
if (!ast_streamfile(chan, "conf-has-not-started", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
ast_variables_destroy(var);
return NULL;
}
for (origvar = var; var; var = var->next) {
if (!strcasecmp(var->name, "pin")) {
pin = ast_strdupa(var->value);
} else if (!strcasecmp(var->name, "adminpin")) {
pinadmin = ast_strdupa(var->value);
} else if (!strcasecmp(var->name, "bookId")) {
ast_copy_string(bookid, var->value, sizeof(bookid));
} else if (!strcasecmp(var->name, "opts")) {
ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
} else if (!strcasecmp(var->name, "maxusers")) {
maxusers = atoi(var->value);
} else if (!strcasecmp(var->name, "adminopts")) {
ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
} else if (!strcasecmp(var->name, "recordingfilename")) {
ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
} else if (!strcasecmp(var->name, "recordingformat")) {
ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
} else if (!strcasecmp(var->name, "endtime")) {
struct ast_tm endtime_tm;
ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
endtime = ast_mktime(&endtime_tm, NULL);
}
}
ast_variables_destroy(origvar);
cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
if (cnf) {
struct ast_flags64 tmp_flags;
cnf->maxusers = maxusers;
cnf->endalert = endalert;
cnf->endtime = endtime.tv_sec;
cnf->useropts = ast_strdup(useropts);
cnf->adminopts = ast_strdup(adminopts);
cnf->bookid = ast_strdup(bookid);
if (!ast_strlen_zero(recordingfilename)) {
cnf->recordingfilename = ast_strdup(recordingfilename);
}
if (!ast_strlen_zero(recordingformat)) {
cnf->recordingformat = ast_strdup(recordingformat);
}
/* Parse the other options into confflags -- need to do this in two
* steps, because the parse_options routine zeroes the buffer. */
ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
if (strchr(cnf->useropts, 'r')) {
if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
ast_channel_lock(chan);
if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
ast_free(cnf->recordingfilename);
cnf->recordingfilename = ast_strdup(var2);
}
ast_channel_unlock(chan);
if (ast_strlen_zero(cnf->recordingfilename)) {
snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, ast_channel_uniqueid(chan));
ast_free(cnf->recordingfilename);
cnf->recordingfilename = ast_strdup(recordingtmp);
}
}
if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
ast_channel_lock(chan);
if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
ast_free(cnf->recordingformat);
cnf->recordingformat = ast_strdup(var2);
}
ast_channel_unlock(chan);
if (ast_strlen_zero(cnf->recordingformat)) {
ast_free(cnf->recordingformat);
cnf->recordingformat = ast_strdup("wav");
}
}
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
}
}
}
if (cnf) {
if (confflags->flags && !cnf->chan &&
!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) | CONFFLAG_INTROUSER_VMREC) {
ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC);
}
if (confflags && !cnf->chan &&
ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
}
}
return cnf;
}
| static struct ast_conf_user* find_user | ( | struct ast_conference * | conf, |
| const char * | callerident | ||
| ) | [static, read] |
Definition at line 4943 of file app_meetme.c.
References ao2_find, user, and ast_conference::usercontainer.
Referenced by admin_exec().
{
struct ast_conf_user *user = NULL;
int cid;
if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) {
user = ao2_find(conf->usercontainer, &cid, 0);
/* reference decremented later in admin_exec */
return user;
}
return NULL;
}
| static const char* get_announce_filename | ( | enum announcetypes | type | ) | [static] |
Definition at line 2246 of file app_meetme.c.
References CONF_HASJOIN, and CONF_HASLEFT.
Referenced by announce_thread().
{
switch (type) {
case CONF_HASLEFT:
return "conf-hasleft";
break;
case CONF_HASJOIN:
return "conf-hasjoin";
break;
default:
return "";
}
}
| static const char* istalking | ( | int | x | ) | [static] |
Definition at line 1040 of file app_meetme.c.
Referenced by meetme_show_cmd().
{
if (x > 0)
return "(talking)";
else if (x < 0)
return "(unmonitored)";
else
return "(not talking)";
}
| static int load_config | ( | int | reload | ) | [static] |
Definition at line 7788 of file app_meetme.c.
References load_config_meetme(), and sla_load_config().
Referenced by load_module(), and reload().
{
load_config_meetme();
return sla_load_config(reload);
}
| static void load_config_meetme | ( | void | ) | [static] |
Definition at line 5560 of file app_meetme.c.
References ast_config_destroy(), ast_config_load, ast_log(), ast_true(), ast_variable_retrieve(), CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, DEFAULT_AUDIO_BUFFERS, LOG_ERROR, LOG_NOTICE, and LOG_WARNING.
Referenced by load_config().
{
struct ast_config *cfg;
struct ast_flags config_flags = { 0 };
const char *val;
if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
return;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
return;
}
audio_buffers = DEFAULT_AUDIO_BUFFERS;
/* Scheduling support is off by default */
rt_schedule = 0;
fuzzystart = 0;
earlyalert = 0;
endalert = 0;
extendby = 0;
/* Logging of participants defaults to ON for compatibility reasons */
rt_log_members = 1;
if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
audio_buffers = DEFAULT_AUDIO_BUFFERS;
} else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
audio_buffers = DEFAULT_AUDIO_BUFFERS;
}
if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
}
if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
rt_schedule = ast_true(val);
if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
rt_log_members = ast_true(val);
if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
fuzzystart = 0;
}
}
if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
if ((sscanf(val, "%30d", &earlyalert) != 1)) {
ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
earlyalert = 0;
}
}
if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
if ((sscanf(val, "%30d", &endalert) != 1)) {
ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
endalert = 0;
}
}
if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
if ((sscanf(val, "%30d", &extendby) != 1)) {
ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
extendby = 0;
}
}
ast_config_destroy(cfg);
}
| static int load_module | ( | void | ) | [static] |
Definition at line 8004 of file app_meetme.c.
References action_meetmelist(), action_meetmelistrooms(), action_meetmemute(), action_meetmeunmute(), admin_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_data_register_multiple, ast_devstate_prov_add(), ast_manager_register_xml, ast_realtime_require_field(), ast_register_application_xml, AST_TEST_REGISTER, channel_admin_exec(), conf_exec(), count_exec(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, load_config(), meetmestate(), RQ_UINTEGER1, RQ_UINTEGER2, sla_state(), sla_station_exec(), and sla_trunk_exec().
{
int res = 0;
res |= load_config(0);
ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
res |= ast_manager_register_xml("MeetmeListRooms", EVENT_FLAG_REPORTING, action_meetmelistrooms);
res |= ast_register_application_xml(app4, channel_admin_exec);
res |= ast_register_application_xml(app3, admin_exec);
res |= ast_register_application_xml(app2, count_exec);
res |= ast_register_application_xml(app, conf_exec);
res |= ast_register_application_xml(slastation_app, sla_station_exec);
res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
#ifdef TEST_FRAMEWORK
AST_TEST_REGISTER(test_meetme_data_provider);
#endif
ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers));
res |= ast_devstate_prov_add("Meetme", meetmestate);
res |= ast_devstate_prov_add("SLA", sla_state);
res |= ast_custom_function_register(&meetme_info_acf);
ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
return res;
}
| static char* meetme_cmd_helper | ( | struct ast_cli_args * | a | ) | [static] |
Definition at line 1632 of file app_meetme.c.
References admin_exec(), ast_cli_args::argv, ast_debug, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), CLI_FAILURE, CLI_SHOWUSAGE, CLI_SUCCESS, and MAX_CONFNUM.
Referenced by meetme_kick_cmd(), meetme_lock_cmd(), and meetme_mute_cmd().
{
/* Process the command */
struct ast_str *cmdline;
/* Max confno length */
if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
return CLI_FAILURE;
}
ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */
if (strcasestr(a->argv[1], "lock")) {
if (strcasecmp(a->argv[1], "lock") == 0) {
/* Lock */
ast_str_append(&cmdline, 0, ",L");
} else {
/* Unlock */
ast_str_append(&cmdline, 0, ",l");
}
} else if (strcasestr(a->argv[1], "mute")) {
if (strcasecmp(a->argv[1], "mute") == 0) {
/* Mute */
if (strcasecmp(a->argv[3], "all") == 0) {
ast_str_append(&cmdline, 0, ",N");
} else {
ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);
}
} else {
/* Unmute */
if (strcasecmp(a->argv[3], "all") == 0) {
ast_str_append(&cmdline, 0, ",n");
} else {
ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
}
}
} else if (strcasecmp(a->argv[1], "kick") == 0) {
if (strcasecmp(a->argv[3], "all") == 0) {
/* Kick all */
ast_str_append(&cmdline, 0, ",K");
} else {
/* Kick a single user */
ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
}
} else {
/*
* Should never get here because it is already filtered by the
* callers.
*/
ast_free(cmdline);
return CLI_SHOWUSAGE;
}
ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
admin_exec(NULL, ast_str_buffer(cmdline));
ast_free(cmdline);
return CLI_SUCCESS;
}
| static int meetme_data_provider_get | ( | const struct ast_data_search * | search, |
| struct ast_data * | data_root | ||
| ) | [static] |
Definition at line 7869 of file app_meetme.c.
References ao2_callback, ao2_container_count(), ast_data_add_node(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, OBJ_NODATA, user_add_provider_cb(), and ast_conference::usercontainer.
{
struct ast_conference *cnf;
struct ast_data *data_meetme, *data_meetme_users;
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
data_meetme = ast_data_add_node(data_root, "meetme");
if (!data_meetme) {
continue;
}
ast_data_add_structure(ast_conference, data_meetme, cnf);
if (ao2_container_count(cnf->usercontainer)) {
data_meetme_users = ast_data_add_node(data_meetme, "users");
if (!data_meetme_users) {
ast_data_remove_node(data_root, data_meetme);
continue;
}
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users);
}
if (!ast_data_search_match(search, data_meetme)) {
ast_data_remove_node(data_root, data_meetme);
}
}
AST_LIST_UNLOCK(&confs);
return 0;
}
| static char* meetme_kick_cmd | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1712 of file app_meetme.c.
References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_mute_kick(), ast_cli_args::line, meetme_cmd_helper(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
{
switch (cmd) {
case CLI_INIT:
e->command = "meetme kick";
e->usage =
"Usage: meetme kick <confno> all|<userno>\n"
" Kick a conference or a user in a conference.\n";
return NULL;
case CLI_GENERATE:
return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
}
if (a->argc != 4) {
return CLI_SHOWUSAGE;
}
return meetme_cmd_helper(a);
}
| static char* meetme_lock_cmd | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1692 of file app_meetme.c.
References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_lock(), meetme_cmd_helper(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
{
switch (cmd) {
case CLI_INIT:
e->command = "meetme {lock|unlock}";
e->usage =
"Usage: meetme lock|unlock <confno>\n"
" Lock or unlock a conference to new users.\n";
return NULL;
case CLI_GENERATE:
return complete_meetmecmd_lock(a->word, a->pos, a->n);
}
if (a->argc != 3) {
return CLI_SHOWUSAGE;
}
return meetme_cmd_helper(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 dahdi_confinfo * | dahdic, | ||
| struct ast_format_cap * | cap_slin | ||
| ) | [static] |
Definition at line 2819 of file app_meetme.c.
References meetme_menu_admin(), meetme_menu_admin_extended(), meetme_menu_normal(), MENU_ADMIN, MENU_ADMIN_EXTENDED, MENU_DISABLED, and MENU_NORMAL.
Referenced by conf_run().
{
switch (*menu_mode) {
case MENU_DISABLED:
break;
case MENU_NORMAL:
meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
break;
case MENU_ADMIN:
meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
/* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
break;
}
case MENU_ADMIN_EXTENDED:
meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user, recordingtmp, recordingtmp_size, dahdic, cap_slin);
break;
}
}
| 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] |
Definition at line 2513 of file app_meetme.c.
References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ao2_callback, ao2_find, ao2_ref, ast_channel_language(), ast_channel_name(), AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_test_flag64, ast_waitstream(), ast_conf_user::chan, CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_conference::locked, MENU_ADMIN_EXTENDED, MENU_DISABLED, OBJ_NODATA, rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), user_max_cmp(), ast_conference::usercontainer, ast_conf_user::userflags, VOL_DOWN, and VOL_UP.
Referenced by meetme_menu().
{
switch(*dtmf) {
case '1': /* Un/Mute */
*menu_mode = MENU_DISABLED;
/* for admin, change both admin and use flags */
if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
} else {
user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
}
if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
break;
case '2': /* Un/Lock the Conference */
*menu_mode = MENU_DISABLED;
if (conf->locked) {
conf->locked = 0;
if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
conf->locked = 1;
if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
break;
case '3': /* Eject last user */
{
struct ast_conf_user *usr = NULL;
int max_no = 0;
ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
*menu_mode = MENU_DISABLED;
usr = ao2_find(conf->usercontainer, &max_no, 0);
if ((ast_channel_name(usr->chan) == ast_channel_name(chan)) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
usr->adminflags |= ADMINFLAG_KICKME;
}
ao2_ref(usr, -1);
ast_stopstream(chan);
break;
}
case '4':
tweak_listen_volume(user, VOL_DOWN);
break;
case '5':
/* Extend RT conference */
if (rt_schedule) {
if (!rt_extend_conf(conf->confno)) {
if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
ast_stopstream(chan);
}
*menu_mode = MENU_DISABLED;
break;
case '6':
tweak_listen_volume(user, VOL_UP);
break;
case '7':
tweak_talk_volume(user, VOL_DOWN);
break;
case '8':
if (!ast_streamfile(chan, "conf-adminmenu-menu8", ast_channel_language(chan))) {
/* If the user provides DTMF while playing the sound, we want to drop right into the extended menu function with new DTMF once we get out of here. */
*dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
}
*menu_mode = MENU_ADMIN_EXTENDED;
break;
case '9':
tweak_talk_volume(user, VOL_UP);
break;
default:
menu_mode = MENU_DISABLED;
/* Play an error message! */
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
break;
}
}
| 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 dahdi_confinfo * | dahdic, | ||
| struct ast_format_cap * | cap_slin | ||
| ) | [static] |
Definition at line 2635 of file app_meetme.c.
References ao2_callback, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_fd(), ast_channel_language(), ast_channel_lock, ast_channel_uniqueid(), ast_channel_unlock, AST_DIGIT_ANY, ast_fileexists(), AST_FORMAT_SLINEAR, ast_hangup(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_request(), ast_say_number(), ast_set_flag64, ast_set_read_format_by_id(), ast_set_write_format_by_id(), ast_stopstream(), ast_strdup, ast_streamfile(), ast_test_flag64, ast_verb, ast_waitstream(), CONFFLAG_RECORDCONF, ast_conference::confno, ast_conference::dahdiconf, ast_conference::gmuted, ast_conference::lchan, LOG_WARNING, MEETME_RECORD_ACTIVE, MENU_DISABLED, ast_conf_user::namerecloc, OBJ_NODATA, pbx_builtin_getvar_helper(), ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), ast_conference::usercontainer, ast_conference::users, and var.
Referenced by meetme_menu().
{
int keepplaying;
int playednamerec;
int res;
struct ao2_iterator user_iter;
struct ast_conf_user *usr = NULL;
switch(*dtmf) {
case '1': /* *81 Roll call */
keepplaying = 1;
playednamerec = 0;
if (conf->users == 1) {
if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0) {
keepplaying = 0;
}
}
} else if (conf->users == 2) {
if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0) {
keepplaying = 0;
}
}
} else {
if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0) {
keepplaying = 0;
}
}
if (keepplaying) {
res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
ast_stopstream(chan);
if (res > 0) {
keepplaying = 0;
}
}
if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0) {
keepplaying = 0;
}
}
}
user_iter = ao2_iterator_init(conf->usercontainer, 0);
while((usr = ao2_iterator_next(&user_iter))) {
if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0) {
keepplaying = 0;
}
}
playednamerec = 1;
}
ao2_ref(usr, -1);
}
ao2_iterator_destroy(&user_iter);
if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0) {
keepplaying = 0;
}
}
*menu_mode = MENU_DISABLED;
break;
case '2': /* *82 Eject all non-admins */
if (conf->users == 1) {
if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
}
ast_stopstream(chan);
*menu_mode = MENU_DISABLED;
break;
case '3': /* *83 (Admin) mute/unmute all non-admins */
if(conf->gmuted) {
conf->gmuted = 0;
ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
conf->gmuted = 1;
ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
ast_stopstream(chan);
*menu_mode = MENU_DISABLED;
break;
case '4': /* *84 Record conference */
if (conf->recording != MEETME_RECORD_ACTIVE) {
ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
if (!conf->recordingfilename) {
const char *var;
ast_channel_lock(chan);
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
conf->recordingfilename = ast_strdup(var);
}
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
conf->recordingformat = ast_strdup(var);
}
ast_channel_unlock(chan);
if (!conf->recordingfilename) {
snprintf(recordingtmp, recordingtmp_size, "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
conf->recordingfilename = ast_strdup(recordingtmp);
}
if (!conf->recordingformat) {
conf->recordingformat = ast_strdup("wav");
}
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
conf->confno, conf->recordingfilename, conf->recordingformat);
}
ast_mutex_lock(&conf->recordthreadlock);
if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
dahdic->chan = 0;
dahdic->confno = conf->dahdiconf;
dahdic->confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, dahdic)) {
ast_log(LOG_WARNING, "Error starting listen channel\n");
ast_hangup(conf->lchan);
conf->lchan = NULL;
} else {
ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
}
}
ast_mutex_unlock(&conf->recordthreadlock);
if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
ast_stopstream(chan);
*menu_mode = MENU_DISABLED;
break;
case '8': /* *88 Exit the menu and return to the conference... without an error message */
ast_stopstream(chan);
*menu_mode = MENU_DISABLED;
break;
default:
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
ast_stopstream(chan);
*menu_mode = MENU_DISABLED;
break;
}
}
| 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] |
Definition at line 2433 of file app_meetme.c.
References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ast_channel_language(), ast_streamfile(), ast_test_flag64, ast_waitstream(), CONFFLAG_MONITOR, ast_conference::confno, MENU_DISABLED, rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), VOL_DOWN, and VOL_UP.
Referenced by meetme_menu().
{
switch (*dtmf) {
case '1': /* Un/Mute */
*menu_mode = MENU_DISABLED;
/* user can only toggle the self-muted state */
user->adminflags ^= ADMINFLAG_SELFMUTED;
/* they can't override the admin mute state */
if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
break;
case '2':
*menu_mode = MENU_DISABLED;
if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
user->adminflags |= ADMINFLAG_T_REQUEST;
}
if (user->adminflags & ADMINFLAG_T_REQUEST) {
if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
}
break;
case '4':
tweak_listen_volume(user, VOL_DOWN);
break;
case '5':
/* Extend RT conference */
if (rt_schedule) {
rt_extend_conf(conf->confno);
}
*menu_mode = MENU_DISABLED;
break;
case '6':
tweak_listen_volume(user, VOL_UP);
break;
case '7':
tweak_talk_volume(user, VOL_DOWN);
break;
case '8':
*menu_mode = MENU_DISABLED;
break;
case '9':
tweak_talk_volume(user, VOL_UP);
break;
default:
*menu_mode = MENU_DISABLED;
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
ast_waitstream(chan, "");
}
break;
}
}
| static char* meetme_mute_cmd | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1732 of file app_meetme.c.
References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_mute_kick(), ast_cli_args::line, meetme_cmd_helper(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
{
switch (cmd) {
case CLI_INIT:
e->command = "meetme {mute|unmute}";
e->usage =
"Usage: meetme mute|unmute <confno> all|<userno>\n"
" Mute or unmute a conference or a user in a conference.\n";
return NULL;
case CLI_GENERATE:
return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
}
if (a->argc != 4) {
return CLI_SHOWUSAGE;
}
return meetme_cmd_helper(a);
}
| static char* meetme_show_cmd | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1489 of file app_meetme.c.
References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_channel_caller(), ast_channel_name(), ast_cli(), ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_test_flag64, ast_conf_user::chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd_list(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_cli_args::fd, ast_party_caller::id, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_party_id::name, ast_party_id::number, ast_cli_args::pos, S_COR, ast_conference::start, ast_party_name::str, ast_party_number::str, STR_CONCISE, ast_conf_user::talking, total, ast_cli_entry::usage, user, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, ast_party_name::valid, ast_party_number::valid, and ast_cli_args::word.
{
/* Process the command */
struct ast_conf_user *user;
struct ast_conference *cnf;
int hr, min, sec;
int total = 0;
time_t now;
#define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n"
#define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
switch (cmd) {
case CLI_INIT:
e->command = "meetme list";
e->usage =
"Usage: meetme list [<confno>] [" STR_CONCISE "]\n"
" List all conferences or a specific conference.\n";
return NULL;
case CLI_GENERATE:
return complete_meetmecmd_list(a->line, a->word, a->pos, a->n);
}
if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) {
/* List all the conferences */
int concise = (a->argc == 3);
struct ast_str *marked_users;
if (!(marked_users = ast_str_create(30))) {
return CLI_FAILURE;
}
now = time(NULL);
AST_LIST_LOCK(&confs);
if (AST_LIST_EMPTY(&confs)) {
if (!concise) {
ast_cli(a->fd, "No active MeetMe conferences.\n");
}
AST_LIST_UNLOCK(&confs);
ast_free(marked_users);
return CLI_SUCCESS;
}
if (!concise) {
ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
}
AST_LIST_TRAVERSE(&confs, cnf, list) {
hr = (now - cnf->start) / 3600;
min = ((now - cnf->start) % 3600) / 60;
sec = (now - cnf->start) % 60;
if (!concise) {
if (cnf->markedusers == 0) {
ast_str_set(&marked_users, 0, "N/A ");
} else {
ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers);
}
ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users,
ast_str_buffer(marked_users), hr, min, sec,
cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
} else {
ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
cnf->confno,
cnf->users,
cnf->markedusers,
hr, min, sec,
cnf->isdynamic,
cnf->locked);
}
total += cnf->users;
}
AST_LIST_UNLOCK(&confs);
if (!concise) {
ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
}
ast_free(marked_users);
return CLI_SUCCESS;
}
if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) {
struct ao2_iterator user_iter;
int concise = (a->argc == 4);
/* List all the users in a conference */
if (AST_LIST_EMPTY(&confs)) {
if (!concise) {
ast_cli(a->fd, "No active MeetMe conferences.\n");
}
return CLI_SUCCESS;
}
/* Find the right conference */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (strcmp(cnf->confno, a->argv[2]) == 0) {
break;
}
}
if (!cnf) {
if (!concise)
ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
AST_LIST_UNLOCK(&confs);
return CLI_SUCCESS;
}
/* Show all the users */
time(&now);
user_iter = ao2_iterator_init(cnf->usercontainer, 0);
while((user = ao2_iterator_next(&user_iter))) {
hr = (now - user->jointime) / 3600;
min = ((now - user->jointime) % 3600) / 60;
sec = (now - user->jointime) % 60;
if (!concise) {
ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
user->user_no,
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
ast_channel_name(user->chan),
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
istalking(user->talking), hr, min, sec);
} else {
ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
user->user_no,
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, ""),
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, ""),
ast_channel_name(user->chan),
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
user->talking, hr, min, sec);
}
ao2_ref(user, -1);
}
ao2_iterator_destroy(&user_iter);
if (!concise) {
ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
}
AST_LIST_UNLOCK(&confs);
return CLI_SUCCESS;
}
return CLI_SHOWUSAGE;
}
| static int meetmemute | ( | struct mansession * | s, |
| const struct message * | m, | ||
| int | mute | ||
| ) | [static] |
Definition at line 5232 of file app_meetme.c.
References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_find, ao2_ref, ast_channel_name(), ast_channel_uniqueid(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_conf_user::chan, ast_conference::confno, ast_conf_user::list, LOG_NOTICE, user, ast_conf_user::user_no, and ast_conference::usercontainer.
Referenced by action_meetmemute(), and action_meetmeunmute().
{
struct ast_conference *conf;
struct ast_conf_user *user;
const char *confid = astman_get_header(m, "Meetme");
char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
int userno;
if (ast_strlen_zero(confid)) {
astman_send_error(s, m, "Meetme conference not specified");
return 0;
}
if (ast_strlen_zero(userid)) {
astman_send_error(s, m, "Meetme user number not specified");
return 0;
}
userno = strtoul(userid, &userid, 10);
if (*userid) {
astman_send_error(s, m, "Invalid user number");
return 0;
}
/* Look in the conference list */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, conf, list) {
if (!strcmp(confid, conf->confno))
break;
}
if (!conf) {
AST_LIST_UNLOCK(&confs);
astman_send_error(s, m, "Meetme conference does not exist");
return 0;
}
user = ao2_find(conf->usercontainer, &userno, 0);
if (!user) {
AST_LIST_UNLOCK(&confs);
astman_send_error(s, m, "User number not found");
return 0;
}
if (mute)
user->adminflags |= ADMINFLAG_MUTED; /* request user muting */
else
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
AST_LIST_UNLOCK(&confs);
ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, ast_channel_name(user->chan), ast_channel_uniqueid(user->chan));
ao2_ref(user, -1);
astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
return 0;
}
| static enum ast_device_state meetmestate | ( | const char * | data | ) | [static] |
Callback for devicestate providers.
Definition at line 5538 of file app_meetme.c.
References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_conference::confno, ast_conference::list, and ast_conference::users.
Referenced by load_module().
{
struct ast_conference *conf;
/* Find conference */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, conf, list) {
if (!strcmp(data, conf->confno))
break;
}
AST_LIST_UNLOCK(&confs);
if (!conf)
return AST_DEVICE_INVALID;
/* SKREP to fill */
if (!conf->users)
return AST_DEVICE_NOT_INUSE;
return AST_DEVICE_INUSE;
}
| static struct sla_ringing_trunk* queue_ringing_trunk | ( | struct sla_trunk * | trunk | ) | [static, read] |
Definition at line 6958 of file app_meetme.c.
References ALL_TRUNK_REFS, ao2_ref, ast_calloc, AST_LIST_INSERT_HEAD, ast_mutex_lock, ast_mutex_unlock, ast_tvnow(), sla_ringing_trunk::ring_begin, sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_TRUNK_STATE_RINGING, and sla_ringing_trunk::trunk.
Referenced by sla_trunk_exec().
{
struct sla_ringing_trunk *ringing_trunk;
if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) {
return NULL;
}
ao2_ref(trunk, 1);
ringing_trunk->trunk = trunk;
ringing_trunk->ring_begin = ast_tvnow();
sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
ast_mutex_lock(&sla.lock);
AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
ast_mutex_unlock(&sla.lock);
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
return ringing_trunk;
}
| static void * recordthread | ( | void * | args | ) | [static] |
Definition at line 5469 of file app_meetme.c.
References args, ast_closestream(), AST_FRAME_BITS, AST_FRAME_VOICE, ast_frdup(), ast_frfree, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_stopstream(), ast_strlen_zero(), ast_waitfor(), ast_writefile(), ast_writestream(), f, filename_parse(), ast_frame::flags, ast_frame::frametype, ast_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::origframe, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, and ast_conference::transframe.
{
struct ast_conference *cnf = args;
struct ast_frame *f = NULL;
int flags;
struct ast_filestream *s = NULL;
int res = 0;
int x;
const char *oldrecordingfilename = NULL;
char filename_buffer[PATH_MAX];
if (!cnf || !cnf->lchan) {
pthread_exit(0);
}
filename_buffer[0] = '\0';
filename_parse(cnf->recordingfilename, filename_buffer);
ast_stopstream(cnf->lchan);
flags = O_CREAT | O_TRUNC | O_WRONLY;
cnf->recording = MEETME_RECORD_ACTIVE;
while (ast_waitfor(cnf->lchan, -1) > -1) {
if (cnf->recording == MEETME_RECORD_TERMINATE) {
AST_LIST_LOCK(&confs);
AST_LIST_UNLOCK(&confs);
break;
}
if (!s && !(ast_strlen_zero(filename_buffer)) && (filename_buffer != oldrecordingfilename)) {
s = ast_writefile(filename_buffer, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
oldrecordingfilename = filename_buffer;
}
f = ast_read(cnf->lchan);
if (!f) {
res = -1;
break;
}
if (f->frametype == AST_FRAME_VOICE) {
ast_mutex_lock(&cnf->listenlock);
for (x = 0; x < AST_FRAME_BITS; x++) {
/* Free any translations that have occured */
if (cnf->transframe[x]) {
ast_frfree(cnf->transframe[x]);
cnf->transframe[x] = NULL;
}
}
if (cnf->origframe)
ast_frfree(cnf->origframe);
cnf->origframe = ast_frdup(f);
ast_mutex_unlock(&cnf->listenlock);
if (s)
res = ast_writestream(s, f);
if (res) {
ast_frfree(f);
break;
}
}
ast_frfree(f);
}
cnf->recording = MEETME_RECORD_OFF;
if (s)
ast_closestream(s);
pthread_exit(0);
}
| static int reload | ( | void | ) | [static] |
Definition at line 8036 of file app_meetme.c.
References ast_unload_realtime(), and load_config().
{
ast_unload_realtime("meetme");
return load_config(1);
}
| static void reset_volumes | ( | struct ast_conf_user * | user | ) | [static] |
Definition at line 1160 of file app_meetme.c.
References ast_channel_setoption(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, and ast_conf_user::chan.
Referenced by admin_exec(), conf_run(), and user_reset_vol_cb().
{
signed char zero_volume = 0;
ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
}
| static int rt_extend_conf | ( | const char * | confno | ) | [static] |
Definition at line 2168 of file app_meetme.c.
References ast_copy_string(), ast_debug, ast_load_realtime(), ast_localtime(), ast_mktime(), ast_strftime(), ast_strptime(), ast_tvnow(), ast_update_realtime(), ast_variables_destroy(), DATE_FORMAT, extendby, ast_variable::name, ast_variable::next, ast_variable::value, and var.
Referenced by admin_exec(), meetme_menu_admin(), and meetme_menu_normal().
{
char currenttime[32];
char endtime[32];
struct timeval now;
struct ast_tm tm;
struct ast_variable *var, *orig_var;
char bookid[51];
if (!extendby) {
return 0;
}
now = ast_tvnow();
ast_localtime(&now, &tm, NULL);
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
var = ast_load_realtime("meetme", "confno",
confno, "startTime<= ", currenttime,
"endtime>= ", currenttime, NULL);
orig_var = var;
/* Identify the specific RealTime conference */
while (var) {
if (!strcasecmp(var->name, "bookid")) {
ast_copy_string(bookid, var->value, sizeof(bookid));
}
if (!strcasecmp(var->name, "endtime")) {
ast_copy_string(endtime, var->value, sizeof(endtime));
}
var = var->next;
}
ast_variables_destroy(orig_var);
ast_strptime(endtime, DATE_FORMAT, &tm);
now = ast_mktime(&tm, NULL);
now.tv_sec += extendby;
ast_localtime(&now, &tm, NULL);
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
strcat(currenttime, "0"); /* Seconds needs to be 00 */
var = ast_load_realtime("meetme", "confno",
confno, "startTime<= ", currenttime,
"endtime>= ", currenttime, NULL);
/* If there is no conflict with extending the conference, update the DB */
if (!var) {
ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
return 0;
}
ast_variables_destroy(var);
return -1;
}
| static void* run_station | ( | void * | data | ) | [static] |
Definition at line 5844 of file app_meetme.c.
References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ao2_cleanup, args, ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_cond_signal, ast_dial_destroy(), ast_dial_join(), ast_free, ast_mutex_lock, ast_mutex_unlock, ast_set_flag64, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), build_conf(), sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, sla_station::dial, dispose_conf(), sla_trunk::hold_stations, sla_trunk::name, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, run_station_args::station, sla_trunk_ref::trunk, and run_station_args::trunk_ref.
Referenced by sla_handle_dial_state_event().
{
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
struct ast_str *conf_name = ast_str_create(16);
struct ast_flags64 conf_flags = { 0 };
struct ast_conference *conf;
{
struct run_station_args *args = data;
station = args->station;
trunk_ref = args->trunk_ref;
ast_mutex_lock(args->cond_lock);
ast_cond_signal(args->cond);
ast_mutex_unlock(args->cond_lock);
/* args is no longer valid here. */
}
ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
ast_set_flag64(&conf_flags,
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
answer_trunk_chan(trunk_ref->chan);
conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
if (conf) {
conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
dispose_conf(conf);
conf = NULL;
}
trunk_ref->chan = NULL;
if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
ast_str_append(&conf_name, 0, ",K");
admin_exec(NULL, ast_str_buffer(conf_name));
trunk_ref->trunk->hold_stations = 0;
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
}
ast_dial_join(station->dial);
ast_dial_destroy(station->dial);
station->dial = NULL;
ast_free(conf_name);
return NULL;
}
| static void send_talking_event | ( | struct ast_channel * | chan, |
| struct ast_conference * | conf, | ||
| struct ast_conf_user * | user, | ||
| int | talking | ||
| ) | [static] |
Definition at line 2326 of file app_meetme.c.
References ast_channel_name(), ast_channel_uniqueid(), ast_manager_event, ast_conference::confno, EVENT_FLAG_CALL, and ast_conf_user::user_no.
Referenced by set_user_talking().
{
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when a MeetMe user begins or ends talking.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Usernum'])" />
<parameter name="Status">
<enumlist>
<enum name="on"/>
<enum name="off"/>
</enumlist>
</parameter>
</syntax>
</managerEventInstance>
***/
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"Status: %s\r\n",
ast_channel_name(chan), ast_channel_uniqueid(chan),
conf->confno,
user->user_no, talking ? "on" : "off");
}
| static int set_listen_volume | ( | struct ast_conf_user * | user, |
| int | volume | ||
| ) | [static] |
Definition at line 1089 of file app_meetme.c.
References ast_channel_setoption(), AST_OPTION_TXGAIN, and ast_conf_user::chan.
Referenced by tweak_listen_volume().
{
char gain_adjust;
/* attempt to make the adjustment in the channel driver;
if successful, don't adjust in the frame reading routine
*/
gain_adjust = gain_map[volume + 5];
return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
}
| static int set_talk_volume | ( | struct ast_conf_user * | user, |
| int | volume | ||
| ) | [static] |
Definition at line 1077 of file app_meetme.c.
References ast_channel_setoption(), AST_OPTION_RXGAIN, and ast_conf_user::chan.
Referenced by conf_run(), and tweak_talk_volume().
{
char gain_adjust;
/* attempt to make the adjustment in the channel driver;
if successful, don't adjust in the frame reading routine
*/
gain_adjust = gain_map[volume + 5];
return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
}
| static void set_user_talking | ( | struct ast_channel * | chan, |
| struct ast_conference * | conf, | ||
| struct ast_conf_user * | user, | ||
| int | talking, | ||
| int | monitor | ||
| ) | [static] |
Definition at line 2354 of file app_meetme.c.
References send_talking_event(), and ast_conf_user::talking.
Referenced by conf_run().
{
int last_talking = user->talking;
if (last_talking == talking)
return;
user->talking = talking;
if (monitor) {
/* Check if talking state changed. Take care of -1 which means unmonitored */
int was_talking = (last_talking > 0);
int now_talking = (talking > 0);
if (was_talking != now_talking) {
send_talking_event(chan, conf, user, now_talking);
}
}
}
| static void sla_add_trunk_to_station | ( | struct sla_station * | station, |
| struct ast_variable * | var | ||
| ) | [static] |
Definition at line 7353 of file app_meetme.c.
References ao2_cleanup, ao2_lock, ao2_ref, ao2_unlock, ast_atomic_fetchadd_int(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), create_trunk_ref(), LOG_ERROR, LOG_WARNING, sla_station_ref::mark, sla_trunk_ref::mark, name, sla_trunk::name, sla_trunk::num_stations, sla_trunk_ref::ring_delay, sla_trunk_ref::ring_timeout, sla_create_station_ref(), sla_find_trunk(), SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, sla_station_ref::station, sla_trunk::stations, sla_trunk_ref::trunk, sla_station::trunks, value, and ast_variable::value.
Referenced by sla_build_station().
{
RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
struct sla_trunk_ref *trunk_ref = NULL;
struct sla_station_ref *station_ref;
char *trunk_name, *options, *cur;
int existing_trunk_ref = 0;
int existing_station_ref = 0;
options = ast_strdupa(var->value);
trunk_name = strsep(&options, ",");
trunk = sla_find_trunk(trunk_name);
if (!trunk) {
ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
return;
}
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->trunk == trunk) {
trunk_ref->mark = 0;
existing_trunk_ref = 1;
break;
}
}
if (!trunk_ref && !(trunk_ref = create_trunk_ref(trunk))) {
return;
}
trunk_ref->state = SLA_TRUNK_STATE_IDLE;
while ((cur = strsep(&options, ","))) {
char *name, *value = cur;
name = strsep(&value, "=");
if (!strcasecmp(name, "ringtimeout")) {
if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
"trunk '%s' on station '%s'\n", value, trunk->name, station->name);
trunk_ref->ring_timeout = 0;
}
} else if (!strcasecmp(name, "ringdelay")) {
if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
"trunk '%s' on station '%s'\n", value, trunk->name, station->name);
trunk_ref->ring_delay = 0;
}
} else {
ast_log(LOG_WARNING, "Invalid option '%s' for "
"trunk '%s' on station '%s'\n", name, trunk->name, station->name);
}
}
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
if (station_ref->station == station) {
station_ref->mark = 0;
existing_station_ref = 1;
break;
}
}
if (!station_ref && !(station_ref = sla_create_station_ref(station))) {
if (!existing_trunk_ref) {
ao2_ref(trunk_ref, -1);
} else {
trunk_ref->mark = 1;
}
return;
}
if (!existing_station_ref) {
ao2_lock(trunk);
AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
ao2_unlock(trunk);
}
if (!existing_trunk_ref) {
ao2_lock(station);
AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
ao2_unlock(station);
}
}
| static int sla_build_station | ( | struct ast_config * | cfg, |
| const char * | cat | ||
| ) | [static] |
Definition at line 7437 of file app_meetme.c.
References ao2_alloc, ao2_cleanup, ao2_link, ao2_lock, ao2_unlock, ast_add_extension2(), ast_context_find_or_create(), ast_free_ptr(), AST_LIST_TRAVERSE, ast_log(), AST_MAX_APP, AST_MAX_EXTENSION, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), context, exten, sla_station::hold_access, ast_variable::lineno, LOG_ERROR, LOG_WARNING, sla_station::mark, ast_variable::name, sla_trunk::name, ast_variable::next, PRIORITY_HINT, sla_station::ring_delay, sla_station::ring_timeout, sla_add_trunk_to_station(), SLA_CONFIG_FILE, sla_find_station(), SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, sla_station_destructor(), sla_stations, sla_trunk_ref::trunk, sla_station::trunks, ast_variable::value, and var.
Referenced by sla_load_config().
{
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
struct ast_variable *var;
const char *dev;
int existing_station = 0;
if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
return -1;
}
if ((station = sla_find_station(cat))) {
station->mark = 0;
existing_station = 1;
} else if ((station = ao2_alloc(sizeof(*station), sla_station_destructor))) {
if (ast_string_field_init(station, 32)) {
return -1;
}
ast_string_field_set(station, name, cat);
} else {
return -1;
}
ao2_lock(station);
ast_string_field_set(station, device, dev);
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
if (!strcasecmp(var->name, "trunk")) {
ao2_unlock(station);
sla_add_trunk_to_station(station, var);
ao2_lock(station);
} else if (!strcasecmp(var->name, "autocontext")) {
ast_string_field_set(station, autocontext, var->value);
} else if (!strcasecmp(var->name, "ringtimeout")) {
if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
var->value, station->name);
station->ring_timeout = 0;
}
} else if (!strcasecmp(var->name, "ringdelay")) {
if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
var->value, station->name);
station->ring_delay = 0;
}
} else if (!strcasecmp(var->name, "hold")) {
if (!strcasecmp(var->value, "private"))
station->hold_access = SLA_HOLD_PRIVATE;
else if (!strcasecmp(var->value, "open"))
station->hold_access = SLA_HOLD_OPEN;
else {
ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
var->value, station->name);
}
} else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
var->name, var->lineno, SLA_CONFIG_FILE);
}
}
ao2_unlock(station);
if (!ast_strlen_zero(station->autocontext)) {
struct ast_context *context;
struct sla_trunk_ref *trunk_ref;
context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
if (!context) {
ast_log(LOG_ERROR, "Failed to automatically find or create "
"context '%s' for SLA!\n", station->autocontext);
return -1;
}
/* The extension for when the handset goes off-hook.
* exten => station1,1,SLAStation(station1) */
if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
ast_log(LOG_ERROR, "Failed to automatically create extension "
"for trunk '%s'!\n", station->name);
return -1;
}
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
char exten[AST_MAX_EXTENSION];
char hint[AST_MAX_APP];
snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
snprintf(hint, sizeof(hint), "SLA:%s", exten);
/* Extension for this line button
* exten => station1_line1,1,SLAStation(station1_line1) */
if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
ast_log(LOG_ERROR, "Failed to automatically create extension "
"for trunk '%s'!\n", station->name);
return -1;
}
/* Hint for this line button
* exten => station1_line1,hint,SLA:station1_line1 */
if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
NULL, NULL, hint, NULL, NULL, sla_registrar)) {
ast_log(LOG_ERROR, "Failed to automatically create hint "
"for trunk '%s'!\n", station->name);
return -1;
}
}
}
if (!existing_station) {
ao2_link(sla_stations, station);
}
return 0;
}
| static int sla_build_trunk | ( | struct ast_config * | cfg, |
| const char * | cat | ||
| ) | [static] |
Definition at line 7264 of file app_meetme.c.
References ao2_alloc, ao2_cleanup, ao2_link, ao2_lock, ao2_unlock, ast_add_extension2(), ast_context_find_or_create(), ast_false(), ast_free_ptr(), ast_log(), ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), sla_trunk::autocontext, sla_trunk::barge_disabled, context, sla_trunk::hold_access, ast_variable::lineno, LOG_ERROR, LOG_WARNING, sla_trunk::mark, ast_variable::name, sla_trunk::name, ast_variable::next, sla_trunk::ring_timeout, sla_check_device(), SLA_CONFIG_FILE, sla_find_trunk(), SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, sla_trunk_destructor(), sla_trunks, ast_variable::value, and var.
Referenced by sla_load_config().
{
RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
struct ast_variable *var;
const char *dev;
int existing_trunk = 0;
if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
return -1;
}
if (sla_check_device(dev)) {
ast_log(LOG_ERROR, "SLA Trunk '%s' defined with invalid device '%s'!\n",
cat, dev);
return -1;
}
if ((trunk = sla_find_trunk(cat))) {
trunk->mark = 0;
existing_trunk = 1;
} else if ((trunk = ao2_alloc(sizeof(*trunk), sla_trunk_destructor))) {
if (ast_string_field_init(trunk, 32)) {
return -1;
}
ast_string_field_set(trunk, name, cat);
} else {
return -1;
}
ao2_lock(trunk);
ast_string_field_set(trunk, device, dev);
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
if (!strcasecmp(var->name, "autocontext"))
ast_string_field_set(trunk, autocontext, var->value);
else if (!strcasecmp(var->name, "ringtimeout")) {
if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
var->value, trunk->name);
trunk->ring_timeout = 0;
}
} else if (!strcasecmp(var->name, "barge"))
trunk->barge_disabled = ast_false(var->value);
else if (!strcasecmp(var->name, "hold")) {
if (!strcasecmp(var->value, "private"))
trunk->hold_access = SLA_HOLD_PRIVATE;
else if (!strcasecmp(var->value, "open"))
trunk->hold_access = SLA_HOLD_OPEN;
else {
ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
var->value, trunk->name);
}
} else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
var->name, var->lineno, SLA_CONFIG_FILE);
}
}
ao2_unlock(trunk);
if (!ast_strlen_zero(trunk->autocontext)) {
struct ast_context *context;
context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
if (!context) {
ast_log(LOG_ERROR, "Failed to automatically find or create "
"context '%s' for SLA!\n", trunk->autocontext);
return -1;
}
if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
ast_log(LOG_ERROR, "Failed to automatically create extension "
"for trunk '%s'!\n", trunk->name);
return -1;
}
}
if (!existing_trunk) {
ao2_link(sla_trunks, trunk);
}
return 0;
}
| static int sla_calc_station_delays | ( | unsigned int * | timeout | ) | [static] |
Calculate the ring delay for a station.
Definition at line 6472 of file app_meetme.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), sla_choose_ringing_trunk(), and sla_stations.
Referenced by sla_process_timers().
{
struct sla_station *station;
int res = 0;
struct ao2_iterator i;
i = ao2_iterator_init(sla_stations, 0);
for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
struct sla_ringing_trunk *ringing_trunk;
int time_left;
/* Ignore stations already ringing */
if (sla_check_ringing_station(station))
continue;
/* Ignore stations already on a call */
if (sla_check_inuse_station(station))
continue;
/* Ignore stations that don't have one of their trunks ringing */
if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
continue;
if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
continue;
/* If there is no time left, then the station needs to start ringing.
* Return non-zero so that an event will be queued up an event to
* make that happen. */
if (time_left <= 0) {
res = 1;
continue;
}
if (time_left < *timeout)
*timeout = time_left;
}
ao2_iterator_destroy(&i);
return res;
}
| static int sla_calc_station_timeouts | ( | unsigned int * | timeout | ) | [static] |
Process station ring timeouts.
Definition at line 6389 of file app_meetme.c.
References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla_ringing_station::ring_begin, sla_station::ring_timeout, sla_trunk_ref::ring_timeout, sla, SLA_STATION_HANGUP_TIMEOUT, sla_stop_ringing_station(), sla_station_ref::station, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.
Referenced by sla_process_timers().
{
struct sla_ringing_trunk *ringing_trunk;
struct sla_ringing_station *ringing_station;
int res = 0;
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
unsigned int ring_timeout = 0;
int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
struct sla_trunk_ref *trunk_ref;
/* If there are any ring timeouts specified for a specific trunk
* on the station, then use the highest per-trunk ring timeout.
* Otherwise, use the ring timeout set for the entire station. */
AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
struct sla_station_ref *station_ref;
int trunk_time_elapsed, trunk_time_left;
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
if (ringing_trunk->trunk == trunk_ref->trunk)
break;
}
if (!ringing_trunk)
continue;
/* If there is a trunk that is ringing without a timeout, then the
* only timeout that could matter is a global station ring timeout. */
if (!trunk_ref->ring_timeout)
break;
/* This trunk on this station is ringing and has a timeout.
* However, make sure this trunk isn't still ringing from a
* previous timeout. If so, don't consider it. */
AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
if (station_ref->station == ringing_station->station)
break;
}
if (station_ref)
continue;
trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
if (trunk_time_left > final_trunk_time_left)
final_trunk_time_left = trunk_time_left;
}
/* No timeout was found for ringing trunks, and no timeout for the entire station */
if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
continue;
/* Compute how much time is left for a global station timeout */
if (ringing_station->station->ring_timeout) {
ring_timeout = ringing_station->station->ring_timeout;
time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
time_left = (ring_timeout * 1000) - time_elapsed;
}
/* If the time left based on the per-trunk timeouts is smaller than the
* global station ring timeout, use that. */
if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
time_left = final_trunk_time_left;
/* If there is no time left, the station needs to stop ringing */
if (time_left <= 0) {
AST_LIST_REMOVE_CURRENT(entry);
sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
res = 1;
continue;
}
/* There is still some time left for this station to ring, so save that
* timeout if it is the first event scheduled to occur */
if (time_left < *timeout)
*timeout = time_left;
}
AST_LIST_TRAVERSE_SAFE_END;
return res;
}
| static int sla_calc_trunk_timeouts | ( | unsigned int * | timeout | ) | [static] |
Process trunk ring timeouts.
Definition at line 6359 of file app_meetme.c.
References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_trunk::chan, pbx_builtin_setvar_helper(), sla_ringing_trunk::ring_begin, sla_trunk::ring_timeout, sla, sla_stop_ringing_trunk(), and sla_ringing_trunk::trunk.
Referenced by sla_process_timers().
{
struct sla_ringing_trunk *ringing_trunk;
int res = 0;
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
int time_left, time_elapsed;
if (!ringing_trunk->trunk->ring_timeout)
continue;
time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
if (time_left <= 0) {
pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
AST_LIST_REMOVE_CURRENT(entry);
sla_stop_ringing_trunk(ringing_trunk);
res = 1;
continue;
}
if (time_left < *timeout)
*timeout = time_left;
}
AST_LIST_TRAVERSE_SAFE_END;
return res;
}
| 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] |
Definition at line 5805 of file app_meetme.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_LIST_TRAVERSE, sla_trunk_ref::chan, sla_trunk::name, sla_state_to_devstate(), sla_stations, state, sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by dial_trunk(), queue_ringing_trunk(), run_station(), sla_handle_dial_state_event(), sla_handle_hold_event(), sla_station_exec(), sla_stop_ringing_trunk(), and sla_trunk_exec().
{
struct sla_station *station;
struct sla_trunk_ref *trunk_ref;
struct ao2_iterator i;
i = ao2_iterator_init(sla_stations, 0);
while ((station = ao2_iterator_next(&i))) {
ao2_lock(station);
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
|| trunk_ref == exclude) {
continue;
}
trunk_ref->state = state;
ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
"SLA:%s_%s", station->name, trunk->name);
break;
}
ao2_unlock(station);
ao2_ref(station, -1);
}
ao2_iterator_destroy(&i);
}
| static int sla_check_device | ( | const char * | device | ) | [static] |
Definition at line 7236 of file app_meetme.c.
References ast_strlen_zero().
Referenced by sla_build_trunk().
{
char *tech, *tech_data;
tech_data = ast_strdupa(device);
tech = strsep(&tech_data, "/");
if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
return -1;
return 0;
}
| static int sla_check_failed_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if this station has failed to be dialed in the past minute.
Definition at line 6108 of file app_meetme.c.
References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_failed_station::last_try, sla, sla_failed_station_destroy(), and sla_failed_station::station.
Referenced by sla_ring_stations().
{
struct sla_failed_station *failed_station;
int res = 0;
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
if (station != failed_station->station)
continue;
if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
AST_LIST_REMOVE_CURRENT(entry);
sla_failed_station_destroy(failed_station);
break;
}
res = 1;
}
AST_LIST_TRAVERSE_SAFE_END
return res;
}
| static int sla_check_inuse_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if a station is in use.
Definition at line 6191 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_trunk_ref::chan, and sla_station::trunks.
Referenced by sla_calc_station_delays(), and sla_ring_stations().
{
struct sla_trunk_ref *trunk_ref;
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->chan)
return 1;
}
return 0;
}
| static int sla_check_ringing_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if this station is already ringing.
Definition at line 6093 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla, and sla_ringing_station::station.
Referenced by sla_calc_station_delays(), and sla_ring_stations().
{
struct sla_ringing_station *ringing_station;
AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
if (station == ringing_station->station)
return 1;
}
return 0;
}
| static int sla_check_station_delay | ( | struct sla_station * | station, |
| struct sla_ringing_trunk * | ringing_trunk | ||
| ) | [static] |
Calculate the ring delay for a given ringing trunk on a station.
| station | the station |
| ringing_trunk | the trunk. If NULL, the highest priority ringing trunk will be used |
Definition at line 6223 of file app_meetme.c.
References ao2_cleanup, ast_tvdiff_ms(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla_station::ring_delay, sla_choose_ringing_trunk(), sla_find_trunk_ref(), and sla_ringing_trunk::trunk.
Referenced by sla_calc_station_delays(), and sla_ring_stations().
{
RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
unsigned int delay = UINT_MAX;
int time_left, time_elapsed;
if (!ringing_trunk)
ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
else
trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
if (!ringing_trunk || !trunk_ref)
return delay;
/* If this station has a ring delay specific to the highest priority
* ringing trunk, use that. Otherwise, use the ring delay specified
* globally for the station. */
delay = trunk_ref->ring_delay;
if (!delay)
delay = station->ring_delay;
if (!delay)
return INT_MAX;
time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
time_left = (delay * 1000) - time_elapsed;
return time_left;
}
| static int sla_check_station_hold_access | ( | const struct sla_trunk * | trunk, |
| const struct sla_station * | station | ||
| ) | [static] |
Definition at line 5656 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::hold_access, SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, sla_station_ref::station, sla_trunk::stations, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_find_trunk_ref_byname().
{
struct sla_station_ref *station_ref;
struct sla_trunk_ref *trunk_ref;
/* For each station that has this call on hold, check for private hold. */
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
if (trunk_ref->trunk != trunk || station_ref->station == station)
continue;
if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
station_ref->station->hold_access == SLA_HOLD_PRIVATE)
return 1;
return 0;
}
}
return 0;
}
| static int sla_check_timed_out_station | ( | const struct sla_ringing_trunk * | ringing_trunk, |
| const struct sla_station * | station | ||
| ) | [static] |
Check to see if dialing this station already timed out for this ringing trunk.
Definition at line 5951 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station_ref::station, and sla_ringing_trunk::timed_out_stations.
Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().
{
struct sla_station_ref *timed_out_station;
AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
if (station == timed_out_station->station)
return 1;
}
return 0;
}
| static struct sla_trunk_ref* sla_choose_idle_trunk | ( | const struct sla_station * | station | ) | [static, read] |
For a given station, choose the highest priority idle trunk.
Definition at line 6768 of file app_meetme.c.
References ao2_ref, AST_LIST_TRAVERSE, SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, and sla_station::trunks.
Referenced by sla_station_exec().
{
struct sla_trunk_ref *trunk_ref = NULL;
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) {
ao2_ref(trunk_ref, 1);
break;
}
}
return trunk_ref;
}
| static struct sla_ringing_trunk* sla_choose_ringing_trunk | ( | struct sla_station * | station, |
| struct sla_trunk_ref ** | trunk_ref, | ||
| int | rm | ||
| ) | [static, read] |
Choose the highest priority ringing trunk for a station.
| station | the station |
| rm | remove the ringing trunk once selected |
| trunk_ref | a place to store the pointer to this stations reference to the selected trunk |
Definition at line 5972 of file app_meetme.c.
References ao2_ref, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, sla, sla_check_timed_out_station(), sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.
Referenced by sla_calc_station_delays(), sla_check_station_delay(), and sla_handle_dial_state_event().
{
struct sla_trunk_ref *s_trunk_ref;
struct sla_ringing_trunk *ringing_trunk = NULL;
AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
/* Make sure this is the trunk we're looking for */
if (s_trunk_ref->trunk != ringing_trunk->trunk)
continue;
/* This trunk on the station is ringing. But, make sure this station
* didn't already time out while this trunk was ringing. */
if (sla_check_timed_out_station(ringing_trunk, station))
continue;
if (rm)
AST_LIST_REMOVE_CURRENT(entry);
if (trunk_ref) {
ao2_ref(s_trunk_ref, 1);
*trunk_ref = s_trunk_ref;
}
break;
}
AST_LIST_TRAVERSE_SAFE_END;
if (ringing_trunk)
break;
}
return ringing_trunk;
}
| static struct sla_failed_station* sla_create_failed_station | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 5763 of file app_meetme.c.
References ao2_ref, ast_calloc, ast_tvnow(), sla_failed_station::last_try, and sla_failed_station::station.
Referenced by sla_ring_station().
{
struct sla_failed_station *failed_station;
if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) {
return NULL;
}
ao2_ref(station, 1);
failed_station->station = station;
failed_station->last_try = ast_tvnow();
return failed_station;
}
| static struct sla_ringing_station* sla_create_ringing_station | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 5739 of file app_meetme.c.
References ao2_ref, ast_calloc, ast_tvnow(), sla_ringing_station::ring_begin, and sla_ringing_station::station.
Referenced by sla_ring_station().
{
struct sla_ringing_station *ringing_station;
if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
return NULL;
ao2_ref(station, 1);
ringing_station->station = station;
ringing_station->ring_begin = ast_tvnow();
return ringing_station;
}
| static struct sla_station_ref* sla_create_station_ref | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 5725 of file app_meetme.c.
References ao2_alloc, ao2_ref, sla_station_ref_destructor(), and sla_station_ref::station.
Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().
{
struct sla_station_ref *station_ref;
if (!(station_ref = ao2_alloc(sizeof(*station_ref), sla_station_ref_destructor))) {
return NULL;
}
ao2_ref(station, 1);
station_ref->station = station;
return station_ref;
}
| static void sla_destroy | ( | void | ) | [static] |
Definition at line 7210 of file app_meetme.c.
References ao2_callback, ao2_ref, ast_cond_destroy, ast_cond_signal, ast_context_destroy(), ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, sla, sla_registrar, sla_station_release_refs(), sla_stations, sla_trunk_release_refs(), and sla_trunks.
Referenced by unload_module().
{
if (sla.thread != AST_PTHREADT_NULL) {
ast_mutex_lock(&sla.lock);
sla.stop = 1;
ast_cond_signal(&sla.cond);
ast_mutex_unlock(&sla.lock);
pthread_join(sla.thread, NULL);
}
/* Drop any created contexts from the dialplan */
ast_context_destroy(NULL, sla_registrar);
ast_mutex_destroy(&sla.lock);
ast_cond_destroy(&sla.cond);
ao2_callback(sla_trunks, 0, sla_trunk_release_refs, NULL);
ao2_callback(sla_stations, 0, sla_station_release_refs, NULL);
ao2_ref(sla_trunks, -1);
sla_trunks = NULL;
ao2_ref(sla_stations, -1);
sla_stations = NULL;
}
| static void sla_dial_state_callback | ( | struct ast_dial * | dial | ) | [static] |
Definition at line 5943 of file app_meetme.c.
References SLA_EVENT_DIAL_STATE, and sla_queue_event().
Referenced by sla_ring_station().
| static void sla_event_destroy | ( | struct sla_event * | event | ) | [static] |
Definition at line 6551 of file app_meetme.c.
References ao2_ref, ast_free, sla_event::station, and sla_event::trunk_ref.
Referenced by sla_thread().
| static void sla_failed_station_destroy | ( | struct sla_failed_station * | failed_station | ) | [static] |
Definition at line 5778 of file app_meetme.c.
References ao2_ref, ast_free, and sla_failed_station::station.
Referenced by sla_check_failed_station(), and sla_thread().
| static struct sla_station* sla_find_station | ( | const char * | name | ) | [static, read] |
Definition at line 5647 of file app_meetme.c.
References ao2_find, name, OBJ_POINTER, and sla_stations.
Referenced by sla_build_station(), sla_state(), and sla_station_exec().
{
struct sla_station tmp_station = {
.name = name,
};
return ao2_find(sla_stations, &tmp_station, OBJ_POINTER);
}
| static struct sla_trunk* sla_find_trunk | ( | const char * | name | ) | [static, read] |
Definition at line 5634 of file app_meetme.c.
References ao2_find, name, sla_trunk::name, OBJ_POINTER, and sla_trunks.
Referenced by sla_add_trunk_to_station(), sla_build_trunk(), and sla_trunk_exec().
{
struct sla_trunk tmp_trunk = {
.name = name,
};
return ao2_find(sla_trunks, &tmp_trunk, OBJ_POINTER);
}
| static struct sla_trunk_ref* sla_find_trunk_ref | ( | const struct sla_station * | station, |
| const struct sla_trunk * | trunk | ||
| ) | [static, read] |
Definition at line 6203 of file app_meetme.c.
References ao2_ref, AST_LIST_TRAVERSE, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_check_station_delay().
{
struct sla_trunk_ref *trunk_ref = NULL;
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->trunk == trunk)
break;
}
ao2_ref(trunk_ref, 1);
return trunk_ref;
}
| static struct sla_trunk_ref* sla_find_trunk_ref_byname | ( | const struct sla_station * | station, |
| const char * | name | ||
| ) | [static, read] |
Find a trunk reference on a station by name.
| station | the station |
| name | the trunk's name |
Definition at line 5686 of file app_meetme.c.
References ao2_ref, AST_LIST_TRAVERSE, sla_trunk::barge_disabled, sla_trunk::hold_access, sla_trunk::hold_stations, sla_trunk::name, sla_check_station_hold_access(), SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_station_exec().
{
struct sla_trunk_ref *trunk_ref = NULL;
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (strcasecmp(trunk_ref->trunk->name, name))
continue;
if ( (trunk_ref->trunk->barge_disabled
&& trunk_ref->state == SLA_TRUNK_STATE_UP) ||
(trunk_ref->trunk->hold_stations
&& trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
&& trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
sla_check_station_hold_access(trunk_ref->trunk, station) )
{
trunk_ref = NULL;
}
break;
}
if (trunk_ref) {
ao2_ref(trunk_ref, 1);
}
return trunk_ref;
}
| static void sla_handle_dial_state_event | ( | void | ) | [static] |
Definition at line 6008 of file app_meetme.c.
References ALL_TRUNK_REFS, answer_trunk_chan(), ao2_cleanup, ao2_ref, ast_cond_destroy, ast_cond_init, ast_cond_wait, ast_debug, ast_dial_answered(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_state(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, sla_trunk::chan, cond, run_station_args::cond, run_station_args::cond_lock, sla_station::dial, run_station(), sla, sla_change_trunk_state(), sla_choose_ringing_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_queue_event(), sla_ringing_station_destroy(), sla_ringing_trunk_destroy(), SLA_STATION_HANGUP_NORMAL, sla_stop_ringing_station(), SLA_TRUNK_STATE_UP, sla_ringing_station::station, run_station_args::station, sla_ringing_trunk::trunk, and run_station_args::trunk_ref.
Referenced by sla_thread().
{
struct sla_ringing_station *ringing_station;
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
RAII_VAR(struct sla_trunk_ref *, s_trunk_ref, NULL, ao2_cleanup);
struct sla_ringing_trunk *ringing_trunk = NULL;
struct run_station_args args;
enum ast_dial_result dial_res;
pthread_t dont_care;
ast_mutex_t cond_lock;
ast_cond_t cond;
switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
case AST_DIAL_RESULT_HANGUP:
case AST_DIAL_RESULT_INVALID:
case AST_DIAL_RESULT_FAILED:
case AST_DIAL_RESULT_TIMEOUT:
case AST_DIAL_RESULT_UNANSWERED:
AST_LIST_REMOVE_CURRENT(entry);
sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
break;
case AST_DIAL_RESULT_ANSWERED:
AST_LIST_REMOVE_CURRENT(entry);
/* Find the appropriate trunk to answer. */
ast_mutex_lock(&sla.lock);
ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
ast_mutex_unlock(&sla.lock);
if (!ringing_trunk) {
/* This case happens in a bit of a race condition. If two stations answer
* the outbound call at the same time, the first one will get connected to
* the trunk. When the second one gets here, it will not see any trunks
* ringing so we have no idea what to conect it to. So, we just hang up
* on it. */
ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
ast_dial_join(ringing_station->station->dial);
ast_dial_destroy(ringing_station->station->dial);
ringing_station->station->dial = NULL;
sla_ringing_station_destroy(ringing_station);
break;
}
/* Track the channel that answered this trunk */
s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
/* Actually answer the trunk */
answer_trunk_chan(ringing_trunk->trunk->chan);
sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
/* Now, start a thread that will connect this station to the trunk. The rest of
* the code here sets up the thread and ensures that it is able to save the arguments
* before they are no longer valid since they are allocated on the stack. */
ao2_ref(s_trunk_ref, 1);
args.trunk_ref = s_trunk_ref;
ao2_ref(ringing_station->station, 1);
args.station = ringing_station->station;
args.cond = &cond;
args.cond_lock = &cond_lock;
sla_ringing_trunk_destroy(ringing_trunk);
sla_ringing_station_destroy(ringing_station);
ast_mutex_init(&cond_lock);
ast_cond_init(&cond, NULL);
ast_mutex_lock(&cond_lock);
ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
ast_cond_wait(&cond, &cond_lock);
ast_mutex_unlock(&cond_lock);
ast_mutex_destroy(&cond_lock);
ast_cond_destroy(&cond);
break;
case AST_DIAL_RESULT_TRYING:
case AST_DIAL_RESULT_RINGING:
case AST_DIAL_RESULT_PROGRESS:
case AST_DIAL_RESULT_PROCEEDING:
break;
}
if (dial_res == AST_DIAL_RESULT_ANSWERED) {
/* Queue up reprocessing ringing trunks, and then ringing stations again */
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
sla_queue_event(SLA_EVENT_DIAL_STATE);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
}
| static void sla_handle_hold_event | ( | struct sla_event * | event | ) | [static] |
Definition at line 6335 of file app_meetme.c.
References sla_trunk::active_stations, ast_atomic_fetchadd_int(), AST_CONTROL_HOLD, AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_indicate(), ast_softhangup(), AST_SOFTHANGUP_DEV, sla_trunk::chan, sla_trunk_ref::chan, sla_trunk::hold_stations, INACTIVE_TRUNK_REFS, sla_trunk::name, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_event::station, sla_trunk_ref::trunk, and sla_event::trunk_ref.
Referenced by sla_thread().
{
ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s",
event->station->name, event->trunk_ref->trunk->name);
sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
INACTIVE_TRUNK_REFS, event->trunk_ref);
if (event->trunk_ref->trunk->active_stations == 1) {
/* The station putting it on hold is the only one on the call, so start
* Music on hold to the trunk. */
event->trunk_ref->trunk->on_hold = 1;
ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
}
ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
event->trunk_ref->chan = NULL;
}
| static void sla_handle_ringing_trunk_event | ( | void | ) | [static] |
Definition at line 6325 of file app_meetme.c.
References ast_mutex_lock, ast_mutex_unlock, sla, sla_hangup_stations(), and sla_ring_stations().
Referenced by sla_thread().
{
ast_mutex_lock(&sla.lock);
sla_ring_stations();
ast_mutex_unlock(&sla.lock);
/* Find stations that shouldn't be ringing anymore. */
sla_hangup_stations();
}
| static void sla_hangup_stations | ( | void | ) | [static] |
Definition at line 6297 of file app_meetme.c.
References ast_dial_destroy(), ast_dial_join(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock, ast_mutex_unlock, sla_station::dial, sla, sla_ringing_station_destroy(), sla_ringing_station::station, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.
Referenced by sla_handle_ringing_trunk_event().
{
struct sla_trunk_ref *trunk_ref;
struct sla_ringing_station *ringing_station;
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
struct sla_ringing_trunk *ringing_trunk;
ast_mutex_lock(&sla.lock);
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
if (trunk_ref->trunk == ringing_trunk->trunk)
break;
}
ast_mutex_unlock(&sla.lock);
if (ringing_trunk)
break;
}
if (!trunk_ref) {
AST_LIST_REMOVE_CURRENT(entry);
ast_dial_join(ringing_station->station->dial);
ast_dial_destroy(ringing_station->station->dial);
ringing_station->station->dial = NULL;
sla_ringing_station_destroy(ringing_station);
}
}
AST_LIST_TRAVERSE_SAFE_END
}
| static const char* sla_hold_str | ( | unsigned int | hold_access | ) | [static] |
Definition at line 1752 of file app_meetme.c.
References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.
Referenced by sla_show_stations(), and sla_show_trunks().
{
const char *hold = "Unknown";
switch (hold_access) {
case SLA_HOLD_OPEN:
hold = "Open";
break;
case SLA_HOLD_PRIVATE:
hold = "Private";
default:
break;
}
return hold;
}
| static int sla_in_use | ( | void | ) | [static] |
Definition at line 7642 of file app_meetme.c.
References ao2_container_count(), sla_stations, and sla_trunks.
Referenced by sla_load_config().
{
return ao2_container_count(sla_trunks) || ao2_container_count(sla_stations);
}
| static int sla_load_config | ( | int | reload | ) | [static] |
Definition at line 7647 of file app_meetme.c.
References ao2_callback, ao2_container_alloc, ast_category_browse(), ast_cond_init, ast_config_destroy(), ast_config_load, ast_log(), ast_mutex_init, ast_pthread_create, AST_PTHREADT_NULL, ast_true(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_ERROR, LOG_WARNING, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, sla, sla_build_station(), sla_build_trunk(), SLA_CONFIG_FILE, sla_in_use(), sla_station_cmp(), sla_station_hash(), sla_station_is_marked(), sla_station_mark(), sla_stations, sla_thread(), sla_trunk_cmp(), sla_trunk_hash(), sla_trunk_is_marked(), sla_trunk_mark(), sla_trunks, and type.
Referenced by load_config().
{
struct ast_config *cfg;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
const char *cat = NULL;
int res = 0;
const char *val;
if (!reload) {
ast_mutex_init(&sla.lock);
ast_cond_init(&sla.cond, NULL);
sla_trunks = ao2_container_alloc(1, sla_trunk_hash, sla_trunk_cmp);
sla_stations = ao2_container_alloc(1, sla_station_hash, sla_station_cmp);
}
if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
return 0; /* Treat no config as normal */
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format. Aborting.\n");
return 0;
}
if (reload) {
ao2_callback(sla_trunks, 0, sla_trunk_mark, NULL);
ao2_callback(sla_stations, 0, sla_station_mark, NULL);
}
if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
sla.attempt_callerid = ast_true(val);
while ((cat = ast_category_browse(cfg, cat)) && !res) {
const char *type;
if (!strcasecmp(cat, "general"))
continue;
if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
SLA_CONFIG_FILE);
continue;
}
if (!strcasecmp(type, "trunk"))
res = sla_build_trunk(cfg, cat);
else if (!strcasecmp(type, "station"))
res = sla_build_station(cfg, cat);
else {
ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
SLA_CONFIG_FILE, type);
}
}
ast_config_destroy(cfg);
if (reload) {
ao2_callback(sla_trunks, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, sla_trunk_is_marked, NULL);
ao2_callback(sla_stations, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, sla_station_is_marked, NULL);
}
/* Start SLA event processing thread once SLA has been configured. */
if (sla.thread == AST_PTHREADT_NULL && sla_in_use()) {
ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
}
return res;
}
| static int sla_process_timers | ( | struct timespec * | ts | ) | [static] |
Calculate the time until the next known event.
Definition at line 6516 of file app_meetme.c.
References ast_samp2tv(), ast_tvadd(), ast_tvnow(), sla_calc_station_delays(), sla_calc_station_timeouts(), sla_calc_trunk_timeouts(), SLA_EVENT_RINGING_TRUNK, and sla_queue_event_nolock().
Referenced by sla_thread().
{
unsigned int timeout = UINT_MAX;
struct timeval wait;
unsigned int change_made = 0;
/* Check for ring timeouts on ringing trunks */
if (sla_calc_trunk_timeouts(&timeout))
change_made = 1;
/* Check for ring timeouts on ringing stations */
if (sla_calc_station_timeouts(&timeout))
change_made = 1;
/* Check for station ring delays */
if (sla_calc_station_delays(&timeout))
change_made = 1;
/* queue reprocessing of ringing trunks */
if (change_made)
sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
/* No timeout */
if (timeout == UINT_MAX)
return 0;
if (ts) {
wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
ts->tv_sec = wait.tv_sec;
ts->tv_nsec = wait.tv_usec * 1000;
}
return 1;
}
| static void sla_queue_event | ( | enum sla_event_type | type | ) | [static] |
Definition at line 2101 of file app_meetme.c.
References sla_queue_event_full().
Referenced by queue_ringing_trunk(), sla_dial_state_callback(), sla_handle_dial_state_event(), sla_station_exec(), and sla_trunk_exec().
{
sla_queue_event_full(type, NULL, NULL, 1);
}
| static void sla_queue_event_conf | ( | enum sla_event_type | type, |
| struct ast_channel * | chan, | ||
| struct ast_conference * | conf | ||
| ) | [static] |
Queue a SLA event from the conference.
Definition at line 2107 of file app_meetme.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_strlen_zero(), sla_trunk_ref::chan, ast_conference::confno, LOG_ERROR, sla_trunk::name, sla_queue_event_full(), sla_stations, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by conf_run().
{
struct sla_station *station;
struct sla_trunk_ref *trunk_ref = NULL;
char *trunk_name;
struct ao2_iterator i;
trunk_name = ast_strdupa(conf->confno);
strsep(&trunk_name, "_");
if (ast_strlen_zero(trunk_name)) {
ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
return;
}
i = ao2_iterator_init(sla_stations, 0);
while ((station = ao2_iterator_next(&i))) {
ao2_lock(station);
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
ao2_ref(trunk_ref, 1);
break;
}
}
ao2_unlock(station);
if (trunk_ref) {
/* station reference given to sla_queue_event_full() */
break;
}
ao2_ref(station, -1);
}
ao2_iterator_destroy(&i);
if (!trunk_ref) {
ast_debug(1, "Trunk not found for event!\n");
return;
}
sla_queue_event_full(type, trunk_ref, station, 1);
}
| static void sla_queue_event_full | ( | enum sla_event_type | type, |
| struct sla_trunk_ref * | trunk_ref, | ||
| struct sla_station * | station, | ||
| int | lock | ||
| ) | [static] |
Definition at line 2064 of file app_meetme.c.
References ao2_ref, ast_calloc, ast_cond_signal, AST_LIST_INSERT_TAIL, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, sla, sla_event::station, sla_event::trunk_ref, and type.
Referenced by sla_queue_event(), sla_queue_event_conf(), and sla_queue_event_nolock().
{
struct sla_event *event;
if (sla.thread == AST_PTHREADT_NULL) {
ao2_ref(station, -1);
ao2_ref(trunk_ref, -1);
return;
}
if (!(event = ast_calloc(1, sizeof(*event)))) {
ao2_ref(station, -1);
ao2_ref(trunk_ref, -1);
return;
}
event->type = type;
event->trunk_ref = trunk_ref;
event->station = station;
if (!lock) {
AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
return;
}
ast_mutex_lock(&sla.lock);
AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
ast_cond_signal(&sla.cond);
ast_mutex_unlock(&sla.lock);
}
| static void sla_queue_event_nolock | ( | enum sla_event_type | type | ) | [static] |
Definition at line 2096 of file app_meetme.c.
References sla_queue_event_full().
Referenced by sla_process_timers().
{
sla_queue_event_full(type, NULL, NULL, 0);
}
| static int sla_ring_station | ( | struct sla_ringing_trunk * | ringing_trunk, |
| struct sla_station * | station | ||
| ) | [static] |
Ring a station.
Definition at line 6131 of file app_meetme.c.
References ast_channel_caller(), ast_channel_caller_set(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), AST_LIST_INSERT_HEAD, ast_party_caller_free(), ast_party_caller_init(), sla_trunk::chan, sla_station::dial, sla, sla_create_failed_station(), sla_create_ringing_station(), sla_dial_state_callback(), and sla_ringing_trunk::trunk.
Referenced by sla_ring_stations().
{
char *tech, *tech_data;
struct ast_dial *dial;
struct sla_ringing_station *ringing_station;
enum ast_dial_result res;
int caller_is_saved;
struct ast_party_caller caller;
if (!(dial = ast_dial_create()))
return -1;
ast_dial_set_state_callback(dial, sla_dial_state_callback);
tech_data = ast_strdupa(station->device);
tech = strsep(&tech_data, "/");
if (ast_dial_append(dial, tech, tech_data) == -1) {
ast_dial_destroy(dial);
return -1;
}
/* Do we need to save off the caller ID data? */
caller_is_saved = 0;
if (!sla.attempt_callerid) {
caller_is_saved = 1;
caller = *ast_channel_caller(ringing_trunk->trunk->chan);
ast_party_caller_init(ast_channel_caller(ringing_trunk->trunk->chan));
}
res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
/* Restore saved caller ID */
if (caller_is_saved) {
ast_party_caller_free(ast_channel_caller(ringing_trunk->trunk->chan));
ast_channel_caller_set(ringing_trunk->trunk->chan, &caller);
}
if (res != AST_DIAL_RESULT_TRYING) {
struct sla_failed_station *failed_station;
ast_dial_destroy(dial);
if ((failed_station = sla_create_failed_station(station))) {
AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
}
return -1;
}
if (!(ringing_station = sla_create_ringing_station(station))) {
ast_dial_join(dial);
ast_dial_destroy(dial);
return -1;
}
station->dial = dial;
AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
return 0;
}
| static void sla_ring_stations | ( | void | ) | [static] |
Ring stations based on current set of ringing trunks.
Definition at line 6256 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla, sla_check_failed_station(), sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), sla_check_timed_out_station(), sla_ring_station(), sla_station_ref::station, sla_trunk::stations, and sla_ringing_trunk::trunk.
Referenced by sla_handle_ringing_trunk_event().
{
struct sla_station_ref *station_ref;
struct sla_ringing_trunk *ringing_trunk;
/* Make sure that every station that uses at least one of the ringing
* trunks, is ringing. */
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
int time_left;
/* Is this station already ringing? */
if (sla_check_ringing_station(station_ref->station))
continue;
/* Is this station already in a call? */
if (sla_check_inuse_station(station_ref->station))
continue;
/* Did we fail to dial this station earlier? If so, has it been
* a minute since we tried? */
if (sla_check_failed_station(station_ref->station))
continue;
/* If this station already timed out while this trunk was ringing,
* do not dial it again for this ringing trunk. */
if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
continue;
/* Check for a ring delay in progress */
time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
if (time_left != INT_MAX && time_left > 0)
continue;
/* It is time to make this station begin to ring. Do it! */
sla_ring_station(ringing_trunk, station_ref->station);
}
}
/* Now, all of the stations that should be ringing, are ringing. */
}
| static void sla_ringing_station_destroy | ( | struct sla_ringing_station * | ringing_station | ) | [static] |
Definition at line 5753 of file app_meetme.c.
References ao2_ref, ast_free, and sla_ringing_station::station.
Referenced by sla_handle_dial_state_event(), sla_hangup_stations(), sla_stop_ringing_station(), and sla_thread().
| static void sla_ringing_trunk_destroy | ( | struct sla_ringing_trunk * | ringing_trunk | ) | [static] |
Definition at line 6981 of file app_meetme.c.
References ao2_ref, ast_free, and sla_ringing_trunk::trunk.
Referenced by sla_handle_dial_state_event(), sla_station_exec(), sla_stop_ringing_trunk(), and sla_trunk_exec().
| static char* sla_show_stations | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1843 of file app_meetme.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli(), AST_LIST_TRAVERSE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, sla_station::hold_access, sla_trunk::name, sla_station::ring_delay, sla_trunk_ref::ring_delay, sla_station::ring_timeout, sla_trunk_ref::ring_timeout, S_OR, sla_hold_str(), sla_stations, sla_trunk_ref::state, sla_trunk_ref::trunk, sla_station::trunks, trunkstate2str(), and ast_cli_entry::usage.
{
struct ao2_iterator i;
struct sla_station *station;
switch (cmd) {
case CLI_INIT:
e->command = "sla show stations";
e->usage =
"Usage: sla show stations\n"
" This will list all stations defined in sla.conf\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
ast_cli(a->fd, "\n"
"=============================================================\n"
"=== Configured SLA Stations =================================\n"
"=============================================================\n"
"===\n");
i = ao2_iterator_init(sla_stations, 0);
for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
struct sla_trunk_ref *trunk_ref;
char ring_timeout[16] = "(none)";
char ring_delay[16] = "(none)";
ao2_lock(station);
if (station->ring_timeout) {
snprintf(ring_timeout, sizeof(ring_timeout),
"%u", station->ring_timeout);
}
if (station->ring_delay) {
snprintf(ring_delay, sizeof(ring_delay),
"%u", station->ring_delay);
}
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
"=== Station Name: %s\n"
"=== ==> Device: %s\n"
"=== ==> AutoContext: %s\n"
"=== ==> RingTimeout: %s\n"
"=== ==> RingDelay: %s\n"
"=== ==> HoldAccess: %s\n"
"=== ==> Trunks ...\n",
station->name, station->device,
S_OR(station->autocontext, "(none)"),
ring_timeout, ring_delay,
sla_hold_str(station->hold_access));
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->ring_timeout) {
snprintf(ring_timeout, sizeof(ring_timeout),
"%u", trunk_ref->ring_timeout);
} else
strcpy(ring_timeout, "(none)");
if (trunk_ref->ring_delay) {
snprintf(ring_delay, sizeof(ring_delay),
"%u", trunk_ref->ring_delay);
} else
strcpy(ring_delay, "(none)");
ast_cli(a->fd, "=== ==> Trunk Name: %s\n"
"=== ==> State: %s\n"
"=== ==> RingTimeout: %s\n"
"=== ==> RingDelay: %s\n",
trunk_ref->trunk->name,
trunkstate2str(trunk_ref->state),
ring_timeout, ring_delay);
}
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
"===\n");
ao2_unlock(station);
}
ao2_iterator_destroy(&i);
ast_cli(a->fd, "============================================================\n"
"\n");
return CLI_SUCCESS;
}
| static char* sla_show_trunks | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1769 of file app_meetme.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli(), AST_LIST_TRAVERSE, sla_trunk::autocontext, sla_trunk::barge_disabled, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, sla_trunk::device, ast_cli_args::fd, sla_trunk::hold_access, sla_trunk::name, sla_trunk::ring_timeout, S_OR, sla_hold_str(), sla_trunks, sla_station_ref::station, sla_trunk::stations, and ast_cli_entry::usage.
{
struct ao2_iterator i;
struct sla_trunk *trunk;
switch (cmd) {
case CLI_INIT:
e->command = "sla show trunks";
e->usage =
"Usage: sla show trunks\n"
" This will list all trunks defined in sla.conf\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
ast_cli(a->fd, "\n"
"=============================================================\n"
"=== Configured SLA Trunks ===================================\n"
"=============================================================\n"
"===\n");
i = ao2_iterator_init(sla_trunks, 0);
for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
struct sla_station_ref *station_ref;
char ring_timeout[16] = "(none)";
ao2_lock(trunk);
if (trunk->ring_timeout) {
snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
}
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
"=== Trunk Name: %s\n"
"=== ==> Device: %s\n"
"=== ==> AutoContext: %s\n"
"=== ==> RingTimeout: %s\n"
"=== ==> BargeAllowed: %s\n"
"=== ==> HoldAccess: %s\n"
"=== ==> Stations ...\n",
trunk->name, trunk->device,
S_OR(trunk->autocontext, "(none)"),
ring_timeout,
trunk->barge_disabled ? "No" : "Yes",
sla_hold_str(trunk->hold_access));
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
}
ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
ao2_unlock(trunk);
}
ao2_iterator_destroy(&i);
ast_cli(a->fd, "=============================================================\n\n");
return CLI_SUCCESS;
}
| static enum ast_device_state sla_state | ( | const char * | data | ) | [static] |
Definition at line 7102 of file app_meetme.c.
References ao2_cleanup, ao2_lock, ao2_unlock, AST_DEVICE_INVALID, AST_LIST_TRAVERSE, ast_log(), LOG_ERROR, sla_trunk::name, sla_find_station(), sla_state_to_devstate(), sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by load_module().
{
char *buf, *station_name, *trunk_name;
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
struct sla_trunk_ref *trunk_ref;
enum ast_device_state res = AST_DEVICE_INVALID;
trunk_name = buf = ast_strdupa(data);
station_name = strsep(&trunk_name, "_");
station = sla_find_station(station_name);
if (station) {
ao2_lock(station);
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) {
res = sla_state_to_devstate(trunk_ref->state);
break;
}
}
ao2_unlock(station);
}
if (res == AST_DEVICE_INVALID) {
ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
trunk_name, station_name);
}
return res;
}
| static enum ast_device_state sla_state_to_devstate | ( | enum sla_trunk_state | state | ) | [static] |
Definition at line 5788 of file app_meetme.c.
References AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_UNKNOWN, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.
Referenced by sla_change_trunk_state(), and sla_state().
{
switch (state) {
case SLA_TRUNK_STATE_IDLE:
return AST_DEVICE_NOT_INUSE;
case SLA_TRUNK_STATE_RINGING:
return AST_DEVICE_RINGING;
case SLA_TRUNK_STATE_UP:
return AST_DEVICE_INUSE;
case SLA_TRUNK_STATE_ONHOLD:
case SLA_TRUNK_STATE_ONHOLD_BYME:
return AST_DEVICE_ONHOLD;
}
return AST_DEVICE_UNKNOWN;
}
| static int sla_station_cmp | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7203 of file app_meetme.c.
References CMP_MATCH, and CMP_STOP.
Referenced by sla_load_config().
{
struct sla_station *station = obj, *station2 = arg;
return !strcasecmp(station->name, station2->name) ? CMP_MATCH | CMP_STOP : 0;
}
| static void sla_station_destructor | ( | void * | obj | ) | [static] |
Definition at line 7156 of file app_meetme.c.
References ast_context_remove_extension(), ast_debug, AST_LIST_TRAVERSE, AST_MAX_APP, AST_MAX_EXTENSION, ast_string_field_free_memory, ast_strlen_zero(), exten, sla_trunk::name, PRIORITY_HINT, sla_registrar, sla_station_release_refs(), sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_build_station().
{
struct sla_station *station = obj;
ast_debug(1, "sla_station destructor for '%s'\n", station->name);
if (!ast_strlen_zero(station->autocontext)) {
struct sla_trunk_ref *trunk_ref;
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
char exten[AST_MAX_EXTENSION];
char hint[AST_MAX_APP];
snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
snprintf(hint, sizeof(hint), "SLA:%s", exten);
ast_context_remove_extension(station->autocontext, exten,
1, sla_registrar);
ast_context_remove_extension(station->autocontext, hint,
PRIORITY_HINT, sla_registrar);
}
}
sla_station_release_refs(station, NULL, 0);
ast_string_field_free_memory(station);
}
| static int sla_station_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 6782 of file app_meetme.c.
References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ao2_cleanup, ao2_lock, ao2_ref, ao2_unlock, ast_answer(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_cond_destroy, ast_cond_init, ast_cond_wait, AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, ast_set_flag64, ast_strlen_zero(), build_conf(), sla_trunk::chan, sla_trunk_ref::chan, cond, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), sla_trunk::hold_stations, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, sla_trunk::name, sla_trunk::on_hold, pbx_builtin_setvar_helper(), sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), sla_ringing_trunk_destroy(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, dial_trunk_args::station, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and dial_trunk_args::trunk_ref.
Referenced by load_module().
{
char *station_name, *trunk_name;
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
char conf_name[MAX_CONFNUM];
struct ast_flags64 conf_flags = { 0 };
struct ast_conference *conf;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
return 0;
}
trunk_name = ast_strdupa(data);
station_name = strsep(&trunk_name, "_");
if (ast_strlen_zero(station_name)) {
ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
return 0;
}
station = sla_find_station(station_name);
if (!station) {
ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
return 0;
}
ao2_lock(station);
if (!ast_strlen_zero(trunk_name)) {
trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
} else {
trunk_ref = sla_choose_idle_trunk(station);
}
ao2_unlock(station);
if (!trunk_ref) {
if (ast_strlen_zero(trunk_name))
ast_log(LOG_NOTICE, "No trunks available for call.\n");
else {
ast_log(LOG_NOTICE, "Can't join existing call on trunk "
"'%s' due to access controls.\n", trunk_name);
}
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
return 0;
}
if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
else {
trunk_ref->state = SLA_TRUNK_STATE_UP;
ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
"SLA:%s_%s", station->name, trunk_ref->trunk->name);
}
} else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
struct sla_ringing_trunk *ringing_trunk;
ast_mutex_lock(&sla.lock);
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
if (ringing_trunk->trunk == trunk_ref->trunk) {
AST_LIST_REMOVE_CURRENT(entry);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END
ast_mutex_unlock(&sla.lock);
if (ringing_trunk) {
answer_trunk_chan(ringing_trunk->trunk->chan);
sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
sla_ringing_trunk_destroy(ringing_trunk);
/* Queue up reprocessing ringing trunks, and then ringing stations again */
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
sla_queue_event(SLA_EVENT_DIAL_STATE);
}
}
trunk_ref->chan = chan;
if (!trunk_ref->trunk->chan) {
ast_mutex_t cond_lock;
ast_cond_t cond;
pthread_t dont_care;
struct dial_trunk_args args = {
.trunk_ref = trunk_ref,
.station = station,
.cond_lock = &cond_lock,
.cond = &cond,
};
ao2_ref(trunk_ref, 1);
ao2_ref(station, 1);
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
/* Create a thread to dial the trunk and dump it into the conference.
* However, we want to wait until the trunk has been dialed and the
* conference is created before continuing on here. */
ast_autoservice_start(chan);
ast_mutex_init(&cond_lock);
ast_cond_init(&cond, NULL);
ast_mutex_lock(&cond_lock);
ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
ast_cond_wait(&cond, &cond_lock);
ast_mutex_unlock(&cond_lock);
ast_mutex_destroy(&cond_lock);
ast_cond_destroy(&cond);
ast_autoservice_stop(chan);
if (!trunk_ref->trunk->chan) {
ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
trunk_ref->chan = NULL;
return 0;
}
}
if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
trunk_ref->trunk->on_hold) {
trunk_ref->trunk->on_hold = 0;
ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
}
snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
ast_set_flag64(&conf_flags,
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
ast_answer(chan);
conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
if (conf) {
conf_run(chan, conf, &conf_flags, NULL);
dispose_conf(conf);
conf = NULL;
}
trunk_ref->chan = NULL;
if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
admin_exec(NULL, conf_name);
trunk_ref->trunk->hold_stations = 0;
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
}
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
return 0;
}
| static int sla_station_hash | ( | const void * | obj, |
| const int | flags | ||
| ) | [static] |
Definition at line 7196 of file app_meetme.c.
References ast_str_case_hash().
Referenced by sla_load_config().
{
const struct sla_station *station = obj;
return ast_str_case_hash(station->name);
}
| static int sla_station_is_marked | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7614 of file app_meetme.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, CMP_MATCH, sla_station::mark, sla_trunk_ref::mark, sla_station_release_refs(), and sla_station::trunks.
Referenced by sla_load_config().
{
struct sla_station *station = obj;
ao2_lock(station);
if (station->mark) {
/* Only remove all of the trunk references if the station itself is going away */
sla_station_release_refs(station, NULL, 0);
} else {
struct sla_trunk_ref *trunk_ref;
/* Otherwise only remove references to trunks no longer in the config */
AST_LIST_TRAVERSE_SAFE_BEGIN(&station->trunks, trunk_ref, entry) {
if (!trunk_ref->mark) {
continue;
}
AST_LIST_REMOVE_CURRENT(entry);
ao2_ref(trunk_ref, -1);
}
AST_LIST_TRAVERSE_SAFE_END
}
ao2_unlock(station);
return station->mark ? CMP_MATCH : 0;
}
| static int sla_station_mark | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7568 of file app_meetme.c.
References ao2_lock, ao2_unlock, AST_LIST_TRAVERSE, sla_station::mark, sla_trunk_ref::mark, and sla_station::trunks.
Referenced by sla_load_config().
{
struct sla_station *station = obj;
struct sla_trunk_ref *trunk_ref;
ao2_lock(station);
station->mark = 1;
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
trunk_ref->mark = 1;
}
ao2_unlock(station);
return 0;
}
| static void sla_station_ref_destructor | ( | void * | obj | ) | [static] |
Definition at line 5715 of file app_meetme.c.
References ao2_ref, and sla_station_ref::station.
Referenced by sla_create_station_ref().
{
struct sla_station_ref *station_ref = obj;
if (station_ref->station) {
ao2_ref(station_ref->station, -1);
station_ref->station = NULL;
}
}
| static int sla_station_release_refs | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7144 of file app_meetme.c.
References ao2_ref, AST_LIST_REMOVE_HEAD, and sla_station::trunks.
Referenced by sla_destroy(), sla_station_destructor(), and sla_station_is_marked().
{
struct sla_station *station = obj;
struct sla_trunk_ref *trunk_ref;
while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) {
ao2_ref(trunk_ref, -1);
}
return 0;
}
| static void sla_stop_ringing_station | ( | struct sla_ringing_station * | ringing_station, |
| enum sla_station_hangup | hangup | ||
| ) | [static] |
Definition at line 5908 of file app_meetme.c.
References ast_dial_destroy(), ast_dial_join(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, sla_station::dial, sla, sla_create_station_ref(), sla_ringing_station_destroy(), SLA_STATION_HANGUP_NORMAL, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.
Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().
{
struct sla_ringing_trunk *ringing_trunk;
struct sla_trunk_ref *trunk_ref;
struct sla_station_ref *station_ref;
ast_dial_join(ringing_station->station->dial);
ast_dial_destroy(ringing_station->station->dial);
ringing_station->station->dial = NULL;
if (hangup == SLA_STATION_HANGUP_NORMAL)
goto done;
/* If the station is being hung up because of a timeout, then add it to the
* list of timed out stations on each of the ringing trunks. This is so
* that when doing further processing to figure out which stations should be
* ringing, which trunk to answer, determining timeouts, etc., we know which
* ringing trunks we should ignore. */
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
if (ringing_trunk->trunk == trunk_ref->trunk)
break;
}
if (!trunk_ref)
continue;
if (!(station_ref = sla_create_station_ref(ringing_station->station)))
continue;
AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
}
done:
sla_ringing_station_destroy(ringing_station);
}
| static void sla_stop_ringing_trunk | ( | struct sla_ringing_trunk * | ringing_trunk | ) | [static] |
Definition at line 5892 of file app_meetme.c.
References admin_exec(), ALL_TRUNK_REFS, ao2_ref, AST_LIST_REMOVE_HEAD, sla_trunk::name, sla_change_trunk_state(), sla_ringing_trunk_destroy(), SLA_TRUNK_STATE_IDLE, sla_ringing_trunk::timed_out_stations, and sla_ringing_trunk::trunk.
Referenced by sla_calc_trunk_timeouts().
{
char buf[80];
struct sla_station_ref *station_ref;
snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
admin_exec(NULL, buf);
sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) {
ao2_ref(station_ref, -1);
}
sla_ringing_trunk_destroy(ringing_trunk);
}
| static void* sla_thread | ( | void * | data | ) | [static] |
Definition at line 6566 of file app_meetme.c.
References ast_cond_timedwait, ast_cond_wait, AST_LIST_EMPTY, AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, sla, sla_event_destroy(), SLA_EVENT_DIAL_STATE, SLA_EVENT_HOLD, SLA_EVENT_RINGING_TRUNK, sla_failed_station_destroy(), sla_handle_dial_state_event(), sla_handle_hold_event(), sla_handle_ringing_trunk_event(), sla_process_timers(), sla_ringing_station_destroy(), and sla_event::type.
Referenced by sla_load_config().
{
struct sla_failed_station *failed_station;
struct sla_ringing_station *ringing_station;
ast_mutex_lock(&sla.lock);
while (!sla.stop) {
struct sla_event *event;
struct timespec ts = { 0, };
unsigned int have_timeout = 0;
if (AST_LIST_EMPTY(&sla.event_q)) {
if ((have_timeout = sla_process_timers(&ts)))
ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
else
ast_cond_wait(&sla.cond, &sla.lock);
if (sla.stop)
break;
}
if (have_timeout)
sla_process_timers(NULL);
while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
ast_mutex_unlock(&sla.lock);
switch (event->type) {
case SLA_EVENT_HOLD:
sla_handle_hold_event(event);
break;
case SLA_EVENT_DIAL_STATE:
sla_handle_dial_state_event();
break;
case SLA_EVENT_RINGING_TRUNK:
sla_handle_ringing_trunk_event();
break;
}
sla_event_destroy(event);
ast_mutex_lock(&sla.lock);
}
}
ast_mutex_unlock(&sla.lock);
while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) {
sla_ringing_station_destroy(ringing_station);
}
while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) {
sla_failed_station_destroy(failed_station);
}
return NULL;
}
| static int sla_trunk_cmp | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7189 of file app_meetme.c.
References CMP_MATCH, CMP_STOP, and sla_trunk::name.
Referenced by sla_load_config().
| static void sla_trunk_destructor | ( | void * | obj | ) | [static] |
Definition at line 7249 of file app_meetme.c.
References ast_context_remove_extension(), ast_debug, ast_string_field_free_memory, ast_strlen_zero(), sla_trunk::autocontext, sla_trunk::name, sla_registrar, and sla_trunk_release_refs().
Referenced by sla_build_trunk().
{
struct sla_trunk *trunk = obj;
ast_debug(1, "sla_trunk destructor for '%s'\n", trunk->name);
if (!ast_strlen_zero(trunk->autocontext)) {
ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
}
sla_trunk_release_refs(trunk, NULL, 0);
ast_string_field_free_memory(trunk);
}
| static int sla_trunk_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 7004 of file app_meetme.c.
References ALL_TRUNK_REFS, ao2_cleanup, args, AST_APP_ARG, ast_app_parse_options(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_set_flag64, AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_test_flag, build_conf(), sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), sla_ringing_trunk_destroy(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.
Referenced by load_module().
{
char conf_name[MAX_CONFNUM];
struct ast_conference *conf;
struct ast_flags64 conf_flags = { 0 };
RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
struct sla_ringing_trunk *ringing_trunk;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(trunk_name);
AST_APP_ARG(options);
);
char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
struct ast_flags opt_flags = { 0 };
char *parse;
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.argc == 2) {
if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
return -1;
}
}
trunk = sla_find_trunk(args.trunk_name);
if (!trunk) {
ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
return 0;
}
if (trunk->chan) {
ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
args.trunk_name);
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
return 0;
}
trunk->chan = chan;
if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
return 0;
}
snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
if (!conf) {
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
return 0;
}
ast_set_flag64(&conf_flags,
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
ast_indicate(chan, -1);
ast_set_flag64(&conf_flags, CONFFLAG_MOH);
} else
ast_indicate(chan, AST_CONTROL_RINGING);
conf_run(chan, conf, &conf_flags, opts);
dispose_conf(conf);
conf = NULL;
trunk->chan = NULL;
trunk->on_hold = 0;
sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
/* Remove the entry from the list of ringing trunks if it is still there. */
ast_mutex_lock(&sla.lock);
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
if (ringing_trunk->trunk == trunk) {
AST_LIST_REMOVE_CURRENT(entry);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
ast_mutex_unlock(&sla.lock);
if (ringing_trunk) {
sla_ringing_trunk_destroy(ringing_trunk);
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
/* Queue reprocessing of ringing trunks to make stations stop ringing
* that shouldn't be ringing after this trunk stopped. */
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
}
return 0;
}
| static int sla_trunk_hash | ( | const void * | obj, |
| const int | flags | ||
| ) | [static] |
Definition at line 7182 of file app_meetme.c.
References ast_str_case_hash(), and sla_trunk::name.
Referenced by sla_load_config().
{
const struct sla_trunk *trunk = obj;
return ast_str_case_hash(trunk->name);
}
| static int sla_trunk_is_marked | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7586 of file app_meetme.c.
References ao2_lock, ao2_ref, ao2_unlock, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, CMP_MATCH, sla_station_ref::mark, sla_trunk::mark, sla_trunk_release_refs(), and sla_trunk::stations.
Referenced by sla_load_config().
{
struct sla_trunk *trunk = obj;
ao2_lock(trunk);
if (trunk->mark) {
/* Only remove all of the station references if the trunk itself is going away */
sla_trunk_release_refs(trunk, NULL, 0);
} else {
struct sla_station_ref *station_ref;
/* Otherwise only remove references to stations no longer in the config */
AST_LIST_TRAVERSE_SAFE_BEGIN(&trunk->stations, station_ref, entry) {
if (!station_ref->mark) {
continue;
}
AST_LIST_REMOVE_CURRENT(entry);
ao2_ref(station_ref, -1);
}
AST_LIST_TRAVERSE_SAFE_END
}
ao2_unlock(trunk);
return trunk->mark ? CMP_MATCH : 0;
}
| static int sla_trunk_mark | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7550 of file app_meetme.c.
References ao2_lock, ao2_unlock, AST_LIST_TRAVERSE, sla_station_ref::mark, sla_trunk::mark, and sla_trunk::stations.
Referenced by sla_load_config().
{
struct sla_trunk *trunk = obj;
struct sla_station_ref *station_ref;
ao2_lock(trunk);
trunk->mark = 1;
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
station_ref->mark = 1;
}
ao2_unlock(trunk);
return 0;
}
| static void sla_trunk_ref_destructor | ( | void * | obj | ) | [static] |
Definition at line 6934 of file app_meetme.c.
References ao2_ref, and sla_trunk_ref::trunk.
Referenced by create_trunk_ref().
{
struct sla_trunk_ref *trunk_ref = obj;
if (trunk_ref->trunk) {
ao2_ref(trunk_ref->trunk, -1);
trunk_ref->trunk = NULL;
}
}
| static int sla_trunk_release_refs | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7132 of file app_meetme.c.
References ao2_ref, AST_LIST_REMOVE_HEAD, and sla_trunk::stations.
Referenced by sla_destroy(), sla_trunk_destructor(), and sla_trunk_is_marked().
{
struct sla_trunk *trunk = obj;
struct sla_station_ref *station_ref;
while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) {
ao2_ref(station_ref, -1);
}
return 0;
}
| static const char* trunkstate2str | ( | enum sla_trunk_state | state | ) | [static] |
Definition at line 1829 of file app_meetme.c.
References S, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.
Referenced by sla_show_stations().
{
#define S(e) case e: return # e;
switch (state) {
S(SLA_TRUNK_STATE_IDLE)
S(SLA_TRUNK_STATE_RINGING)
S(SLA_TRUNK_STATE_UP)
S(SLA_TRUNK_STATE_ONHOLD)
S(SLA_TRUNK_STATE_ONHOLD_BYME)
}
return "Uknown State";
#undef S
}
| static void tweak_listen_volume | ( | struct ast_conf_user * | user, |
| enum volume_action | action | ||
| ) | [static] |
Definition at line 1148 of file app_meetme.c.
References volume::actual, volume::desired, ast_conf_user::listen, set_listen_volume(), and tweak_volume().
Referenced by admin_exec(), meetme_menu_admin(), meetme_menu_normal(), user_listen_voldown_cb(), and user_listen_volup_cb().
| static void tweak_talk_volume | ( | struct ast_conf_user * | user, |
| enum volume_action | action | ||
| ) | [static] |
Definition at line 1136 of file app_meetme.c.
References volume::actual, volume::desired, set_talk_volume(), ast_conf_user::talk, and tweak_volume().
Referenced by admin_exec(), meetme_menu_admin(), meetme_menu_normal(), user_talk_voldown_cb(), and user_talk_volup_cb().
| static void tweak_volume | ( | struct volume * | vol, |
| enum volume_action | action | ||
| ) | [static] |
Definition at line 1101 of file app_meetme.c.
References volume::desired, VOL_DOWN, and VOL_UP.
Referenced by tweak_listen_volume(), and tweak_talk_volume().
{
switch (action) {
case VOL_UP:
switch (vol->desired) {
case 5:
break;
case 0:
vol->desired = 2;
break;
case -2:
vol->desired = 0;
break;
default:
vol->desired++;
break;
}
break;
case VOL_DOWN:
switch (vol->desired) {
case -5:
break;
case 2:
vol->desired = 0;
break;
case 0:
vol->desired = -2;
break;
default:
vol->desired--;
break;
}
}
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 7972 of file app_meetme.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_data_unregister, ast_devstate_prov_del(), ast_manager_unregister(), AST_TEST_UNREGISTER, ast_unload_realtime(), ast_unregister_application(), and sla_destroy().
{
int res = 0;
ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
res = ast_manager_unregister("MeetmeMute");
res |= ast_manager_unregister("MeetmeUnmute");
res |= ast_manager_unregister("MeetmeList");
res |= ast_manager_unregister("MeetmeListRooms");
res |= ast_unregister_application(app4);
res |= ast_unregister_application(app3);
res |= ast_unregister_application(app2);
res |= ast_unregister_application(app);
res |= ast_unregister_application(slastation_app);
res |= ast_unregister_application(slatrunk_app);
#ifdef TEST_FRAMEWORK
AST_TEST_UNREGISTER(test_meetme_data_provider);
#endif
ast_data_unregister(NULL);
ast_devstate_prov_del("Meetme");
ast_devstate_prov_del("SLA");
sla_destroy();
res |= ast_custom_function_unregister(&meetme_info_acf);
ast_unload_realtime("meetme");
return res;
}
| static int user_add_provider_cb | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7823 of file app_meetme.c.
References volume::actual, ast_channel_data_add_structure(), ast_data_add_int(), ast_data_add_node(), ast_data_add_structure, ast_conf_user::chan, volume::desired, ast_conf_user::listen, and ast_conf_user::talk.
Referenced by meetme_data_provider_get().
{
struct ast_data *data_meetme_user;
struct ast_data *data_meetme_user_channel;
struct ast_data *data_meetme_user_volume;
struct ast_conf_user *user = obj;
struct ast_data *data_meetme_users = arg;
data_meetme_user = ast_data_add_node(data_meetme_users, "user");
if (!data_meetme_user) {
return 0;
}
/* user structure */
ast_data_add_structure(ast_conf_user, data_meetme_user, user);
/* user's channel */
data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel");
if (!data_meetme_user_channel) {
return 0;
}
ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1);
/* volume structure */
data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume");
if (!data_meetme_user_volume) {
return 0;
}
ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired);
ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual);
data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume");
if (!data_meetme_user_volume) {
return 0;
}
ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired);
ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual);
return 0;
}
| static int user_chan_cb | ( | void * | obj, |
| void * | args, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4991 of file app_meetme.c.
References args, ast_channel_name(), ast_conf_user::chan, CMP_MATCH, and CMP_STOP.
Referenced by channel_admin_exec().
{
struct ast_conf_user *user = obj;
const char *channel = args;
if (!strcmp(ast_channel_name(user->chan), channel)) {
return (CMP_MATCH | CMP_STOP);
}
return 0;
}
| static int user_listen_voldown_cb | ( | void * | obj, |
| void * | unused, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4963 of file app_meetme.c.
References tweak_listen_volume(), and VOL_DOWN.
Referenced by admin_exec().
{
struct ast_conf_user *user = obj;
tweak_listen_volume(user, VOL_DOWN);
return 0;
}
| static int user_listen_volup_cb | ( | void * | obj, |
| void * | unused, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4956 of file app_meetme.c.
References tweak_listen_volume(), and VOL_UP.
Referenced by admin_exec().
{
struct ast_conf_user *user = obj;
tweak_listen_volume(user, VOL_UP);
return 0;
}
| static int user_max_cmp | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 1221 of file app_meetme.c.
References ast_conf_user::user_no.
Referenced by admin_exec(), conf_run(), and meetme_menu_admin().
{
struct ast_conf_user *user = obj;
int *max_no = arg;
if (user->user_no > *max_no) {
*max_no = user->user_no;
}
return 0;
}
| static int user_no_cmp | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 1209 of file app_meetme.c.
References CMP_MATCH, CMP_STOP, and ast_conf_user::user_no.
Referenced by build_conf().
| static int user_reset_vol_cb | ( | void * | obj, |
| void * | unused, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4984 of file app_meetme.c.
References reset_volumes().
Referenced by admin_exec().
{
struct ast_conf_user *user = obj;
reset_volumes(user);
return 0;
}
| static int user_set_hangup_cb | ( | void * | obj, |
| void * | check_admin_arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 2372 of file app_meetme.c.
References ADMINFLAG_HANGUP, ast_conf_user::adminflags, ast_test_flag64, CONFFLAG_ADMIN, and ast_conf_user::userflags.
Referenced by conf_run().
{
struct ast_conf_user *user = obj;
/* actual pointer contents of check_admin_arg is irrelevant */
if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
user->adminflags |= ADMINFLAG_HANGUP;
}
return 0;
}
| static int user_set_kickme_cb | ( | void * | obj, |
| void * | check_admin_arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 2383 of file app_meetme.c.
References ADMINFLAG_KICKME, ast_conf_user::adminflags, ast_test_flag64, CONFFLAG_ADMIN, and ast_conf_user::userflags.
Referenced by admin_exec(), and meetme_menu_admin_extended().
{
struct ast_conf_user *user = obj;
/* actual pointer contents of check_admin_arg is irrelevant */
if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
user->adminflags |= ADMINFLAG_KICKME;
}
return 0;
}
| static int user_set_muted_cb | ( | void * | obj, |
| void * | check_admin_arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 2405 of file app_meetme.c.
References ADMINFLAG_MUTED, ast_conf_user::adminflags, ast_test_flag64, CONFFLAG_ADMIN, and ast_conf_user::userflags.
Referenced by admin_exec(), and meetme_menu_admin_extended().
{
struct ast_conf_user *user = obj;
/* actual pointer contents of check_admin_arg is irrelevant */
if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
user->adminflags |= ADMINFLAG_MUTED;
}
return 0;
}
| static int user_set_unmuted_cb | ( | void * | obj, |
| void * | check_admin_arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 2394 of file app_meetme.c.
References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ast_test_flag64, CONFFLAG_ADMIN, and ast_conf_user::userflags.
Referenced by admin_exec(), and meetme_menu_admin_extended().
{
struct ast_conf_user *user = obj;
/* actual pointer contents of check_admin_arg is irrelevant */
if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
}
return 0;
}
| static int user_talk_voldown_cb | ( | void * | obj, |
| void * | unused, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4977 of file app_meetme.c.
References tweak_talk_volume(), and VOL_DOWN.
Referenced by admin_exec().
{
struct ast_conf_user *user = obj;
tweak_talk_volume(user, VOL_DOWN);
return 0;
}
| static int user_talk_volup_cb | ( | void * | obj, |
| void * | unused, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4970 of file app_meetme.c.
References tweak_talk_volume(), and VOL_UP.
Referenced by admin_exec().
{
struct ast_conf_user *user = obj;
tweak_talk_volume(user, VOL_UP);
return 0;
}
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, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, } [static] |
Definition at line 8047 of file app_meetme.c.
const char* const app = "MeetMe" [static] |
Definition at line 709 of file app_meetme.c.
const char* const app2 = "MeetMeCount" [static] |
Definition at line 710 of file app_meetme.c.
const char* const app3 = "MeetMeAdmin" [static] |
Definition at line 711 of file app_meetme.c.
const char* const app4 = "MeetMeChannelAdmin" [static] |
Definition at line 712 of file app_meetme.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 8047 of file app_meetme.c.
| unsigned int attempt_callerid |
Attempt to handle CallerID, even though it is known not to work properly in some situations.
Definition at line 1006 of file app_meetme.c.
int audio_buffers [static] |
The number of audio buffers to be allocated on pseudo channels when in a conference.
Definition at line 1013 of file app_meetme.c.
Referenced by conf_run().
struct ast_cli_entry cli_meetme[] [static] |
Definition at line 1923 of file app_meetme.c.
Definition at line 997 of file app_meetme.c.
Referenced by _macro_exec(), ast_safe_sleep_conditional(), gosubif_exec(), sla_handle_dial_state_event(), sla_station_exec(), and smdi_message_wait().
unsigned int conf_map[1024] = {0, } [static] |
Definition at line 795 of file app_meetme.c.
Referenced by build_conf(), conf_exec(), and dispose_conf().
int earlyalert [static] |
Definition at line 719 of file app_meetme.c.
Referenced by find_conf_realtime().
int endalert [static] |
Definition at line 720 of file app_meetme.c.
Referenced by find_conf_realtime().
| struct { ... } event_q |
int extendby [static] |
Definition at line 721 of file app_meetme.c.
Referenced by rt_extend_conf().
| struct { ... } failed_stations |
Definition at line 999 of file app_meetme.c.
Referenced by _ast_xmldoc_build_seealso(), ast_fax_caps_to_str(), ast_format_str_reduce(), ast_pbx_hangup_handler_show(), ast_print_group(), ast_print_namedgroups(), cdr_handler(), check_goto(), context_merge(), gen_prios(), generate_filenames_string(), generic_thread_loop(), get_goto_target(), get_pattern_node(), h261_encap(), h263_encap(), h263p_encap(), h264_encap(), handle_missing_table(), listfilter(), log_jack_status(), mpeg4_encap(), multiplexed_thread_function(), odbc_log(), pgsql_log(), realtime_sqlite3_destroy(), realtime_sqlite3_helper(), realtime_sqlite3_store(), realtime_sqlite3_update(), realtime_sqlite3_update2(), realtime_update2_handler(), realtimefield_read(), sip_show_channel(), update2_curl(), update2_pgsql(), update2_prepare(), xmldoc_get_syntax_cmd(), and xmldoc_parse_cmd_enumlist().
int fuzzystart [static] |
Definition at line 718 of file app_meetme.c.
Referenced by find_conf_realtime().
const char gain_map[] [static] |
Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers.
Definition at line 1022 of file app_meetme.c.
Definition at line 999 of file app_meetme.c.
Referenced by add_extensions(), aji_handle_presence(), apply_outgoing(), ast_config_engine_deregister(), ast_db_freetree(), ast_db_gettree(), build_calendar(), config_odbc(), config_pgsql(), do_monitor(), function_db_keys(), get_pattern_node(), gtalk_free_candidates(), internal_ao2_callback(), jingle_free_candidates(), load_password(), parse_contact_header(), try_firmware(), and update_scoreboard().
Definition at line 998 of file app_meetme.c.
Referenced by ast_localtime_wakeup_monitor(), generic_lock_unlock_helper(), load_module(), reload(), smdi_message_wait(), and write_cdr().
struct ast_data_handler meetme_data_provider [static] |
{
.version = AST_DATA_HANDLER_VERSION,
.get = meetme_data_provider_get
}
Definition at line 7903 of file app_meetme.c.
struct ast_data_entry meetme_data_providers[] [static] |
{
AST_DATA_ENTRY("asterisk/application/meetme/list", &meetme_data_provider),
}
Definition at line 7908 of file app_meetme.c.
struct ast_custom_function meetme_info_acf [static] |
{
.name = "MEETME_INFO",
.read = acf_meetme_info,
}
Definition at line 7782 of file app_meetme.c.
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] |
Definition at line 707 of file app_meetme.c.
Referenced by conf_exec(), and find_conf_realtime().
| struct { ... } ringing_stations |
| struct { ... } ringing_trunks |
int rt_log_members [static] |
Log participant count to the RealTime backend
Definition at line 724 of file app_meetme.c.
int rt_schedule [static] |
Definition at line 717 of file app_meetme.c.
struct { ... } sla [static] |
A structure for data used by the sla thread.
Referenced by dial_trunk(), queue_ringing_trunk(), sla_calc_station_timeouts(), sla_calc_trunk_timeouts(), sla_check_failed_station(), sla_check_ringing_station(), sla_choose_ringing_trunk(), sla_destroy(), sla_handle_dial_state_event(), sla_handle_ringing_trunk_event(), sla_hangup_stations(), sla_load_config(), sla_queue_event_full(), sla_ring_station(), sla_ring_stations(), sla_station_exec(), sla_stop_ringing_station(), sla_thread(), and sla_trunk_exec().
const char sla_registrar[] = "SLA" [static] |
Definition at line 942 of file app_meetme.c.
Referenced by sla_build_station(), sla_build_trunk(), sla_destroy(), sla_station_destructor(), and sla_trunk_destructor().
struct ao2_container* sla_stations [static] |
Definition at line 939 of file app_meetme.c.
Referenced by sla_build_station(), sla_calc_station_delays(), sla_change_trunk_state(), sla_destroy(), sla_find_station(), sla_in_use(), sla_load_config(), sla_queue_event_conf(), and sla_show_stations().
struct ast_app_option sla_trunk_opts[128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, } [static] |
Definition at line 7002 of file app_meetme.c.
Referenced by sla_trunk_exec().
struct ao2_container* sla_trunks [static] |
Definition at line 940 of file app_meetme.c.
Referenced by sla_build_trunk(), sla_destroy(), sla_find_trunk(), sla_in_use(), sla_load_config(), and sla_show_trunks().
const char* const slastation_app = "SLAStation" [static] |
Definition at line 713 of file app_meetme.c.
const char* const slatrunk_app = "SLATrunk" [static] |
Definition at line 714 of file app_meetme.c.
| unsigned int stop |
Definition at line 1003 of file app_meetme.c.
Referenced by build_dialplan_useage_spaces(), controlplayback_exec(), cops_gate_cmd(), handle_controlstreamfile(), multiplexed_thread_function(), park_add_hints(), pktccops_show_pools(), queue_exec(), remove_dead_spaces_usage(), and usage_context_add_spaces().
| pthread_t thread |
The SLA thread ID
Definition at line 996 of file app_meetme.c.
Referenced by __schedule_action(), ast_bridge_depart(), ast_bridge_destroy(), bridge_call_thread_launch(), cleanup_thread_list(), find_idle_thread(), handle_cli_iax2_show_threads(), iax2_process_thread(), iax2_process_thread_cleanup(), launch_monitor_thread(), load_module(), multiplexed_add_or_remove(), socket_read(), start_network_thread(), and unload_module().