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 |
| struct | sla_stations |
| struct | sla_trunk |
| struct | sla_trunk_ref |
| struct | sla_trunks |
| struct | volume |
Defines | |
| #define | AST_FRAME_BITS 32 |
| #define | CONF_SIZE 320 |
| #define | CONFFLAG_INTROMSG (1ULL << 32) |
| #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" |
Enumerations | |
| enum | { ADMINFLAG_MUTED = (1 << 1), ADMINFLAG_SELFMUTED = (1 << 2), ADMINFLAG_KICKME = (1 << 3), ADMINFLAG_T_REQUEST = (1 << 4) } |
| 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_ARRAY_SIZE = 6 } |
| 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 | 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, SLA_EVENT_RELOAD, SLA_EVENT_CHECK_RELOAD } |
| 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_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_meetmecmd (const char *line, const char *word, int pos, 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 | destroy_station (struct sla_station *station) |
| static void | destroy_trunk (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 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 (struct ast_cli_entry *e, int cmd, 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_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 void | sla_check_reload (void) |
| Check if we can do a reload of SLA, and do it if we can. | |
| 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_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 struct sla_station * | sla_find_station (const char *name) |
| Find an SLA station by name. | |
| static struct sla_trunk * | sla_find_trunk (const char *name) |
| Find an SLA trunk by 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_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 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_exec (struct ast_channel *chan, const char *data) |
| 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_exec (struct ast_channel *chan, const char *data) |
| 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_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 = "7a1b8b48c852d7a7061c7e499b9bd0d2" , .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 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ '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 | |
| unsigned int reload:1 | |
| 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 sla_stations | 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 sla_trunks | 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 528 of file app_meetme.c.
Referenced by conf_free(), conf_run(), and recordthread().
| #define CONF_SIZE 320 |
Definition at line 547 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 611 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 609 of file app_meetme.c.
Referenced by can_write(), conf_run(), and sla_trunk_exec().
| #define CONFIG_FILE_NAME "meetme.conf" |
Definition at line 508 of file app_meetme.c.
Referenced by find_conf(), conf_exec(), and load_config_meetme().
| #define DATE_FORMAT "%Y-%m-%d %H:%M:%S" |
String format for scheduled conferences
Definition at line 515 of file app_meetme.c.
Referenced by rt_extend_conf(), conf_run(), and find_conf_realtime().
| #define DEFAULT_AUDIO_BUFFERS 32 |
each buffer is 20ms, so this is 640ms total
Definition at line 512 of file app_meetme.c.
Referenced by load_config_meetme().
| #define MAX_CONFNUM 80 |
Definition at line 673 of file app_meetme.c.
Referenced by meetme_show_cmd(), meetme_cmd(), conf_exec(), dial_trunk(), sla_station_exec(), and sla_trunk_exec().
| #define MAX_PIN 80 |
Definition at line 674 of file app_meetme.c.
Referenced by conf_exec().
| #define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3) |
Definition at line 678 of file app_meetme.c.
Referenced by find_conf(), and conf_exec().
| #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 6918 of file app_meetme.c.
| #define MEETME_DELAYDETECTENDTALK 1000 |
Definition at line 526 of file app_meetme.c.
Referenced by conf_run().
| #define MEETME_DELAYDETECTTALK 300 |
Definition at line 525 of file app_meetme.c.
Referenced by conf_run().
| #define MEETME_USER_DATA_EXPORT | ( | MEMBER | ) |
Definition at line 6935 of file app_meetme.c.
| #define OPTIONS_LEN 100 |
Definition at line 675 of file app_meetme.c.
Referenced by find_conf_realtime().
| #define S | ( | e | ) | case e: return # e; |
Referenced by trunkstate2str(), and sms_readfile().
| #define SLA_CONFIG_FILE "sla.conf" |
Definition at line 509 of file app_meetme.c.
Referenced by sla_build_trunk(), sla_build_station(), and sla_load_config().
| anonymous enum |
| ADMINFLAG_MUTED |
User is muted |
| ADMINFLAG_SELFMUTED |
User muted self |
| ADMINFLAG_KICKME |
User has been kicked |
| ADMINFLAG_T_REQUEST |
User has requested to speak |
Definition at line 517 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),
};
| anonymous enum |
Definition at line 549 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 MeetMe will return if all marked with this flag left */
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_ARRAY_SIZE |
Definition at line 613 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_ARRAY_SIZE = 6,
};
| anonymous enum |
Definition at line 6293 of file app_meetme.c.
{
SLA_TRUNK_OPT_MOH = (1 << 0),
};
| anonymous enum |
Definition at line 6297 of file app_meetme.c.
{
SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
};
| enum announcetypes |
Definition at line 680 of file app_meetme.c.
{
CONF_HASJOIN,
CONF_HASLEFT
};
| enum entrance_sound |
| enum recording_state |
Definition at line 540 of file app_meetme.c.
| enum sla_event_type |
Event types that can be queued up for the SLA thread.
Definition at line 874 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,
/*! A reload of configuration has been requested */
SLA_EVENT_RELOAD,
/*! Poke the SLA thread so it can check if it can perform a reload */
SLA_EVENT_CHECK_RELOAD,
};
| enum sla_hold_access |
Definition at line 784 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 911 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 776 of file app_meetme.c.
| enum sla_which_trunk_refs |
Definition at line 771 of file app_meetme.c.
| enum volume_action |
| static void __reg_module | ( | void | ) | [static] |
Definition at line 7171 of file app_meetme.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 7171 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 6847 of file app_meetme.c.
References parse(), AST_DECLARE_APP_ARGS, args, AST_APP_ARG, ast_strlen_zero(), ast_log(), LOG_ERROR, ast_strdupa, AST_STANDARD_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conference::list, ast_conference::confno, acf_meetme_info_eval(), AST_LIST_UNLOCK, and LOG_NOTICE.
{
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 6829 of file app_meetme.c.
References ast_conference::locked, ast_conference::users, ast_conference::start, and ast_conference::isdynamic.
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 4770 of file app_meetme.c.
References astman_get_header(), user, total, ast_strlen_zero(), AST_LIST_EMPTY, astman_send_error(), astman_send_listack(), AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conference::confno, ao2_iterator_init(), ast_conference::usercontainer, ao2_iterator_next, astman_append(), ast_conf_user::user_no, S_COR, ast_conf_user::chan, ast_channel::caller, ast_party_caller::id, ast_party_id::number, ast_party_number::valid, ast_party_number::str, ast_party_id::name, ast_party_name::valid, ast_party_name::str, ast_channel::connected, ast_party_connected_line::id, ast_channel::name, ast_test_flag64, ast_conf_user::userflags, CONFFLAG_ADMIN, CONFFLAG_MONITOR, CONFFLAG_TALKER, CONFFLAG_MARKEDUSER, ast_conf_user::adminflags, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::talking, ao2_ref, ao2_iterator_destroy(), and AST_LIST_UNLOCK.
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(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<no name>"),
user->chan->name,
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_meetmemute | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 4760 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 4765 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 4498 of file app_meetme.c.
References AST_DECLARE_APP_ARGS, args, AST_APP_ARG, ast_strlen_zero(), ast_log(), LOG_WARNING, pbx_builtin_setvar_helper(), ast_strdupa, AST_STANDARD_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conf_user::list, ast_conference::confno, AST_LIST_UNLOCK, ast_atomic_fetchadd_int(), ast_conference::refcount, find_user(), LOG_NOTICE, ast_conference::locked, ao2_callback, ast_conference::usercontainer, OBJ_NODATA, user_set_kickme_cb(), user_max_cmp(), ao2_find, ast_test_flag64, ast_conf_user::userflags, CONFFLAG_ADMIN, ast_conf_user::adminflags, ADMINFLAG_KICKME, ao2_ref, ADMINFLAG_MUTED, user_set_muted_cb(), ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, user_set_unmuted_cb(), user_listen_voldown_cb(), user_listen_volup_cb(), user_talk_voldown_cb(), user_talk_volup_cb(), user_reset_vol_cb(), reset_volumes(), tweak_listen_volume(), VOL_UP, VOL_DOWN, tweak_talk_volume(), rt_extend_conf(), and dispose_conf().
Referenced by meetme_show_cmd(), meetme_cmd(), run_station(), sla_stop_ringing_trunk(), sla_station_exec(), and load_module().
{
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;
}
}
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;
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
user = ao2_find(cnf->usercontainer, &max_no, 0);
if (!ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))
user->adminflags |= ADMINFLAG_KICKME;
else {
res = -1;
ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
}
ao2_ref(user, -1);
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, NULL);
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 2066 of file app_meetme.c.
References AST_LIST_HEAD_NOLOCK, AST_LIST_HEAD_INIT_NOLOCK, ast_conference::announcethread_stop, ast_mutex_lock, ast_conference::announcelistlock, ast_mutex_unlock, AST_LIST_EMPTY, ast_conference::announcelist, ast_cond_wait, ast_conference::announcelist_addition, AST_LIST_APPEND_LIST, AST_LIST_REMOVE_HEAD, ao2_ref, ast_log(), LOG_DEBUG, announce_listitem::namerecloc, ast_fileexists(), announce_listitem::confchan, announce_listitem::confusers, ast_check_hangup(), ast_streamfile(), announce_listitem::language, ast_waitstream(), ast_copy_string(), get_announce_filename(), announce_listitem::announcetype, CONF_HASLEFT, and ast_filedelete().
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_log(LOG_DEBUG, "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) {
ast_filedelete(current->namerecloc, NULL);
}
}
}
/* thread marked to stop, clean up */
while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
ast_filedelete(current->namerecloc, NULL);
ao2_ref(current, -1);
}
return NULL;
}
| static void answer_trunk_chan | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 5153 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);
}
| 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 | ||
| ) | [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 1175 of file app_meetme.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conference::confno, ast_calloc, ast_conference::usercontainer, ao2_container_alloc, user_no_cmp(), ast_mutex_init, ast_conference::playlock, ast_conference::listenlock, ast_conference::recordthread, AST_PTHREADT_NULL, ast_conference::recordthreadlock, ast_conference::announcethread, ast_conference::announcethreadlock, ast_copy_string(), ast_conference::pin, ast_conference::pinadmin, ast_conference::uniqueid, ast_channel::uniqueid, ast_conference::fd, ast_test_status_update, ast_log(), LOG_WARNING, ao2_ref, ast_mutex_destroy, ast_free, ast_conference::dahdiconf, ast_conference::chan, ast_request(), AST_FORMAT_SLINEAR, ast_set_read_format(), ast_set_write_format(), ast_channel::fds, ast_hangup(), ast_conference::start, ast_conference::maxusers, ast_conference::isdynamic, ast_verb, AST_LIST_INSERT_HEAD, conf_map, ast_atomic_fetchadd_int(), ast_conference::refcount, and AST_LIST_UNLOCK.
Referenced by find_conf_realtime(), find_conf(), run_station(), dial_trunk(), sla_station_exec(), and sla_trunk_exec().
{
struct ast_conference *cnf;
struct dahdi_confinfo dahdic = { 0, };
int confno_int = 0;
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno))
break;
}
if (cnf || (!make && !dynamic))
goto cnfout;
/* 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, chan->uniqueid, 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", AST_FORMAT_SLINEAR, chan, "pseudo", NULL);
if (cnf->chan) {
ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
dahdic.chan = 0;
dahdic.confno = cnf->dahdiconf;
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
if (ioctl(cnf->chan->fds[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:
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 2119 of file app_meetme.c.
References ast_test_flag64, CONFFLAG_NO_AUDIO_UNTIL_UP, ast_channel::_state, and AST_STATE_UP.
Referenced by conf_run().
{
if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
return 1;
}
return (chan->_state == AST_STATE_UP);
}
| static int careful_write | ( | int | fd, |
| unsigned char * | data, | ||
| int | len, | ||
| int | block | ||
| ) | [static] |
Definition at line 985 of file app_meetme.c.
References errno, ast_log(), 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 4639 of file app_meetme.c.
References AST_DECLARE_APP_ARGS, args, AST_APP_ARG, ast_strlen_zero(), ast_log(), LOG_WARNING, ast_strdupa, AST_STANDARD_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conf_user::list, ao2_callback, ast_conference::usercontainer, user_chan_cb(), LOG_NOTICE, AST_LIST_UNLOCK, ast_conf_user::adminflags, ADMINFLAG_MUTED, ADMINFLAG_KICKME, and ao2_ref.
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_meetmecmd | ( | const char * | line, |
| const char * | word, | ||
| int | pos, | ||
| int | state | ||
| ) | [static] |
Definition at line 1285 of file app_meetme.c.
References len(), ast_cli_complete(), AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conf_user::list, ast_conference::confno, ast_strdup, AST_LIST_UNLOCK, ast_strdupa, strsep(), ao2_iterator_init(), ast_conference::usercontainer, ao2_iterator_next, ast_conf_user::user_no, ao2_ref, and ao2_iterator_destroy().
Referenced by meetme_show_cmd(), and meetme_cmd().
{
static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
int len = strlen(word);
int which = 0;
struct ast_conference *cnf = NULL;
struct ast_conf_user *usr = NULL;
char *confno = NULL;
char usrno[50] = "";
char *myline, *ret = NULL;
if (pos == 1) { /* Command */
return ast_cli_complete(word, cmds, state);
} else if (pos == 2) { /* Conference Number */
AST_LIST_LOCK(&confs);
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
ret = cnf->confno;
break;
}
}
ret = ast_strdup(ret); /* dup before releasing the lock */
AST_LIST_UNLOCK(&confs);
return ret;
} else if (pos == 3) {
/* User Number || Conf Command option*/
if (strstr(line, "mute") || strstr(line, "kick")) {
if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
return ast_strdup("all");
which++;
AST_LIST_LOCK(&confs);
/* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
myline = ast_strdupa(line);
if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
;
}
AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno))
break;
}
if (cnf) {
struct ao2_iterator user_iter;
user_iter = ao2_iterator_init(cnf->usercontainer, 0);
while((usr = ao2_iterator_next(&user_iter))) {
snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
if (!strncasecmp(word, usrno, len) && ++which > state) {
ao2_ref(usr, -1);
break;
}
ao2_ref(usr, -1);
}
ao2_iterator_destroy(&user_iter);
AST_LIST_UNLOCK(&confs);
return usr ? ast_strdup(usrno) : NULL;
}
AST_LIST_UNLOCK(&confs);
}
}
return NULL;
}
| static int conf_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
The meetme() application.
Definition at line 4128 of file app_meetme.c.
References MAX_CONFNUM, MAX_PIN, AST_DECLARE_APP_ARGS, args, AST_APP_ARG, OPT_ARG_ARRAY_SIZE, ast_strlen_zero(), ast_channel::_state, AST_STATE_UP, ast_answer(), ast_strdupa, AST_STANDARD_APP_ARGS, ast_copy_string(), ast_app_parse_options64(), meetme_opts, ast_test_flag64, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_ALWAYSPROMPT, var, ast_config_load, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_variable_browse(), parse(), MAX_SETTINGS, ast_variable::name, ast_variable::value, strsep(), AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conference::confno, AST_LIST_UNLOCK, ast_variable::next, ast_config_destroy(), ast_load_realtime_multientry(), SENTINEL, ast_category_browse(), ast_variable_retrieve(), ARRAY_LEN, conf_map, ast_streamfile(), ast_channel::language, ast_waitstream(), CONFFLAG_QUIET, ast_say_digits(), ast_log(), LOG_ERROR, ast_app_getdata(), find_conf(), find_conf_realtime(), ast_conference::pin, ast_conference::pinadmin, CONFFLAG_ADMIN, ast_conference::adminopts, ast_conference::useropts, ast_verb, ast_conference::recordingfilename, ast_conference::recordingformat, conf_run(), AST_DIGIT_ANY, ast_stopstream(), LOG_WARNING, and dispose_conf().
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 (chan->_state != 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);
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", chan->language);
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", chan->language);
if (!res) {
ast_waitstream(chan, "");
res = ast_say_digits(chan, confno_int, "", chan->language);
}
}
} 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", chan->language);
if (!res)
ast_waitstream(chan, "");
res = -1;
}
} else {
/* Check to see if the conference requires a pin
* and we ALWAYS prompt or no pin was provided */
if ((!ast_strlen_zero(cnf->pin) ||
(!ast_strlen_zero(cnf->pinadmin) &&
ast_test_flag64(&confflags, CONFFLAG_ADMIN))) &&
(ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT) ||
ast_strlen_zero(args.pin))) {
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 */
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", chan->language)) {
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 1765 of file app_meetme.c.
References f, ast_waitfor(), ast_read(), ast_frfree, ast_log(), 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)) {
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 1797 of file app_meetme.c.
References AST_LIST_REMOVE, manager_event, EVENT_FLAG_CALL, ast_conference::confno, ast_conference::recording, MEETME_RECORD_ACTIVE, MEETME_RECORD_TERMINATE, AST_LIST_UNLOCK, AST_LIST_LOCK, MEETME_RECORD_OFF, AST_FRAME_BITS, ast_conference::transframe, ast_frfree, ast_conference::transpath, ast_translator_free_path(), ast_conference::announcethread, AST_PTHREADT_NULL, ast_mutex_lock, ast_conference::announcelistlock, ast_conference::announcethread_stop, ast_softhangup(), ast_conference::chan, AST_SOFTHANGUP_EXPLICIT, ast_cond_signal, ast_conference::announcelist_addition, ast_mutex_unlock, AST_LIST_REMOVE_HEAD, ast_conference::announcelist, ast_filedelete(), announce_listitem::namerecloc, ao2_ref, ast_mutex_destroy, ast_conference::origframe, ast_conference::lchan, ast_hangup(), ast_conference::fd, ast_conference::recordingfilename, ast_free, ast_conference::usercontainer, ast_conference::recordingformat, ast_conference::playlock, ast_conference::listenlock, ast_conference::recordthreadlock, and ast_conference::announcethreadlock.
Referenced by dispose_conf().
{
int x;
struct announce_listitem *item;
AST_LIST_REMOVE(&confs, conf, list);
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))) {
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 1103 of file app_meetme.c.
References len(), ast_check_hangup(), ast_autoservice_start(), AST_LIST_LOCK, ENTER, enter, LEAVE, leave, careful_write(), ast_conference::fd, AST_LIST_UNLOCK, and ast_autoservice_stop().
Referenced by conf_run().
{
unsigned char *data;
int len;
int res = -1;
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 1864 of file app_meetme.c.
References user, ao2_iterator_init(), ast_conference::usercontainer, ao2_iterator_next, ao2_ref, ast_write(), ast_conf_user::chan, ast_log(), LOG_WARNING, ast_channel::name, and ao2_iterator_destroy().
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", user->chan->name);
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 2190 of file app_meetme.c.
References f, exitcontext, AST_MAX_CONTEXT, AST_MAX_EXTENSION, CONF_SIZE, AST_FRIENDLY_OFFSET, parse(), ao2_alloc, ast_test_flag64, CONFFLAG_WAITMARKED, ast_strlen_zero(), OPT_ARG_WAITMARKED, CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP, ast_verb, CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT, var, strsep(), ast_channel_lock, pbx_builtin_getvar_helper(), ast_strdupa, ast_channel_unlock, ast_debug, CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS, CONFFLAG_RECORDCONF, ast_conference::recordingfilename, ast_strdup, ast_conference::recordingformat, ast_conference::confno, ast_channel::uniqueid, ast_mutex_lock, ast_conference::recordthreadlock, ast_conference::recordthread, AST_PTHREADT_NULL, ast_conference::lchan, ast_request(), AST_FORMAT_SLINEAR, ast_set_read_format(), ast_set_write_format(), ast_conference::dahdiconf, ast_channel::fds, ast_log(), LOG_WARNING, ast_hangup(), ast_pthread_create_detached_background, ast_mutex_unlock, ast_conference::announcethreadlock, ast_conference::announcethread, CONFFLAG_QUIET, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, ast_mutex_init, ast_conference::announcelistlock, AST_LIST_HEAD_INIT_NOLOCK, ast_conference::announcelist, ast_pthread_create_background, announce_thread(), ast_conf_user::jointime, ast_conf_user::timelimit, ast_conf_user::play_warning, ast_conf_user::warning_freq, ast_conf_user::warning_sound, ast_conf_user::end_sound, ast_conf_user::kicktime, ast_tvzero(), ast_conf_user::start_time, ast_tvnow(), ast_tvadd(), ast_samp2tv(), ast_tvsub(), ast_conference::locked, CONFFLAG_ADMIN, ast_streamfile(), ast_channel::language, ast_waitstream(), ast_conference::playlock, ast_conference::maxusers, ast_conference::users, ao2_lock, ast_conference::usercontainer, ao2_callback, OBJ_NODATA, user_max_cmp(), ast_conf_user::user_no, ao2_link, ao2_unlock, ast_conf_user::chan, ast_conf_user::userflags, ast_conf_user::adminflags, CONFFLAG_STARTMUTED, ADMINFLAG_SELFMUTED, ast_conference::gmuted, ADMINFLAG_MUTED, ast_conf_user::talking, ast_config_AST_SPOOL_DIR, ast_mkdir(), errno, ast_conf_user::namerecloc, ast_play_and_record(), ast_dsp_get_threshold_from_settings(), THRESHOLD_SILENCE, ast_record_review(), CONFFLAG_MARKEDUSER, ast_conference::markedusers, ast_realtime_require_field(), RQ_UINTEGER4, RQ_UINTEGER3, RQ_UINTEGER2, RQ_UINTEGER1, ast_update_realtime(), ast_devstate_changed(), AST_DEVICE_INUSE, pbx_builtin_setvar_helper(), ast_conference::uniqueid, CONFFLAG_EXIT_CONTEXT, ast_copy_string(), ast_channel::macrocontext, ast_channel::context, CONFFLAG_INTROMSG, OPT_ARG_INTROMSG, CONFFLAG_NOONLYPERSON, CONFFLAG_ANNOUNCEUSERCOUNT, AST_DIGIT_ANY, ast_stopstream(), ast_say_number(), CONFFLAG_NO_AUDIO_UNTIL_UP, ast_indicate(), ast_channel::name, ast_module_helper(), ast_free, ast_func_write(), ast_channel::tech, ast_channel_tech::type, ast_channel::audiohooks, ast_channel::monitor, ast_conf_user::dahdichannel, audio_buffers, announce_listitem::namerecloc, announce_listitem::language, announce_listitem::confchan, ast_conference::chan, announce_listitem::confusers, announce_listitem::announcetype, CONF_HASJOIN, ao2_ref, AST_LIST_INSERT_TAIL, ast_cond_signal, ast_conference::announcelist_addition, ast_check_hangup(), ast_safe_sleep(), CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_manager_event, EVENT_FLAG_CALL, S_COR, ast_channel::caller, ast_party_caller::id, ast_party_id::number, ast_party_number::valid, ast_party_number::str, ast_party_id::name, ast_party_name::valid, ast_party_name::str, ast_channel::connected, ast_party_connected_line::id, conf_play(), ENTER, conf_flush(), ast_dsp_free(), ast_dsp_new(), CONFFLAG_AGI, ast_channel_setoption(), AST_OPTION_TONE_VERIFY, pbx_findapp(), pbx_exec(), CONFFLAG_STARMENU, ast_conference::endtime, ast_localtime(), ast_strftime(), DATE_FORMAT, ast_load_realtime(), ast_variable::next, ast_variable::name, ast_strptime(), ast_variable::value, ast_mktime(), ast_variables_destroy(), ast_verbose(), ast_conference::endalert, ast_say_digits(), conf_start_moh(), OPT_ARG_MOH_CLASS, CONFFLAG_KICK_CONTINUE, ast_tvdiff_ms(), ast_conf_user::listen, volume::desired, volume::actual, set_talk_volume(), CONFFLAG_MARKEDEXIT, CONFFLAG_MOH, ast_moh_stop(), CONFFLAG_MONITORTALKER, CONFFLAG_OPTIMIZETALKER, set_user_talking(), ADMINFLAG_T_REQUEST, ADMINFLAG_KICKME, ast_waitfor_nandfds(), dtmfstr, ast_read_noaudio(), ast_read(), ast_frame::frametype, AST_FRAME_DTMF, ast_frame::subclass, ast_frame_subclass::integer, AST_FRAME_VOICE, ast_frame_subclass::codec, ast_conf_user::talk, ast_frame_adjust_volume(), ast_dsp_silence(), MEETME_DELAYDETECTTALK, MEETME_DELAYDETECTENDTALK, careful_write(), ast_frame::data, ast_frame::ptr, ast_frame::datalen, CONFFLAG_PASS_DTMF, conf_queue_dtmf(), ast_frfree, ao2_iterator_init(), ao2_iterator_next, ast_fileexists(), ao2_iterator_destroy(), user_set_kickme_cb(), user_set_unmuted_cb(), user_set_muted_cb(), ast_conference::recording, MEETME_RECORD_ACTIVE, ast_set_flag64, ao2_find, tweak_listen_volume(), VOL_DOWN, rt_extend_conf(), VOL_UP, tweak_talk_volume(), ast_exists_extension(), ast_goto_if_exists(), AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, CONFFLAG_SLA_STATION, AST_FRAME_CONTROL, AST_CONTROL_HOLD, sla_queue_event_conf(), SLA_EVENT_HOLD, AST_FRAME_NULL, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, ast_frame::samples, ast_frame::offset, AST_FRAME_BITS, ast_channel::rawwriteformat, ast_conference::listenlock, ast_conference::transframe, ast_conference::origframe, ast_conference::transpath, ast_translator_build_path(), ast_translate(), ast_null_frame, can_write(), AST_LIST_NEXT, ast_write(), ast_moh_start(), reset_volumes(), LEAVE, CONF_HASLEFT, ast_filedelete(), AST_LIST_LOCK, ao2_unlink, AST_DEVICE_NOT_INUSE, ast_conference::bookid, and AST_LIST_UNLOCK.
Referenced by conf_exec(), run_station(), dial_trunk(), 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;
int menu_active = 0;
int menu8_active = 0;
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, 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;
if (!(user = ao2_alloc(sizeof(*user), NULL))) {
return ret;
}
/* 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, chan->uniqueid);
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", AST_FORMAT_SLINEAR, chan, "pseudo", NULL)))) {
ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
dahdic.chan = 0;
dahdic.confno = conf->dahdiconf;
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
if (ioctl(conf->lchan->fds[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) || ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW))) {
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", chan->language))
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", chan->language))
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) ||
ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW))) {
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;
}
snprintf(user->namerecloc, sizeof(user->namerecloc),
"%s/meetme-username-%s-%d", destdir,
conf->confno, user->user_no);
if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW))
res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
else
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, "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(chan->macrocontext)) {
ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
} else {
ast_copy_string(exitcontext, chan->context, 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], chan->language)) {
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", chan->language))
ast_waitstream(chan, "");
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
ast_waitstream(chan, "");
}
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) &&
conf->users > 1) {
int keepplaying = 1;
if (conf->users == 2) {
if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
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", chan->language)) {
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, chan->language, (char *) NULL);
if (res > 0)
keepplaying = 0;
else if (res == -1)
goto outrun;
}
if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
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(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
goto outrun;
}
if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
goto outrun;
}
/* Reduce background noise from each participant */
if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
ast_free(mod_speex);
ast_func_write(chan, "DENOISE(rx)", "on");
}
retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
user->dahdichannel = !retrydahdi;
dahdiretry:
origfd = chan->fds[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 = chan->fds[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)) && 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, chan->language, sizeof(item->language));
item->confchan = conf->chan;
item->confusers = conf->users;
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", chan->name, conf->dahdiconf);
if (!sent_event) {
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",
chan->name, chan->uniqueid, conf->confno,
user->user_no,
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
S_COR(user->chan->connected.id.name.valid, user->chan->connected.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 {
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", chan->language))
ast_waitstream(chan, "");
ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
if (!ast_streamfile(chan, "minutes", chan->language))
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, chan->language);
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", chan->language);
res = ast_waitstream(chan, "");
if (minutes) {
res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
res = ast_streamfile(chan, "queue-minutes", chan->language);
res = ast_waitstream(chan, "");
}
if (seconds) {
res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
res = ast_streamfile(chan, "queue-seconds", chan->language);
res = ast_waitstream(chan, "");
}
} else {
res = ast_streamfile(chan, user->warning_sound, chan->language);
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_active && menu_was_active && user->listen.desired && !user->listen.actual) {
set_talk_volume(user, user->listen.desired);
}
menu_was_active = menu_active;
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, chan->language, (char *) NULL);
if (conf->users - 1 == 1) {
if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) {
ast_waitstream(chan, "");
}
}
}
if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
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", chan->language)) {
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", chan->language)) {
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;
}
/* 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));
}
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %i\r\n"
"Status: on\r\n",
chan->name, chan->uniqueid, 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;
}
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %i\r\n"
"Status: off\r\n",
chan->name, chan->uniqueid, conf->confno, user->user_no);
}
if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
(user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
talkreq_manager = 1;
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %i\r\n"
"Status: on\r\n",
chan->name, chan->uniqueid, conf->confno, user->user_no);
}
if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
!(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
talkreq_manager = 0;
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
"Channel: %s\r\n"
"Uniqueid: %s\r\n"
"Meetme: %s\r\n"
"Usernum: %i\r\n"
"Status: off\r\n",
chan->name, chan->uniqueid, conf->confno, user->user_no);
}
/* 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", chan->language)) {
ast_waitstream(chan, "");
}
ret = 0;
break;
}
c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
if (c) {
char dtmfstr[2] = "";
if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
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(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 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.codec == 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_active)) {
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_active && user->talk.desired && !user->talk.actual) {
set_talk_volume(user, 0);
}
if (musiconhold) {
ast_moh_stop(chan);
}
if (menu8_active) {
/* *8 Submenu */
dtmf = f->subclass.integer;
if (dtmf) {
int keepplaying;
int playednamerec;
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", chan->language)) {
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", chan->language)) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0)
keepplaying = 0;
}
} else {
if (keepplaying && !ast_streamfile(chan, "conf-thereare", chan->language)) {
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, chan->language, (char *) NULL);
if (res > 0)
keepplaying = 0;
}
if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
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, chan->language)) {
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", chan->language)) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res > 0)
keepplaying = 0;
}
break;
case '2': /* *82 Eject all non-admins */
if (conf->users == 1) {
if(!ast_streamfile(chan, "conf-errormenu", chan->language))
ast_waitstream(chan, "");
} else {
ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
}
ast_stopstream(chan);
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", chan->language))
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", chan->language))
ast_waitstream(chan, "");
}
ast_stopstream(chan);
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, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
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", AST_FORMAT_SLINEAR, chan, "pseudo", NULL)))) {
ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
dahdic.chan = 0;
dahdic.confno = conf->dahdiconf;
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
if (ioctl(conf->lchan->fds[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", chan->language))
ast_waitstream(chan, "");
}
ast_stopstream(chan);
break;
default:
if (!ast_streamfile(chan, "conf-errormenu", chan->language))
ast_waitstream(chan, "");
ast_stopstream(chan);
break;
}
}
menu8_active = 0;
menu_active = 0;
} else if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
/* Admin menu */
if (!menu_active) {
menu_active = 1;
/* Record this sound! */
if (!ast_streamfile(chan, "conf-adminmenu-162", chan->language)) {
dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
} else {
dtmf = 0;
}
} else {
dtmf = f->subclass.integer;
}
if (dtmf) {
switch(dtmf) {
case '1': /* Un/Mute */
menu_active = 0;
/* 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", chan->language)) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
ast_waitstream(chan, "");
}
}
break;
case '2': /* Un/Lock the Conference */
menu_active = 0;
if (conf->locked) {
conf->locked = 0;
if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) {
ast_waitstream(chan, "");
}
} else {
conf->locked = 1;
if (!ast_streamfile(chan, "conf-lockednow", chan->language)) {
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_active = 0;
usr = ao2_find(conf->usercontainer, &max_no, 0);
if ((usr->chan->name == chan->name) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
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", chan->language)) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-nonextended", chan->language)) {
ast_waitstream(chan, "");
}
}
ast_stopstream(chan);
}
menu_active = 0;
break;
case '6':
tweak_listen_volume(user, VOL_UP);
break;
case '7':
tweak_talk_volume(user, VOL_DOWN);
break;
case '8':
menu8_active = 1;
break;
case '9':
tweak_talk_volume(user, VOL_UP);
break;
default:
menu_active = 0;
/* Play an error message! */
if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
ast_waitstream(chan, "");
}
break;
}
}
} else {
/* User menu */
if (!menu_active) {
menu_active = 1;
if (!ast_streamfile(chan, "conf-usermenu-162", chan->language)) {
dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
} else {
dtmf = 0;
}
} else {
dtmf = f->subclass.integer;
}
if (dtmf) {
switch (dtmf) {
case '1': /* Un/Mute */
menu_active = 0;
/* 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", chan->language)) {
ast_waitstream(chan, "");
}
} else {
if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
ast_waitstream(chan, "");
}
}
break;
case '2':
menu_active = 0;
if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
user->adminflags |= ADMINFLAG_T_REQUEST;
}
if (user->adminflags & ADMINFLAG_T_REQUEST) {
if (!ast_streamfile(chan, "beep", chan->language)) {
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_active = 0;
break;
case '6':
tweak_listen_volume(user, VOL_UP);
break;
case '7':
tweak_talk_volume(user, VOL_DOWN);
break;
case '8':
menu_active = 0;
break;
case '9':
tweak_talk_volume(user, VOL_UP);
break;
default:
menu_active = 0;
if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
ast_waitstream(chan, "");
}
break;
}
}
}
if (musiconhold && !menu_active) {
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 this option could absorb DTMF meant for the previous (menu), we have to check this one last */
} 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",
chan->name, f->frametype, f->subclass.integer);
}
} else {
ast_debug(1,
"Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
chan->name, 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;
fr.subclass.codec = AST_FORMAT_SLINEAR;
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 (chan->rawwriteformat & (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]) {
conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
}
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", chan->name);
break;
}
}
if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
mohtempstopped = 0;
ast_moh_start(chan, NULL, NULL);
}
}
} 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", chan->name);
}
if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
mohtempstopped = 0;
ast_moh_start(chan, NULL, NULL);
}
}
} 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) || ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW)) && 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, chan->language, sizeof(item->language));
item->confchan = conf->chan;
item->confusers = conf->users;
item->announcetype = CONF_HASLEFT;
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) ||
ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW)) && 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) {
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",
chan->name, chan->uniqueid, conf->confno,
user->user_no,
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
S_COR(user->chan->connected.id.name.valid, user->chan->connected.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, "meetme:%s", conf->confno);
}
/* 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);
return ret;
}
| static void conf_start_moh | ( | struct ast_channel * | chan, |
| const char * | musicclass | ||
| ) | [static] |
Definition at line 2036 of file app_meetme.c.
References ast_channel_lock, ast_strdupa, ast_channel::musicclass, ast_string_field_set, ast_channel_unlock, and ast_moh_start().
Referenced by conf_run().
{
char *original_moh;
ast_channel_lock(chan);
original_moh = ast_strdupa(chan->musicclass);
ast_string_field_set(chan, musicclass, musicclass);
ast_channel_unlock(chan);
ast_moh_start(chan, original_moh, NULL);
ast_channel_lock(chan);
ast_string_field_set(chan, musicclass, original_moh);
ast_channel_unlock(chan);
}
| static int count_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
The MeetmeCount application.
Definition at line 4082 of file app_meetme.c.
References AST_DECLARE_APP_ARGS, args, AST_APP_ARG, ast_strlen_zero(), ast_log(), LOG_WARNING, ast_strdupa, AST_STANDARD_APP_ARGS, find_conf(), ast_conference::users, dispose_conf(), pbx_builtin_setvar_helper(), ast_channel::_state, AST_STATE_UP, ast_answer(), ast_say_number(), and ast_channel::language.
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;
}
if (!(localdata = ast_strdupa(data)))
return -1;
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 (chan->_state != AST_STATE_UP) {
ast_answer(chan);
}
res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
}
return res;
}
| static struct sla_trunk_ref* create_trunk_ref | ( | struct sla_trunk * | trunk | ) | [static, read] |
Definition at line 6260 of file app_meetme.c.
References ast_calloc, and sla_trunk_ref::trunk.
Referenced by sla_add_trunk_to_station().
{
struct sla_trunk_ref *trunk_ref;
if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
return NULL;
trunk_ref->trunk = trunk;
return trunk_ref;
}
| static void destroy_station | ( | struct sla_station * | station | ) | [static] |
Definition at line 6468 of file app_meetme.c.
References ast_strlen_zero(), AST_RWLIST_RDLOCK, AST_LIST_TRAVERSE, sla_station::trunks, exten, AST_MAX_EXTENSION, AST_MAX_APP, sla_trunk_ref::trunk, ast_context_remove_extension(), sla_registrar, PRIORITY_HINT, AST_RWLIST_UNLOCK, AST_LIST_REMOVE_HEAD, ast_free, and ast_string_field_free_memory.
Referenced by sla_destroy(), and sla_build_station().
{
struct sla_trunk_ref *trunk_ref;
if (!ast_strlen_zero(station->autocontext)) {
AST_RWLIST_RDLOCK(&sla_trunks);
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);
}
AST_RWLIST_UNLOCK(&sla_trunks);
}
while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
ast_free(trunk_ref);
ast_string_field_free_memory(station);
ast_free(station);
}
| static void destroy_trunk | ( | struct sla_trunk * | trunk | ) | [static] |
Definition at line 6454 of file app_meetme.c.
References ast_strlen_zero(), ast_context_remove_extension(), sla_registrar, AST_LIST_REMOVE_HEAD, sla_trunk::stations, ast_free, and ast_string_field_free_memory.
Referenced by sla_destroy(), and sla_build_trunk().
{
struct sla_station_ref *station_ref;
if (!ast_strlen_zero(trunk->autocontext))
ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
ast_free(station_ref);
ast_string_field_free_memory(trunk);
ast_free(trunk);
}
| static void* dial_trunk | ( | void * | data | ) | [static] |
Definition at line 5973 of file app_meetme.c.
References args, MAX_CONFNUM, dial_trunk_args::trunk_ref, ast_dial_create(), ast_mutex_lock, dial_trunk_args::cond_lock, ast_cond_signal, dial_trunk_args::cond, ast_mutex_unlock, ast_strdupa, sla_trunk_ref::trunk, strsep(), ast_dial_append(), ast_dial_destroy(), sla, sla_trunk_ref::chan, ast_channel::caller, ast_party_caller_init(), ast_dial_run(), ast_party_caller_free(), AST_DIAL_RESULT_TRYING, ast_dial_state(), AST_DIAL_RESULT_ANSWERED, sla_trunk::chan, ast_dial_answered(), AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_UNANSWERED, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_PROCEEDING, ast_dial_join(), ast_set_flag64, CONFFLAG_QUIET, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_SLA_TRUNK, build_conf(), conf_run(), dispose_conf(), sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, and sla_trunk::on_hold.
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 };
struct sla_trunk_ref *trunk_ref = args->trunk_ref;
int caller_is_saved;
struct ast_party_caller caller;
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 = trunk_ref->chan->caller;
ast_party_caller_init(&trunk_ref->chan->caller);
}
dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
/* Restore saved caller ID */
if (caller_is_saved) {
ast_party_caller_free(&trunk_ref->chan->caller);
trunk_ref->chan->caller = 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;
case AST_DIAL_RESULT_TRYING:
case AST_DIAL_RESULT_RINGING:
case AST_DIAL_RESULT_PROGRESS:
case AST_DIAL_RESULT_PROCEEDING:
break;
}
if (done)
break;
}
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 1955 of file app_meetme.c.
References AST_LIST_LOCK, ast_atomic_dec_and_test(), ast_conference::refcount, ast_conference::confno, conf_map, conf_free(), and AST_LIST_UNLOCK.
Referenced by count_exec(), conf_exec(), admin_exec(), run_station(), dial_trunk(), 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 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 3978 of file app_meetme.c.
References var, AST_DECLARE_APP_ARGS, args, AST_APP_ARG, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conference::list, ast_conference::confno, ast_conference::refcount, AST_LIST_UNLOCK, ast_app_getdata(), build_conf(), ast_config_load, CONFIG_FILE_NAME, ast_log(), LOG_WARNING, CONFIG_STATUS_FILEINVALID, LOG_ERROR, ast_variable_browse(), ast_variable::next, parse(), MAX_SETTINGS, ast_variable::name, ast_copy_string(), ast_variable::value, AST_STANDARD_APP_ARGS, S_OR, ast_config_destroy(), ast_conference::chan, ast_test_flag64, CONFFLAG_QUIET, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, ast_clear_flag64, and CONFFLAG_RECORDCONF.
Referenced by count_exec(), and conf_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)) {
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);
}
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 3794 of file app_meetme.c.
References var, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conference::list, ast_conference::confno, ast_conference::refcount, AST_LIST_UNLOCK, AST_MAX_EXTENSION, OPTIONS_LEN, ast_tvnow(), ast_localtime(), ast_strftime(), DATE_FORMAT, ast_debug, ast_load_realtime(), fuzzystart, earlyalert, ast_streamfile(), ast_channel::language, ast_waitstream(), ast_variables_destroy(), ast_variable::next, ast_variable::name, ast_strdupa, ast_variable::value, ast_copy_string(), ast_strptime(), ast_mktime(), build_conf(), ast_conference::maxusers, ast_conference::endalert, endalert, ast_conference::endtime, ast_conference::useropts, ast_strdup, ast_conference::adminopts, ast_conference::bookid, ast_conference::recordingfilename, ast_conference::recordingformat, ast_app_parse_options64(), meetme_opts, ast_copy_flags64, ast_flags64::flags, ast_strlen_zero(), ast_channel_lock, pbx_builtin_getvar_helper(), ast_free, ast_channel_unlock, ast_channel::uniqueid, ast_verb, ast_conference::chan, ast_test_flag64, CONFFLAG_QUIET, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, ast_log(), LOG_WARNING, ast_clear_flag64, and CONFFLAG_RECORDCONF.
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", chan->language)) {
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);
cnf->recordingfilename = ast_strdup(recordingfilename);
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, chan->uniqueid);
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)) {
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);
}
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 4434 of file app_meetme.c.
References ao2_find, ast_conference::usercontainer, and user.
Referenced by admin_exec().
{
struct ast_conf_user *user = NULL;
int cid;
sscanf(callerident, "%30i", &cid);
if (conf && callerident) {
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 2052 of file app_meetme.c.
References CONF_HASLEFT, and CONF_HASJOIN.
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 975 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 6904 of file app_meetme.c.
References load_config_meetme(), sla, AST_PTHREADT_NULL, sla_queue_event(), SLA_EVENT_RELOAD, ast_log(), LOG_NOTICE, and sla_load_config().
Referenced by load_module(), and reload().
{
load_config_meetme();
if (reload && sla.thread != AST_PTHREADT_NULL) {
sla_queue_event(SLA_EVENT_RELOAD);
ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
"and will be completed when the system is idle.\n");
return 0;
}
return sla_load_config(0);
}
| static void load_config_meetme | ( | void | ) | [static] |
Definition at line 4932 of file app_meetme.c.
References ast_config_load, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_log(), LOG_ERROR, DEFAULT_AUDIO_BUFFERS, ast_variable_retrieve(), LOG_WARNING, LOG_NOTICE, ast_true(), and ast_config_destroy().
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 7129 of file app_meetme.c.
References load_config(), ast_cli_register_multiple(), ARRAY_LEN, ast_manager_register_xml, EVENT_FLAG_CALL, action_meetmemute(), action_meetmeunmute(), EVENT_FLAG_REPORTING, action_meetmelist(), ast_register_application_xml, channel_admin_exec(), admin_exec(), count_exec(), conf_exec(), sla_station_exec(), sla_trunk_exec(), AST_TEST_REGISTER, ast_data_register_multiple, ast_devstate_prov_add(), meetmestate(), sla_state(), ast_custom_function_register, ast_realtime_require_field(), RQ_UINTEGER2, and RQ_UINTEGER1.
{
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_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 | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1511 of file app_meetme.c.
References CLI_INIT, ast_cli_entry::command, ast_cli_entry::usage, CLI_GENERATE, complete_meetmecmd(), ast_cli_args::line, ast_cli_args::word, ast_cli_args::pos, ast_cli_args::n, ast_cli_args::argc, ast_cli(), ast_cli_args::fd, ast_cli_args::argv, ast_str_create(), MAX_CONFNUM, CLI_FAILURE, ast_free, CLI_SHOWUSAGE, ast_str_set(), ast_str_append(), ast_debug, ast_str_buffer(), admin_exec(), and CLI_SUCCESS.
{
/* Process the command */
struct ast_str *cmdline = NULL;
int i = 0;
switch (cmd) {
case CLI_INIT:
e->command = "meetme {lock|unlock|mute|unmute|kick}";
e->usage =
"Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
" Executes a command for the conference or on a conferee\n";
return NULL;
case CLI_GENERATE:
return complete_meetmecmd(a->line, a->word, a->pos, a->n);
}
if (a->argc > 8)
ast_cli(a->fd, "Invalid Arguments.\n");
/* Check for length so no buffer will overflow... */
for (i = 0; i < a->argc; i++) {
if (strlen(a->argv[i]) > 100)
ast_cli(a->fd, "Invalid Arguments.\n");
}
/* Max confno length */
if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
return CLI_FAILURE;
}
if (a->argc < 1) {
ast_free(cmdline);
return CLI_SHOWUSAGE;
}
ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */
if (strstr(a->argv[1], "lock")) {
if (strcmp(a->argv[1], "lock") == 0) {
/* Lock */
ast_str_append(&cmdline, 0, ",L");
} else {
/* Unlock */
ast_str_append(&cmdline, 0, ",l");
}
} else if (strstr(a->argv[1], "mute")) {
if (a->argc < 4) {
ast_free(cmdline);
return CLI_SHOWUSAGE;
}
if (strcmp(a->argv[1], "mute") == 0) {
/* Mute */
if (strcmp(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 (strcmp(a->argv[3], "all") == 0) {
ast_str_append(&cmdline, 0, ",n");
} else {
ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
}
}
} else if (strcmp(a->argv[1], "kick") == 0) {
if (a->argc < 4) {
ast_free(cmdline);
return CLI_SHOWUSAGE;
}
if (strcmp(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 {
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 6993 of file app_meetme.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_data_add_node(), ast_data_add_structure, ao2_container_count(), ast_conference::usercontainer, ast_data_remove_node(), ao2_callback, OBJ_NODATA, user_add_provider_cb(), ast_data_search_match(), and AST_LIST_UNLOCK.
{
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_show_cmd | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1353 of file app_meetme.c.
References user, total, CLI_INIT, ast_cli_entry::command, ast_cli_entry::usage, CLI_GENERATE, complete_meetmecmd(), ast_cli_args::line, ast_cli_args::word, ast_cli_args::pos, ast_cli_args::n, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_cli_args::fd, ast_str_create(), MAX_CONFNUM, CLI_FAILURE, AST_LIST_LOCK, AST_LIST_EMPTY, AST_LIST_UNLOCK, ast_free, CLI_SUCCESS, MC_HEADER_FORMAT, AST_LIST_TRAVERSE, ast_conference::markedusers, ast_str_set(), ast_conference::start, MC_DATA_FORMAT, ast_conference::confno, ast_conference::users, ast_str_buffer(), ast_conference::isdynamic, ast_conference::locked, ao2_iterator_init(), ast_conference::usercontainer, ao2_iterator_next, ast_conf_user::jointime, ast_conf_user::user_no, S_COR, ast_conf_user::chan, ast_channel::caller, ast_party_caller::id, ast_party_id::number, ast_party_number::valid, ast_party_number::str, ast_party_id::name, ast_party_name::valid, ast_party_name::str, ast_channel::name, ast_test_flag64, ast_conf_user::userflags, CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conf_user::adminflags, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, istalking(), ast_conf_user::talking, ao2_ref, ao2_iterator_destroy(), CLI_SHOWUSAGE, ast_debug, and admin_exec().
{
/* Process the command */
struct ast_conf_user *user;
struct ast_conference *cnf;
int hr, min, sec;
int i = 0, total = 0;
time_t now;
struct ast_str *cmdline = NULL;
#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 [concise]";
e->usage =
"Usage: meetme list [concise] <confno> \n"
" List all or a specific conference.\n";
return NULL;
case CLI_GENERATE:
return complete_meetmecmd(a->line, a->word, a->pos, a->n);
}
/* Check for length so no buffer will overflow... */
for (i = 0; i < a->argc; i++) {
if (strlen(a->argv[i]) > 100)
ast_cli(a->fd, "Invalid Arguments.\n");
}
/* Max confno length */
if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
return CLI_FAILURE;
}
if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
/* List all the conferences */
int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
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(cmdline);
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) {
if (cnf->markedusers == 0) {
ast_str_set(&cmdline, 0, "N/A ");
} else {
ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
}
hr = (now - cnf->start) / 3600;
min = ((now - cnf->start) % 3600) / 60;
sec = (now - cnf->start) % 60;
if (!concise) {
ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), 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(cmdline);
return CLI_SUCCESS;
} else if (strcmp(a->argv[1], "list") == 0) {
struct ao2_iterator user_iter;
int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
/* List all the users in a conference */
if (AST_LIST_EMPTY(&confs)) {
if (!concise) {
ast_cli(a->fd, "No active MeetMe conferences.\n");
}
ast_free(cmdline);
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);
ast_free(cmdline);
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(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
user->chan->name,
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(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, ""),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, ""),
user->chan->name,
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);
ast_free(cmdline);
return CLI_SUCCESS;
}
if (a->argc < 2) {
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 meetmemute | ( | struct mansession * | s, |
| const struct message * | m, | ||
| int | mute | ||
| ) | [static] |
Definition at line 4700 of file app_meetme.c.
References user, astman_get_header(), ast_strdupa, ast_strlen_zero(), astman_send_error(), AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conf_user::list, ast_conference::confno, AST_LIST_UNLOCK, ao2_find, ast_conference::usercontainer, ast_conf_user::adminflags, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_log(), LOG_NOTICE, ast_conf_user::user_no, ast_conf_user::chan, ast_channel::name, ast_channel::uniqueid, ao2_ref, and astman_send_ack().
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, user->chan->name, user->chan->uniqueid);
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 4910 of file app_meetme.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_conference::list, ast_conference::confno, AST_LIST_UNLOCK, AST_DEVICE_INVALID, ast_conference::users, AST_DEVICE_NOT_INUSE, and AST_DEVICE_INUSE.
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 6272 of file app_meetme.c.
References ast_calloc, sla_ringing_trunk::trunk, sla_ringing_trunk::ring_begin, ast_tvnow(), sla_change_trunk_state(), SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, ast_mutex_lock, sla, AST_LIST_INSERT_HEAD, ast_mutex_unlock, sla_queue_event(), and SLA_EVENT_RINGING_TRUNK.
Referenced by sla_trunk_exec().
{
struct sla_ringing_trunk *ringing_trunk;
if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
return NULL;
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 4845 of file app_meetme.c.
References args, f, ast_frame::flags, ast_conference::lchan, ast_stopstream(), ast_conference::recording, MEETME_RECORD_ACTIVE, ast_waitfor(), MEETME_RECORD_TERMINATE, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_conference::recordingfilename, ast_writefile(), ast_conference::recordingformat, AST_FILE_MODE, ast_read(), ast_frame::frametype, AST_FRAME_VOICE, ast_mutex_lock, ast_conference::listenlock, AST_FRAME_BITS, ast_conference::transframe, ast_frfree, ast_conference::origframe, ast_frdup(), ast_mutex_unlock, ast_writestream(), MEETME_RECORD_OFF, and ast_closestream().
{
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;
if (!cnf || !cnf->lchan) {
pthread_exit(0);
}
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 && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
oldrecordingfilename = cnf->recordingfilename;
}
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 7160 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 1095 of file app_meetme.c.
References ast_channel_setoption(), ast_conf_user::chan, AST_OPTION_TXGAIN, and AST_OPTION_RXGAIN.
Referenced by conf_run(), user_reset_vol_cb(), and admin_exec().
{
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 1974 of file app_meetme.c.
References var, ast_tvnow(), ast_localtime(), ast_strftime(), DATE_FORMAT, ast_load_realtime(), ast_variable::name, ast_copy_string(), ast_variable::value, ast_variable::next, ast_variables_destroy(), ast_strptime(), ast_mktime(), extendby, ast_debug, and ast_update_realtime().
Referenced by conf_run(), and admin_exec().
{
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 5159 of file app_meetme.c.
References ast_str_create(), args, run_station_args::station, run_station_args::trunk_ref, ast_mutex_lock, run_station_args::cond_lock, ast_cond_signal, run_station_args::cond, ast_mutex_unlock, ast_atomic_fetchadd_int(), sla_trunk_ref::trunk, sla_trunk::active_stations, ast_str_set(), ast_set_flag64, CONFFLAG_QUIET, CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_SLA_STATION, answer_trunk_chan(), sla_trunk_ref::chan, build_conf(), ast_str_buffer(), conf_run(), dispose_conf(), ast_atomic_dec_and_test(), sla_trunk_ref::state, SLA_TRUNK_STATE_ONHOLD_BYME, ast_str_append(), admin_exec(), sla_trunk::hold_stations, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, ast_dial_join(), sla_station::dial, ast_dial_destroy(), and ast_free.
Referenced by sla_handle_dial_state_event().
{
struct sla_station *station;
struct sla_trunk_ref *trunk_ref;
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 2128 of file app_meetme.c.
References ast_manager_event, EVENT_FLAG_CALL, ast_channel::name, ast_channel::uniqueid, ast_conference::confno, and ast_conf_user::user_no.
Referenced by set_user_talking().
{
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",
chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
}
| static int set_listen_volume | ( | struct ast_conf_user * | user, |
| int | volume | ||
| ) | [static] |
Definition at line 1024 of file app_meetme.c.
References ast_channel_setoption(), ast_conf_user::chan, and AST_OPTION_TXGAIN.
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 1012 of file app_meetme.c.
References ast_channel_setoption(), ast_conf_user::chan, and AST_OPTION_RXGAIN.
Referenced by tweak_talk_volume(), and conf_run().
{
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 2139 of file app_meetme.c.
References ast_conf_user::talking, and send_talking_event().
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 6612 of file app_meetme.c.
References ast_strdupa, ast_variable::value, strsep(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_log(), LOG_ERROR, create_trunk_ref(), sla_trunk_ref::state, SLA_TRUNK_STATE_IDLE, name, value, sla_trunk_ref::ring_timeout, LOG_WARNING, sla_trunk_ref::ring_delay, sla_create_station_ref(), ast_free, ast_atomic_fetchadd_int(), sla_trunk::num_stations, AST_RWLIST_WRLOCK, AST_LIST_INSERT_TAIL, sla_trunk::stations, and sla_station::trunks.
Referenced by sla_build_station().
{
struct sla_trunk *trunk;
struct sla_trunk_ref *trunk_ref;
struct sla_station_ref *station_ref;
char *trunk_name, *options, *cur;
options = ast_strdupa(var->value);
trunk_name = strsep(&options, ",");
AST_RWLIST_RDLOCK(&sla_trunks);
AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
if (!strcasecmp(trunk->name, trunk_name))
break;
}
AST_RWLIST_UNLOCK(&sla_trunks);
if (!trunk) {
ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
return;
}
if (!(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);
}
}
if (!(station_ref = sla_create_station_ref(station))) {
ast_free(trunk_ref);
return;
}
ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
AST_RWLIST_WRLOCK(&sla_trunks);
AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
AST_RWLIST_UNLOCK(&sla_trunks);
AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
}
| static int sla_build_station | ( | struct ast_config * | cfg, |
| const char * | cat | ||
| ) | [static] |
Definition at line 6669 of file app_meetme.c.
References var, ast_variable_retrieve(), ast_log(), LOG_ERROR, ast_calloc_with_stringfields, ast_string_field_set, ast_variable_browse(), ast_variable::next, ast_variable::name, sla_add_trunk_to_station(), ast_variable::value, sla_station::ring_timeout, LOG_WARNING, sla_station::ring_delay, sla_station::hold_access, SLA_HOLD_PRIVATE, SLA_HOLD_OPEN, ast_variable::lineno, SLA_CONFIG_FILE, ast_strlen_zero(), context, ast_context_find_or_create(), sla_registrar, destroy_station(), ast_add_extension2(), ast_strdup, ast_free_ptr, AST_RWLIST_RDLOCK, AST_LIST_TRAVERSE, sla_station::trunks, exten, AST_MAX_EXTENSION, AST_MAX_APP, sla_trunk_ref::trunk, PRIORITY_HINT, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and AST_RWLIST_INSERT_TAIL.
Referenced by sla_load_config().
{
struct sla_station *station;
struct ast_variable *var;
const char *dev;
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 = ast_calloc_with_stringfields(1, struct sla_station, 32))) {
return -1;
}
ast_string_field_set(station, name, cat);
ast_string_field_set(station, device, dev);
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
if (!strcasecmp(var->name, "trunk"))
sla_add_trunk_to_station(station, var);
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);
}
}
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);
destroy_station(station);
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);
destroy_station(station);
return -1;
}
AST_RWLIST_RDLOCK(&sla_trunks);
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);
destroy_station(station);
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);
destroy_station(station);
return -1;
}
}
AST_RWLIST_UNLOCK(&sla_trunks);
}
AST_RWLIST_WRLOCK(&sla_stations);
AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
AST_RWLIST_UNLOCK(&sla_stations);
return 0;
}
| static int sla_build_trunk | ( | struct ast_config * | cfg, |
| const char * | cat | ||
| ) | [static] |
Definition at line 6537 of file app_meetme.c.
References var, ast_variable_retrieve(), ast_log(), LOG_ERROR, sla_check_device(), ast_calloc_with_stringfields, ast_string_field_set, ast_variable_browse(), ast_variable::next, ast_variable::name, ast_variable::value, sla_trunk::ring_timeout, LOG_WARNING, sla_trunk::barge_disabled, ast_false(), sla_trunk::hold_access, SLA_HOLD_PRIVATE, SLA_HOLD_OPEN, ast_variable::lineno, SLA_CONFIG_FILE, ast_strlen_zero(), context, ast_context_find_or_create(), sla_registrar, destroy_trunk(), ast_add_extension2(), ast_strdup, ast_free_ptr, AST_RWLIST_WRLOCK, AST_RWLIST_INSERT_TAIL, and AST_RWLIST_UNLOCK.
Referenced by sla_load_config().
{
struct sla_trunk *trunk;
struct ast_variable *var;
const char *dev;
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' define with invalid device '%s'!\n",
cat, dev);
return -1;
}
if (!(trunk = ast_calloc_with_stringfields(1, struct sla_trunk, 32))) {
return -1;
}
ast_string_field_set(trunk, name, cat);
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);
}
}
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);
destroy_trunk(trunk);
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);
destroy_trunk(trunk);
return -1;
}
}
AST_RWLIST_WRLOCK(&sla_trunks);
AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
AST_RWLIST_UNLOCK(&sla_trunks);
return 0;
}
| static int sla_calc_station_delays | ( | unsigned int * | timeout | ) | [static] |
Calculate the ring delay for a station.
Definition at line 5771 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_check_ringing_station(), sla_check_inuse_station(), sla_choose_ringing_trunk(), and sla_check_station_delay().
Referenced by sla_process_timers().
{
struct sla_station *station;
int res = 0;
AST_LIST_TRAVERSE(&sla_stations, station, entry) {
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;
}
return res;
}
| static int sla_calc_station_timeouts | ( | unsigned int * | timeout | ) | [static] |
Process station ring timeouts.
Definition at line 5688 of file app_meetme.c.
References AST_LIST_TRAVERSE_SAFE_BEGIN, sla, AST_LIST_TRAVERSE, sla_ringing_station::station, sla_station::trunks, sla_ringing_trunk::trunk, sla_trunk_ref::trunk, sla_trunk_ref::ring_timeout, sla_ringing_trunk::timed_out_stations, sla_station_ref::station, ast_tvdiff_ms(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla_station::ring_timeout, sla_ringing_station::ring_begin, AST_LIST_REMOVE_CURRENT, sla_stop_ringing_station(), SLA_STATION_HANGUP_TIMEOUT, and AST_LIST_TRAVERSE_SAFE_END.
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 5658 of file app_meetme.c.
References AST_LIST_TRAVERSE_SAFE_BEGIN, sla, sla_ringing_trunk::trunk, sla_trunk::ring_timeout, ast_tvdiff_ms(), ast_tvnow(), sla_ringing_trunk::ring_begin, pbx_builtin_setvar_helper(), sla_trunk::chan, AST_LIST_REMOVE_CURRENT, sla_stop_ringing_trunk(), and AST_LIST_TRAVERSE_SAFE_END.
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 5127 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::trunks, sla_trunk_ref::trunk, sla_trunk_ref::chan, sla_trunk_ref::state, state, ast_devstate_changed(), and sla_state_to_devstate().
Referenced by run_station(), sla_stop_ringing_trunk(), sla_handle_dial_state_event(), sla_handle_hold_event(), dial_trunk(), sla_station_exec(), queue_ringing_trunk(), and sla_trunk_exec().
{
struct sla_station *station;
struct sla_trunk_ref *trunk_ref;
AST_LIST_TRAVERSE(&sla_stations, station, entry) {
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),
"SLA:%s_%s", station->name, trunk->name);
break;
}
}
}
| static int sla_check_device | ( | const char * | device | ) | [static] |
Definition at line 6524 of file app_meetme.c.
References ast_strdupa, strsep(), and 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 5407 of file app_meetme.c.
References AST_LIST_TRAVERSE_SAFE_BEGIN, sla, sla_failed_station::station, ast_tvdiff_ms(), ast_tvnow(), sla_failed_station::last_try, AST_LIST_REMOVE_CURRENT, ast_free, and AST_LIST_TRAVERSE_SAFE_END.
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);
ast_free(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 5492 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::trunks, and sla_trunk_ref::chan.
Referenced by sla_ring_stations(), and sla_calc_station_delays().
{
struct sla_trunk_ref *trunk_ref;
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->chan)
return 1;
}
return 0;
}
| static void sla_check_reload | ( | void | ) | [static] |
Check if we can do a reload of SLA, and do it if we can.
Definition at line 5850 of file app_meetme.c.
References ast_mutex_lock, sla, AST_LIST_EMPTY, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, sla_station::ref_count, AST_RWLIST_UNLOCK, sla_trunk::ref_count, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_REMOVE_CURRENT, ast_free, AST_RWLIST_TRAVERSE_SAFE_END, and sla_load_config().
Referenced by sla_thread().
{
struct sla_station *station;
struct sla_trunk *trunk;
ast_mutex_lock(&sla.lock);
if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
|| !AST_LIST_EMPTY(&sla.ringing_stations)) {
ast_mutex_unlock(&sla.lock);
return;
}
AST_RWLIST_RDLOCK(&sla_stations);
AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
if (station->ref_count)
break;
}
AST_RWLIST_UNLOCK(&sla_stations);
if (station) {
ast_mutex_unlock(&sla.lock);
return;
}
AST_RWLIST_RDLOCK(&sla_trunks);
AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
if (trunk->ref_count)
break;
}
AST_RWLIST_UNLOCK(&sla_trunks);
if (trunk) {
ast_mutex_unlock(&sla.lock);
return;
}
/* We need to actually delete the previous versions of trunks and stations now */
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_stations, station, entry) {
AST_RWLIST_REMOVE_CURRENT(entry);
ast_free(station);
}
AST_RWLIST_TRAVERSE_SAFE_END;
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_trunks, trunk, entry) {
AST_RWLIST_REMOVE_CURRENT(entry);
ast_free(trunk);
}
AST_RWLIST_TRAVERSE_SAFE_END;
/* yay */
sla_load_config(1);
sla.reload = 0;
ast_mutex_unlock(&sla.lock);
}
| static int sla_check_ringing_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if this station is already ringing.
Definition at line 5392 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla, and sla_ringing_station::station.
Referenced by sla_ring_stations(), and sla_calc_station_delays().
{
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 5522 of file app_meetme.c.
References sla_choose_ringing_trunk(), sla_find_trunk_ref(), sla_ringing_trunk::trunk, sla_trunk_ref::ring_delay, sla_station::ring_delay, ast_tvdiff_ms(), ast_tvnow(), and sla_ringing_trunk::ring_begin.
Referenced by sla_ring_stations(), and sla_calc_station_delays().
{
struct sla_trunk_ref *trunk_ref;
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 5032 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_trunk::stations, sla_station_ref::station, sla_station::trunks, sla_trunk_ref::trunk, sla_trunk_ref::state, SLA_TRUNK_STATE_ONHOLD_BYME, sla_station::hold_access, and SLA_HOLD_PRIVATE.
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 5263 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_ringing_trunk::timed_out_stations, and sla_station_ref::station.
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 6087 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::trunks, sla_trunk_ref::state, and SLA_TRUNK_STATE_IDLE.
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)
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 5284 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::trunks, AST_LIST_TRAVERSE_SAFE_BEGIN, sla, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, sla_check_timed_out_station(), AST_LIST_REMOVE_CURRENT, and AST_LIST_TRAVERSE_SAFE_END.
Referenced by sla_handle_dial_state_event(), sla_check_station_delay(), and sla_calc_station_delays().
{
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)
*trunk_ref = s_trunk_ref;
break;
}
AST_LIST_TRAVERSE_SAFE_END;
if (ringing_trunk)
break;
}
return ringing_trunk;
}
| static struct sla_ringing_station* sla_create_ringing_station | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 5097 of file app_meetme.c.
References ast_calloc, sla_ringing_station::station, sla_ringing_station::ring_begin, and ast_tvnow().
Referenced by sla_ring_station().
{
struct sla_ringing_station *ringing_station;
if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
return NULL;
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 5085 of file app_meetme.c.
References ast_calloc, and sla_station_ref::station.
Referenced by sla_stop_ringing_station(), and sla_add_trunk_to_station().
{
struct sla_station_ref *station_ref;
if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
return NULL;
station_ref->station = station;
return station_ref;
}
| static void sla_destroy | ( | void | ) | [static] |
Definition at line 6494 of file app_meetme.c.
References AST_RWLIST_WRLOCK, AST_RWLIST_REMOVE_HEAD, destroy_trunk(), AST_RWLIST_UNLOCK, destroy_station(), sla, AST_PTHREADT_NULL, ast_mutex_lock, ast_cond_signal, ast_mutex_unlock, ast_context_destroy(), sla_registrar, ast_mutex_destroy, and ast_cond_destroy.
Referenced by unload_module().
{
struct sla_trunk *trunk;
struct sla_station *station;
AST_RWLIST_WRLOCK(&sla_trunks);
while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
destroy_trunk(trunk);
AST_RWLIST_UNLOCK(&sla_trunks);
AST_RWLIST_WRLOCK(&sla_stations);
while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
destroy_station(station);
AST_RWLIST_UNLOCK(&sla_stations);
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);
}
| static void sla_dial_state_callback | ( | struct ast_dial * | dial | ) | [static] |
Definition at line 5255 of file app_meetme.c.
References sla_queue_event(), and SLA_EVENT_DIAL_STATE.
Referenced by sla_ring_station().
| static struct sla_station* sla_find_station | ( | const char * | name | ) | [static, read] |
Find an SLA station by name.
Definition at line 5020 of file app_meetme.c.
References AST_RWLIST_TRAVERSE.
Referenced by sla_station_exec().
{
struct sla_station *station = NULL;
AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
if (!strcasecmp(station->name, name))
break;
}
return station;
}
| static struct sla_trunk* sla_find_trunk | ( | const char * | name | ) | [static, read] |
Find an SLA trunk by name.
Definition at line 5005 of file app_meetme.c.
References AST_RWLIST_TRAVERSE.
Referenced by sla_trunk_exec().
{
struct sla_trunk *trunk = NULL;
AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
if (!strcasecmp(trunk->name, name))
break;
}
return trunk;
}
| static struct sla_trunk_ref* sla_find_trunk_ref | ( | const struct sla_station * | station, |
| const struct sla_trunk * | trunk | ||
| ) | [static, read] |
Definition at line 5504 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::trunks, and sla_trunk_ref::trunk.
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;
}
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 5060 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::trunks, sla_trunk_ref::trunk, sla_trunk::barge_disabled, sla_trunk_ref::state, SLA_TRUNK_STATE_UP, sla_trunk::hold_stations, sla_trunk::hold_access, SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, and sla_check_station_hold_access().
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;
}
return trunk_ref;
}
| static void sla_handle_dial_state_event | ( | void | ) | [static] |
Definition at line 5318 of file app_meetme.c.
References AST_LIST_TRAVERSE_SAFE_BEGIN, sla, run_station_args::cond_lock, cond, ast_dial_state(), sla_ringing_station::station, sla_station::dial, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_UNANSWERED, AST_LIST_REMOVE_CURRENT, sla_stop_ringing_station(), SLA_STATION_HANGUP_NORMAL, AST_DIAL_RESULT_ANSWERED, ast_mutex_lock, sla_choose_ringing_trunk(), ast_mutex_unlock, ast_debug, sla_trunk_ref::chan, ast_dial_answered(), answer_trunk_chan(), sla_ringing_trunk::trunk, sla_trunk::chan, sla_change_trunk_state(), SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, run_station_args::trunk_ref, run_station_args::station, run_station_args::cond, ast_free, ast_mutex_init, ast_cond_init, ast_pthread_create_detached_background, run_station(), ast_cond_wait, ast_mutex_destroy, ast_cond_destroy, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_PROCEEDING, sla_queue_event(), SLA_EVENT_RINGING_TRUNK, SLA_EVENT_DIAL_STATE, and AST_LIST_TRAVERSE_SAFE_END.
Referenced by sla_thread().
{
struct sla_ringing_station *ringing_station;
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
struct sla_trunk_ref *s_trunk_ref = NULL;
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) {
ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
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. */
args.trunk_ref = s_trunk_ref;
args.station = ringing_station->station;
args.cond = &cond;
args.cond_lock = &cond_lock;
ast_free(ringing_trunk);
ast_free(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 5634 of file app_meetme.c.
References ast_atomic_fetchadd_int(), sla_event::trunk_ref, sla_trunk_ref::trunk, sla_trunk::hold_stations, SLA_TRUNK_STATE_ONHOLD_BYME, ast_devstate_changed(), AST_DEVICE_ONHOLD, sla_event::station, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, INACTIVE_TRUNK_REFS, sla_trunk::active_stations, ast_indicate(), sla_trunk::chan, AST_CONTROL_HOLD, ast_softhangup(), sla_trunk_ref::chan, and AST_SOFTHANGUP_DEV.
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, "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 5624 of file app_meetme.c.
References ast_mutex_lock, sla, sla_ring_stations(), ast_mutex_unlock, and sla_hangup_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 5596 of file app_meetme.c.
References AST_LIST_TRAVERSE_SAFE_BEGIN, sla, AST_LIST_TRAVERSE, sla_ringing_station::station, sla_station::trunks, ast_mutex_lock, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, ast_mutex_unlock, AST_LIST_REMOVE_CURRENT, ast_dial_join(), sla_station::dial, ast_dial_destroy(), ast_free, and AST_LIST_TRAVERSE_SAFE_END.
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;
ast_free(ringing_station);
}
}
AST_LIST_TRAVERSE_SAFE_END
}
| static const char* sla_hold_str | ( | unsigned int | hold_access | ) | [static] |
Definition at line 1600 of file app_meetme.c.
References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.
Referenced by sla_show_trunks(), and sla_show_stations().
{
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_load_config | ( | int | reload | ) | [static] |
Definition at line 6774 of file app_meetme.c.
References CONFIG_FLAG_FILEUNCHANGED, ast_mutex_init, sla, ast_cond_init, ast_config_load, SLA_CONFIG_FILE, CONFIG_STATUS_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, ast_log(), LOG_ERROR, ast_variable_retrieve(), ast_true(), ast_category_browse(), type, LOG_WARNING, sla_build_trunk(), sla_build_station(), ast_config_destroy(), AST_PTHREADT_NULL, AST_LIST_EMPTY, ast_pthread_create, and sla_thread().
Referenced by sla_check_reload(), and 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);
}
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 ((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);
/* Even if we don't have any stations, we may after a reload and we need to
* be able to process the SLA_EVENT_RELOAD event in that case */
if (sla.thread == AST_PTHREADT_NULL && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_trunks))) {
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 5812 of file app_meetme.c.
References sla_calc_trunk_timeouts(), sla_calc_station_timeouts(), sla_calc_station_delays(), sla_queue_event_nolock(), SLA_EVENT_RINGING_TRUNK, ast_tvadd(), ast_tvnow(), and ast_samp2tv().
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 1915 of file app_meetme.c.
References sla_queue_event_full().
Referenced by sla_dial_state_callback(), sla_handle_dial_state_event(), sla_station_exec(), queue_ringing_trunk(), sla_trunk_exec(), and load_config().
{
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 1921 of file app_meetme.c.
References ast_strdupa, ast_conference::confno, strsep(), ast_strlen_zero(), ast_log(), LOG_ERROR, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_LIST_TRAVERSE, sla_station::trunks, sla_trunk_ref::chan, sla_trunk_ref::trunk, AST_RWLIST_UNLOCK, ast_debug, and sla_queue_event_full().
Referenced by conf_run().
{
struct sla_station *station;
struct sla_trunk_ref *trunk_ref = NULL;
char *trunk_name;
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;
}
AST_RWLIST_RDLOCK(&sla_stations);
AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
break;
}
if (trunk_ref)
break;
}
AST_RWLIST_UNLOCK(&sla_stations);
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 1883 of file app_meetme.c.
References sla, AST_PTHREADT_NULL, ast_calloc, sla_event::type, type, sla_event::trunk_ref, sla_event::station, AST_LIST_INSERT_TAIL, ast_mutex_lock, ast_cond_signal, and ast_mutex_unlock.
Referenced by sla_queue_event_nolock(), sla_queue_event(), and sla_queue_event_conf().
{
struct sla_event *event;
if (sla.thread == AST_PTHREADT_NULL) {
return;
}
if (!(event = ast_calloc(1, sizeof(*event))))
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 1910 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 5430 of file app_meetme.c.
References ast_dial_create(), ast_dial_set_state_callback(), sla_dial_state_callback(), ast_strdupa, strsep(), ast_dial_append(), ast_dial_destroy(), sla, sla_ringing_trunk::trunk, sla_trunk::chan, ast_channel::caller, ast_party_caller_init(), ast_dial_run(), ast_party_caller_free(), AST_DIAL_RESULT_TRYING, ast_calloc, sla_failed_station::station, sla_failed_station::last_try, ast_tvnow(), AST_LIST_INSERT_HEAD, sla_create_ringing_station(), ast_dial_join(), and sla_station::dial.
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 = ringing_trunk->trunk->chan->caller;
ast_party_caller_init(&ringing_trunk->trunk->chan->caller);
}
res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
/* Restore saved caller ID */
if (caller_is_saved) {
ast_party_caller_free(&ringing_trunk->trunk->chan->caller);
ringing_trunk->trunk->chan->caller = caller;
}
if (res != AST_DIAL_RESULT_TRYING) {
struct sla_failed_station *failed_station;
ast_dial_destroy(dial);
if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
return -1;
failed_station->station = station;
failed_station->last_try = ast_tvnow();
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 5555 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla, sla_ringing_trunk::trunk, sla_trunk::stations, sla_check_ringing_station(), sla_station_ref::station, sla_check_inuse_station(), sla_check_failed_station(), sla_check_timed_out_station(), sla_check_station_delay(), and sla_ring_station().
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 char* sla_show_stations | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1682 of file app_meetme.c.
References CLI_INIT, ast_cli_entry::command, ast_cli_entry::usage, CLI_GENERATE, ast_cli(), ast_cli_args::fd, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, sla_station::ring_timeout, sla_station::ring_delay, S_OR, sla_hold_str(), sla_station::hold_access, AST_LIST_TRAVERSE, sla_station::trunks, sla_trunk_ref::ring_timeout, sla_trunk_ref::ring_delay, sla_trunk_ref::trunk, trunkstate2str(), sla_trunk_ref::state, AST_RWLIST_UNLOCK, and CLI_SUCCESS.
{
const 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");
AST_RWLIST_RDLOCK(&sla_stations);
AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
struct sla_trunk_ref *trunk_ref;
char ring_timeout[16] = "(none)";
char ring_delay[16] = "(none)";
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_RWLIST_RDLOCK(&sla_trunks);
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_RWLIST_UNLOCK(&sla_trunks);
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
"===\n");
}
AST_RWLIST_UNLOCK(&sla_stations);
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 1617 of file app_meetme.c.
References CLI_INIT, ast_cli_entry::command, ast_cli_entry::usage, CLI_GENERATE, ast_cli(), ast_cli_args::fd, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, sla_trunk::ring_timeout, S_OR, sla_trunk::barge_disabled, sla_hold_str(), sla_trunk::hold_access, AST_LIST_TRAVERSE, sla_trunk::stations, sla_station_ref::station, AST_RWLIST_UNLOCK, and CLI_SUCCESS.
{
const 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");
AST_RWLIST_RDLOCK(&sla_trunks);
AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
struct sla_station_ref *station_ref;
char ring_timeout[16] = "(none)";
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_RWLIST_RDLOCK(&sla_stations);
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
AST_RWLIST_UNLOCK(&sla_stations);
ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
}
AST_RWLIST_UNLOCK(&sla_trunks);
ast_cli(a->fd, "=============================================================\n\n");
return CLI_SUCCESS;
}
| static enum ast_device_state sla_state | ( | const char * | data | ) | [static] |
Definition at line 6418 of file app_meetme.c.
References AST_DEVICE_INVALID, ast_strdupa, strsep(), AST_RWLIST_RDLOCK, AST_LIST_TRAVERSE, sla_station::trunks, sla_trunk_ref::trunk, AST_RWLIST_UNLOCK, sla_state_to_devstate(), sla_trunk_ref::state, ast_log(), and LOG_ERROR.
Referenced by load_module().
{
char *buf, *station_name, *trunk_name;
struct sla_station *station;
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, "_");
AST_RWLIST_RDLOCK(&sla_stations);
AST_LIST_TRAVERSE(&sla_stations, station, entry) {
if (strcasecmp(station_name, station->name))
continue;
AST_RWLIST_RDLOCK(&sla_trunks);
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
break;
}
if (!trunk_ref) {
AST_RWLIST_UNLOCK(&sla_trunks);
break;
}
res = sla_state_to_devstate(trunk_ref->state);
AST_RWLIST_UNLOCK(&sla_trunks);
}
AST_RWLIST_UNLOCK(&sla_stations);
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 5110 of file app_meetme.c.
References SLA_TRUNK_STATE_IDLE, AST_DEVICE_NOT_INUSE, SLA_TRUNK_STATE_RINGING, AST_DEVICE_RINGING, SLA_TRUNK_STATE_UP, AST_DEVICE_INUSE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, AST_DEVICE_ONHOLD, and AST_DEVICE_UNKNOWN.
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_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 6099 of file app_meetme.c.
References MAX_CONFNUM, ast_strlen_zero(), ast_log(), LOG_WARNING, pbx_builtin_setvar_helper(), ast_strdupa, strsep(), AST_RWLIST_RDLOCK, sla_find_station(), ast_atomic_fetchadd_int(), sla_station::ref_count, AST_RWLIST_UNLOCK, sla_queue_event(), SLA_EVENT_CHECK_RELOAD, sla_find_trunk_ref_byname(), sla_choose_idle_trunk(), LOG_NOTICE, sla_trunk_ref::state, SLA_TRUNK_STATE_ONHOLD_BYME, ast_atomic_dec_and_test(), sla_trunk_ref::trunk, sla_trunk::hold_stations, sla_change_trunk_state(), SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, ast_devstate_changed(), AST_DEVICE_INUSE, SLA_TRUNK_STATE_RINGING, ast_mutex_lock, sla, AST_LIST_TRAVERSE_SAFE_BEGIN, sla_ringing_trunk::trunk, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_unlock, answer_trunk_chan(), sla_trunk::chan, free, SLA_EVENT_RINGING_TRUNK, SLA_EVENT_DIAL_STATE, sla_trunk_ref::chan, cond, dial_trunk_args::trunk_ref, dial_trunk_args::station, dial_trunk_args::cond_lock, ast_autoservice_start(), ast_mutex_init, ast_cond_init, ast_pthread_create_detached_background, dial_trunk(), ast_cond_wait, ast_mutex_destroy, ast_cond_destroy, ast_autoservice_stop(), ast_debug, SLA_TRUNK_STATE_IDLE, sla_trunk::active_stations, sla_trunk::on_hold, ast_indicate(), AST_CONTROL_UNHOLD, ast_set_flag64, CONFFLAG_QUIET, CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_SLA_STATION, ast_answer(), build_conf(), conf_run(), dispose_conf(), and admin_exec().
Referenced by load_module().
{
char *station_name, *trunk_name;
struct sla_station *station;
struct sla_trunk_ref *trunk_ref = NULL;
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;
}
AST_RWLIST_RDLOCK(&sla_stations);
station = sla_find_station(station_name);
if (station)
ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
AST_RWLIST_UNLOCK(&sla_stations);
if (!station) {
ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
return 0;
}
AST_RWLIST_RDLOCK(&sla_trunks);
if (!ast_strlen_zero(trunk_name)) {
trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
} else
trunk_ref = sla_choose_idle_trunk(station);
AST_RWLIST_UNLOCK(&sla_trunks);
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");
ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
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,
"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);
free(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,
};
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;
ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
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");
ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
return 0;
}
| static void sla_stop_ringing_station | ( | struct sla_ringing_station * | ringing_station, |
| enum sla_station_hangup | hangup | ||
| ) | [static] |
Definition at line 5220 of file app_meetme.c.
References ast_dial_join(), sla_ringing_station::station, sla_station::dial, ast_dial_destroy(), SLA_STATION_HANGUP_NORMAL, AST_LIST_TRAVERSE, sla, sla_station::trunks, sla_ringing_trunk::trunk, sla_trunk_ref::trunk, sla_create_station_ref(), AST_LIST_INSERT_TAIL, sla_ringing_trunk::timed_out_stations, and ast_free.
Referenced by sla_handle_dial_state_event(), and sla_calc_station_timeouts().
{
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:
ast_free(ringing_station);
}
| static void sla_stop_ringing_trunk | ( | struct sla_ringing_trunk * | ringing_trunk | ) | [static] |
Definition at line 5205 of file app_meetme.c.
References sla_ringing_trunk::trunk, admin_exec(), sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, AST_LIST_REMOVE_HEAD, sla_ringing_trunk::timed_out_stations, and ast_free.
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)))
ast_free(station_ref);
ast_free(ringing_trunk);
}
| static void* sla_thread | ( | void * | data | ) | [static] |
Definition at line 5905 of file app_meetme.c.
References ast_mutex_lock, sla, AST_LIST_EMPTY, sla_process_timers(), ast_cond_timedwait, ast_cond_wait, AST_LIST_REMOVE_HEAD, ast_mutex_unlock, sla_event::type, SLA_EVENT_HOLD, sla_handle_hold_event(), SLA_EVENT_DIAL_STATE, sla_handle_dial_state_event(), SLA_EVENT_RINGING_TRUNK, sla_handle_ringing_trunk_event(), SLA_EVENT_RELOAD, SLA_EVENT_CHECK_RELOAD, ast_free, and sla_check_reload().
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;
case SLA_EVENT_RELOAD:
sla.reload = 1;
case SLA_EVENT_CHECK_RELOAD:
break;
}
ast_free(event);
ast_mutex_lock(&sla.lock);
}
if (sla.reload) {
sla_check_reload();
}
}
ast_mutex_unlock(&sla.lock);
while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
ast_free(ringing_station);
while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
ast_free(failed_station);
return NULL;
}
| static int sla_trunk_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 6306 of file app_meetme.c.
References MAX_CONFNUM, AST_DECLARE_APP_ARGS, args, AST_APP_ARG, SLA_TRUNK_OPT_ARG_ARRAY_SIZE, parse(), ast_strlen_zero(), ast_log(), LOG_ERROR, ast_strdupa, AST_STANDARD_APP_ARGS, ast_app_parse_options(), sla_trunk_opts, AST_RWLIST_RDLOCK, sla_find_trunk(), ast_atomic_fetchadd_int(), sla_trunk::ref_count, AST_RWLIST_UNLOCK, pbx_builtin_setvar_helper(), sla_queue_event(), SLA_EVENT_CHECK_RELOAD, sla_trunk::chan, queue_ringing_trunk(), build_conf(), ast_set_flag64, CONFFLAG_QUIET, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_NO_AUDIO_UNTIL_UP, ast_test_flag, SLA_TRUNK_OPT_MOH, ast_indicate(), CONFFLAG_MOH, AST_CONTROL_RINGING, conf_run(), dispose_conf(), sla_trunk::on_hold, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, pbx_builtin_getvar_helper(), ast_mutex_lock, sla, AST_LIST_TRAVERSE_SAFE_BEGIN, sla_ringing_trunk::trunk, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_unlock, ast_free, and SLA_EVENT_RINGING_TRUNK.
Referenced by load_module().
{
char conf_name[MAX_CONFNUM];
struct ast_conference *conf;
struct ast_flags64 conf_flags = { 0 };
struct sla_trunk *trunk;
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;
}
}
AST_RWLIST_RDLOCK(&sla_trunks);
trunk = sla_find_trunk(args.trunk_name);
if (trunk)
ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
AST_RWLIST_UNLOCK(&sla_trunks);
if (!trunk) {
ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
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");
ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
return 0;
}
trunk->chan = chan;
if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
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");
ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
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) {
ast_free(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);
}
ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
sla_queue_event(SLA_EVENT_CHECK_RELOAD);
return 0;
}
| static const char* trunkstate2str | ( | enum sla_trunk_state | state | ) | [static] |
Definition at line 1668 of file app_meetme.c.
References S, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, SLA_TRUNK_STATE_ONHOLD, and SLA_TRUNK_STATE_ONHOLD_BYME.
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 1083 of file app_meetme.c.
References tweak_volume(), ast_conf_user::listen, set_listen_volume(), volume::desired, and volume::actual.
Referenced by conf_run(), user_listen_volup_cb(), user_listen_voldown_cb(), and admin_exec().
| static void tweak_talk_volume | ( | struct ast_conf_user * | user, |
| enum volume_action | action | ||
| ) | [static] |
Definition at line 1071 of file app_meetme.c.
References tweak_volume(), ast_conf_user::talk, set_talk_volume(), volume::desired, and volume::actual.
Referenced by conf_run(), user_talk_volup_cb(), user_talk_voldown_cb(), and admin_exec().
| static void tweak_volume | ( | struct volume * | vol, |
| enum volume_action | action | ||
| ) | [static] |
Definition at line 1036 of file app_meetme.c.
References VOL_UP, volume::desired, and VOL_DOWN.
Referenced by tweak_talk_volume(), and tweak_listen_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 7096 of file app_meetme.c.
References ast_cli_unregister_multiple(), ARRAY_LEN, ast_manager_unregister(), ast_unregister_application(), AST_TEST_UNREGISTER, ast_data_unregister, ast_devstate_prov_del(), sla_destroy(), ast_custom_function_unregister(), and ast_unload_realtime().
{
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_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 6947 of file app_meetme.c.
References ast_data_add_node(), ast_data_add_structure, ast_channel_data_add_structure(), ast_conf_user::chan, ast_data_add_int(), ast_conf_user::listen, volume::desired, volume::actual, 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 4483 of file app_meetme.c.
References args, ast_conf_user::chan, ast_channel::name, CMP_MATCH, and CMP_STOP.
Referenced by channel_admin_exec().
| static int user_listen_voldown_cb | ( | void * | obj, |
| void * | unused, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4455 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 4448 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 1149 of file app_meetme.c.
References ast_conf_user::user_no.
Referenced by conf_run(), and admin_exec().
{
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 1137 of file app_meetme.c.
References ast_conf_user::user_no, CMP_MATCH, and CMP_STOP.
Referenced by build_conf().
| static int user_reset_vol_cb | ( | void * | obj, |
| void * | unused, | ||
| int | flags | ||
| ) | [static] |
Definition at line 4476 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_kickme_cb | ( | void * | obj, |
| void * | check_admin_arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 2157 of file app_meetme.c.
References ast_test_flag64, ast_conf_user::userflags, CONFFLAG_ADMIN, ast_conf_user::adminflags, and ADMINFLAG_KICKME.
Referenced by conf_run(), and admin_exec().
{
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 2179 of file app_meetme.c.
References ast_test_flag64, ast_conf_user::userflags, CONFFLAG_ADMIN, ast_conf_user::adminflags, and ADMINFLAG_MUTED.
Referenced by conf_run(), and admin_exec().
{
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 2168 of file app_meetme.c.
References ast_test_flag64, ast_conf_user::userflags, CONFFLAG_ADMIN, ast_conf_user::adminflags, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, and ADMINFLAG_T_REQUEST.
Referenced by conf_run(), and admin_exec().
{
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 4469 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 4462 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 = "7a1b8b48c852d7a7061c7e499b9bd0d2" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, } [static] |
Definition at line 7171 of file app_meetme.c.
const char* const app = "MeetMe" [static] |
Definition at line 656 of file app_meetme.c.
const char* const app2 = "MeetMeCount" [static] |
Definition at line 657 of file app_meetme.c.
const char* const app3 = "MeetMeAdmin" [static] |
Definition at line 658 of file app_meetme.c.
const char* const app4 = "MeetMeChannelAdmin" [static] |
Definition at line 659 of file app_meetme.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 7171 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 939 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 948 of file app_meetme.c.
Referenced by conf_run().
struct ast_cli_entry cli_meetme[] [static] |
Definition at line 1758 of file app_meetme.c.
Definition at line 930 of file app_meetme.c.
Referenced by _macro_exec(), sla_handle_dial_state_event(), sla_station_exec(), gosubif_exec(), usbradio_indicate(), ast_safe_sleep_conditional(), and smdi_message_wait().
unsigned int conf_map[1024] = {0, } [static] |
Definition at line 741 of file app_meetme.c.
Referenced by build_conf(), dispose_conf(), and conf_exec().
int earlyalert [static] |
Definition at line 666 of file app_meetme.c.
Referenced by find_conf_realtime().
int endalert [static] |
Definition at line 667 of file app_meetme.c.
Referenced by find_conf_realtime().
| struct { ... } event_q |
int extendby [static] |
Definition at line 668 of file app_meetme.c.
Referenced by rt_extend_conf().
| struct { ... } failed_stations |
Definition at line 932 of file app_meetme.c.
Referenced by log_jack_status(), multiplexed_thread_function(), generic_thread_loop(), odbc_log(), pgsql_log(), ast_print_group(), ast_format_str_reduce(), realtimefield_read(), listfilter(), context_merge(), get_goto_target(), check_goto(), gen_prios(), update2_curl(), update2_prepare(), update2_pgsql(), cdr_handler(), realtime_update2_handler(), ast_fax_caps_to_str(), generate_filenames_string(), h263p_encap(), h263_encap(), h261_encap(), mpeg4_encap(), h264_encap(), xmldoc_parse_cmd_enumlist(), xmldoc_get_syntax_cmd(), and ast_xmldoc_build_seealso().
int fuzzystart [static] |
Definition at line 665 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 957 of file app_meetme.c.
Definition at line 932 of file app_meetme.c.
Referenced by node_lookup(), internal_ao2_callback(), do_monitor(), gtalk_free_candidates(), try_firmware(), jingle_free_candidates(), ast_config_engine_deregister(), process_db_keys(), ast_db_freetree(), update_scoreboard(), load_password(), apply_outgoing(), add_extensions(), config_odbc(), config_pgsql(), and aji_handle_presence().
Definition at line 931 of file app_meetme.c.
Referenced by load_rpt_vars(), rpt_master(), unload_module(), write_cdr(), reload(), ast_localtime_wakeup_monitor(), and smdi_message_wait().
struct ast_data_handler meetme_data_provider [static] |
{
.version = AST_DATA_HANDLER_VERSION,
.get = meetme_data_provider_get
}
Definition at line 7027 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 7032 of file app_meetme.c.
struct ast_custom_function meetme_info_acf [static] |
{
.name = "MEETME_INFO",
.read = acf_meetme_info,
}
Definition at line 6898 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 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ '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 654 of file app_meetme.c.
Referenced by find_conf_realtime(), and conf_exec().
| static int reload |
A reload has been requested
reload: Part of Asterisk module interface ---
Definition at line 941 of file app_meetme.c.
Referenced by handle_minivm_reload(), rpt_do_reload(), reload(), and handle_cli_moh_reload().
| struct { ... } ringing_stations |
| struct { ... } ringing_trunks |
int rt_log_members [static] |
Log participant count to the RealTime backend
Definition at line 671 of file app_meetme.c.
int rt_schedule [static] |
Definition at line 664 of file app_meetme.c.
struct { ... } sla [static] |
A structure for data used by the sla thread.
Referenced by sla_queue_event_full(), sla_stop_ringing_station(), sla_choose_ringing_trunk(), sla_handle_dial_state_event(), sla_check_ringing_station(), sla_check_failed_station(), sla_ring_station(), sla_ring_stations(), sla_hangup_stations(), sla_handle_ringing_trunk_event(), sla_calc_trunk_timeouts(), sla_calc_station_timeouts(), sla_check_reload(), sla_thread(), dial_trunk(), sla_station_exec(), queue_ringing_trunk(), sla_trunk_exec(), sla_destroy(), sla_load_config(), and load_config().
const char sla_registrar[] = "SLA" [static] |
Definition at line 871 of file app_meetme.c.
Referenced by destroy_trunk(), destroy_station(), sla_destroy(), sla_build_trunk(), and sla_build_station().
struct sla_stations 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] |
Definition at line 6304 of file app_meetme.c.
Referenced by sla_trunk_exec().
struct sla_trunks sla_trunks [static] |
const char* const slastation_app = "SLAStation" [static] |
Definition at line 660 of file app_meetme.c.
const char* const slatrunk_app = "SLATrunk" [static] |
Definition at line 661 of file app_meetme.c.
| unsigned int stop |
Definition at line 936 of file app_meetme.c.
Referenced by controlplayback_exec(), queue_exec(), park_add_hints(), build_dialplan_useage_spaces(), usage_context_add_spaces(), remove_dead_spaces_usage(), handle_controlstreamfile(), cops_gate_cmd(), and pktccops_show_pools().
| pthread_t thread |
The SLA thread ID
Definition at line 929 of file app_meetme.c.
Referenced by launch_monitor_thread(), multiplexed_add_or_remove(), ast_bridge_depart(), find_idle_thread(), __schedule_action(), handle_cli_iax2_show_threads(), socket_read(), iax2_process_thread_cleanup(), iax2_process_thread(), start_network_thread(), cleanup_thread_list(), unload_module(), bridge_call_thread_launch(), and load_module().