#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 "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 | 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 | MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n" |
| #define | MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n" |
| #define | MEETME_DELAYDETECTENDTALK 1000 |
| #define | MEETME_DELAYDETECTTALK 300 |
| #define | OPTIONS_LEN 100 |
| #define | S(e) case e: return # e; |
| #define | SLA_CONFIG_FILE "sla.conf" |
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), CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31) } |
| 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_ARRAY_SIZE = 5 } |
| 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 | __fini_sla_stations (void) |
| static void | __fini_sla_trunks (void) |
| static void | __init_sla_stations (void) |
| static void | __init_sla_trunks (void) |
| 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) |
| 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) |
| Find or create a conference. | |
| static int | can_write (struct ast_channel *chan, int 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, int 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_flags *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_flags *confflags, int *too_early) |
| 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 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 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 | 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) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| 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 int | earlyalert |
| static int | endalert |
| static int | extendby |
| static int | fuzzystart |
| static const char | gain_map [] |
| 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 }, [ '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 ast_app_option | sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, } |
| static const char *const | slastation_app = "SLAStation" |
| static const char *const | slatrunk_app = "SLATrunk" |
Definition in file app_meetme.c.
| #define AST_FRAME_BITS 32 |
Definition at line 519 of file app_meetme.c.
Referenced by conf_free(), conf_run(), and recordthread().
| #define CONF_SIZE 320 |
Definition at line 538 of file app_meetme.c.
| #define CONFIG_FILE_NAME "meetme.conf" |
Definition at line 499 of file app_meetme.c.
Referenced by _dsp_init(), conf_exec(), find_conf(), and load_config_meetme().
| #define DATE_FORMAT "%Y-%m-%d %H:%M:%S" |
String format for scheduled conferences
Definition at line 506 of file app_meetme.c.
Referenced by append_date(), build_radius_record(), conf_run(), execute_cb(), find_conf_realtime(), format_date(), get_date(), manager_log(), pgsql_log(), and rt_extend_conf().
| #define DEFAULT_AUDIO_BUFFERS 32 |
each buffer is 20ms, so this is 640ms total
Definition at line 503 of file app_meetme.c.
Referenced by load_config_meetme().
| #define MAX_CONFNUM 80 |
Definition at line 659 of file app_meetme.c.
Referenced by conf_exec(), dial_trunk(), meetme_cmd(), meetme_show_cmd(), sla_station_exec(), and sla_trunk_exec().
| #define MAX_PIN 80 |
| #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_DELAYDETECTENDTALK 1000 |
| #define MEETME_DELAYDETECTTALK 300 |
| #define OPTIONS_LEN 100 |
| #define S | ( | e | ) | case e: return # e; |
Referenced by sms_readfile(), and trunkstate2str().
| #define SLA_CONFIG_FILE "sla.conf" |
Definition at line 500 of file app_meetme.c.
Referenced by sla_build_station(), sla_build_trunk(), 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 508 of file app_meetme.c.
00508 { 00509 ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */ 00510 ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */ 00511 ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */ 00512 /*! User has requested to speak */ 00513 ADMINFLAG_T_REQUEST = (1 << 4), 00514 };
| anonymous enum |
| CONFFLAG_ADMIN | user has admin access on the conference |
| CONFFLAG_MONITOR | If set the user can only receive audio from the conference |
| CONFFLAG_KEYEXIT | If set asterisk will exit conference when key defined in p() option is pressed |
| CONFFLAG_STARMENU | If set asterisk will provide a menu to the user when '*' is pressed |
| CONFFLAG_TALKER | If set the use can only send audio to the conference |
| CONFFLAG_QUIET | If set there will be no enter or leave sounds |
| CONFFLAG_ANNOUNCEUSERCOUNT | If set, when user joins the conference, they will be told the number of users that are already in |
| CONFFLAG_AGI | Set to run AGI Script in Background |
| CONFFLAG_MOH | Set to have music on hold when user is alone in conference |
| CONFFLAG_MARKEDEXIT | If set the MeetMe will return if all marked with this flag left |
| CONFFLAG_WAITMARKED | If set, the MeetMe will wait until a marked user enters |
| CONFFLAG_EXIT_CONTEXT | If set, the MeetMe will exit to the specified context |
| CONFFLAG_MARKEDUSER | If set, the user will be marked |
| CONFFLAG_INTROUSER | If set, user will be ask record name on entry of conference |
| CONFFLAG_RECORDCONF | If set, the MeetMe will be recorded |
| CONFFLAG_MONITORTALKER | If set, the user will be monitored if the user is talking or not |
| CONFFLAG_DYNAMIC | |
| CONFFLAG_DYNAMICPIN | |
| CONFFLAG_EMPTY | |
| CONFFLAG_EMPTYNOPIN | |
| CONFFLAG_ALWAYSPROMPT | |
| CONFFLAG_OPTIMIZETALKER | If set, treat talking users as muted users |
| CONFFLAG_NOONLYPERSON | If set, won't speak the extra prompt when the first person enters the conference |
| CONFFLAG_INTROUSERNOREVIEW | If set, user will be asked to record name on entry of conference without review |
| CONFFLAG_STARTMUTED | If set, the user will be initially self-muted |
| CONFFLAG_PASS_DTMF | Pass DTMF through the conference |
| CONFFLAG_SLA_STATION | |
| CONFFLAG_SLA_TRUNK | |
| CONFFLAG_KICK_CONTINUE | If set, the user should continue in the dialplan if kicked out |
| CONFFLAG_DURATION_STOP | |
| CONFFLAG_DURATION_LIMIT | |
| CONFFLAG_NO_AUDIO_UNTIL_UP | Do not write any audio to this channel until the state is up. |
Definition at line 540 of file app_meetme.c.
00540 { 00541 /*! user has admin access on the conference */ 00542 CONFFLAG_ADMIN = (1 << 0), 00543 /*! If set the user can only receive audio from the conference */ 00544 CONFFLAG_MONITOR = (1 << 1), 00545 /*! If set asterisk will exit conference when key defined in p() option is pressed */ 00546 CONFFLAG_KEYEXIT = (1 << 2), 00547 /*! If set asterisk will provide a menu to the user when '*' is pressed */ 00548 CONFFLAG_STARMENU = (1 << 3), 00549 /*! If set the use can only send audio to the conference */ 00550 CONFFLAG_TALKER = (1 << 4), 00551 /*! If set there will be no enter or leave sounds */ 00552 CONFFLAG_QUIET = (1 << 5), 00553 /*! If set, when user joins the conference, they will be told the number 00554 * of users that are already in */ 00555 CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6), 00556 /*! Set to run AGI Script in Background */ 00557 CONFFLAG_AGI = (1 << 7), 00558 /*! Set to have music on hold when user is alone in conference */ 00559 CONFFLAG_MOH = (1 << 8), 00560 /*! If set the MeetMe will return if all marked with this flag left */ 00561 CONFFLAG_MARKEDEXIT = (1 << 9), 00562 /*! If set, the MeetMe will wait until a marked user enters */ 00563 CONFFLAG_WAITMARKED = (1 << 10), 00564 /*! If set, the MeetMe will exit to the specified context */ 00565 CONFFLAG_EXIT_CONTEXT = (1 << 11), 00566 /*! If set, the user will be marked */ 00567 CONFFLAG_MARKEDUSER = (1 << 12), 00568 /*! If set, user will be ask record name on entry of conference */ 00569 CONFFLAG_INTROUSER = (1 << 13), 00570 /*! If set, the MeetMe will be recorded */ 00571 CONFFLAG_RECORDCONF = (1<< 14), 00572 /*! If set, the user will be monitored if the user is talking or not */ 00573 CONFFLAG_MONITORTALKER = (1 << 15), 00574 CONFFLAG_DYNAMIC = (1 << 16), 00575 CONFFLAG_DYNAMICPIN = (1 << 17), 00576 CONFFLAG_EMPTY = (1 << 18), 00577 CONFFLAG_EMPTYNOPIN = (1 << 19), 00578 CONFFLAG_ALWAYSPROMPT = (1 << 20), 00579 /*! If set, treat talking users as muted users */ 00580 CONFFLAG_OPTIMIZETALKER = (1 << 21), 00581 /*! If set, won't speak the extra prompt when the first person 00582 * enters the conference */ 00583 CONFFLAG_NOONLYPERSON = (1 << 22), 00584 /*! If set, user will be asked to record name on entry of conference 00585 * without review */ 00586 CONFFLAG_INTROUSERNOREVIEW = (1 << 23), 00587 /*! If set, the user will be initially self-muted */ 00588 CONFFLAG_STARTMUTED = (1 << 24), 00589 /*! Pass DTMF through the conference */ 00590 CONFFLAG_PASS_DTMF = (1 << 25), 00591 CONFFLAG_SLA_STATION = (1 << 26), 00592 CONFFLAG_SLA_TRUNK = (1 << 27), 00593 /*! If set, the user should continue in the dialplan if kicked out */ 00594 CONFFLAG_KICK_CONTINUE = (1 << 28), 00595 CONFFLAG_DURATION_STOP = (1 << 29), 00596 CONFFLAG_DURATION_LIMIT = (1 << 30), 00597 /*! Do not write any audio to this channel until the state is up. */ 00598 CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31), 00599 };
| anonymous enum |
| OPT_ARG_WAITMARKED | |
| OPT_ARG_EXITKEYS | |
| OPT_ARG_DURATION_STOP | |
| OPT_ARG_DURATION_LIMIT | |
| OPT_ARG_MOH_CLASS | |
| OPT_ARG_ARRAY_SIZE |
Definition at line 601 of file app_meetme.c.
00601 { 00602 OPT_ARG_WAITMARKED = 0, 00603 OPT_ARG_EXITKEYS = 1, 00604 OPT_ARG_DURATION_STOP = 2, 00605 OPT_ARG_DURATION_LIMIT = 3, 00606 OPT_ARG_MOH_CLASS = 4, 00607 OPT_ARG_ARRAY_SIZE = 5, 00608 };
| anonymous enum |
| anonymous enum |
Definition at line 5855 of file app_meetme.c.
05855 { 05856 SLA_TRUNK_OPT_ARG_MOH_CLASS = 0, 05857 SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1, 05858 };
| enum announcetypes |
Definition at line 663 of file app_meetme.c.
00663 { 00664 CONF_HASJOIN, 00665 CONF_HASLEFT 00666 };
| enum entrance_sound |
| enum recording_state |
Definition at line 531 of file app_meetme.c.
00531 { 00532 MEETME_RECORD_OFF, 00533 MEETME_RECORD_STARTED, 00534 MEETME_RECORD_ACTIVE, 00535 MEETME_RECORD_TERMINATE 00536 };
| enum sla_event_type |
Event types that can be queued up for the SLA thread.
| SLA_EVENT_HOLD | A station has put the call on hold |
| SLA_EVENT_DIAL_STATE | The state of a dial has changed |
| SLA_EVENT_RINGING_TRUNK | The state of a ringing trunk has changed |
| SLA_EVENT_RELOAD | A reload of configuration has been requested |
| SLA_EVENT_CHECK_RELOAD | Poke the SLA thread so it can check if it can perform a reload |
Definition at line 856 of file app_meetme.c.
00856 { 00857 /*! A station has put the call on hold */ 00858 SLA_EVENT_HOLD, 00859 /*! The state of a dial has changed */ 00860 SLA_EVENT_DIAL_STATE, 00861 /*! The state of a ringing trunk has changed */ 00862 SLA_EVENT_RINGING_TRUNK, 00863 /*! A reload of configuration has been requested */ 00864 SLA_EVENT_RELOAD, 00865 /*! Poke the SLA thread so it can check if it can perform a reload */ 00866 SLA_EVENT_CHECK_RELOAD, 00867 };
| enum sla_hold_access |
Definition at line 766 of file app_meetme.c.
00766 { 00767 /*! This means that any station can put it on hold, and any station 00768 * can retrieve the call from hold. */ 00769 SLA_HOLD_OPEN, 00770 /*! This means that only the station that put the call on hold may 00771 * retrieve it from hold. */ 00772 SLA_HOLD_PRIVATE, 00773 };
| enum sla_station_hangup |
Definition at line 893 of file app_meetme.c.
00893 { 00894 SLA_STATION_HANGUP_NORMAL, 00895 SLA_STATION_HANGUP_TIMEOUT, 00896 };
| 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 758 of file app_meetme.c.
00758 { 00759 SLA_TRUNK_STATE_IDLE, 00760 SLA_TRUNK_STATE_RINGING, 00761 SLA_TRUNK_STATE_UP, 00762 SLA_TRUNK_STATE_ONHOLD, 00763 SLA_TRUNK_STATE_ONHOLD_BYME, 00764 };
| enum sla_which_trunk_refs |
Definition at line 753 of file app_meetme.c.
00753 { 00754 ALL_TRUNK_REFS, 00755 INACTIVE_TRUNK_REFS, 00756 };
| enum volume_action |
| static void __fini_sla_stations | ( | void | ) | [static] |
| static void __fini_sla_trunks | ( | void | ) | [static] |
| static void __init_sla_stations | ( | void | ) | [static] |
| static void __init_sla_trunks | ( | void | ) | [static] |
| static void __reg_module | ( | void | ) | [static] |
Definition at line 6542 of file app_meetme.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 6542 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 6411 of file app_meetme.c.
References acf_meetme_info_eval(), AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conference::confno, ast_conference::list, LOG_ERROR, and parse().
06412 { 06413 struct ast_conference *conf; 06414 char *parse; 06415 int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */ 06416 AST_DECLARE_APP_ARGS(args, 06417 AST_APP_ARG(keyword); 06418 AST_APP_ARG(confno); 06419 ); 06420 06421 if (ast_strlen_zero(data)) { 06422 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n"); 06423 return -1; 06424 } 06425 06426 parse = ast_strdupa(data); 06427 AST_STANDARD_APP_ARGS(args, parse); 06428 06429 if (ast_strlen_zero(args.keyword)) { 06430 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n"); 06431 return -1; 06432 } 06433 06434 if (ast_strlen_zero(args.confno)) { 06435 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n"); 06436 return -1; 06437 } 06438 06439 AST_LIST_LOCK(&confs); 06440 AST_LIST_TRAVERSE(&confs, conf, list) { 06441 if (!strcmp(args.confno, conf->confno)) { 06442 result = acf_meetme_info_eval(args.keyword, conf); 06443 break; 06444 } 06445 } 06446 AST_LIST_UNLOCK(&confs); 06447 06448 if (result > -1) { 06449 snprintf(buf, len, "%d", result); 06450 } else if (result == -1) { 06451 snprintf(buf, len, "%s %s", "Error: invalid keyword:", args.keyword); 06452 } else if (result == -2) { 06453 snprintf(buf, len, "Error: conference (%s) not found", args.confno); 06454 } 06455 06456 return 0; 06457 }
| static int acf_meetme_info_eval | ( | const char * | keyword, | |
| const struct ast_conference * | conf | |||
| ) | [static] |
Definition at line 6393 of file app_meetme.c.
References ast_conference::isdynamic, ast_conference::locked, ast_conference::start, and ast_conference::users.
Referenced by acf_meetme_info().
06394 { 06395 if (!strcasecmp("lock", keyword)) { 06396 return conf->locked; 06397 } else if (!strcasecmp("parties", keyword)) { 06398 return conf->users; 06399 } else if (!strcasecmp("activity", keyword)) { 06400 time_t now; 06401 now = time(NULL); 06402 return (now - conf->start); 06403 } else if (!strcasecmp("dynamic", keyword)) { 06404 return conf->isdynamic; 06405 } else { 06406 return -1; 06407 } 06408 06409 }
| static int action_meetmelist | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 4348 of file app_meetme.c.
References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_conf_user::list, ast_channel::name, S_OR, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conf_user::userflags, and ast_conference::userlist.
Referenced by load_module().
04349 { 04350 const char *actionid = astman_get_header(m, "ActionID"); 04351 const char *conference = astman_get_header(m, "Conference"); 04352 char idText[80] = ""; 04353 struct ast_conference *cnf; 04354 struct ast_conf_user *user; 04355 int total = 0; 04356 04357 if (!ast_strlen_zero(actionid)) 04358 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid); 04359 04360 if (AST_LIST_EMPTY(&confs)) { 04361 astman_send_error(s, m, "No active conferences."); 04362 return 0; 04363 } 04364 04365 astman_send_listack(s, m, "Meetme user list will follow", "start"); 04366 04367 /* Find the right conference */ 04368 AST_LIST_LOCK(&confs); 04369 AST_LIST_TRAVERSE(&confs, cnf, list) { 04370 /* If we ask for one particular, and this isn't it, skip it */ 04371 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference)) 04372 continue; 04373 04374 /* Show all the users */ 04375 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04376 total++; 04377 astman_append(s, 04378 "Event: MeetmeList\r\n" 04379 "%s" 04380 "Conference: %s\r\n" 04381 "UserNumber: %d\r\n" 04382 "CallerIDNum: %s\r\n" 04383 "CallerIDName: %s\r\n" 04384 "Channel: %s\r\n" 04385 "Admin: %s\r\n" 04386 "Role: %s\r\n" 04387 "MarkedUser: %s\r\n" 04388 "Muted: %s\r\n" 04389 "Talking: %s\r\n" 04390 "\r\n", 04391 idText, 04392 cnf->confno, 04393 user->user_no, 04394 S_OR(user->chan->cid.cid_num, "<unknown>"), 04395 S_OR(user->chan->cid.cid_name, "<no name>"), 04396 user->chan->name, 04397 user->userflags & CONFFLAG_ADMIN ? "Yes" : "No", 04398 user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen", 04399 user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No", 04400 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No", 04401 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored"); 04402 } 04403 } 04404 AST_LIST_UNLOCK(&confs); 04405 /* Send final confirmation */ 04406 astman_append(s, 04407 "Event: MeetmeListComplete\r\n" 04408 "EventList: Complete\r\n" 04409 "ListItems: %d\r\n" 04410 "%s" 04411 "\r\n", total, idText); 04412 return 0; 04413 }
| static int action_meetmemute | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 4338 of file app_meetme.c.
References meetmemute().
Referenced by load_module().
04339 { 04340 return meetmemute(s, m, 1); 04341 }
| static int action_meetmeunmute | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 4343 of file app_meetme.c.
References meetmemute().
Referenced by load_module().
04344 { 04345 return meetmemute(s, m, 0); 04346 }
| static int admin_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
The MeetMeadmin application.
MeetMeAdmin(confno, command, caller)
Definition at line 4033 of file app_meetme.c.
References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), CONFFLAG_ADMIN, ast_conference::confno, dispose_conf(), find_user(), ast_conf_user::list, ast_conference::locked, LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), ast_conference::refcount, reset_volumes(), rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), ast_conf_user::userflags, ast_conference::userlist, VOL_DOWN, and VOL_UP.
Referenced by load_module(), meetme_cmd(), meetme_show_cmd(), run_station(), sla_station_exec(), and sla_stop_ringing_trunk().
04033 { 04034 char *params; 04035 struct ast_conference *cnf; 04036 struct ast_conf_user *user = NULL; 04037 AST_DECLARE_APP_ARGS(args, 04038 AST_APP_ARG(confno); 04039 AST_APP_ARG(command); 04040 AST_APP_ARG(user); 04041 ); 04042 int res = 0; 04043 04044 if (ast_strlen_zero(data)) { 04045 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n"); 04046 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE"); 04047 return -1; 04048 } 04049 04050 params = ast_strdupa(data); 04051 AST_STANDARD_APP_ARGS(args, params); 04052 04053 if (!args.command) { 04054 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n"); 04055 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE"); 04056 return -1; 04057 } 04058 04059 AST_LIST_LOCK(&confs); 04060 AST_LIST_TRAVERSE(&confs, cnf, list) { 04061 if (!strcmp(cnf->confno, args.confno)) 04062 break; 04063 } 04064 04065 if (!cnf) { 04066 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno); 04067 AST_LIST_UNLOCK(&confs); 04068 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND"); 04069 return 0; 04070 } 04071 04072 ast_atomic_fetchadd_int(&cnf->refcount, 1); 04073 04074 if (args.user) 04075 user = find_user(cnf, args.user); 04076 04077 switch (*args.command) { 04078 case 76: /* L: Lock */ 04079 cnf->locked = 1; 04080 break; 04081 case 108: /* l: Unlock */ 04082 cnf->locked = 0; 04083 break; 04084 case 75: /* K: kick all users */ 04085 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 04086 user->adminflags |= ADMINFLAG_KICKME; 04087 break; 04088 case 101: /* e: Eject last user*/ 04089 user = AST_LIST_LAST(&cnf->userlist); 04090 if (!(user->userflags & CONFFLAG_ADMIN)) 04091 user->adminflags |= ADMINFLAG_KICKME; 04092 else { 04093 res = -1; 04094 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n"); 04095 } 04096 break; 04097 case 77: /* M: Mute */ 04098 if (user) { 04099 user->adminflags |= ADMINFLAG_MUTED; 04100 } else { 04101 res = -2; 04102 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04103 } 04104 break; 04105 case 78: /* N: Mute all (non-admin) users */ 04106 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04107 if (!(user->userflags & CONFFLAG_ADMIN)) { 04108 user->adminflags |= ADMINFLAG_MUTED; 04109 } 04110 } 04111 break; 04112 case 109: /* m: Unmute */ 04113 if (user) { 04114 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); 04115 } else { 04116 res = -2; 04117 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04118 } 04119 break; 04120 case 110: /* n: Unmute all users */ 04121 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04122 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); 04123 } 04124 break; 04125 case 107: /* k: Kick user */ 04126 if (user) { 04127 user->adminflags |= ADMINFLAG_KICKME; 04128 } else { 04129 res = -2; 04130 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04131 } 04132 break; 04133 case 118: /* v: Lower all users listen volume */ 04134 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04135 tweak_listen_volume(user, VOL_DOWN); 04136 } 04137 break; 04138 case 86: /* V: Raise all users listen volume */ 04139 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04140 tweak_listen_volume(user, VOL_UP); 04141 } 04142 break; 04143 case 115: /* s: Lower all users speaking volume */ 04144 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04145 tweak_talk_volume(user, VOL_DOWN); 04146 } 04147 break; 04148 case 83: /* S: Raise all users speaking volume */ 04149 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04150 tweak_talk_volume(user, VOL_UP); 04151 } 04152 break; 04153 case 82: /* R: Reset all volume levels */ 04154 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 04155 reset_volumes(user); 04156 } 04157 break; 04158 case 114: /* r: Reset user's volume level */ 04159 if (user) { 04160 reset_volumes(user); 04161 } else { 04162 res = -2; 04163 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04164 } 04165 break; 04166 case 85: /* U: Raise user's listen volume */ 04167 if (user) { 04168 tweak_listen_volume(user, VOL_UP); 04169 } else { 04170 res = -2; 04171 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04172 } 04173 break; 04174 case 117: /* u: Lower user's listen volume */ 04175 if (user) { 04176 tweak_listen_volume(user, VOL_DOWN); 04177 } else { 04178 res = -2; 04179 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04180 } 04181 break; 04182 case 84: /* T: Raise user's talk volume */ 04183 if (user) { 04184 tweak_talk_volume(user, VOL_UP); 04185 } else { 04186 res = -2; 04187 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04188 } 04189 break; 04190 case 116: /* t: Lower user's talk volume */ 04191 if (user) { 04192 tweak_talk_volume(user, VOL_DOWN); 04193 } else { 04194 res = -2; 04195 ast_log(LOG_NOTICE, "Specified User not found!\n"); 04196 } 04197 break; 04198 case 'E': /* E: Extend conference */ 04199 if (rt_extend_conf(args.confno)) { 04200 res = -1; 04201 } 04202 break; 04203 } 04204 04205 AST_LIST_UNLOCK(&confs); 04206 04207 dispose_conf(cnf); 04208 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK"); 04209 04210 return 0; 04211 }
| static void* announce_thread | ( | void * | data | ) | [static] |
Definition at line 1981 of file app_meetme.c.
References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread_stop, announce_listitem::announcetype, ao2_ref, ast_check_hangup(), ast_cond_wait(), ast_copy_string(), ast_filedelete(), ast_fileexists(), AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_REMOVE_HEAD, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), CONF_HASLEFT, announce_listitem::confchan, announce_listitem::confusers, get_announce_filename(), announce_listitem::language, LOG_DEBUG, and announce_listitem::namerecloc.
Referenced by conf_run().
01982 { 01983 struct announce_listitem *current; 01984 struct ast_conference *conf = data; 01985 int res; 01986 char filename[PATH_MAX] = ""; 01987 AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list; 01988 AST_LIST_HEAD_INIT_NOLOCK(&local_list); 01989 01990 while (!conf->announcethread_stop) { 01991 ast_mutex_lock(&conf->announcelistlock); 01992 if (conf->announcethread_stop) { 01993 ast_mutex_unlock(&conf->announcelistlock); 01994 break; 01995 } 01996 if (AST_LIST_EMPTY(&conf->announcelist)) 01997 ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock); 01998 01999 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry); 02000 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist); 02001 02002 ast_mutex_unlock(&conf->announcelistlock); 02003 if (conf->announcethread_stop) { 02004 break; 02005 } 02006 02007 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) { 02008 ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc); 02009 if (!ast_fileexists(current->namerecloc, NULL, NULL)) 02010 continue; 02011 if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) { 02012 if (!ast_streamfile(current->confchan, current->namerecloc, current->language)) 02013 res = ast_waitstream(current->confchan, ""); 02014 if (!res) { 02015 ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename)); 02016 if (!ast_streamfile(current->confchan, filename, current->language)) 02017 ast_waitstream(current->confchan, ""); 02018 } 02019 } 02020 if (current->announcetype == CONF_HASLEFT) { 02021 ast_filedelete(current->namerecloc, NULL); 02022 } 02023 } 02024 } 02025 02026 /* thread marked to stop, clean up */ 02027 while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) { 02028 ast_filedelete(current->namerecloc, NULL); 02029 ao2_ref(current, -1); 02030 } 02031 return NULL; 02032 }
| static void answer_trunk_chan | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 4723 of file app_meetme.c.
References ast_answer(), and ast_indicate().
Referenced by run_station(), sla_handle_dial_state_event(), and sla_station_exec().
04724 { 04725 ast_answer(chan); 04726 ast_indicate(chan, -1); 04727 }
| 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 | |||
| ) | [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 1132 of file app_meetme.c.
References ast_conference::announcethread, ast_conference::announcethreadlock, ast_atomic_fetchadd_int(), ast_calloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_free, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_channel::fds, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, ast_channel::uniqueid, and ast_conference::uniqueid.
Referenced by dial_trunk(), find_conf(), find_conf_realtime(), run_station(), sla_station_exec(), and sla_trunk_exec().
01135 { 01136 struct ast_conference *cnf; 01137 struct dahdi_confinfo dahdic = { 0, }; 01138 int confno_int = 0; 01139 01140 AST_LIST_LOCK(&confs); 01141 01142 AST_LIST_TRAVERSE(&confs, cnf, list) { 01143 if (!strcmp(confno, cnf->confno)) 01144 break; 01145 } 01146 01147 if (cnf || (!make && !dynamic)) 01148 goto cnfout; 01149 01150 /* Make a new one */ 01151 if (!(cnf = ast_calloc(1, sizeof(*cnf)))) 01152 goto cnfout; 01153 01154 ast_mutex_init(&cnf->playlock); 01155 ast_mutex_init(&cnf->listenlock); 01156 cnf->recordthread = AST_PTHREADT_NULL; 01157 ast_mutex_init(&cnf->recordthreadlock); 01158 cnf->announcethread = AST_PTHREADT_NULL; 01159 ast_mutex_init(&cnf->announcethreadlock); 01160 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno)); 01161 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin)); 01162 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin)); 01163 ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid)); 01164 01165 /* Setup a new dahdi conference */ 01166 dahdic.confno = -1; 01167 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; 01168 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR); 01169 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) { 01170 ast_log(LOG_WARNING, "Unable to open pseudo device\n"); 01171 if (cnf->fd >= 0) 01172 close(cnf->fd); 01173 ast_free(cnf); 01174 cnf = NULL; 01175 goto cnfout; 01176 } 01177 01178 cnf->dahdiconf = dahdic.confno; 01179 01180 /* Setup a new channel for playback of audio files */ 01181 cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL); 01182 if (cnf->chan) { 01183 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR); 01184 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR); 01185 dahdic.chan = 0; 01186 dahdic.confno = cnf->dahdiconf; 01187 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; 01188 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) { 01189 ast_log(LOG_WARNING, "Error setting conference\n"); 01190 if (cnf->chan) 01191 ast_hangup(cnf->chan); 01192 else 01193 close(cnf->fd); 01194 01195 ast_free(cnf); 01196 cnf = NULL; 01197 goto cnfout; 01198 } 01199 } 01200 01201 /* Fill the conference struct */ 01202 cnf->start = time(NULL); 01203 cnf->maxusers = 0x7fffffff; 01204 cnf->isdynamic = dynamic ? 1 : 0; 01205 ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno); 01206 AST_LIST_INSERT_HEAD(&confs, cnf, list); 01207 01208 /* Reserve conference number in map */ 01209 if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) 01210 conf_map[confno_int] = 1; 01211 01212 cnfout: 01213 if (cnf) 01214 ast_atomic_fetchadd_int(&cnf->refcount, refcount); 01215 01216 AST_LIST_UNLOCK(&confs); 01217 01218 return cnf; 01219 }
| static int can_write | ( | struct ast_channel * | chan, | |
| int | confflags | |||
| ) | [static] |
Definition at line 2034 of file app_meetme.c.
References ast_channel::_state, AST_STATE_UP, and CONFFLAG_NO_AUDIO_UNTIL_UP.
Referenced by conf_run().
02035 { 02036 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) { 02037 return 1; 02038 } 02039 02040 return (chan->_state == AST_STATE_UP); 02041 }
| static int careful_write | ( | int | fd, | |
| unsigned char * | data, | |||
| int | len, | |||
| int | block | |||
| ) | [static] |
Definition at line 966 of file app_meetme.c.
References ast_log(), errno, and LOG_WARNING.
00967 { 00968 int res; 00969 int x; 00970 00971 while (len) { 00972 if (block) { 00973 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT; 00974 res = ioctl(fd, DAHDI_IOMUX, &x); 00975 } else 00976 res = 0; 00977 if (res >= 0) 00978 res = write(fd, data, len); 00979 if (res < 1) { 00980 if (errno != EAGAIN) { 00981 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno)); 00982 return -1; 00983 } else 00984 return 0; 00985 } 00986 len -= res; 00987 data += res; 00988 } 00989 00990 return 0; 00991 }
| static int channel_admin_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).
Definition at line 4215 of file app_meetme.c.
References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conf_user::chan, ast_conf_user::list, LOG_NOTICE, LOG_WARNING, ast_channel::name, and ast_conference::userlist.
Referenced by load_module().
04215 { 04216 char *params; 04217 struct ast_conference *conf = NULL; 04218 struct ast_conf_user *user = NULL; 04219 AST_DECLARE_APP_ARGS(args, 04220 AST_APP_ARG(channel); 04221 AST_APP_ARG(command); 04222 ); 04223 04224 if (ast_strlen_zero(data)) { 04225 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n"); 04226 return -1; 04227 } 04228 04229 params = ast_strdupa(data); 04230 AST_STANDARD_APP_ARGS(args, params); 04231 04232 if (!args.channel) { 04233 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n"); 04234 return -1; 04235 } 04236 04237 if (!args.command) { 04238 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n"); 04239 return -1; 04240 } 04241 04242 AST_LIST_LOCK(&confs); 04243 AST_LIST_TRAVERSE(&confs, conf, list) { 04244 AST_LIST_TRAVERSE(&conf->userlist, user, list) { 04245 if (!strcmp(user->chan->name, args.channel)) 04246 break; 04247 } 04248 } 04249 04250 if (!user) { 04251 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel); 04252 AST_LIST_UNLOCK(&confs); 04253 return 0; 04254 } 04255 04256 /* perform the specified action */ 04257 switch (*args.command) { 04258 case 77: /* M: Mute */ 04259 user->adminflags |= ADMINFLAG_MUTED; 04260 break; 04261 case 109: /* m: Unmute */ 04262 user->adminflags &= ~ADMINFLAG_MUTED; 04263 break; 04264 case 107: /* k: Kick user */ 04265 user->adminflags |= ADMINFLAG_KICKME; 04266 break; 04267 default: /* unknown command */ 04268 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command); 04269 break; 04270 } 04271 04272 AST_LIST_UNLOCK(&confs); 04273 04274 return 0; 04275 }
| static char* complete_meetmecmd | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 1221 of file app_meetme.c.
References ast_cli_complete(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, ast_conference::confno, len(), ast_conf_user::list, strsep(), ast_conf_user::user_no, and ast_conference::userlist.
Referenced by meetme_cmd(), and meetme_show_cmd().
01222 { 01223 static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL}; 01224 01225 int len = strlen(word); 01226 int which = 0; 01227 struct ast_conference *cnf = NULL; 01228 struct ast_conf_user *usr = NULL; 01229 char *confno = NULL; 01230 char usrno[50] = ""; 01231 char *myline, *ret = NULL; 01232 01233 if (pos == 1) { /* Command */ 01234 return ast_cli_complete(word, cmds, state); 01235 } else if (pos == 2) { /* Conference Number */ 01236 AST_LIST_LOCK(&confs); 01237 AST_LIST_TRAVERSE(&confs, cnf, list) { 01238 if (!strncasecmp(word, cnf->confno, len) && ++which > state) { 01239 ret = cnf->confno; 01240 break; 01241 } 01242 } 01243 ret = ast_strdup(ret); /* dup before releasing the lock */ 01244 AST_LIST_UNLOCK(&confs); 01245 return ret; 01246 } else if (pos == 3) { 01247 /* User Number || Conf Command option*/ 01248 if (strstr(line, "mute") || strstr(line, "kick")) { 01249 if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len)) 01250 return ast_strdup("all"); 01251 which++; 01252 AST_LIST_LOCK(&confs); 01253 01254 /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */ 01255 myline = ast_strdupa(line); 01256 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) { 01257 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0)) 01258 ; 01259 } 01260 01261 AST_LIST_TRAVERSE(&confs, cnf, list) { 01262 if (!strcmp(confno, cnf->confno)) 01263 break; 01264 } 01265 01266 if (cnf) { 01267 /* Search for the user */ 01268 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) { 01269 snprintf(usrno, sizeof(usrno), "%d", usr->user_no); 01270 if (!strncasecmp(word, usrno, len) && ++which > state) 01271 break; 01272 } 01273 } 01274 AST_LIST_UNLOCK(&confs); 01275 return usr ? ast_strdup(usrno) : NULL; 01276 } 01277 } 01278 01279 return NULL; 01280 }
| static int conf_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
The meetme() application.
Definition at line 3757 of file app_meetme.c.
References ast_channel::_state, ast_conference::adminopts, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_say_digits(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), ast_verb, ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, config_flags, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, ast_channel::language, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, meetme_opts, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, strsep(), ast_conference::useropts, ast_variable::value, and var.
03758 { 03759 int res = -1; 03760 char confno[MAX_CONFNUM] = ""; 03761 int allowretry = 0; 03762 int retrycnt = 0; 03763 struct ast_conference *cnf = NULL; 03764 struct ast_flags confflags = {0}, config_flags = { 0 }; 03765 int dynamic = 0; 03766 int empty = 0, empty_no_pin = 0; 03767 int always_prompt = 0; 03768 const char *notdata; 03769 char *info, the_pin[MAX_PIN] = ""; 03770 AST_DECLARE_APP_ARGS(args, 03771 AST_APP_ARG(confno); 03772 AST_APP_ARG(options); 03773 AST_APP_ARG(pin); 03774 ); 03775 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, }; 03776 03777 if (ast_strlen_zero(data)) { 03778 allowretry = 1; 03779 notdata = ""; 03780 } else { 03781 notdata = data; 03782 } 03783 03784 if (chan->_state != AST_STATE_UP) 03785 ast_answer(chan); 03786 03787 info = ast_strdupa(notdata); 03788 03789 AST_STANDARD_APP_ARGS(args, info); 03790 03791 if (args.confno) { 03792 ast_copy_string(confno, args.confno, sizeof(confno)); 03793 if (ast_strlen_zero(confno)) { 03794 allowretry = 1; 03795 } 03796 } 03797 03798 if (args.pin) 03799 ast_copy_string(the_pin, args.pin, sizeof(the_pin)); 03800 03801 if (args.options) { 03802 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options); 03803 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN); 03804 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin)) 03805 strcpy(the_pin, "q"); 03806 03807 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN); 03808 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN); 03809 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN); 03810 } 03811 03812 do { 03813 if (retrycnt > 3) 03814 allowretry = 0; 03815 if (empty) { 03816 int i; 03817 struct ast_config *cfg; 03818 struct ast_variable *var; 03819 int confno_int; 03820 03821 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */ 03822 if ((empty_no_pin) || (!dynamic)) { 03823 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags); 03824 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) { 03825 var = ast_variable_browse(cfg, "rooms"); 03826 while (var) { 03827 if (!strcasecmp(var->name, "conf")) { 03828 char *stringp = ast_strdupa(var->value); 03829 if (stringp) { 03830 char *confno_tmp = strsep(&stringp, "|,"); 03831 int found = 0; 03832 if (!dynamic) { 03833 /* For static: run through the list and see if this conference is empty */ 03834 AST_LIST_LOCK(&confs); 03835 AST_LIST_TRAVERSE(&confs, cnf, list) { 03836 if (!strcmp(confno_tmp, cnf->confno)) { 03837 /* The conference exists, therefore it's not empty */ 03838 found = 1; 03839 break; 03840 } 03841 } 03842 AST_LIST_UNLOCK(&confs); 03843 if (!found) { 03844 /* At this point, we have a confno_tmp (static conference) that is empty */ 03845 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) { 03846 /* Case 1: empty_no_pin and pin is nonexistent (NULL) 03847 * Case 2: empty_no_pin and pin is blank (but not NULL) 03848 * Case 3: not empty_no_pin 03849 */ 03850 ast_copy_string(confno, confno_tmp, sizeof(confno)); 03851 break; 03852 /* XXX the map is not complete (but we do have a confno) */ 03853 } 03854 } 03855 } 03856 } 03857 } 03858 var = var->next; 03859 } 03860 ast_config_destroy(cfg); 03861 } 03862 } 03863 03864 /* Select first conference number not in use */ 03865 if (ast_strlen_zero(confno) && dynamic) { 03866 AST_LIST_LOCK(&confs); 03867 for (i = 0; i < ARRAY_LEN(conf_map); i++) { 03868 if (!conf_map[i]) { 03869 snprintf(confno, sizeof(confno), "%d", i); 03870 conf_map[i] = 1; 03871 break; 03872 } 03873 } 03874 AST_LIST_UNLOCK(&confs); 03875 } 03876 03877 /* Not found? */ 03878 if (ast_strlen_zero(confno)) { 03879 res = ast_streamfile(chan, "conf-noempty", chan->language); 03880 if (!res) 03881 ast_waitstream(chan, ""); 03882 } else { 03883 if (sscanf(confno, "%30d", &confno_int) == 1) { 03884 if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) { 03885 res = ast_streamfile(chan, "conf-enteringno", chan->language); 03886 if (!res) { 03887 ast_waitstream(chan, ""); 03888 res = ast_say_digits(chan, confno_int, "", chan->language); 03889 } 03890 } 03891 } else { 03892 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno); 03893 } 03894 } 03895 } 03896 03897 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) { 03898 /* Prompt user for conference number */ 03899 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0); 03900 if (res < 0) { 03901 /* Don't try to validate when we catch an error */ 03902 confno[0] = '\0'; 03903 allowretry = 0; 03904 break; 03905 } 03906 } 03907 if (!ast_strlen_zero(confno)) { 03908 /* Check the validity of the conference */ 03909 cnf = find_conf(chan, confno, 1, dynamic, the_pin, 03910 sizeof(the_pin), 1, &confflags); 03911 if (!cnf) { 03912 int too_early = 0; 03913 03914 cnf = find_conf_realtime(chan, confno, 1, dynamic, 03915 the_pin, sizeof(the_pin), 1, &confflags,&too_early); 03916 if (rt_schedule && too_early) 03917 allowretry = 0; 03918 } 03919 03920 if (!cnf) { 03921 if (allowretry) { 03922 confno[0] = '\0'; 03923 res = ast_streamfile(chan, "conf-invalid", chan->language); 03924 if (!res) 03925 ast_waitstream(chan, ""); 03926 res = -1; 03927 } 03928 } else { 03929 if ((!ast_strlen_zero(cnf->pin) && 03930 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) || 03931 (!ast_strlen_zero(cnf->pinadmin) && 03932 ast_test_flag(&confflags, CONFFLAG_ADMIN))) { 03933 char pin[MAX_PIN] = ""; 03934 int j; 03935 03936 /* Allow the pin to be retried up to 3 times */ 03937 for (j = 0; j < 3; j++) { 03938 if (*the_pin && (always_prompt == 0)) { 03939 ast_copy_string(pin, the_pin, sizeof(pin)); 03940 res = 0; 03941 } else { 03942 /* Prompt user for pin if pin is required */ 03943 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0); 03944 } 03945 if (res >= 0) { 03946 if (!strcasecmp(pin, cnf->pin) || 03947 (!ast_strlen_zero(cnf->pinadmin) && 03948 !strcasecmp(pin, cnf->pinadmin))) { 03949 /* Pin correct */ 03950 allowretry = 0; 03951 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) { 03952 if (!ast_strlen_zero(cnf->adminopts)) { 03953 char *opts = ast_strdupa(cnf->adminopts); 03954 ast_app_parse_options(meetme_opts, &confflags, optargs, opts); 03955 } 03956 } else { 03957 if (!ast_strlen_zero(cnf->useropts)) { 03958 char *opts = ast_strdupa(cnf->useropts); 03959 ast_app_parse_options(meetme_opts, &confflags, optargs, opts); 03960 } 03961 } 03962 /* Run the conference */ 03963 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat); 03964 res = conf_run(chan, cnf, confflags.flags, optargs); 03965 break; 03966 } else { 03967 /* Pin invalid */ 03968 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) { 03969 res = ast_waitstream(chan, AST_DIGIT_ANY); 03970 ast_stopstream(chan); 03971 } else { 03972 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n"); 03973 break; 03974 } 03975 if (res < 0) 03976 break; 03977 pin[0] = res; 03978 pin[1] = '\0'; 03979 res = -1; 03980 if (allowretry) 03981 confno[0] = '\0'; 03982 } 03983 } else { 03984 /* failed when getting the pin */ 03985 res = -1; 03986 allowretry = 0; 03987 /* see if we need to get rid of the conference */ 03988 break; 03989 } 03990 03991 /* Don't retry pin with a static pin */ 03992 if (*the_pin && (always_prompt == 0)) { 03993 break; 03994 } 03995 } 03996 } else { 03997 /* No pin required */ 03998 allowretry = 0; 03999 04000 /* Run the conference */ 04001 res = conf_run(chan, cnf, confflags.flags, optargs); 04002 } 04003 dispose_conf(cnf); 04004 cnf = NULL; 04005 } 04006 } 04007 } while (allowretry); 04008 04009 if (cnf) 04010 dispose_conf(cnf); 04011 04012 return res; 04013 }
| static void conf_flush | ( | int | fd, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Definition at line 1690 of file app_meetme.c.
References ast_frfree, ast_log(), ast_read(), ast_waitfor(), f, and LOG_WARNING.
Referenced by conf_run().
01691 { 01692 int x; 01693 01694 /* read any frames that may be waiting on the channel 01695 and throw them away 01696 */ 01697 if (chan) { 01698 struct ast_frame *f; 01699 01700 /* when no frames are available, this will wait 01701 for 1 millisecond maximum 01702 */ 01703 while (ast_waitfor(chan, 1)) { 01704 f = ast_read(chan); 01705 if (f) 01706 ast_frfree(f); 01707 else /* channel was hung up or something else happened */ 01708 break; 01709 } 01710 } 01711 01712 /* flush any data sitting in the pseudo channel */ 01713 x = DAHDI_FLUSH_ALL; 01714 if (ioctl(fd, DAHDI_FLUSH, &x)) 01715 ast_log(LOG_WARNING, "Error flushing channel\n"); 01716 01717 }
| 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 1722 of file app_meetme.c.
References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethread_stop, ast_conference::announcethreadlock, ao2_ref, ast_cond_signal(), ast_filedelete(), AST_FRAME_BITS, ast_free, ast_frfree, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), ast_conference::chan, ast_conference::confno, EVENT_FLAG_CALL, ast_conference::fd, ast_conference::lchan, ast_conference::listenlock, manager_event, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, announce_listitem::namerecloc, ast_conference::origframe, ast_conference::playlock, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthreadlock, ast_conference::transframe, and ast_conference::transpath.
Referenced by dispose_conf().
01723 { 01724 int x; 01725 struct announce_listitem *item; 01726 01727 AST_LIST_REMOVE(&confs, conf, list); 01728 manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno); 01729 01730 if (conf->recording == MEETME_RECORD_ACTIVE) { 01731 conf->recording = MEETME_RECORD_TERMINATE; 01732 AST_LIST_UNLOCK(&confs); 01733 while (1) { 01734 usleep(1); 01735 AST_LIST_LOCK(&confs); 01736 if (conf->recording == MEETME_RECORD_OFF) 01737 break; 01738 AST_LIST_UNLOCK(&confs); 01739 } 01740 } 01741 01742 for (x = 0; x < AST_FRAME_BITS; x++) { 01743 if (conf->transframe[x]) 01744 ast_frfree(conf->transframe[x]); 01745 if (conf->transpath[x]) 01746 ast_translator_free_path(conf->transpath[x]); 01747 } 01748 if (conf->announcethread != AST_PTHREADT_NULL) { 01749 ast_mutex_lock(&conf->announcelistlock); 01750 conf->announcethread_stop = 1; 01751 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT); 01752 ast_cond_signal(&conf->announcelist_addition); 01753 ast_mutex_unlock(&conf->announcelistlock); 01754 pthread_join(conf->announcethread, NULL); 01755 01756 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) { 01757 ast_filedelete(item->namerecloc, NULL); 01758 ao2_ref(item, -1); 01759 } 01760 ast_mutex_destroy(&conf->announcelistlock); 01761 } 01762 if (conf->origframe) 01763 ast_frfree(conf->origframe); 01764 if (conf->lchan) 01765 ast_hangup(conf->lchan); 01766 if (conf->chan) 01767 ast_hangup(conf->chan); 01768 if (conf->fd >= 0) 01769 close(conf->fd); 01770 if (conf->recordingfilename) { 01771 ast_free(conf->recordingfilename); 01772 } 01773 if (conf->recordingformat) { 01774 ast_free(conf->recordingformat); 01775 } 01776 ast_mutex_destroy(&conf->playlock); 01777 ast_mutex_destroy(&conf->listenlock); 01778 ast_mutex_destroy(&conf->recordthreadlock); 01779 ast_mutex_destroy(&conf->announcethreadlock); 01780 ast_free(conf); 01781 01782 return 0; 01783 }
| static void conf_play | ( | struct ast_channel * | chan, | |
| struct ast_conference * | conf, | |||
| enum entrance_sound | sound | |||
| ) | [static] |
Definition at line 1084 of file app_meetme.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_check_hangup(), AST_LIST_LOCK, AST_LIST_UNLOCK, careful_write(), enter, ENTER, ast_conference::fd, leave, LEAVE, and len().
Referenced by conf_run().
01085 { 01086 unsigned char *data; 01087 int len; 01088 int res = -1; 01089 01090 if (!ast_check_hangup(chan)) 01091 res = ast_autoservice_start(chan); 01092 01093 AST_LIST_LOCK(&confs); 01094 01095 switch(sound) { 01096 case ENTER: 01097 data = enter; 01098 len = sizeof(enter); 01099 break; 01100 case LEAVE: 01101 data = leave; 01102 len = sizeof(leave); 01103 break; 01104 default: 01105 data = NULL; 01106 len = 0; 01107 } 01108 if (data) { 01109 careful_write(conf->fd, data, len, 1); 01110 } 01111 01112 AST_LIST_UNLOCK(&confs); 01113 01114 if (!res) 01115 ast_autoservice_stop(chan); 01116 }
| static void conf_queue_dtmf | ( | const struct ast_conference * | conf, | |
| const struct ast_conf_user * | sender, | |||
| struct ast_frame * | f | |||
| ) | [static] |
Definition at line 1785 of file app_meetme.c.
References AST_LIST_TRAVERSE, ast_log(), ast_write(), ast_conf_user::chan, ast_conf_user::list, LOG_WARNING, ast_channel::name, and ast_conference::userlist.
Referenced by conf_run().
01787 { 01788 struct ast_conf_user *user; 01789 01790 AST_LIST_TRAVERSE(&conf->userlist, user, list) { 01791 if (user == sender) 01792 continue; 01793 if (ast_write(user->chan, f) < 0) 01794 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name); 01795 } 01796 }
| static int conf_run | ( | struct ast_channel * | chan, | |
| struct ast_conference * | conf, | |||
| int | confflags, | |||
| char * | optargs[] | |||
| ) | [static] |
Definition at line 2043 of file app_meetme.c.
References volume::actual, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, announce_thread(), ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethreadlock, announce_listitem::announcetype, ao2_alloc, ao2_ref, ast_calloc, ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_cond_signal(), ast_config_AST_SPOOL_DIR, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_module_helper(), ast_moh_start(), ast_moh_stop(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_variables_destroy(), ast_verb, ast_verbose, ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_channel::audiohooks, buf, can_write(), careful_write(), ast_conference::chan, ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), announce_listitem::confchan, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, announce_listitem::confusers, ast_channel::context, ast_conf_user::dahdichannel, ast_conference::dahdiconf, ast_frame::data, ast_frame::datalen, DATE_FORMAT, volume::desired, dtmfstr, ast_conf_user::end_sound, ast_conference::endalert, ast_conference::endtime, ENTER, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frame_list, ast_frame::frametype, ast_conf_user::jointime, ast_conf_user::kicktime, announce_listitem::language, ast_channel::language, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_channel::macrocontext, manager_event, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, ast_variable::name, ast_channel::name, announce_listitem::namerecloc, ast_conf_user::namerecloc, ast_variable::next, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, ast_conference::origframe, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conf_user::play_warning, ast_conference::playlock, ast_frame::ptr, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, rt_extend_conf(), S_OR, ast_frame::samples, sec, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, strsep(), ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, ast_channel::tech, THRESHOLD_SILENCE, ast_conf_user::timelimit, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conference::uniqueid, ast_channel::uniqueid, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, ast_variable::value, var, VOL_DOWN, VOL_UP, ast_conf_user::warning_freq, and ast_conf_user::warning_sound.
02044 { 02045 struct ast_conf_user *user = NULL; 02046 struct ast_conf_user *usr = NULL; 02047 int fd; 02048 struct dahdi_confinfo dahdic, dahdic_empty; 02049 struct ast_frame *f; 02050 struct ast_channel *c; 02051 struct ast_frame fr; 02052 int outfd; 02053 int ms; 02054 int nfds; 02055 int res; 02056 int retrydahdi; 02057 int origfd; 02058 int musiconhold = 0, mohtempstopped = 0; 02059 int firstpass = 0; 02060 int lastmarked = 0; 02061 int currentmarked = 0; 02062 int ret = -1; 02063 int x; 02064 int menu_active = 0; 02065 int talkreq_manager = 0; 02066 int using_pseudo = 0; 02067 int duration = 20; 02068 int hr, min, sec; 02069 int sent_event = 0; 02070 int checked = 0; 02071 int announcement_played = 0; 02072 struct timeval now; 02073 struct ast_dsp *dsp = NULL; 02074 struct ast_app *agi_app; 02075 char *agifile, *mod_speex; 02076 const char *agifiledefault = "conf-background.agi", *tmpvar; 02077 char meetmesecs[30] = ""; 02078 char exitcontext[AST_MAX_CONTEXT] = ""; 02079 char recordingtmp[AST_MAX_EXTENSION] = ""; 02080 char members[10] = ""; 02081 int dtmf, opt_waitmarked_timeout = 0; 02082 time_t timeout = 0; 02083 struct dahdi_bufferinfo bi; 02084 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; 02085 char *buf = __buf + AST_FRIENDLY_OFFSET; 02086 char *exitkeys = NULL; 02087 unsigned int calldurationlimit = 0; 02088 long timelimit = 0; 02089 long play_warning = 0; 02090 long warning_freq = 0; 02091 const char *warning_sound = NULL; 02092 const char *end_sound = NULL; 02093 char *parse; 02094 long time_left_ms = 0; 02095 struct timeval nexteventts = { 0, }; 02096 int to; 02097 int setusercount = 0; 02098 int confsilence = 0, totalsilence = 0; 02099 02100 if (!(user = ast_calloc(1, sizeof(*user)))) 02101 return ret; 02102 02103 /* Possible timeout waiting for marked user */ 02104 if ((confflags & CONFFLAG_WAITMARKED) && 02105 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) && 02106 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) && 02107 (opt_waitmarked_timeout > 0)) { 02108 timeout = time(NULL) + opt_waitmarked_timeout; 02109 } 02110 02111 if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) { 02112 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]); 02113 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit); 02114 } 02115 02116 if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) { 02117 char *limit_str, *warning_str, *warnfreq_str; 02118 const char *var; 02119 02120 parse = optargs[OPT_ARG_DURATION_LIMIT]; 02121 limit_str = strsep(&parse, ":"); 02122 warning_str = strsep(&parse, ":"); 02123 warnfreq_str = parse; 02124 02125 timelimit = atol(limit_str); 02126 if (warning_str) 02127 play_warning = atol(warning_str); 02128 if (warnfreq_str) 02129 warning_freq = atol(warnfreq_str); 02130 02131 if (!timelimit) { 02132 timelimit = play_warning = warning_freq = 0; 02133 warning_sound = NULL; 02134 } else if (play_warning > timelimit) { 02135 if (!warning_freq) { 02136 play_warning = 0; 02137 } else { 02138 while (play_warning > timelimit) 02139 play_warning -= warning_freq; 02140 if (play_warning < 1) 02141 play_warning = warning_freq = 0; 02142 } 02143 } 02144 02145 ast_channel_lock(chan); 02146 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) { 02147 var = ast_strdupa(var); 02148 } 02149 ast_channel_unlock(chan); 02150 02151 warning_sound = var ? var : "timeleft"; 02152 02153 ast_channel_lock(chan); 02154 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) { 02155 var = ast_strdupa(var); 02156 } 02157 ast_channel_unlock(chan); 02158 02159 end_sound = var ? var : NULL; 02160 02161 /* undo effect of S(x) in case they are both used */ 02162 calldurationlimit = 0; 02163 /* more efficient do it like S(x) does since no advanced opts */ 02164 if (!play_warning && !end_sound && timelimit) { 02165 calldurationlimit = timelimit / 1000; 02166 timelimit = play_warning = warning_freq = 0; 02167 } else { 02168 ast_debug(2, "Limit Data for this call:\n"); 02169 ast_debug(2, "- timelimit = %ld\n", timelimit); 02170 ast_debug(2, "- play_warning = %ld\n", play_warning); 02171 ast_debug(2, "- warning_freq = %ld\n", warning_freq); 02172 ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF"); 02173 ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF"); 02174 } 02175 } 02176 02177 /* Get exit keys */ 02178 if ((confflags & CONFFLAG_KEYEXIT)) { 02179 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS])) 02180 exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]); 02181 else 02182 exitkeys = ast_strdupa("#"); /* Default */ 02183 } 02184 02185 if (confflags & CONFFLAG_RECORDCONF) { 02186 if (!conf->recordingfilename) { 02187 const char *var; 02188 ast_channel_lock(chan); 02189 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) { 02190 conf->recordingfilename = ast_strdup(var); 02191 } 02192 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) { 02193 conf->recordingformat = ast_strdup(var); 02194 } 02195 ast_channel_unlock(chan); 02196 if (!conf->recordingfilename) { 02197 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid); 02198 conf->recordingfilename = ast_strdup(recordingtmp); 02199 } 02200 if (!conf->recordingformat) { 02201 conf->recordingformat = ast_strdup("wav"); 02202 } 02203 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", 02204 conf->confno, conf->recordingfilename, conf->recordingformat); 02205 } 02206 } 02207 02208 ast_mutex_lock(&conf->recordthreadlock); 02209 if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL)))) { 02210 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR); 02211 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR); 02212 dahdic.chan = 0; 02213 dahdic.confno = conf->dahdiconf; 02214 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; 02215 if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) { 02216 ast_log(LOG_WARNING, "Error starting listen channel\n"); 02217 ast_hangup(conf->lchan); 02218 conf->lchan = NULL; 02219 } else { 02220 ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf); 02221 } 02222 } 02223 ast_mutex_unlock(&conf->recordthreadlock); 02224 02225 ast_mutex_lock(&conf->announcethreadlock); 02226 if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) { 02227 ast_mutex_init(&conf->announcelistlock); 02228 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist); 02229 ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf); 02230 } 02231 ast_mutex_unlock(&conf->announcethreadlock); 02232 02233 time(&user->jointime); 02234 02235 user->timelimit = timelimit; 02236 user->play_warning = play_warning; 02237 user->warning_freq = warning_freq; 02238 user->warning_sound = warning_sound; 02239 user->end_sound = end_sound; 02240 02241 if (calldurationlimit > 0) { 02242 time(&user->kicktime); 02243 user->kicktime = user->kicktime + calldurationlimit; 02244 } 02245 02246 if (ast_tvzero(user->start_time)) 02247 user->start_time = ast_tvnow(); 02248 time_left_ms = user->timelimit; 02249 02250 if (user->timelimit) { 02251 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000)); 02252 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000)); 02253 } 02254 02255 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) { 02256 /* Sorry, but this conference is locked! */ 02257 if (!ast_streamfile(chan, "conf-locked", chan->language)) 02258 ast_waitstream(chan, ""); 02259 goto outrun; 02260 } 02261 02262 ast_mutex_lock(&conf->playlock); 02263 02264 if (AST_LIST_EMPTY(&conf->userlist)) 02265 user->user_no = 1; 02266 else 02267 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1; 02268 02269 if (rt_schedule && conf->maxusers) 02270 if (conf->users >= conf->maxusers) { 02271 /* Sorry, but this confernce has reached the participant limit! */ 02272 if (!ast_streamfile(chan, "conf-full", chan->language)) 02273 ast_waitstream(chan, ""); 02274 ast_mutex_unlock(&conf->playlock); 02275 user->user_no = 0; 02276 goto outrun; 02277 } 02278 02279 AST_LIST_INSERT_TAIL(&conf->userlist, user, list); 02280 02281 user->chan = chan; 02282 user->userflags = confflags; 02283 user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0; 02284 user->talking = -1; 02285 02286 ast_mutex_unlock(&conf->playlock); 02287 02288 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) { 02289 char destdir[PATH_MAX]; 02290 02291 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR); 02292 02293 if (ast_mkdir(destdir, 0777) != 0) { 02294 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno)); 02295 goto outrun; 02296 } 02297 02298 snprintf(user->namerecloc, sizeof(user->namerecloc), 02299 "%s/meetme-username-%s-%d", destdir, 02300 conf->confno, user->user_no); 02301 if (confflags & CONFFLAG_INTROUSERNOREVIEW) 02302 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL); 02303 else 02304 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL); 02305 if (res == -1) 02306 goto outrun; 02307 } 02308 02309 ast_mutex_lock(&conf->playlock); 02310 02311 if (confflags & CONFFLAG_MARKEDUSER) 02312 conf->markedusers++; 02313 conf->users++; 02314 if (rt_log_members) { 02315 /* Update table */ 02316 snprintf(members, sizeof(members), "%d", conf->users); 02317 ast_realtime_require_field("meetme", 02318 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno), 02319 "members", RQ_UINTEGER1, strlen(members), 02320 NULL); 02321 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL); 02322 } 02323 setusercount = 1; 02324 02325 /* This device changed state now - if this is the first user */ 02326 if (conf->users == 1) 02327 ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno); 02328 02329 ast_mutex_unlock(&conf->playlock); 02330 02331 /* return the unique ID of the conference */ 02332 pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid); 02333 02334 if (confflags & CONFFLAG_EXIT_CONTEXT) { 02335 ast_channel_lock(chan); 02336 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) { 02337 ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext)); 02338 } else if (!ast_strlen_zero(chan->macrocontext)) { 02339 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); 02340 } else { 02341 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); 02342 } 02343 ast_channel_unlock(chan); 02344 } 02345 02346 if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) { 02347 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED)) 02348 if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) 02349 ast_waitstream(chan, ""); 02350 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0) 02351 if (!ast_streamfile(chan, "conf-waitforleader", chan->language)) 02352 ast_waitstream(chan, ""); 02353 } 02354 02355 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) { 02356 int keepplaying = 1; 02357 02358 if (conf->users == 2) { 02359 if (!ast_streamfile(chan, "conf-onlyone", chan->language)) { 02360 res = ast_waitstream(chan, AST_DIGIT_ANY); 02361 ast_stopstream(chan); 02362 if (res > 0) 02363 keepplaying = 0; 02364 else if (res == -1) 02365 goto outrun; 02366 } 02367 } else { 02368 if (!ast_streamfile(chan, "conf-thereare", chan->language)) { 02369 res = ast_waitstream(chan, AST_DIGIT_ANY); 02370 ast_stopstream(chan); 02371 if (res > 0) 02372 keepplaying = 0; 02373 else if (res == -1) 02374 goto outrun; 02375 } 02376 if (keepplaying) { 02377 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); 02378 if (res > 0) 02379 keepplaying = 0; 02380 else if (res == -1) 02381 goto outrun; 02382 } 02383 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) { 02384 res = ast_waitstream(chan, AST_DIGIT_ANY); 02385 ast_stopstream(chan); 02386 if (res > 0) 02387 keepplaying = 0; 02388 else if (res == -1) 02389 goto outrun; 02390 } 02391 } 02392 } 02393 02394 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) { 02395 /* We're leaving this alone until the state gets changed to up */ 02396 ast_indicate(chan, -1); 02397 } 02398 02399 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 02400 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); 02401 goto outrun; 02402 } 02403 02404 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { 02405 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); 02406 goto outrun; 02407 } 02408 02409 /* Reduce background noise from each participant */ 02410 if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) { 02411 ast_free(mod_speex); 02412 ast_func_write(chan, "DENOISE(rx)", "on"); 02413 } 02414 02415 retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0); 02416 user->dahdichannel = !retrydahdi; 02417 02418 dahdiretry: 02419 origfd = chan->fds[0]; 02420 if (retrydahdi) { 02421 /* open pseudo in non-blocking mode */ 02422 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK); 02423 if (fd < 0) { 02424 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); 02425 goto outrun; 02426 } 02427 using_pseudo = 1; 02428 /* Setup buffering information */ 02429 memset(&bi, 0, sizeof(bi)); 02430 bi.bufsize = CONF_SIZE / 2; 02431 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; 02432 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; 02433 bi.numbufs = audio_buffers; 02434 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) { 02435 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); 02436 close(fd); 02437 goto outrun; 02438 } 02439 x = 1; 02440 if (ioctl(fd, DAHDI_SETLINEAR, &x)) { 02441 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno)); 02442 close(fd); 02443 goto outrun; 02444 } 02445 nfds = 1; 02446 } else { 02447 /* XXX Make sure we're not running on a pseudo channel XXX */ 02448 fd = chan->fds[0]; 02449 nfds = 0; 02450 } 02451 memset(&dahdic, 0, sizeof(dahdic)); 02452 memset(&dahdic_empty, 0, sizeof(dahdic_empty)); 02453 /* Check to see if we're in a conference... */ 02454 dahdic.chan = 0; 02455 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) { 02456 ast_log(LOG_WARNING, "Error getting conference\n"); 02457 close(fd); 02458 goto outrun; 02459 } 02460 if (dahdic.confmode) { 02461 /* Whoa, already in a conference... Retry... */ 02462 if (!retrydahdi) { 02463 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n"); 02464 retrydahdi = 1; 02465 goto dahdiretry; 02466 } 02467 } 02468 memset(&dahdic, 0, sizeof(dahdic)); 02469 /* Add us to the conference */ 02470 dahdic.chan = 0; 02471 dahdic.confno = conf->dahdiconf; 02472 02473 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) { 02474 struct announce_listitem *item; 02475 if (!(item = ao2_alloc(sizeof(*item), NULL))) 02476 return -1; 02477 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc)); 02478 ast_copy_string(item->language, chan->language, sizeof(item->language)); 02479 item->confchan = conf->chan; 02480 item->confusers = conf->users; 02481 item->announcetype = CONF_HASJOIN; 02482 ast_mutex_lock(&conf->announcelistlock); 02483 ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */ 02484 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry); 02485 ast_cond_signal(&conf->announcelist_addition); 02486 ast_mutex_unlock(&conf->announcelistlock); 02487 02488 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) { 02489 ; 02490 } 02491 ao2_ref(item, -1); 02492 } 02493 02494 if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers) 02495 dahdic.confmode = DAHDI_CONF_CONF; 02496 else if (confflags & CONFFLAG_MONITOR) 02497 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER; 02498 else if (confflags & CONFFLAG_TALKER) 02499 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER; 02500 else 02501 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER; 02502 02503 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02504 ast_log(LOG_WARNING, "Error setting conference\n"); 02505 close(fd); 02506 goto outrun; 02507 } 02508 ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf); 02509 02510 if (!sent_event) { 02511 manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 02512 "Channel: %s\r\n" 02513 "Uniqueid: %s\r\n" 02514 "Meetme: %s\r\n" 02515 "Usernum: %d\r\n" 02516 "CallerIDnum: %s\r\n" 02517 "CallerIDname: %s\r\n", 02518 chan->name, chan->uniqueid, conf->confno, 02519 user->user_no, 02520 S_OR(user->chan->cid.cid_num, "<unknown>"), 02521 S_OR(user->chan->cid.cid_name, "<unknown>") 02522 ); 02523 sent_event = 1; 02524 } 02525 02526 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { 02527 firstpass = 1; 02528 if (!(confflags & CONFFLAG_QUIET)) 02529 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1))) 02530 conf_play(chan, conf, ENTER); 02531 } 02532 02533 conf_flush(fd, chan); 02534 02535 if (!(dsp = ast_dsp_new())) { 02536 ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); 02537 res = -1; 02538 } 02539 02540 if (confflags & CONFFLAG_AGI) { 02541 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) 02542 or use default filename of conf-background.agi */ 02543 02544 ast_channel_lock(chan); 02545 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) { 02546 agifile = ast_strdupa(tmpvar); 02547 } else { 02548 agifile = ast_strdupa(agifiledefault); 02549 } 02550 ast_channel_unlock(chan); 02551 02552 if (user->dahdichannel) { 02553 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */ 02554 x = 1; 02555 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 02556 } 02557 /* Find a pointer to the agi app and execute the script */ 02558 agi_app = pbx_findapp("agi"); 02559 if (agi_app) { 02560 ret = pbx_exec(chan, agi_app, agifile); 02561 } else { 02562 ast_log(LOG_WARNING, "Could not find application (agi)\n"); 02563 ret = -2; 02564 } 02565 if (user->dahdichannel) { 02566 /* Remove CONFMUTE mode on DAHDI channel */ 02567 x = 0; 02568 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 02569 } 02570 } else { 02571 if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) { 02572 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */ 02573 x = 1; 02574 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 02575 } 02576 for (;;) { 02577 int menu_was_active = 0; 02578 02579 outfd = -1; 02580 ms = -1; 02581 now = ast_tvnow(); 02582 02583 if (rt_schedule && conf->endtime) { 02584 char currenttime[32]; 02585 long localendtime = 0; 02586 int extended = 0; 02587 struct ast_tm tm; 02588 struct ast_variable *var, *origvar; 02589 struct timeval tmp; 02590 02591 if (now.tv_sec % 60 == 0) { 02592 if (!checked) { 02593 ast_localtime(&now, &tm, NULL); 02594 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); 02595 var = origvar = ast_load_realtime("meetme", "confno", 02596 conf->confno, "starttime <=", currenttime, 02597 "endtime >=", currenttime, NULL); 02598 02599 for ( ; var; var = var->next) { 02600 if (!strcasecmp(var->name, "endtime")) { 02601 struct ast_tm endtime_tm; 02602 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm); 02603 tmp = ast_mktime(&endtime_tm, NULL); 02604 localendtime = tmp.tv_sec; 02605 } 02606 } 02607 ast_variables_destroy(origvar); 02608 02609 /* A conference can be extended from the 02610 Admin/User menu or by an external source */ 02611 if (localendtime > conf->endtime){ 02612 conf->endtime = localendtime; 02613 extended = 1; 02614 } 02615 02616 if (conf->endtime && (now.tv_sec >= conf->endtime)) { 02617 ast_verbose("Quitting time...\n"); 02618 goto outrun; 02619 } 02620 02621 if (!announcement_played && conf->endalert) { 02622 if (now.tv_sec + conf->endalert >= conf->endtime) { 02623 if (!ast_streamfile(chan, "conf-will-end-in", chan->language)) 02624 ast_waitstream(chan, ""); 02625 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language); 02626 if (!ast_streamfile(chan, "minutes", chan->language)) 02627 ast_waitstream(chan, ""); 02628 announcement_played = 1; 02629 } 02630 } 02631 02632 if (extended) { 02633 announcement_played = 0; 02634 } 02635 02636 checked = 1; 02637 } 02638 } else { 02639 checked = 0; 02640 } 02641 } 02642 02643 if (user->kicktime && (user->kicktime <= now.tv_sec)) { 02644 break; 02645 } 02646 02647 to = -1; 02648 if (user->timelimit) { 02649 int minutes = 0, seconds = 0, remain = 0; 02650 02651 to = ast_tvdiff_ms(nexteventts, now); 02652 if (to < 0) { 02653 to = 0; 02654 } 02655 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time); 02656 if (time_left_ms < to) { 02657 to = time_left_ms; 02658 } 02659 02660 if (time_left_ms <= 0) { 02661 if (user->end_sound) { 02662 res = ast_streamfile(chan, user->end_sound, chan->language); 02663 res = ast_waitstream(chan, ""); 02664 } 02665 break; 02666 } 02667 02668 if (!to) { 02669 if (time_left_ms >= 5000) { 02670 02671 remain = (time_left_ms + 500) / 1000; 02672 if (remain / 60 >= 1) { 02673 minutes = remain / 60; 02674 seconds = remain % 60; 02675 } else { 02676 seconds = remain; 02677 } 02678 02679 /* force the time left to round up if appropriate */ 02680 if (user->warning_sound && user->play_warning) { 02681 if (!strcmp(user->warning_sound, "timeleft")) { 02682 02683 res = ast_streamfile(chan, "vm-youhave", chan->language); 02684 res = ast_waitstream(chan, ""); 02685 if (minutes) { 02686 res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL); 02687 res = ast_streamfile(chan, "queue-minutes", chan->language); 02688 res = ast_waitstream(chan, ""); 02689 } 02690 if (seconds) { 02691 res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL); 02692 res = ast_streamfile(chan, "queue-seconds", chan->language); 02693 res = ast_waitstream(chan, ""); 02694 } 02695 } else { 02696 res = ast_streamfile(chan, user->warning_sound, chan->language); 02697 res = ast_waitstream(chan, ""); 02698 } 02699 } 02700 } 02701 if (user->warning_freq) { 02702 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000)); 02703 } else { 02704 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000)); 02705 } 02706 } 02707 } 02708 02709 now = ast_tvnow(); 02710 if (timeout && now.tv_sec >= timeout) { 02711 break; 02712 } 02713 02714 /* if we have just exited from the menu, and the user had a channel-driver 02715 volume adjustment, restore it 02716 */ 02717 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) { 02718 set_talk_volume(user, user->listen.desired); 02719 } 02720 02721 menu_was_active = menu_active; 02722 02723 currentmarked = conf->markedusers; 02724 if (!(confflags & CONFFLAG_QUIET) && 02725 (confflags & CONFFLAG_MARKEDUSER) && 02726 (confflags & CONFFLAG_WAITMARKED) && 02727 lastmarked == 0) { 02728 if (currentmarked == 1 && conf->users > 1) { 02729 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); 02730 if (conf->users - 1 == 1) { 02731 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) { 02732 ast_waitstream(chan, ""); 02733 } 02734 } else { 02735 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) { 02736 ast_waitstream(chan, ""); 02737 } 02738 } 02739 } 02740 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) { 02741 if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) { 02742 ast_waitstream(chan, ""); 02743 } 02744 } 02745 } 02746 02747 /* Update the struct with the actual confflags */ 02748 user->userflags = confflags; 02749 02750 if (confflags & CONFFLAG_WAITMARKED) { 02751 if (currentmarked == 0) { 02752 if (lastmarked != 0) { 02753 if (!(confflags & CONFFLAG_QUIET)) { 02754 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) { 02755 ast_waitstream(chan, ""); 02756 } 02757 } 02758 if (confflags & CONFFLAG_MARKEDEXIT) { 02759 if (confflags & CONFFLAG_KICK_CONTINUE) { 02760 ret = 0; 02761 } 02762 break; 02763 } else { 02764 dahdic.confmode = DAHDI_CONF_CONF; 02765 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02766 ast_log(LOG_WARNING, "Error setting conference\n"); 02767 close(fd); 02768 goto outrun; 02769 } 02770 } 02771 } 02772 if (!musiconhold && (confflags & CONFFLAG_MOH)) { 02773 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]); 02774 musiconhold = 1; 02775 } 02776 } else if (currentmarked >= 1 && lastmarked == 0) { 02777 /* Marked user entered, so cancel timeout */ 02778 timeout = 0; 02779 if (confflags & CONFFLAG_MONITOR) { 02780 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER; 02781 } else if (confflags & CONFFLAG_TALKER) { 02782 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER; 02783 } else { 02784 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER; 02785 } 02786 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02787 ast_log(LOG_WARNING, "Error setting conference\n"); 02788 close(fd); 02789 goto outrun; 02790 } 02791 if (musiconhold && (confflags & CONFFLAG_MOH)) { 02792 ast_moh_stop(chan); 02793 musiconhold = 0; 02794 } 02795 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) { 02796 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) { 02797 ast_waitstream(chan, ""); 02798 } 02799 conf_play(chan, conf, ENTER); 02800 } 02801 } 02802 } 02803 02804 /* trying to add moh for single person conf */ 02805 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) { 02806 if (conf->users == 1) { 02807 if (!musiconhold) { 02808 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]); 02809 musiconhold = 1; 02810 } 02811 } else { 02812 if (musiconhold) { 02813 ast_moh_stop(chan); 02814 musiconhold = 0; 02815 } 02816 } 02817 } 02818 02819 /* Leave if the last marked user left */ 02820 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) { 02821 if (confflags & CONFFLAG_KICK_CONTINUE) { 02822 ret = 0; 02823 } else { 02824 ret = -1; 02825 } 02826 break; 02827 } 02828 02829 /* Check if my modes have changed */ 02830 02831 /* If I should be muted but am still talker, mute me */ 02832 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) { 02833 dahdic.confmode ^= DAHDI_CONF_TALKER; 02834 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02835 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 02836 ret = -1; 02837 break; 02838 } 02839 02840 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 02841 "Channel: %s\r\n" 02842 "Uniqueid: %s\r\n" 02843 "Meetme: %s\r\n" 02844 "Usernum: %i\r\n" 02845 "Status: on\r\n", 02846 chan->name, chan->uniqueid, conf->confno, user->user_no); 02847 } 02848 02849 /* If I should be un-muted but am not talker, un-mute me */ 02850 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) { 02851 dahdic.confmode |= DAHDI_CONF_TALKER; 02852 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02853 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 02854 ret = -1; 02855 break; 02856 } 02857 02858 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 02859 "Channel: %s\r\n" 02860 "Uniqueid: %s\r\n" 02861 "Meetme: %s\r\n" 02862 "Usernum: %i\r\n" 02863 "Status: off\r\n", 02864 chan->name, chan->uniqueid, conf->confno, user->user_no); 02865 } 02866 02867 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 02868 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) { 02869 talkreq_manager = 1; 02870 02871 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 02872 "Channel: %s\r\n" 02873 "Uniqueid: %s\r\n" 02874 "Meetme: %s\r\n" 02875 "Usernum: %i\r\n" 02876 "Status: on\r\n", 02877 chan->name, chan->uniqueid, conf->confno, user->user_no); 02878 } 02879 02880 02881 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 02882 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) { 02883 talkreq_manager = 0; 02884 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 02885 "Channel: %s\r\n" 02886 "Uniqueid: %s\r\n" 02887 "Meetme: %s\r\n" 02888 "Usernum: %i\r\n" 02889 "Status: off\r\n", 02890 chan->name, chan->uniqueid, conf->confno, user->user_no); 02891 } 02892 02893 /* If I have been kicked, exit the conference */ 02894 if (user->adminflags & ADMINFLAG_KICKME) { 02895 /* You have been kicked. */ 02896 if (!(confflags & CONFFLAG_QUIET) && 02897 !ast_streamfile(chan, "conf-kicked", chan->language)) { 02898 ast_waitstream(chan, ""); 02899 } 02900 ret = 0; 02901 break; 02902 } 02903 02904 /* Perform an extra hangup check just in case */ 02905 if (ast_check_hangup(chan)) { 02906 break; 02907 } 02908 02909 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); 02910 02911 if (c) { 02912 char dtmfstr[2] = ""; 02913 02914 if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) { 02915 if (using_pseudo) { 02916 /* Kill old pseudo */ 02917 close(fd); 02918 using_pseudo = 0; 02919 } 02920 ast_debug(1, "Ooh, something swapped out under us, starting over\n"); 02921 retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0); 02922 user->dahdichannel = !retrydahdi; 02923 goto dahdiretry; 02924 } 02925 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { 02926 f = ast_read_noaudio(c); 02927 } else { 02928 f = ast_read(c); 02929 } 02930 if (!f) { 02931 break; 02932 } 02933 if (f->frametype == AST_FRAME_DTMF) { 02934 dtmfstr[0] = f->subclass; 02935 dtmfstr[1] = '\0'; 02936 } 02937 02938 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) { 02939 if (user->talk.actual) { 02940 ast_frame_adjust_volume(f, user->talk.actual); 02941 } 02942 02943 if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) { 02944 if (user->talking == -1) { 02945 user->talking = 0; 02946 } 02947 02948 res = ast_dsp_silence(dsp, f, &totalsilence); 02949 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) { 02950 user->talking = 1; 02951 if (confflags & CONFFLAG_MONITORTALKER) 02952 manager_event(EVENT_FLAG_CALL, "MeetmeTalking", 02953 "Channel: %s\r\n" 02954 "Uniqueid: %s\r\n" 02955 "Meetme: %s\r\n" 02956 "Usernum: %d\r\n" 02957 "Status: on\r\n", 02958 chan->name, chan->uniqueid, conf->confno, user->user_no); 02959 } 02960 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) { 02961 user->talking = 0; 02962 if (confflags & CONFFLAG_MONITORTALKER) { 02963 manager_event(EVENT_FLAG_CALL, "MeetmeTalking", 02964 "Channel: %s\r\n" 02965 "Uniqueid: %s\r\n" 02966 "Meetme: %s\r\n" 02967 "Usernum: %d\r\n" 02968 "Status: off\r\n", 02969 chan->name, chan->uniqueid, conf->confno, user->user_no); 02970 } 02971 } 02972 } 02973 if (using_pseudo) { 02974 /* Absolutely do _not_ use careful_write here... 02975 it is important that we read data from the channel 02976 as fast as it arrives, and feed it into the conference. 02977 The buffering in the pseudo channel will take care of any 02978 timing differences, unless they are so drastic as to lose 02979 audio frames (in which case carefully writing would only 02980 have delayed the audio even further). 02981 */ 02982 /* As it turns out, we do want to use careful write. We just 02983 don't want to block, but we do want to at least *try* 02984 to write out all the samples. 02985 */ 02986 if (user->talking && !(confflags & CONFFLAG_OPTIMIZETALKER)) { 02987 careful_write(fd, f->data.ptr, f->datalen, 0); 02988 } 02989 } 02990 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { 02991 if (confflags & CONFFLAG_PASS_DTMF) { 02992 conf_queue_dtmf(conf, user, f); 02993 } 02994 if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) { 02995 ast_log(LOG_WARNING, "Error setting conference\n"); 02996 close(fd); 02997 ast_frfree(f); 02998 goto outrun; 02999 } 03000 03001 /* if we are entering the menu, and the user has a channel-driver 03002 volume adjustment, clear it 03003 */ 03004 if (!menu_active && user->talk.desired && !user->talk.actual) { 03005 set_talk_volume(user, 0); 03006 } 03007 03008 if (musiconhold) { 03009 ast_moh_stop(chan); 03010 } 03011 if ((confflags & CONFFLAG_ADMIN)) { 03012 /* Admin menu */ 03013 if (!menu_active) { 03014 menu_active = 1; 03015 /* Record this sound! */ 03016 if (!ast_streamfile(chan, "conf-adminmenu-162", chan->language)) { 03017 dtmf = ast_waitstream(chan, AST_DIGIT_ANY); 03018 ast_stopstream(chan); 03019 } else { 03020 dtmf = 0; 03021 } 03022 } else { 03023 dtmf = f->subclass; 03024 } 03025 if (dtmf) { 03026 switch(dtmf) { 03027 case '1': /* Un/Mute */ 03028 menu_active = 0; 03029 03030 /* for admin, change both admin and use flags */ 03031 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) { 03032 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED); 03033 } else { 03034 user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED); 03035 } 03036 03037 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { 03038 if (!ast_streamfile(chan, "conf-muted", chan->language)) { 03039 ast_waitstream(chan, ""); 03040 } 03041 } else { 03042 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) { 03043 ast_waitstream(chan, ""); 03044 } 03045 } 03046 break; 03047 case '2': /* Un/Lock the Conference */ 03048 menu_active = 0; 03049 if (conf->locked) { 03050 conf->locked = 0; 03051 if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) { 03052 ast_waitstream(chan, ""); 03053 } 03054 } else { 03055 conf->locked = 1; 03056 if (!ast_streamfile(chan, "conf-lockednow", chan->language)) { 03057 ast_waitstream(chan, ""); 03058 } 03059 } 03060 break; 03061 case '3': /* Eject last user */ 03062 menu_active = 0; 03063 usr = AST_LIST_LAST(&conf->userlist); 03064 if ((usr->chan->name == chan->name) || (usr->userflags & CONFFLAG_ADMIN)) { 03065 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) { 03066 ast_waitstream(chan, ""); 03067 } 03068 } else { 03069 usr->adminflags |= ADMINFLAG_KICKME; 03070 } 03071 ast_stopstream(chan); 03072 break; 03073 case '4': 03074 tweak_listen_volume(user, VOL_DOWN); 03075 break; 03076 case '5': 03077 /* Extend RT conference */ 03078 if (rt_schedule) { 03079 if (!rt_extend_conf(conf->confno)) { 03080 if (!ast_streamfile(chan, "conf-extended", chan->language)) { 03081 ast_waitstream(chan, ""); 03082 } 03083 } else { 03084 if (!ast_streamfile(chan, "conf-nonextended", chan->language)) { 03085 ast_waitstream(chan, ""); 03086 } 03087 } 03088 ast_stopstream(chan); 03089 } 03090 menu_active = 0; 03091 break; 03092 case '6': 03093 tweak_listen_volume(user, VOL_UP); 03094 break; 03095 case '7': 03096 tweak_talk_volume(user, VOL_DOWN); 03097 break; 03098 case '8': 03099 menu_active = 0; 03100 break; 03101 case '9': 03102 tweak_talk_volume(user, VOL_UP); 03103 break; 03104 default: 03105 menu_active = 0; 03106 /* Play an error message! */ 03107 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) { 03108 ast_waitstream(chan, ""); 03109 } 03110 break; 03111 } 03112 } 03113 } else { 03114 /* User menu */ 03115 if (!menu_active) { 03116 menu_active = 1; 03117 if (!ast_streamfile(chan, "conf-usermenu-162", chan->language)) { 03118 dtmf = ast_waitstream(chan, AST_DIGIT_ANY); 03119 ast_stopstream(chan); 03120 } else { 03121 dtmf = 0; 03122 } 03123 } else { 03124 dtmf = f->subclass; 03125 } 03126 if (dtmf) { 03127 switch (dtmf) { 03128 case '1': /* Un/Mute */ 03129 menu_active = 0; 03130 03131 /* user can only toggle the self-muted state */ 03132 user->adminflags ^= ADMINFLAG_SELFMUTED; 03133 03134 /* they can't override the admin mute state */ 03135 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { 03136 if (!ast_streamfile(chan, "conf-muted", chan->language)) { 03137 ast_waitstream(chan, ""); 03138 } 03139 } else { 03140 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) { 03141 ast_waitstream(chan, ""); 03142 } 03143 } 03144 break; 03145 case '2': 03146 menu_active = 0; 03147 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) { 03148 user->adminflags |= ADMINFLAG_T_REQUEST; 03149 } 03150 03151 if (user->adminflags & ADMINFLAG_T_REQUEST) { 03152 if (!ast_streamfile(chan, "beep", chan->language)) { 03153 ast_waitstream(chan, ""); 03154 } 03155 } 03156 break; 03157 case '4': 03158 tweak_listen_volume(user, VOL_DOWN); 03159 break; 03160 case '5': 03161 /* Extend RT conference */ 03162 if (rt_schedule) { 03163 rt_extend_conf(conf->confno); 03164 } 03165 menu_active = 0; 03166 break; 03167 case '6': 03168 tweak_listen_volume(user, VOL_UP); 03169 break; 03170 case '7': 03171 tweak_talk_volume(user, VOL_DOWN); 03172 break; 03173 case '8': 03174 menu_active = 0; 03175 break; 03176 case '9': 03177 tweak_talk_volume(user, VOL_UP); 03178 break; 03179 default: 03180 menu_active = 0; 03181 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) { 03182 ast_waitstream(chan, ""); 03183 } 03184 break; 03185 } 03186 } 03187 } 03188 if (musiconhold) { 03189 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]); 03190 } 03191 03192 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 03193 ast_log(LOG_WARNING, "Error setting conference\n"); 03194 close(fd); 03195 ast_frfree(f); 03196 goto outrun; 03197 } 03198 03199 conf_flush(fd, chan); 03200 /* Since this option could absorb DTMF meant for the previous (menu), we have to check this one last */ 03201 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) { 03202 if (confflags & CONFFLAG_PASS_DTMF) { 03203 conf_queue_dtmf(conf, user, f); 03204 } 03205 03206 if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) { 03207 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext); 03208 ret = 0; 03209 ast_frfree(f); 03210 break; 03211 } else { 03212 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext); 03213 } 03214 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) { 03215 pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr); 03216 03217 if (confflags & CONFFLAG_PASS_DTMF) { 03218 conf_queue_dtmf(conf, user, f); 03219 } 03220 ret = 0; 03221 ast_frfree(f); 03222 break; 03223 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) 03224 && confflags & CONFFLAG_PASS_DTMF) { 03225 conf_queue_dtmf(conf, user, f); 03226 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) { 03227 switch (f->subclass) { 03228 case AST_CONTROL_HOLD: 03229 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf); 03230 break; 03231 default: 03232 break; 03233 } 03234 } else if (f->frametype == AST_FRAME_NULL) { 03235 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */ 03236 } else { 03237 ast_debug(1, 03238 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n", 03239 chan->name, f->frametype, f->subclass); 03240 } 03241 ast_frfree(f); 03242 } else if (outfd > -1) { 03243 res = read(outfd, buf, CONF_SIZE); 03244 if (res > 0) { 03245 memset(&fr, 0, sizeof(fr)); 03246 fr.frametype = AST_FRAME_VOICE; 03247 fr.subclass = AST_FORMAT_SLINEAR; 03248 fr.datalen = res; 03249 fr.samples = res / 2; 03250 fr.data.ptr = buf; 03251 fr.offset = AST_FRIENDLY_OFFSET; 03252 if (!user->listen.actual && 03253 ((confflags & CONFFLAG_MONITOR) || 03254 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) || 03255 (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER)) 03256 )) { 03257 int idx; 03258 for (idx = 0; idx < AST_FRAME_BITS; idx++) { 03259 if (chan->rawwriteformat & (1 << idx)) { 03260 break; 03261 } 03262 } 03263 if (idx >= AST_FRAME_BITS) { 03264 goto bailoutandtrynormal; 03265 } 03266 ast_mutex_lock(&conf->listenlock); 03267 if (!conf->transframe[idx]) { 03268 if (conf->origframe) { 03269 if (!conf->transpath[idx]) { 03270 conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR); 03271 } 03272 if (conf->transpath[idx]) { 03273 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0); 03274 if (!conf->transframe[idx]) { 03275 conf->transframe[idx] = &ast_null_frame; 03276 } 03277 } 03278 } 03279 } 03280 if (conf->transframe[idx]) { 03281 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) && 03282 can_write(chan, confflags)) { 03283 struct ast_frame *cur; 03284 if (musiconhold && !ast_dsp_silence(dsp, conf->transframe[idx], &confsilence) && confsilence < MEETME_DELAYDETECTTALK) { 03285 ast_moh_stop(chan); 03286 mohtempstopped = 1; 03287 } 03288 03289 /* the translator may have returned a list of frames, so 03290 write each one onto the channel 03291 */ 03292 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 03293 if (ast_write(chan, cur)) { 03294 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name); 03295 break; 03296 } 03297 } 03298 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) { 03299 mohtempstopped = 0; 03300 ast_moh_start(chan, NULL, NULL); 03301 } 03302 } 03303 } else { 03304 ast_mutex_unlock(&conf->listenlock); 03305 goto bailoutandtrynormal; 03306 } 03307 ast_mutex_unlock(&conf->listenlock); 03308 } else { 03309 bailoutandtrynormal: 03310 if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) { 03311 ast_moh_stop(chan); 03312 mohtempstopped = 1; 03313 } 03314 if (user->listen.actual) { 03315 ast_frame_adjust_volume(&fr, user->listen.actual); 03316 } 03317 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) { 03318 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name); 03319 } 03320 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) { 03321 mohtempstopped = 0; 03322 ast_moh_start(chan, NULL, NULL); 03323 } 03324 } 03325 } else { 03326 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); 03327 } 03328 } 03329 lastmarked = currentmarked; 03330 } 03331 } 03332 03333 if (musiconhold) { 03334 ast_moh_stop(chan); 03335 } 03336 03337 if (using_pseudo) { 03338 close(fd); 03339 } else { 03340 /* Take out of conference */ 03341 dahdic.chan = 0; 03342 dahdic.confno = 0; 03343 dahdic.confmode = 0; 03344 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 03345 ast_log(LOG_WARNING, "Error setting conference\n"); 03346 } 03347 } 03348 03349 reset_volumes(user); 03350 03351 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { 03352 conf_play(chan, conf, LEAVE); 03353 } 03354 03355 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) { 03356 struct announce_listitem *item; 03357 if (!(item = ao2_alloc(sizeof(*item), NULL))) 03358 return -1; 03359 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc)); 03360 ast_copy_string(item->language, chan->language, sizeof(item->language)); 03361 item->confchan = conf->chan; 03362 item->confusers = conf->users; 03363 item->announcetype = CONF_HASLEFT; 03364 ast_mutex_lock(&conf->announcelistlock); 03365 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry); 03366 ast_cond_signal(&conf->announcelist_addition); 03367 ast_mutex_unlock(&conf->announcelistlock); 03368 } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) { 03369 /* Last person is leaving, so no reason to try and announce, but should delete the name recording */ 03370 ast_filedelete(user->namerecloc, NULL); 03371 } 03372 03373 outrun: 03374 AST_LIST_LOCK(&confs); 03375 03376 if (dsp) { 03377 ast_dsp_free(dsp); 03378 } 03379 03380 if (user->user_no) { /* Only cleanup users who really joined! */ 03381 now = ast_tvnow(); 03382 hr = (now.tv_sec - user->jointime) / 3600; 03383 min = ((now.tv_sec - user->jointime) % 3600) / 60; 03384 sec = (now.tv_sec - user->jointime) % 60; 03385 03386 if (sent_event) { 03387 manager_event(EVENT_FLAG_CALL, "MeetmeLeave", 03388 "Channel: %s\r\n" 03389 "Uniqueid: %s\r\n" 03390 "Meetme: %s\r\n" 03391 "Usernum: %d\r\n" 03392 "CallerIDNum: %s\r\n" 03393 "CallerIDName: %s\r\n" 03394 "Duration: %ld\r\n", 03395 chan->name, chan->uniqueid, conf->confno, 03396 user->user_no, 03397 S_OR(user->chan->cid.cid_num, "<unknown>"), 03398 S_OR(user->chan->cid.cid_name, "<unknown>"), 03399 (long)(now.tv_sec - user->jointime)); 03400 } 03401 03402 if (setusercount) { 03403 conf->users--; 03404 if (rt_log_members) { 03405 /* Update table */ 03406 snprintf(members, sizeof(members), "%d", conf->users); 03407 ast_realtime_require_field("meetme", 03408 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno), 03409 "members", RQ_UINTEGER1, strlen(members), 03410 NULL); 03411 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL); 03412 } 03413 if (confflags & CONFFLAG_MARKEDUSER) { 03414 conf->markedusers--; 03415 } 03416 } 03417 /* Remove ourselves from the list */ 03418 AST_LIST_REMOVE(&conf->userlist, user, list); 03419 03420 /* Change any states */ 03421 if (!conf->users) { 03422 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno); 03423 } 03424 03425 /* Return the number of seconds the user was in the conf */ 03426 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime)); 03427 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); 03428 } 03429 ast_free(user); 03430 AST_LIST_UNLOCK(&confs); 03431 03432 return ret; 03433 }
| static void conf_start_moh | ( | struct ast_channel * | chan, | |
| const char * | musicclass | |||
| ) | [static] |
Definition at line 1951 of file app_meetme.c.
References ast_channel_lock, ast_channel_unlock, ast_moh_start(), ast_strdupa, ast_string_field_set, and ast_channel::musicclass.
Referenced by conf_run().
01952 { 01953 char *original_moh; 01954 01955 ast_channel_lock(chan); 01956 original_moh = ast_strdupa(chan->musicclass); 01957 ast_string_field_set(chan, musicclass, musicclass); 01958 ast_channel_unlock(chan); 01959 01960 ast_moh_start(chan, original_moh, NULL); 01961 01962 ast_channel_lock(chan); 01963 ast_string_field_set(chan, musicclass, original_moh); 01964 ast_channel_unlock(chan); 01965 }
| static int count_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
The MeetmeCount application.
Definition at line 3711 of file app_meetme.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_say_number(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), dispose_conf(), find_conf(), ast_channel::language, LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.
Referenced by load_module().
03712 { 03713 int res = 0; 03714 struct ast_conference *conf; 03715 int count; 03716 char *localdata; 03717 char val[80] = "0"; 03718 AST_DECLARE_APP_ARGS(args, 03719 AST_APP_ARG(confno); 03720 AST_APP_ARG(varname); 03721 ); 03722 03723 if (ast_strlen_zero(data)) { 03724 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n"); 03725 return -1; 03726 } 03727 03728 if (!(localdata = ast_strdupa(data))) 03729 return -1; 03730 03731 AST_STANDARD_APP_ARGS(args, localdata); 03732 03733 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL); 03734 03735 if (conf) { 03736 count = conf->users; 03737 dispose_conf(conf); 03738 conf = NULL; 03739 } else 03740 count = 0; 03741 03742 if (!ast_strlen_zero(args.varname)) { 03743 /* have var so load it and exit */ 03744 snprintf(val, sizeof(val), "%d", count); 03745 pbx_builtin_setvar_helper(chan, args.varname, val); 03746 } else { 03747 if (chan->_state != AST_STATE_UP) { 03748 ast_answer(chan); 03749 } 03750 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */ 03751 } 03752 03753 return res; 03754 }
| static struct sla_trunk_ref* create_trunk_ref | ( | struct sla_trunk * | trunk | ) | [static, read] |
Definition at line 5818 of file app_meetme.c.
References ast_calloc, and sla_trunk_ref::trunk.
Referenced by sla_add_trunk_to_station().
05819 { 05820 struct sla_trunk_ref *trunk_ref; 05821 05822 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref)))) 05823 return NULL; 05824 05825 trunk_ref->trunk = trunk; 05826 05827 return trunk_ref; 05828 }
| static void destroy_station | ( | struct sla_station * | station | ) | [static] |
Definition at line 6029 of file app_meetme.c.
References ast_context_remove_extension(), ast_free, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_string_field_free_memory, ast_strlen_zero(), sla_station::autocontext, exten, sla_trunk::name, sla_station::name, PRIORITY_HINT, sla_registrar, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_build_station(), and sla_destroy().
06030 { 06031 struct sla_trunk_ref *trunk_ref; 06032 06033 if (!ast_strlen_zero(station->autocontext)) { 06034 AST_RWLIST_RDLOCK(&sla_trunks); 06035 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 06036 char exten[AST_MAX_EXTENSION]; 06037 char hint[AST_MAX_APP]; 06038 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name); 06039 snprintf(hint, sizeof(hint), "SLA:%s", exten); 06040 ast_context_remove_extension(station->autocontext, exten, 06041 1, sla_registrar); 06042 ast_context_remove_extension(station->autocontext, hint, 06043 PRIORITY_HINT, sla_registrar); 06044 } 06045 AST_RWLIST_UNLOCK(&sla_trunks); 06046 } 06047 06048 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) 06049 ast_free(trunk_ref); 06050 06051 ast_string_field_free_memory(station); 06052 ast_free(station); 06053 }
| static void destroy_trunk | ( | struct sla_trunk * | trunk | ) | [static] |
Definition at line 6015 of file app_meetme.c.
References ast_context_remove_extension(), ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_strlen_zero(), sla_trunk::autocontext, sla_registrar, and sla_trunk::stations.
Referenced by sla_build_trunk(), and sla_destroy().
06016 { 06017 struct sla_station_ref *station_ref; 06018 06019 if (!ast_strlen_zero(trunk->autocontext)) 06020 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar); 06021 06022 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) 06023 ast_free(station_ref); 06024 06025 ast_string_field_free_memory(trunk); 06026 ast_free(trunk); 06027 }
| static void* dial_trunk | ( | void * | data | ) | [static] |
Definition at line 5530 of file app_meetme.c.
References ALL_TRUNK_REFS, ast_cond_signal(), ast_dial_answered(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_run(), ast_dial_state(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), build_conf(), sla_trunk::chan, sla_trunk_ref::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, dial_trunk_args::cond, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_TRUNK, sla_trunk::device, dispose_conf(), ast_flags::flags, MAX_CONFNUM, sla_trunk::name, sla_trunk::on_hold, sla, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, strsep(), sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.
Referenced by sla_station_exec().
05531 { 05532 struct dial_trunk_args *args = data; 05533 struct ast_dial *dial; 05534 char *tech, *tech_data; 05535 enum ast_dial_result dial_res; 05536 char conf_name[MAX_CONFNUM]; 05537 struct ast_conference *conf; 05538 struct ast_flags conf_flags = { 0 }; 05539 struct sla_trunk_ref *trunk_ref = args->trunk_ref; 05540 const char *cid_name = NULL, *cid_num = NULL; 05541 05542 if (!(dial = ast_dial_create())) { 05543 ast_mutex_lock(args->cond_lock); 05544 ast_cond_signal(args->cond); 05545 ast_mutex_unlock(args->cond_lock); 05546 return NULL; 05547 } 05548 05549 tech_data = ast_strdupa(trunk_ref->trunk->device); 05550 tech = strsep(&tech_data, "/"); 05551 if (ast_dial_append(dial, tech, tech_data) == -1) { 05552 ast_mutex_lock(args->cond_lock); 05553 ast_cond_signal(args->cond); 05554 ast_mutex_unlock(args->cond_lock); 05555 ast_dial_destroy(dial); 05556 return NULL; 05557 } 05558 05559 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) { 05560 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name); 05561 ast_free(trunk_ref->chan->cid.cid_name); 05562 trunk_ref->chan->cid.cid_name = NULL; 05563 } 05564 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) { 05565 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num); 05566 ast_free(trunk_ref->chan->cid.cid_num); 05567 trunk_ref->chan->cid.cid_num = NULL; 05568 } 05569 05570 dial_res = ast_dial_run(dial, trunk_ref->chan, 1); 05571 05572 if (cid_name) 05573 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name); 05574 if (cid_num) 05575 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num); 05576 05577 if (dial_res != AST_DIAL_RESULT_TRYING) { 05578 ast_mutex_lock(args->cond_lock); 05579 ast_cond_signal(args->cond); 05580 ast_mutex_unlock(args->cond_lock); 05581 ast_dial_destroy(dial); 05582 return NULL; 05583 } 05584 05585 for (;;) { 05586 unsigned int done = 0; 05587 switch ((dial_res = ast_dial_state(dial))) { 05588 case AST_DIAL_RESULT_ANSWERED: 05589 trunk_ref->trunk->chan = ast_dial_answered(dial); 05590 case AST_DIAL_RESULT_HANGUP: 05591 case AST_DIAL_RESULT_INVALID: 05592 case AST_DIAL_RESULT_FAILED: 05593 case AST_DIAL_RESULT_TIMEOUT: 05594 case AST_DIAL_RESULT_UNANSWERED: 05595 done = 1; 05596 case AST_DIAL_RESULT_TRYING: 05597 case AST_DIAL_RESULT_RINGING: 05598 case AST_DIAL_RESULT_PROGRESS: 05599 case AST_DIAL_RESULT_PROCEEDING: 05600 break; 05601 } 05602 if (done) 05603 break; 05604 } 05605 05606 if (!trunk_ref->trunk->chan) { 05607 ast_mutex_lock(args->cond_lock); 05608 ast_cond_signal(args->cond); 05609 ast_mutex_unlock(args->cond_lock); 05610 ast_dial_join(dial); 05611 ast_dial_destroy(dial); 05612 return NULL; 05613 } 05614 05615 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name); 05616 ast_set_flag(&conf_flags, 05617 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 05618 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK); 05619 conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan); 05620 05621 ast_mutex_lock(args->cond_lock); 05622 ast_cond_signal(args->cond); 05623 ast_mutex_unlock(args->cond_lock); 05624 05625 if (conf) { 05626 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL); 05627 dispose_conf(conf); 05628 conf = NULL; 05629 } 05630 05631 /* If the trunk is going away, it is definitely now IDLE. */ 05632 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 05633 05634 trunk_ref->trunk->chan = NULL; 05635 trunk_ref->trunk->on_hold = 0; 05636 05637 ast_dial_join(dial); 05638 ast_dial_destroy(dial); 05639 05640 return NULL; 05641 }
| static int dispose_conf | ( | struct ast_conference * | conf | ) | [static] |
Decrement reference counts, as incremented by find_conf().
Definition at line 1870 of file app_meetme.c.
References ast_atomic_dec_and_test(), AST_LIST_LOCK, AST_LIST_UNLOCK, conf_free(), conf_map, ast_conference::confno, and ast_conference::refcount.
Referenced by admin_exec(), conf_exec(), count_exec(), dial_trunk(), run_station(), sla_station_exec(), and sla_trunk_exec().
01871 { 01872 int res = 0; 01873 int confno_int = 0; 01874 01875 AST_LIST_LOCK(&confs); 01876 if (ast_atomic_dec_and_test(&conf->refcount)) { 01877 /* Take the conference room number out of an inuse state */ 01878 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) { 01879 conf_map[confno_int] = 0; 01880 } 01881 conf_free(conf); 01882 res = 1; 01883 } 01884 AST_LIST_UNLOCK(&confs); 01885 01886 return res; 01887 }
| 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_flags * | confflags | |||
| ) | [static, read] |
Definition at line 3609 of file app_meetme.c.
References AST_APP_ARG, ast_app_getdata(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_test_flag, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, ast_conference::list, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, parse(), ast_conference::refcount, S_OR, ast_variable::value, and var.
Referenced by conf_exec(), and count_exec().
03611 { 03612 struct ast_config *cfg; 03613 struct ast_variable *var; 03614 struct ast_flags config_flags = { 0 }; 03615 struct ast_conference *cnf; 03616 char *parse; 03617 AST_DECLARE_APP_ARGS(args, 03618 AST_APP_ARG(confno); 03619 AST_APP_ARG(pin); 03620 AST_APP_ARG(pinadmin); 03621 ); 03622 03623 /* Check first in the conference list */ 03624 ast_debug(1, "The requested confno is '%s'?\n", confno); 03625 AST_LIST_LOCK(&confs); 03626 AST_LIST_TRAVERSE(&confs, cnf, list) { 03627 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno); 03628 if (!strcmp(confno, cnf->confno)) 03629 break; 03630 } 03631 if (cnf) { 03632 cnf->refcount += refcount; 03633 } 03634 AST_LIST_UNLOCK(&confs); 03635 03636 if (!cnf) { 03637 if (dynamic) { 03638 /* No need to parse meetme.conf */ 03639 ast_debug(1, "Building dynamic conference '%s'\n", confno); 03640 if (dynamic_pin) { 03641 if (dynamic_pin[0] == 'q') { 03642 /* Query the user to enter a PIN */ 03643 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0) 03644 return NULL; 03645 } 03646 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan); 03647 } else { 03648 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan); 03649 } 03650 } else { 03651 /* Check the config */ 03652 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags); 03653 if (!cfg) { 03654 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME); 03655 return NULL; 03656 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 03657 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n"); 03658 return NULL; 03659 } 03660 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) { 03661 if (strcasecmp(var->name, "conf")) 03662 continue; 03663 03664 if (!(parse = ast_strdupa(var->value))) 03665 return NULL; 03666 03667 AST_STANDARD_APP_ARGS(args, parse); 03668 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno); 03669 if (!strcasecmp(args.confno, confno)) { 03670 /* Bingo it's a valid conference */ 03671 cnf = build_conf(args.confno, 03672 S_OR(args.pin, ""), 03673 S_OR(args.pinadmin, ""), 03674 make, dynamic, refcount, chan); 03675 break; 03676 } 03677 } 03678 if (!var) { 03679 ast_debug(1, "%s isn't a valid conference\n", confno); 03680 } 03681 ast_config_destroy(cfg); 03682 } 03683 } else if (dynamic_pin) { 03684 /* Correct for the user selecting 'D' instead of 'd' to have 03685 someone join into a conference that has already been created 03686 with a pin. */ 03687 if (dynamic_pin[0] == 'q') { 03688 dynamic_pin[0] = '\0'; 03689 } 03690 } 03691 03692 if (cnf) { 03693 if (confflags && !cnf->chan && 03694 !ast_test_flag(confflags, CONFFLAG_QUIET) && 03695 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) { 03696 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n"); 03697 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW); 03698 } 03699 03700 if (confflags && !cnf->chan && 03701 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) { 03702 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n"); 03703 ast_clear_flag(confflags, CONFFLAG_RECORDCONF); 03704 } 03705 } 03706 03707 return cnf; 03708 }
| 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_flags * | confflags, | |||
| int * | too_early | |||
| ) | [static, read] |
Definition at line 3435 of file app_meetme.c.
References ast_conference::adminopts, ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), AST_MAX_EXTENSION, ast_mktime(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag, ast_tvnow(), ast_variables_destroy(), ast_verb, ast_waitstream(), ast_conference::bookid, build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, ast_conference::endalert, ast_conference::endtime, ast_channel::language, ast_conference::list, LOG_WARNING, ast_conference::maxusers, ast_variable::name, ast_variable::next, OPTIONS_LEN, pbx_builtin_getvar_helper(), ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::refcount, ast_channel::uniqueid, ast_conference::useropts, ast_variable::value, and var.
Referenced by conf_exec().
03437 { 03438 struct ast_variable *var, *origvar; 03439 struct ast_conference *cnf; 03440 03441 *too_early = 0; 03442 03443 /* Check first in the conference list */ 03444 AST_LIST_LOCK(&confs); 03445 AST_LIST_TRAVERSE(&confs, cnf, list) { 03446 if (!strcmp(confno, cnf->confno)) 03447 break; 03448 } 03449 if (cnf) { 03450 cnf->refcount += refcount; 03451 } 03452 AST_LIST_UNLOCK(&confs); 03453 03454 if (!cnf) { 03455 char *pin = NULL, *pinadmin = NULL; /* For temp use */ 03456 int maxusers = 0; 03457 struct timeval now; 03458 char recordingfilename[256] = ""; 03459 char recordingformat[11] = ""; 03460 char currenttime[19] = ""; 03461 char eatime[19] = ""; 03462 char bookid[51] = ""; 03463 char recordingtmp[AST_MAX_EXTENSION] = ""; 03464 char useropts[OPTIONS_LEN + 1]; /* Used for RealTime conferences */ 03465 char adminopts[OPTIONS_LEN + 1]; 03466 struct ast_tm tm, etm; 03467 struct timeval endtime = { .tv_sec = 0 }; 03468 const char *var2; 03469 03470 if (rt_schedule) { 03471 now = ast_tvnow(); 03472 03473 ast_localtime(&now, &tm, NULL); 03474 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); 03475 03476 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime); 03477 03478 var = ast_load_realtime("meetme", "confno", 03479 confno, "starttime <= ", currenttime, "endtime >= ", 03480 currenttime, NULL); 03481 03482 if (!var && fuzzystart) { 03483 now = ast_tvnow(); 03484 now.tv_sec += fuzzystart; 03485 03486 ast_localtime(&now, &tm, NULL); 03487 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); 03488 var = ast_load_realtime("meetme", "confno", 03489 confno, "starttime <= ", currenttime, "endtime >= ", 03490 currenttime, NULL); 03491 } 03492 03493 if (!var && earlyalert) { 03494 now = ast_tvnow(); 03495 now.tv_sec += earlyalert; 03496 ast_localtime(&now, &etm, NULL); 03497 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm); 03498 var = ast_load_realtime("meetme", "confno", 03499 confno, "starttime <= ", eatime, "endtime >= ", 03500 currenttime, NULL); 03501 if (var) { 03502 *too_early = 1; 03503 } 03504 } 03505 03506 } else { 03507 var = ast_load_realtime("meetme", "confno", confno, NULL); 03508 } 03509 03510 if (!var) 03511 return NULL; 03512 03513 if (rt_schedule && *too_early) { 03514 /* Announce that the caller is early and exit */ 03515 if (!ast_streamfile(chan, "conf-has-not-started", chan->language)) 03516 ast_waitstream(chan, ""); 03517 ast_variables_destroy(var); 03518 return NULL; 03519 } 03520 03521 for (origvar = var; var; var = var->next) { 03522 if (!strcasecmp(var->name, "pin")) { 03523 pin = ast_strdupa(var->value); 03524 } else if (!strcasecmp(var->name, "adminpin")) { 03525 pinadmin = ast_strdupa(var->value); 03526 } else if (!strcasecmp(var->name, "bookId")) { 03527 ast_copy_string(bookid, var->value, sizeof(bookid)); 03528 } else if (!strcasecmp(var->name, "opts")) { 03529 ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1])); 03530 } else if (!strcasecmp(var->name, "maxusers")) { 03531 maxusers = atoi(var->value); 03532 } else if (!strcasecmp(var->name, "adminopts")) { 03533 ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1])); 03534 } else if (!strcasecmp(var->name, "recordingfilename")) { 03535 ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename)); 03536 } else if (!strcasecmp(var->name, "recordingformat")) { 03537 ast_copy_string(recordingformat, var->value, sizeof(recordingformat)); 03538 } else if (!strcasecmp(var->name, "endtime")) { 03539 struct ast_tm endtime_tm; 03540 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm); 03541 endtime = ast_mktime(&endtime_tm, NULL); 03542 } 03543 } 03544 03545 ast_variables_destroy(origvar); 03546 03547 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan); 03548 03549 if (cnf) { 03550 cnf->maxusers = maxusers; 03551 cnf->endalert = endalert; 03552 cnf->endtime = endtime.tv_sec; 03553 cnf->useropts = ast_strdup(useropts); 03554 cnf->adminopts = ast_strdup(adminopts); 03555 cnf->bookid = ast_strdup(bookid); 03556 cnf->recordingfilename = ast_strdup(recordingfilename); 03557 cnf->recordingformat = ast_strdup(recordingformat); 03558 03559 if (strchr(cnf->useropts, 'r')) { 03560 if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */ 03561 ast_channel_lock(chan); 03562 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) { 03563 ast_free(cnf->recordingfilename); 03564 cnf->recordingfilename = ast_strdup(var2); 03565 } 03566 ast_channel_unlock(chan); 03567 if (ast_strlen_zero(cnf->recordingfilename)) { 03568 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid); 03569 ast_free(cnf->recordingfilename); 03570 cnf->recordingfilename = ast_strdup(recordingtmp); 03571 } 03572 } 03573 if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */ 03574 ast_channel_lock(chan); 03575 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) { 03576 ast_free(cnf->recordingformat); 03577 cnf->recordingformat = ast_strdup(var2); 03578 } 03579 ast_channel_unlock(chan); 03580 if (ast_strlen_zero(cnf->recordingformat)) { 03581 ast_free(cnf->recordingformat); 03582 cnf->recordingformat = ast_strdup("wav"); 03583 } 03584 } 03585 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat); 03586 } 03587 } 03588 } 03589 03590 if (cnf) { 03591 if (confflags && !cnf->chan && 03592 !ast_test_flag(confflags, CONFFLAG_QUIET) && 03593 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) { 03594 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n"); 03595 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW); 03596 } 03597 03598 if (confflags && !cnf->chan && 03599 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) { 03600 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n"); 03601 ast_clear_flag(confflags, CONFFLAG_RECORDCONF); 03602 } 03603 } 03604 03605 return cnf; 03606 }
| static struct ast_conf_user* find_user | ( | struct ast_conference * | conf, | |
| const char * | callerident | |||
| ) | [static, read] |
Definition at line 4015 of file app_meetme.c.
References AST_LIST_TRAVERSE, ast_conf_user::list, ast_conf_user::user_no, and ast_conference::userlist.
Referenced by acf_mailbox_exists(), admin_exec(), advanced_options(), calltoken_required(), forward_message(), handle_cli_iax2_prune_realtime(), leave_voicemail(), pp_each_extension_helper(), requirecalltoken_mark_auto(), set_config(), setup_incoming_call(), vm_authenticate(), vm_box_exists(), and vm_execmain().
04016 { 04017 struct ast_conf_user *user = NULL; 04018 int cid; 04019 04020 sscanf(callerident, "%30i", &cid); 04021 if (conf && callerident) { 04022 AST_LIST_TRAVERSE(&conf->userlist, user, list) { 04023 if (cid == user->user_no) 04024 return user; 04025 } 04026 } 04027 return NULL; 04028 }
| static const char* get_announce_filename | ( | enum announcetypes | type | ) | [static] |
Definition at line 1967 of file app_meetme.c.
References CONF_HASJOIN, and CONF_HASLEFT.
Referenced by announce_thread().
01968 { 01969 switch (type) { 01970 case CONF_HASLEFT: 01971 return "conf-hasleft"; 01972 break; 01973 case CONF_HASJOIN: 01974 return "conf-hasjoin"; 01975 break; 01976 default: 01977 return ""; 01978 } 01979 }
| static const char* istalking | ( | int | x | ) | [static] |
Definition at line 956 of file app_meetme.c.
Referenced by meetme_show_cmd().
00957 { 00958 if (x > 0) 00959 return "(talking)"; 00960 else if (x < 0) 00961 return "(unmonitored)"; 00962 else 00963 return "(not talking)"; 00964 }
| static int load_config | ( | int | reload | ) | [static] |
Definition at line 6466 of file app_meetme.c.
References ast_log(), load_config_meetme(), LOG_NOTICE, SLA_EVENT_RELOAD, sla_load_config(), and sla_queue_event().
06467 { 06468 load_config_meetme(); 06469 06470 if (reload) { 06471 sla_queue_event(SLA_EVENT_RELOAD); 06472 ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested " 06473 "and will be completed when the system is idle.\n"); 06474 return 0; 06475 } 06476 06477 return sla_load_config(0); 06478 }
| static void load_config_meetme | ( | void | ) | [static] |
Definition at line 4502 of file app_meetme.c.
References ast_config_destroy(), ast_config_load, ast_log(), ast_true(), ast_variable_retrieve(), CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, DEFAULT_AUDIO_BUFFERS, LOG_ERROR, LOG_NOTICE, and LOG_WARNING.
Referenced by load_config().
04503 { 04504 struct ast_config *cfg; 04505 struct ast_flags config_flags = { 0 }; 04506 const char *val; 04507 04508 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) { 04509 return; 04510 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 04511 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n"); 04512 return; 04513 } 04514 04515 audio_buffers = DEFAULT_AUDIO_BUFFERS; 04516 04517 /* Scheduling support is off by default */ 04518 rt_schedule = 0; 04519 fuzzystart = 0; 04520 earlyalert = 0; 04521 endalert = 0; 04522 extendby = 0; 04523 04524 /* Logging of participants defaults to ON for compatibility reasons */ 04525 rt_log_members = 1; 04526 04527 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) { 04528 if ((sscanf(val, "%30d", &audio_buffers) != 1)) { 04529 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val); 04530 audio_buffers = DEFAULT_AUDIO_BUFFERS; 04531 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) { 04532 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n", 04533 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS); 04534 audio_buffers = DEFAULT_AUDIO_BUFFERS; 04535 } 04536 if (audio_buffers != DEFAULT_AUDIO_BUFFERS) 04537 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers); 04538 } 04539 04540 if ((val = ast_variable_retrieve(cfg, "general", "schedule"))) 04541 rt_schedule = ast_true(val); 04542 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount"))) 04543 rt_log_members = ast_true(val); 04544 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) { 04545 if ((sscanf(val, "%30d", &fuzzystart) != 1)) { 04546 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val); 04547 fuzzystart = 0; 04548 } 04549 } 04550 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) { 04551 if ((sscanf(val, "%30d", &earlyalert) != 1)) { 04552 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val); 04553 earlyalert = 0; 04554 } 04555 } 04556 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) { 04557 if ((sscanf(val, "%30d", &endalert) != 1)) { 04558 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val); 04559 endalert = 0; 04560 } 04561 } 04562 if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) { 04563 if ((sscanf(val, "%30d", &extendby) != 1)) { 04564 ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val); 04565 extendby = 0; 04566 } 04567 } 04568 04569 ast_config_destroy(cfg); 04570 }
| static int load_module | ( | void | ) | [static] |
Definition at line 6506 of file app_meetme.c.
References action_meetmelist(), action_meetmemute(), action_meetmeunmute(), admin_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_devstate_prov_add(), ast_manager_register_xml, ast_realtime_require_field(), ast_register_application_xml, channel_admin_exec(), conf_exec(), count_exec(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, load_config(), meetmestate(), RQ_UINTEGER1, RQ_UINTEGER2, sla_state(), sla_station_exec(), and sla_trunk_exec().
06507 { 06508 int res = 0; 06509 06510 res |= load_config(0); 06511 06512 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme)); 06513 res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute); 06514 res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute); 06515 res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist); 06516 res |= ast_register_application_xml(app4, channel_admin_exec); 06517 res |= ast_register_application_xml(app3, admin_exec); 06518 res |= ast_register_application_xml(app2, count_exec); 06519 res |= ast_register_application_xml(app, conf_exec); 06520 res |= ast_register_application_xml(slastation_app, sla_station_exec); 06521 res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec); 06522 06523 res |= ast_devstate_prov_add("Meetme", meetmestate); 06524 res |= ast_devstate_prov_add("SLA", sla_state); 06525 06526 res |= ast_custom_function_register(&meetme_info_acf); 06527 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL); 06528 06529 return res; 06530 }
| static char* meetme_cmd | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1436 of file app_meetme.c.
References admin_exec(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_debug, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), ast_cli_args::fd, ast_cli_args::line, MAX_CONFNUM, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
01437 { 01438 /* Process the command */ 01439 struct ast_str *cmdline = NULL; 01440 int i = 0; 01441 01442 switch (cmd) { 01443 case CLI_INIT: 01444 e->command = "meetme {lock|unlock|mute|unmute|kick}"; 01445 e->usage = 01446 "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n" 01447 " Executes a command for the conference or on a conferee\n"; 01448 return NULL; 01449 case CLI_GENERATE: 01450 return complete_meetmecmd(a->line, a->word, a->pos, a->n); 01451 } 01452 01453 if (a->argc > 8) 01454 ast_cli(a->fd, "Invalid Arguments.\n"); 01455 /* Check for length so no buffer will overflow... */ 01456 for (i = 0; i < a->argc; i++) { 01457 if (strlen(a->argv[i]) > 100) 01458 ast_cli(a->fd, "Invalid Arguments.\n"); 01459 } 01460 01461 /* Max confno length */ 01462 if (!(cmdline = ast_str_create(MAX_CONFNUM))) { 01463 return CLI_FAILURE; 01464 } 01465 01466 if (a->argc < 1) { 01467 ast_free(cmdline); 01468 return CLI_SHOWUSAGE; 01469 } 01470 01471 ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */ 01472 if (strstr(a->argv[1], "lock")) { 01473 if (strcmp(a->argv[1], "lock") == 0) { 01474 /* Lock */ 01475 ast_str_append(&cmdline, 0, ",L"); 01476 } else { 01477 /* Unlock */ 01478 ast_str_append(&cmdline, 0, ",l"); 01479 } 01480 } else if (strstr(a->argv[1], "mute")) { 01481 if (a->argc < 4) { 01482 ast_free(cmdline); 01483 return CLI_SHOWUSAGE; 01484 } 01485 if (strcmp(a->argv[1], "mute") == 0) { 01486 /* Mute */ 01487 if (strcmp(a->argv[3], "all") == 0) { 01488 ast_str_append(&cmdline, 0, ",N"); 01489 } else { 01490 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]); 01491 } 01492 } else { 01493 /* Unmute */ 01494 if (strcmp(a->argv[3], "all") == 0) { 01495 ast_str_append(&cmdline, 0, ",n"); 01496 } else { 01497 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]); 01498 } 01499 } 01500 } else if (strcmp(a->argv[1], "kick") == 0) { 01501 if (a->argc < 4) { 01502 ast_free(cmdline); 01503 return CLI_SHOWUSAGE; 01504 } 01505 if (strcmp(a->argv[3], "all") == 0) { 01506 /* Kick all */ 01507 ast_str_append(&cmdline, 0, ",K"); 01508 } else { 01509 /* Kick a single user */ 01510 ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]); 01511 } 01512 } else { 01513 ast_free(cmdline); 01514 return CLI_SHOWUSAGE; 01515 } 01516 01517 ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline)); 01518 01519 admin_exec(NULL, ast_str_buffer(cmdline)); 01520 ast_free(cmdline); 01521 01522 return CLI_SUCCESS; 01523 }
| static char* meetme_show_cmd | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1282 of file app_meetme.c.
References admin_exec(), ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_debug, ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_cli_args::fd, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MAX_CONFNUM, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_channel::name, ast_cli_args::pos, S_OR, sec, ast_conference::start, ast_conf_user::talking, total, ast_cli_entry::usage, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, and ast_cli_args::word.
01283 { 01284 /* Process the command */ 01285 struct ast_conf_user *user; 01286 struct ast_conference *cnf; 01287 int hr, min, sec; 01288 int i = 0, total = 0; 01289 time_t now; 01290 struct ast_str *cmdline = NULL; 01291 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n" 01292 #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n" 01293 01294 switch (cmd) { 01295 case CLI_INIT: 01296 e->command = "meetme list [concise]"; 01297 e->usage = 01298 "Usage: meetme list [concise] <confno> \n" 01299 " List all or a specific conference.\n"; 01300 return NULL; 01301 case CLI_GENERATE: 01302 return complete_meetmecmd(a->line, a->word, a->pos, a->n); 01303 } 01304 01305 /* Check for length so no buffer will overflow... */ 01306 for (i = 0; i < a->argc; i++) { 01307 if (strlen(a->argv[i]) > 100) 01308 ast_cli(a->fd, "Invalid Arguments.\n"); 01309 } 01310 01311 /* Max confno length */ 01312 if (!(cmdline = ast_str_create(MAX_CONFNUM))) { 01313 return CLI_FAILURE; 01314 } 01315 01316 if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) { 01317 /* List all the conferences */ 01318 int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise")); 01319 now = time(NULL); 01320 AST_LIST_LOCK(&confs); 01321 if (AST_LIST_EMPTY(&confs)) { 01322 if (!concise) { 01323 ast_cli(a->fd, "No active MeetMe conferences.\n"); 01324 } 01325 AST_LIST_UNLOCK(&confs); 01326 ast_free(cmdline); 01327 return CLI_SUCCESS; 01328 } 01329 if (!concise) { 01330 ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked"); 01331 } 01332 AST_LIST_TRAVERSE(&confs, cnf, list) { 01333 if (cnf->markedusers == 0) { 01334 ast_str_set(&cmdline, 0, "N/A "); 01335 } else { 01336 ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers); 01337 } 01338 hr = (now - cnf->start) / 3600; 01339 min = ((now - cnf->start) % 3600) / 60; 01340 sec = (now - cnf->start) % 60; 01341 if (!concise) { 01342 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"); 01343 } else { 01344 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n", 01345 cnf->confno, 01346 cnf->users, 01347 cnf->markedusers, 01348 hr, min, sec, 01349 cnf->isdynamic, 01350 cnf->locked); 01351 } 01352 01353 total += cnf->users; 01354 } 01355 AST_LIST_UNLOCK(&confs); 01356 if (!concise) { 01357 ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total); 01358 } 01359 ast_free(cmdline); 01360 return CLI_SUCCESS; 01361 } else if (strcmp(a->argv[1], "list") == 0) { 01362 int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise"))); 01363 /* List all the users in a conference */ 01364 if (AST_LIST_EMPTY(&confs)) { 01365 if (!concise) { 01366 ast_cli(a->fd, "No active MeetMe conferences.\n"); 01367 } 01368 ast_free(cmdline); 01369 return CLI_SUCCESS; 01370 } 01371 /* Find the right conference */ 01372 AST_LIST_LOCK(&confs); 01373 AST_LIST_TRAVERSE(&confs, cnf, list) { 01374 if (strcmp(cnf->confno, a->argv[2]) == 0) { 01375 break; 01376 } 01377 } 01378 if (!cnf) { 01379 if (!concise) 01380 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]); 01381 AST_LIST_UNLOCK(&confs); 01382 ast_free(cmdline); 01383 return CLI_SUCCESS; 01384 } 01385 /* Show all the users */ 01386 time(&now); 01387 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 01388 hr = (now - user->jointime) / 3600; 01389 min = ((now - user->jointime) % 3600) / 60; 01390 sec = (now - user->jointime) % 60; 01391 if (!concise) { 01392 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n", 01393 user->user_no, 01394 S_OR(user->chan->cid.cid_num, "<unknown>"), 01395 S_OR(user->chan->cid.cid_name, "<no name>"), 01396 user->chan->name, 01397 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "", 01398 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "", 01399 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "", 01400 user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "", 01401 istalking(user->talking), hr, min, sec); 01402 } else { 01403 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n", 01404 user->user_no, 01405 S_OR(user->chan->cid.cid_num, ""), 01406 S_OR(user->chan->cid.cid_name, ""), 01407 user->chan->name, 01408 user->userflags & CONFFLAG_ADMIN ? "1" : "", 01409 user->userflags & CONFFLAG_MONITOR ? "1" : "", 01410 user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "", 01411 user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "", 01412 user->talking, hr, min, sec); 01413 } 01414 } 01415 if (!concise) { 01416 ast_cli(a->fd, "%d users in that conference.\n", cnf->users); 01417 } 01418 AST_LIST_UNLOCK(&confs); 01419 ast_free(cmdline); 01420 return CLI_SUCCESS; 01421 } 01422 if (a->argc < 2) { 01423 ast_free(cmdline); 01424 return CLI_SHOWUSAGE; 01425 } 01426 01427 ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline)); 01428 01429 admin_exec(NULL, ast_str_buffer(cmdline)); 01430 ast_free(cmdline); 01431 01432 return CLI_SUCCESS; 01433 }
| static int meetmemute | ( | struct mansession * | s, | |
| const struct message * | m, | |||
| int | mute | |||
| ) | [static] |
Definition at line 4277 of file app_meetme.c.
References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_conf_user::chan, ast_conference::confno, ast_conf_user::list, LOG_NOTICE, ast_channel::name, ast_channel::uniqueid, ast_conf_user::user_no, and ast_conference::userlist.
Referenced by action_meetmemute(), and action_meetmeunmute().
04278 { 04279 struct ast_conference *conf; 04280 struct ast_conf_user *user; 04281 const char *confid = astman_get_header(m, "Meetme"); 04282 char *userid = ast_strdupa(astman_get_header(m, "Usernum")); 04283 int userno; 04284 04285 if (ast_strlen_zero(confid)) { 04286 astman_send_error(s, m, "Meetme conference not specified"); 04287 return 0; 04288 } 04289 04290 if (ast_strlen_zero(userid)) { 04291 astman_send_error(s, m, "Meetme user number not specified"); 04292 return 0; 04293 } 04294 04295 userno = strtoul(userid, &userid, 10); 04296 04297 if (*userid) { 04298 astman_send_error(s, m, "Invalid user number"); 04299 return 0; 04300 } 04301 04302 /* Look in the conference list */ 04303 AST_LIST_LOCK(&confs); 04304 AST_LIST_TRAVERSE(&confs, conf, list) { 04305 if (!strcmp(confid, conf->confno)) 04306 break; 04307 } 04308 04309 if (!conf) { 04310 AST_LIST_UNLOCK(&confs); 04311 astman_send_error(s, m, "Meetme conference does not exist"); 04312 return 0; 04313 } 04314 04315 AST_LIST_TRAVERSE(&conf->userlist, user, list) 04316 if (user->user_no == userno) 04317 break; 04318 04319 if (!user) { 04320 AST_LIST_UNLOCK(&confs); 04321 astman_send_error(s, m, "User number not found"); 04322 return 0; 04323 } 04324 04325 if (mute) 04326 user->adminflags |= ADMINFLAG_MUTED; /* request user muting */ 04327 else 04328 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */ 04329 04330 AST_LIST_UNLOCK(&confs); 04331 04332 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); 04333 04334 astman_send_ack(s, m, mute ? "User muted" : "User unmuted"); 04335 return 0; 04336 }
| static enum ast_device_state meetmestate | ( | const char * | data | ) | [static] |
Callback for devicestate providers.
Definition at line 4480 of file app_meetme.c.
References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_conference::confno, ast_conference::list, and ast_conference::users.
Referenced by load_module().
04481 { 04482 struct ast_conference *conf; 04483 04484 /* Find conference */ 04485 AST_LIST_LOCK(&confs); 04486 AST_LIST_TRAVERSE(&confs, conf, list) { 04487 if (!strcmp(data, conf->confno)) 04488 break; 04489 } 04490 AST_LIST_UNLOCK(&confs); 04491 if (!conf) 04492 return AST_DEVICE_INVALID; 04493 04494 04495 /* SKREP to fill */ 04496 if (!conf->users) 04497 return AST_DEVICE_NOT_INUSE; 04498 04499 return AST_DEVICE_INUSE; 04500 }
| static struct sla_ringing_trunk* queue_ringing_trunk | ( | struct sla_trunk * | trunk | ) | [static, read] |
Definition at line 5830 of file app_meetme.c.
References ALL_TRUNK_REFS, ast_calloc, AST_LIST_INSERT_HEAD, ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_TRUNK_STATE_RINGING, and sla_ringing_trunk::trunk.
Referenced by sla_trunk_exec().
05831 { 05832 struct sla_ringing_trunk *ringing_trunk; 05833 05834 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) 05835 return NULL; 05836 05837 ringing_trunk->trunk = trunk; 05838 ringing_trunk->ring_begin = ast_tvnow(); 05839 05840 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL); 05841 05842 ast_mutex_lock(&sla.lock); 05843 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry); 05844 ast_mutex_unlock(&sla.lock); 05845 05846 sla_queue_event(SLA_EVENT_RINGING_TRUNK); 05847 05848 return ringing_trunk; 05849 }
| static void * recordthread | ( | void * | args | ) | [static] |
Definition at line 4415 of file app_meetme.c.
References ast_closestream(), AST_FILE_MODE, AST_FRAME_BITS, AST_FRAME_VOICE, ast_frdup(), ast_frfree, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_stopstream(), ast_waitfor(), ast_writefile(), ast_writestream(), f, ast_frame::flags, ast_frame::frametype, ast_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::origframe, ast_conference::recordingfilename, ast_conference::recordingformat, s, and ast_conference::transframe.
04416 { 04417 struct ast_conference *cnf = args; 04418 struct ast_frame *f = NULL; 04419 int flags; 04420 struct ast_filestream *s = NULL; 04421 int res = 0; 04422 int x; 04423 const char *oldrecordingfilename = NULL; 04424 04425 if (!cnf || !cnf->lchan) { 04426 pthread_exit(0); 04427 } 04428 04429 ast_stopstream(cnf->lchan); 04430 flags = O_CREAT | O_TRUNC | O_WRONLY; 04431 04432 04433 cnf->recording = MEETME_RECORD_ACTIVE; 04434 while (ast_waitfor(cnf->lchan, -1) > -1) { 04435 if (cnf->recording == MEETME_RECORD_TERMINATE) { 04436 AST_LIST_LOCK(&confs); 04437 AST_LIST_UNLOCK(&confs); 04438 break; 04439 } 04440 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) { 04441 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE); 04442 oldrecordingfilename = cnf->recordingfilename; 04443 } 04444 04445 f = ast_read(cnf->lchan); 04446 if (!f) { 04447 res = -1; 04448 break; 04449 } 04450 if (f->frametype == AST_FRAME_VOICE) { 04451 ast_mutex_lock(&cnf->listenlock); 04452 for (x = 0; x < AST_FRAME_BITS; x++) { 04453 /* Free any translations that have occured */ 04454 if (cnf->transframe[x]) { 04455 ast_frfree(cnf->transframe[x]); 04456 cnf->transframe[x] = NULL; 04457 } 04458 } 04459 if (cnf->origframe) 04460 ast_frfree(cnf->origframe); 04461 cnf->origframe = ast_frdup(f); 04462 ast_mutex_unlock(&cnf->listenlock); 04463 if (s) 04464 res = ast_writestream(s, f); 04465 if (res) { 04466 ast_frfree(f); 04467 break; 04468 } 04469 } 04470 ast_frfree(f); 04471 } 04472 cnf->recording = MEETME_RECORD_OFF; 04473 if (s) 04474 ast_closestream(s); 04475 04476 pthread_exit(0); 04477 }
| static int reload | ( | void | ) | [static] |
Definition at line 6532 of file app_meetme.c.
References ast_unload_realtime(), and load_config().
06533 { 06534 ast_unload_realtime("meetme"); 06535 return load_config(1); 06536 }
| static void reset_volumes | ( | struct ast_conf_user * | user | ) | [static] |
Definition at line 1076 of file app_meetme.c.
References ast_channel_setoption(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, and ast_conf_user::chan.
Referenced by admin_exec(), and conf_run().
01077 { 01078 signed char zero_volume = 0; 01079 01080 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 01081 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0); 01082 }
| static int rt_extend_conf | ( | const char * | confno | ) | [static] |
Definition at line 1889 of file app_meetme.c.
References ast_copy_string(), ast_debug, ast_load_realtime(), ast_localtime(), ast_mktime(), ast_strftime(), ast_strptime(), ast_tvnow(), ast_update_realtime(), ast_variables_destroy(), DATE_FORMAT, ast_variable::name, ast_variable::next, ast_variable::value, and var.
Referenced by admin_exec(), and conf_run().
01890 { 01891 char currenttime[32]; 01892 char endtime[32]; 01893 struct timeval now; 01894 struct ast_tm tm; 01895 struct ast_variable *var, *orig_var; 01896 char bookid[51]; 01897 01898 if (!extendby) { 01899 return 0; 01900 } 01901 01902 now = ast_tvnow(); 01903 01904 ast_localtime(&now, &tm, NULL); 01905 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); 01906 01907 var = ast_load_realtime("meetme", "confno", 01908 confno, "startTime<= ", currenttime, 01909 "endtime>= ", currenttime, NULL); 01910 01911 orig_var = var; 01912 01913 /* Identify the specific RealTime conference */ 01914 while (var) { 01915 if (!strcasecmp(var->name, "bookid")) { 01916 ast_copy_string(bookid, var->value, sizeof(bookid)); 01917 } 01918 if (!strcasecmp(var->name, "endtime")) { 01919 ast_copy_string(endtime, var->value, sizeof(endtime)); 01920 } 01921 01922 var = var->next; 01923 } 01924 ast_variables_destroy(orig_var); 01925 01926 ast_strptime(endtime, DATE_FORMAT, &tm); 01927 now = ast_mktime(&tm, NULL); 01928 01929 now.tv_sec += extendby; 01930 01931 ast_localtime(&now, &tm, NULL); 01932 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); 01933 strcat(currenttime, "0"); /* Seconds needs to be 00 */ 01934 01935 var = ast_load_realtime("meetme", "confno", 01936 confno, "startTime<= ", currenttime, 01937 "endtime>= ", currenttime, NULL); 01938 01939 /* If there is no conflict with extending the conference, update the DB */ 01940 if (!var) { 01941 ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime); 01942 ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL); 01943 return 0; 01944 01945 } 01946 01947 ast_variables_destroy(var); 01948 return -1; 01949 }
| static void* run_station | ( | void * | data | ) | [static] |
Definition at line 4729 of file app_meetme.c.
References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_cond_signal(), ast_dial_destroy(), ast_dial_join(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), build_conf(), sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, sla_station::dial, dispose_conf(), ast_flags::flags, sla_trunk::hold_stations, sla_trunk::name, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, run_station_args::station, sla_trunk_ref::trunk, and run_station_args::trunk_ref.
Referenced by sla_handle_dial_state_event().
04730 { 04731 struct sla_station *station; 04732 struct sla_trunk_ref *trunk_ref; 04733 struct ast_str *conf_name = ast_str_create(16); 04734 struct ast_flags conf_flags = { 0 }; 04735 struct ast_conference *conf; 04736 04737 { 04738 struct run_station_args *args = data; 04739 station = args->station; 04740 trunk_ref = args->trunk_ref; 04741 ast_mutex_lock(args->cond_lock); 04742 ast_cond_signal(args->cond); 04743 ast_mutex_unlock(args->cond_lock); 04744 /* args is no longer valid here. */ 04745 } 04746 04747 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1); 04748 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name); 04749 ast_set_flag(&conf_flags, 04750 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION); 04751 answer_trunk_chan(trunk_ref->chan); 04752 conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan); 04753 if (conf) { 04754 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL); 04755 dispose_conf(conf); 04756 conf = NULL; 04757 } 04758 trunk_ref->chan = NULL; 04759 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) && 04760 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) { 04761 ast_str_append(&conf_name, 0, ",K"); 04762 admin_exec(NULL, ast_str_buffer(conf_name)); 04763 trunk_ref->trunk->hold_stations = 0; 04764 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 04765 } 04766 04767 ast_dial_join(station->dial); 04768 ast_dial_destroy(station->dial); 04769 station->dial = NULL; 04770 ast_free(conf_name); 04771 04772 return NULL; 04773 }
| static int set_listen_volume | ( | struct ast_conf_user * | user, | |
| int | volume | |||
| ) | [static] |
Definition at line 1005 of file app_meetme.c.
References ast_channel_setoption(), AST_OPTION_TXGAIN, and ast_conf_user::chan.
Referenced by tweak_listen_volume().
01006 { 01007 char gain_adjust; 01008 01009 /* attempt to make the adjustment in the channel driver; 01010 if successful, don't adjust in the frame reading routine 01011 */ 01012 gain_adjust = gain_map[volume + 5]; 01013 01014 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0); 01015 }
| static int set_talk_volume | ( | struct ast_conf_user * | user, | |
| int | volume | |||
| ) | [static] |
Definition at line 993 of file app_meetme.c.
References ast_channel_setoption(), AST_OPTION_RXGAIN, and ast_conf_user::chan.
Referenced by conf_run(), and tweak_talk_volume().
00994 { 00995 char gain_adjust; 00996 00997 /* attempt to make the adjustment in the channel driver; 00998 if successful, don't adjust in the frame reading routine 00999 */ 01000 gain_adjust = gain_map[volume + 5]; 01001 01002 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0); 01003 }
| static void sla_add_trunk_to_station | ( | struct sla_station * | station, | |
| struct ast_variable * | var | |||
| ) | [static] |
Definition at line 6176 of file app_meetme.c.
References ast_atomic_fetchadd_int(), ast_free, AST_LIST_INSERT_TAIL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, create_trunk_ref(), LOG_ERROR, LOG_WARNING, sla_station::name, sla_trunk::name, sla_trunk::num_stations, sla_trunk_ref::ring_delay, sla_trunk_ref::ring_timeout, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, sla_trunk::stations, strsep(), sla_station::trunks, value, and ast_variable::value.
Referenced by sla_build_station().
06177 { 06178 struct sla_trunk *trunk; 06179 struct sla_trunk_ref *trunk_ref; 06180 struct sla_station_ref *station_ref; 06181 char *trunk_name, *options, *cur; 06182 06183 options = ast_strdupa(var->value); 06184 trunk_name = strsep(&options, ","); 06185 06186 AST_RWLIST_RDLOCK(&sla_trunks); 06187 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) { 06188 if (!strcasecmp(trunk->name, trunk_name)) 06189 break; 06190 } 06191 06192 AST_RWLIST_UNLOCK(&sla_trunks); 06193 if (!trunk) { 06194 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value); 06195 return; 06196 } 06197 if (!(trunk_ref = create_trunk_ref(trunk))) 06198 return; 06199 trunk_ref->state = SLA_TRUNK_STATE_IDLE; 06200 06201 while ((cur = strsep(&options, ","))) { 06202 char *name, *value = cur; 06203 name = strsep(&value, "="); 06204 if (!strcasecmp(name, "ringtimeout")) { 06205 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) { 06206 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for " 06207 "trunk '%s' on station '%s'\n", value, trunk->name, station->name); 06208 trunk_ref->ring_timeout = 0; 06209 } 06210 } else if (!strcasecmp(name, "ringdelay")) { 06211 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) { 06212 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for " 06213 "trunk '%s' on station '%s'\n", value, trunk->name, station->name); 06214 trunk_ref->ring_delay = 0; 06215 } 06216 } else { 06217 ast_log(LOG_WARNING, "Invalid option '%s' for " 06218 "trunk '%s' on station '%s'\n", name, trunk->name, station->name); 06219 } 06220 } 06221 06222 if (!(station_ref = sla_create_station_ref(station))) { 06223 ast_free(trunk_ref); 06224 return; 06225 } 06226 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1); 06227 AST_RWLIST_WRLOCK(&sla_trunks); 06228 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry); 06229 AST_RWLIST_UNLOCK(&sla_trunks); 06230 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry); 06231 }
| static int sla_build_station | ( | struct ast_config * | cfg, | |
| const char * | cat | |||
| ) | [static] |
Definition at line 6233 of file app_meetme.c.
References ast_add_extension2(), ast_calloc, ast_context_find_or_create(), ast_free, ast_free_ptr, AST_LIST_TRAVERSE, ast_log(), AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), sla_station::autocontext, context, destroy_station(), exten, sla_station::hold_access, ast_variable::lineno, LOG_ERROR, LOG_WARNING, sla_trunk::name, sla_station::name, ast_variable::name, ast_variable::next, PRIORITY_HINT, sla_station::ring_delay, sla_station::ring_timeout, sla_add_trunk_to_station(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, sla_trunk_ref::trunk, sla_station::trunks, ast_variable::value, and var.
Referenced by sla_load_config().
06234 { 06235 struct sla_station *station; 06236 struct ast_variable *var; 06237 const char *dev; 06238 06239 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) { 06240 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat); 06241 return -1; 06242 } 06243 06244 if (!(station = ast_calloc(1, sizeof(*station)))) 06245 return -1; 06246 if (ast_string_field_init(station, 32)) { 06247 ast_free(station); 06248 return -1; 06249 } 06250 06251 ast_string_field_set(station, name, cat); 06252 ast_string_field_set(station, device, dev); 06253 06254 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 06255 if (!strcasecmp(var->name, "trunk")) 06256 sla_add_trunk_to_station(station, var); 06257 else if (!strcasecmp(var->name, "autocontext")) 06258 ast_string_field_set(station, autocontext, var->value); 06259 else if (!strcasecmp(var->name, "ringtimeout")) { 06260 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) { 06261 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n", 06262 var->value, station->name); 06263 station->ring_timeout = 0; 06264 } 06265 } else if (!strcasecmp(var->name, "ringdelay")) { 06266 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) { 06267 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n", 06268 var->value, station->name); 06269 station->ring_delay = 0; 06270 } 06271 } else if (!strcasecmp(var->name, "hold")) { 06272 if (!strcasecmp(var->value, "private")) 06273 station->hold_access = SLA_HOLD_PRIVATE; 06274 else if (!strcasecmp(var->value, "open")) 06275 station->hold_access = SLA_HOLD_OPEN; 06276 else { 06277 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n", 06278 var->value, station->name); 06279 } 06280 06281 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) { 06282 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", 06283 var->name, var->lineno, SLA_CONFIG_FILE); 06284 } 06285 } 06286 06287 if (!ast_strlen_zero(station->autocontext)) { 06288 struct ast_context *context; 06289 struct sla_trunk_ref *trunk_ref; 06290 context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar); 06291 if (!context) { 06292 ast_log(LOG_ERROR, "Failed to automatically find or create " 06293 "context '%s' for SLA!\n", station->autocontext); 06294 destroy_station(station); 06295 return -1; 06296 } 06297 /* The extension for when the handset goes off-hook. 06298 * exten => station1,1,SLAStation(station1) */ 06299 if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1, 06300 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) { 06301 ast_log(LOG_ERROR, "Failed to automatically create extension " 06302 "for trunk '%s'!\n", station->name); 06303 destroy_station(station); 06304 return -1; 06305 } 06306 AST_RWLIST_RDLOCK(&sla_trunks); 06307 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 06308 char exten[AST_MAX_EXTENSION]; 06309 char hint[AST_MAX_APP]; 06310 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name); 06311 snprintf(hint, sizeof(hint), "SLA:%s", exten); 06312 /* Extension for this line button 06313 * exten => station1_line1,1,SLAStation(station1_line1) */ 06314 if (ast_add_extension2(context, 0 /* don't replace */, exten, 1, 06315 NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) { 06316 ast_log(LOG_ERROR, "Failed to automatically create extension " 06317 "for trunk '%s'!\n", station->name); 06318 destroy_station(station); 06319 return -1; 06320 } 06321 /* Hint for this line button 06322 * exten => station1_line1,hint,SLA:station1_line1 */ 06323 if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT, 06324 NULL, NULL, hint, NULL, NULL, sla_registrar)) { 06325 ast_log(LOG_ERROR, "Failed to automatically create hint " 06326 "for trunk '%s'!\n", station->name); 06327 destroy_station(station); 06328 return -1; 06329 } 06330 } 06331 AST_RWLIST_UNLOCK(&sla_trunks); 06332 } 06333 06334 AST_RWLIST_WRLOCK(&sla_stations); 06335 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry); 06336 AST_RWLIST_UNLOCK(&sla_stations); 06337 06338 return 0; 06339 }
| static int sla_build_trunk | ( | struct ast_config * | cfg, | |
| const char * | cat | |||
| ) | [static] |
Definition at line 6098 of file app_meetme.c.
References ast_add_extension2(), ast_calloc, ast_context_find_or_create(), ast_false(), ast_free, ast_free_ptr, ast_log(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), sla_trunk::autocontext, sla_trunk::barge_disabled, context, destroy_trunk(), sla_trunk::hold_access, ast_variable::lineno, LOG_ERROR, LOG_WARNING, sla_trunk::name, ast_variable::name, ast_variable::next, sla_trunk::ring_timeout, sla_check_device(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, ast_variable::value, and var.
Referenced by sla_load_config().
06099 { 06100 struct sla_trunk *trunk; 06101 struct ast_variable *var; 06102 const char *dev; 06103 06104 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) { 06105 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat); 06106 return -1; 06107 } 06108 06109 if (sla_check_device(dev)) { 06110 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n", 06111 cat, dev); 06112 return -1; 06113 } 06114 06115 if (!(trunk = ast_calloc(1, sizeof(*trunk)))) 06116 return -1; 06117 if (ast_string_field_init(trunk, 32)) { 06118 ast_free(trunk); 06119 return -1; 06120 } 06121 06122 ast_string_field_set(trunk, name, cat); 06123 ast_string_field_set(trunk, device, dev); 06124 06125 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 06126 if (!strcasecmp(var->name, "autocontext")) 06127 ast_string_field_set(trunk, autocontext, var->value); 06128 else if (!strcasecmp(var->name, "ringtimeout")) { 06129 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) { 06130 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n", 06131 var->value, trunk->name); 06132 trunk->ring_timeout = 0; 06133 } 06134 } else if (!strcasecmp(var->name, "barge")) 06135 trunk->barge_disabled = ast_false(var->value); 06136 else if (!strcasecmp(var->name, "hold")) { 06137 if (!strcasecmp(var->value, "private")) 06138 trunk->hold_access = SLA_HOLD_PRIVATE; 06139 else if (!strcasecmp(var->value, "open")) 06140 trunk->hold_access = SLA_HOLD_OPEN; 06141 else { 06142 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n", 06143 var->value, trunk->name); 06144 } 06145 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) { 06146 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", 06147 var->name, var->lineno, SLA_CONFIG_FILE); 06148 } 06149 } 06150 06151 if (!ast_strlen_zero(trunk->autocontext)) { 06152 struct ast_context *context; 06153 context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar); 06154 if (!context) { 06155 ast_log(LOG_ERROR, "Failed to automatically find or create " 06156 "context '%s' for SLA!\n", trunk->autocontext); 06157 destroy_trunk(trunk); 06158 return -1; 06159 } 06160 if (ast_add_extension2(context, 0 /* don't replace */, "s", 1, 06161 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) { 06162 ast_log(LOG_ERROR, "Failed to automatically create extension " 06163 "for trunk '%s'!\n", trunk->name); 06164 destroy_trunk(trunk); 06165 return -1; 06166 } 06167 } 06168 06169 AST_RWLIST_WRLOCK(&sla_trunks); 06170 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry); 06171 AST_RWLIST_UNLOCK(&sla_trunks); 06172 06173 return 0; 06174 }
| static int sla_calc_station_delays | ( | unsigned int * | timeout | ) | [static] |
Calculate the ring delay for a station.
Definition at line 5342 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), and sla_choose_ringing_trunk().
Referenced by sla_process_timers().
05343 { 05344 struct sla_station *station; 05345 int res = 0; 05346 05347 AST_LIST_TRAVERSE(&sla_stations, station, entry) { 05348 struct sla_ringing_trunk *ringing_trunk; 05349 int time_left; 05350 05351 /* Ignore stations already ringing */ 05352 if (sla_check_ringing_station(station)) 05353 continue; 05354 05355 /* Ignore stations already on a call */ 05356 if (sla_check_inuse_station(station)) 05357 continue; 05358 05359 /* Ignore stations that don't have one of their trunks ringing */ 05360 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0))) 05361 continue; 05362 05363 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX) 05364 continue; 05365 05366 /* If there is no time left, then the station needs to start ringing. 05367 * Return non-zero so that an event will be queued up an event to 05368 * make that happen. */ 05369 if (time_left <= 0) { 05370 res = 1; 05371 continue; 05372 } 05373 05374 if (time_left < *timeout) 05375 *timeout = time_left; 05376 } 05377 05378 return res; 05379 }
| static int sla_calc_station_timeouts | ( | unsigned int * | timeout | ) | [static] |
Process station ring timeouts.
Definition at line 5259 of file app_meetme.c.
References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_ringing_station::ring_begin, sla_ringing_trunk::ring_begin, sla_station::ring_timeout, sla_trunk_ref::ring_timeout, sla, SLA_STATION_HANGUP_TIMEOUT, sla_stop_ringing_station(), sla_station_ref::station, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.
Referenced by sla_process_timers().
05260 { 05261 struct sla_ringing_trunk *ringing_trunk; 05262 struct sla_ringing_station *ringing_station; 05263 int res = 0; 05264 05265 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) { 05266 unsigned int ring_timeout = 0; 05267 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN; 05268 struct sla_trunk_ref *trunk_ref; 05269 05270 /* If there are any ring timeouts specified for a specific trunk 05271 * on the station, then use the highest per-trunk ring timeout. 05272 * Otherwise, use the ring timeout set for the entire station. */ 05273 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) { 05274 struct sla_station_ref *station_ref; 05275 int trunk_time_elapsed, trunk_time_left; 05276 05277 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) { 05278 if (ringing_trunk->trunk == trunk_ref->trunk) 05279 break; 05280 } 05281 if (!ringing_trunk) 05282 continue; 05283 05284 /* If there is a trunk that is ringing without a timeout, then the 05285 * only timeout that could matter is a global station ring timeout. */ 05286 if (!trunk_ref->ring_timeout) 05287 break; 05288 05289 /* This trunk on this station is ringing and has a timeout. 05290 * However, make sure this trunk isn't still ringing from a 05291 * previous timeout. If so, don't consider it. */ 05292 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) { 05293 if (station_ref->station == ringing_station->station) 05294 break; 05295 } 05296 if (station_ref) 05297 continue; 05298 05299 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin); 05300 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed; 05301 if (trunk_time_left > final_trunk_time_left) 05302 final_trunk_time_left = trunk_time_left; 05303 } 05304 05305 /* No timeout was found for ringing trunks, and no timeout for the entire station */ 05306 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout) 05307 continue; 05308 05309 /* Compute how much time is left for a global station timeout */ 05310 if (ringing_station->station->ring_timeout) { 05311 ring_timeout = ringing_station->station->ring_timeout; 05312 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin); 05313 time_left = (ring_timeout * 1000) - time_elapsed; 05314 } 05315 05316 /* If the time left based on the per-trunk timeouts is smaller than the 05317 * global station ring timeout, use that. */ 05318 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left) 05319 time_left = final_trunk_time_left; 05320 05321 /* If there is no time left, the station needs to stop ringing */ 05322 if (time_left <= 0) { 05323 AST_LIST_REMOVE_CURRENT(entry); 05324 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT); 05325 res = 1; 05326 continue; 05327 } 05328 05329 /* There is still some time left for this station to ring, so save that 05330 * timeout if it is the first event scheduled to occur */ 05331 if (time_left < *timeout) 05332 *timeout = time_left; 05333 } 05334 AST_LIST_TRAVERSE_SAFE_END; 05335 05336 return res; 05337 }
| static int sla_calc_trunk_timeouts | ( | unsigned int * | timeout | ) | [static] |
Process trunk ring timeouts.
Definition at line 5229 of file app_meetme.c.
References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_trunk::chan, pbx_builtin_setvar_helper(), sla_ringing_trunk::ring_begin, sla_trunk::ring_timeout, sla, sla_stop_ringing_trunk(), and sla_ringing_trunk::trunk.
Referenced by sla_process_timers().
05230 { 05231 struct sla_ringing_trunk *ringing_trunk; 05232 int res = 0; 05233 05234 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) { 05235 int time_left, time_elapsed; 05236 if (!ringing_trunk->trunk->ring_timeout) 05237 continue; 05238 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin); 05239 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed; 05240 if (time_left <= 0) { 05241 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT"); 05242 AST_LIST_REMOVE_CURRENT(entry); 05243 sla_stop_ringing_trunk(ringing_trunk); 05244 res = 1; 05245 continue; 05246 } 05247 if (time_left < *timeout) 05248 *timeout = time_left; 05249 } 05250 AST_LIST_TRAVERSE_SAFE_END; 05251 05252 return res; 05253 }
| 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 4697 of file app_meetme.c.
References ast_devstate_changed(), AST_LIST_TRAVERSE, sla_trunk_ref::chan, sla_trunk::name, sla_station::name, sla_state_to_devstate(), sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by dial_trunk(), queue_ringing_trunk(), run_station(), sla_handle_dial_state_event(), sla_handle_hold_event(), sla_station_exec(), sla_stop_ringing_trunk(), and sla_trunk_exec().
04699 { 04700 struct sla_station *station; 04701 struct sla_trunk_ref *trunk_ref; 04702 04703 AST_LIST_TRAVERSE(&sla_stations, station, entry) { 04704 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 04705 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0) 04706 || trunk_ref == exclude) 04707 continue; 04708 trunk_ref->state = state; 04709 ast_devstate_changed(sla_state_to_devstate(state), 04710 "SLA:%s_%s", station->name, trunk->name); 04711 break; 04712 } 04713 } 04714 }
| static int sla_check_device | ( | const char * | device | ) | [static] |
Definition at line 6085 of file app_meetme.c.
References ast_strdupa, ast_strlen_zero(), and strsep().
Referenced by sla_build_trunk().
06086 { 06087 char *tech, *tech_data; 06088 06089 tech_data = ast_strdupa(device); 06090 tech = strsep(&tech_data, "/"); 06091 06092 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data)) 06093 return -1; 06094 06095 return 0; 06096 }
| 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 4977 of file app_meetme.c.
References ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_failed_station::last_try, sla, and sla_failed_station::station.
Referenced by sla_ring_stations().
04978 { 04979 struct sla_failed_station *failed_station; 04980 int res = 0; 04981 04982 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) { 04983 if (station != failed_station->station) 04984 continue; 04985 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) { 04986 AST_LIST_REMOVE_CURRENT(entry); 04987 ast_free(failed_station); 04988 break; 04989 } 04990 res = 1; 04991 } 04992 AST_LIST_TRAVERSE_SAFE_END 04993 04994 return res; 04995 }
| static int sla_check_inuse_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if a station is in use.
Definition at line 5063 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_trunk_ref::chan, and sla_station::trunks.
Referenced by sla_calc_station_delays(), and sla_ring_stations().
05064 { 05065 struct sla_trunk_ref *trunk_ref; 05066 05067 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 05068 if (trunk_ref->chan) 05069 return 1; 05070 } 05071 05072 return 0; 05073 }
| 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 5421 of file app_meetme.c.
References AST_LIST_EMPTY, ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_trunk::ref_count, sla_station::ref_count, sla, and sla_load_config().
Referenced by sla_thread().
05422 { 05423 struct sla_station *station; 05424 struct sla_trunk *trunk; 05425 05426 ast_mutex_lock(&sla.lock); 05427 05428 if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 05429 || !AST_LIST_EMPTY(&sla.ringing_stations)) { 05430 ast_mutex_unlock(&sla.lock); 05431 return; 05432 } 05433 05434 AST_RWLIST_RDLOCK(&sla_stations); 05435 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) { 05436 if (station->ref_count) 05437 break; 05438 } 05439 AST_RWLIST_UNLOCK(&sla_stations); 05440 if (station) { 05441 ast_mutex_unlock(&sla.lock); 05442 return; 05443 } 05444 05445 AST_RWLIST_RDLOCK(&sla_trunks); 05446 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) { 05447 if (trunk->ref_count) 05448 break; 05449 } 05450 AST_RWLIST_UNLOCK(&sla_trunks); 05451 if (trunk) { 05452 ast_mutex_unlock(&sla.lock); 05453 return; 05454 } 05455 05456 /* yay */ 05457 sla_load_config(1); 05458 sla.reload = 0; 05459 05460 ast_mutex_unlock(&sla.lock); 05461 }
| static int sla_check_ringing_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if this station is already ringing.
Definition at line 4962 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla, and sla_ringing_station::station.
Referenced by sla_calc_station_delays(), and sla_ring_stations().
04963 { 04964 struct sla_ringing_station *ringing_station; 04965 04966 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) { 04967 if (station == ringing_station->station) 04968 return 1; 04969 } 04970 04971 return 0; 04972 }
| 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 5093 of file app_meetme.c.
References ast_tvdiff_ms(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla_station::ring_delay, sla_trunk_ref::ring_delay, sla_choose_ringing_trunk(), sla_find_trunk_ref(), and sla_ringing_trunk::trunk.
Referenced by sla_calc_station_delays(), and sla_ring_stations().
05095 { 05096 struct sla_trunk_ref *trunk_ref; 05097 unsigned int delay = UINT_MAX; 05098 int time_left, time_elapsed; 05099 05100 if (!ringing_trunk) 05101 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0); 05102 else 05103 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk); 05104 05105 if (!ringing_trunk || !trunk_ref) 05106 return delay; 05107 05108 /* If this station has a ring delay specific to the highest priority 05109 * ringing trunk, use that. Otherwise, use the ring delay specified 05110 * globally for the station. */ 05111 delay = trunk_ref->ring_delay; 05112 if (!delay) 05113 delay = station->ring_delay; 05114 if (!delay) 05115 return INT_MAX; 05116 05117 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin); 05118 time_left = (delay * 1000) - time_elapsed; 05119 05120 return time_left; 05121 }
| static int sla_check_station_hold_access | ( | const struct sla_trunk * | trunk, | |
| const struct sla_station * | station | |||
| ) | [static] |
Definition at line 4602 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station::hold_access, SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, sla_station_ref::station, sla_trunk::stations, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_find_trunk_ref_byname().
04604 { 04605 struct sla_station_ref *station_ref; 04606 struct sla_trunk_ref *trunk_ref; 04607 04608 /* For each station that has this call on hold, check for private hold. */ 04609 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) { 04610 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) { 04611 if (trunk_ref->trunk != trunk || station_ref->station == station) 04612 continue; 04613 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME && 04614 station_ref->station->hold_access == SLA_HOLD_PRIVATE) 04615 return 1; 04616 return 0; 04617 } 04618 } 04619 04620 return 0; 04621 }
| 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 4833 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_station_ref::station, and sla_ringing_trunk::timed_out_stations.
Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().
04835 { 04836 struct sla_station_ref *timed_out_station; 04837 04838 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) { 04839 if (station == timed_out_station->station) 04840 return 1; 04841 } 04842 04843 return 0; 04844 }
| 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 5645 of file app_meetme.c.
References AST_LIST_TRAVERSE, SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, and sla_station::trunks.
Referenced by sla_station_exec().
05646 { 05647 struct sla_trunk_ref *trunk_ref = NULL; 05648 05649 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 05650 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) 05651 break; 05652 } 05653 05654 return trunk_ref; 05655 }
| 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 | |
| remove | 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 4854 of file app_meetme.c.
References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, sla, sla_check_timed_out_station(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_calc_station_delays(), sla_check_station_delay(), and sla_handle_dial_state_event().
04856 { 04857 struct sla_trunk_ref *s_trunk_ref; 04858 struct sla_ringing_trunk *ringing_trunk = NULL; 04859 04860 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) { 04861 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) { 04862 /* Make sure this is the trunk we're looking for */ 04863 if (s_trunk_ref->trunk != ringing_trunk->trunk) 04864 continue; 04865 04866 /* This trunk on the station is ringing. But, make sure this station 04867 * didn't already time out while this trunk was ringing. */ 04868 if (sla_check_timed_out_station(ringing_trunk, station)) 04869 continue; 04870 04871 if (rm) 04872 AST_LIST_REMOVE_CURRENT(entry); 04873 04874 if (trunk_ref) 04875 *trunk_ref = s_trunk_ref; 04876 04877 break; 04878 } 04879 AST_LIST_TRAVERSE_SAFE_END; 04880 04881 if (ringing_trunk) 04882 break; 04883 } 04884 04885 return ringing_trunk; 04886 }
| static struct sla_ringing_station* sla_create_ringing_station | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 4667 of file app_meetme.c.
References ast_calloc, ast_tvnow(), sla_ringing_station::ring_begin, and sla_ringing_station::station.
Referenced by sla_ring_station().
04668 { 04669 struct sla_ringing_station *ringing_station; 04670 04671 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station)))) 04672 return NULL; 04673 04674 ringing_station->station = station; 04675 ringing_station->ring_begin = ast_tvnow(); 04676 04677 return ringing_station; 04678 }
| static struct sla_station_ref* sla_create_station_ref | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 4655 of file app_meetme.c.
References ast_calloc, and sla_station_ref::station.
Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().
04656 { 04657 struct sla_station_ref *station_ref; 04658 04659 if (!(station_ref = ast_calloc(1, sizeof(*station_ref)))) 04660 return NULL; 04661 04662 station_ref->station = station; 04663 04664 return station_ref; 04665 }
| static void sla_destroy | ( | void | ) | [static] |
Definition at line 6055 of file app_meetme.c.
References ast_cond_destroy(), ast_cond_signal(), ast_context_destroy(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, destroy_station(), destroy_trunk(), sla, and sla_registrar.
Referenced by unload_module().
06056 { 06057 struct sla_trunk *trunk; 06058 struct sla_station *station; 06059 06060 AST_RWLIST_WRLOCK(&sla_trunks); 06061 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry))) 06062 destroy_trunk(trunk); 06063 AST_RWLIST_UNLOCK(&sla_trunks); 06064 06065 AST_RWLIST_WRLOCK(&sla_stations); 06066 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry))) 06067 destroy_station(station); 06068 AST_RWLIST_UNLOCK(&sla_stations); 06069 06070 if (sla.thread != AST_PTHREADT_NULL) { 06071 ast_mutex_lock(&sla.lock); 06072 sla.stop = 1; 06073 ast_cond_signal(&sla.cond); 06074 ast_mutex_unlock(&sla.lock); 06075 pthread_join(sla.thread, NULL); 06076 } 06077 06078 /* Drop any created contexts from the dialplan */ 06079 ast_context_destroy(NULL, sla_registrar); 06080 06081 ast_mutex_destroy(&sla.lock); 06082 ast_cond_destroy(&sla.cond); 06083 }
| static void sla_dial_state_callback | ( | struct ast_dial * | dial | ) | [static] |
Definition at line 4825 of file app_meetme.c.
References SLA_EVENT_DIAL_STATE, and sla_queue_event().
Referenced by sla_ring_station().
04826 { 04827 sla_queue_event(SLA_EVENT_DIAL_STATE); 04828 }
| static struct sla_station* sla_find_station | ( | const char * | name | ) | [static, read] |
Find an SLA station by name.
Definition at line 4590 of file app_meetme.c.
References AST_RWLIST_TRAVERSE, and sla_station::name.
Referenced by sla_station_exec().
04591 { 04592 struct sla_station *station = NULL; 04593 04594 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) { 04595 if (!strcasecmp(station->name, name)) 04596 break; 04597 } 04598 04599 return station; 04600 }
| static struct sla_trunk* sla_find_trunk | ( | const char * | name | ) | [static, read] |
Find an SLA trunk by name.
Definition at line 4575 of file app_meetme.c.
References AST_RWLIST_TRAVERSE, and sla_trunk::name.
Referenced by sla_trunk_exec().
04576 { 04577 struct sla_trunk *trunk = NULL; 04578 04579 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) { 04580 if (!strcasecmp(trunk->name, name)) 04581 break; 04582 } 04583 04584 return trunk; 04585 }
| static struct sla_trunk_ref* sla_find_trunk_ref | ( | const struct sla_station * | station, | |
| const struct sla_trunk * | trunk | |||
| ) | [static, read] |
Definition at line 5075 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_check_station_delay().
05077 { 05078 struct sla_trunk_ref *trunk_ref = NULL; 05079 05080 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 05081 if (trunk_ref->trunk == trunk) 05082 break; 05083 } 05084 05085 return trunk_ref; 05086 }
| 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 4630 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_trunk::barge_disabled, sla_trunk::hold_access, sla_trunk::hold_stations, sla_trunk::name, sla_check_station_hold_access(), SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_station_exec().
04632 { 04633 struct sla_trunk_ref *trunk_ref = NULL; 04634 04635 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 04636 if (strcasecmp(trunk_ref->trunk->name, name)) 04637 continue; 04638 04639 if ( (trunk_ref->trunk->barge_disabled 04640 && trunk_ref->state == SLA_TRUNK_STATE_UP) || 04641 (trunk_ref->trunk->hold_stations 04642 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE 04643 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) || 04644 sla_check_station_hold_access(trunk_ref->trunk, station) ) 04645 { 04646 trunk_ref = NULL; 04647 } 04648 04649 break; 04650 } 04651 04652 return trunk_ref; 04653 }
| static void sla_handle_dial_state_event | ( | void | ) | [static] |
Definition at line 4888 of file app_meetme.c.
References ALL_TRUNK_REFS, answer_trunk_chan(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), ast_debug, ast_dial_answered(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_state(), ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, sla_trunk::chan, sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, sla_station::dial, sla_station::name, run_station(), sla, sla_change_trunk_state(), sla_choose_ringing_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_STATION_HANGUP_NORMAL, sla_stop_ringing_station(), SLA_TRUNK_STATE_UP, run_station_args::station, sla_ringing_station::station, sla_ringing_trunk::trunk, and run_station_args::trunk_ref.
Referenced by sla_thread().
04889 { 04890 struct sla_ringing_station *ringing_station; 04891 04892 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) { 04893 struct sla_trunk_ref *s_trunk_ref = NULL; 04894 struct sla_ringing_trunk *ringing_trunk = NULL; 04895 struct run_station_args args; 04896 enum ast_dial_result dial_res; 04897 pthread_t dont_care; 04898 ast_mutex_t cond_lock; 04899 ast_cond_t cond; 04900 04901 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) { 04902 case AST_DIAL_RESULT_HANGUP: 04903 case AST_DIAL_RESULT_INVALID: 04904 case AST_DIAL_RESULT_FAILED: 04905 case AST_DIAL_RESULT_TIMEOUT: 04906 case AST_DIAL_RESULT_UNANSWERED: 04907 AST_LIST_REMOVE_CURRENT(entry); 04908 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL); 04909 break; 04910 case AST_DIAL_RESULT_ANSWERED: 04911 AST_LIST_REMOVE_CURRENT(entry); 04912 /* Find the appropriate trunk to answer. */ 04913 ast_mutex_lock(&sla.lock); 04914 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1); 04915 ast_mutex_unlock(&sla.lock); 04916 if (!ringing_trunk) { 04917 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name); 04918 break; 04919 } 04920 /* Track the channel that answered this trunk */ 04921 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial); 04922 /* Actually answer the trunk */ 04923 answer_trunk_chan(ringing_trunk->trunk->chan); 04924 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL); 04925 /* Now, start a thread that will connect this station to the trunk. The rest of 04926 * the code here sets up the thread and ensures that it is able to save the arguments 04927 * before they are no longer valid since they are allocated on the stack. */ 04928 args.trunk_ref = s_trunk_ref; 04929 args.station = ringing_station->station; 04930 args.cond = &cond; 04931 args.cond_lock = &cond_lock; 04932 ast_free(ringing_trunk); 04933 ast_free(ringing_station); 04934 ast_mutex_init(&cond_lock); 04935 ast_cond_init(&cond, NULL); 04936 ast_mutex_lock(&cond_lock); 04937 ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args); 04938 ast_cond_wait(&cond, &cond_lock); 04939 ast_mutex_unlock(&cond_lock); 04940 ast_mutex_destroy(&cond_lock); 04941 ast_cond_destroy(&cond); 04942 break; 04943 case AST_DIAL_RESULT_TRYING: 04944 case AST_DIAL_RESULT_RINGING: 04945 case AST_DIAL_RESULT_PROGRESS: 04946 case AST_DIAL_RESULT_PROCEEDING: 04947 break; 04948 } 04949 if (dial_res == AST_DIAL_RESULT_ANSWERED) { 04950 /* Queue up reprocessing ringing trunks, and then ringing stations again */ 04951 sla_queue_event(SLA_EVENT_RINGING_TRUNK); 04952 sla_queue_event(SLA_EVENT_DIAL_STATE); 04953 break; 04954 } 04955 } 04956 AST_LIST_TRAVERSE_SAFE_END; 04957 }
| static void sla_handle_hold_event | ( | struct sla_event * | event | ) | [static] |
Definition at line 5205 of file app_meetme.c.
References sla_trunk::active_stations, ast_atomic_fetchadd_int(), AST_CONTROL_HOLD, AST_DEVICE_ONHOLD, ast_devstate_changed(), ast_indicate(), ast_softhangup(), AST_SOFTHANGUP_DEV, sla_trunk_ref::chan, sla_trunk::chan, sla_trunk::hold_stations, INACTIVE_TRUNK_REFS, sla_trunk::name, sla_station::name, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_event::station, sla_trunk_ref::trunk, and sla_event::trunk_ref.
Referenced by sla_thread().
05206 { 05207 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1); 05208 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME; 05209 ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 05210 event->station->name, event->trunk_ref->trunk->name); 05211 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 05212 INACTIVE_TRUNK_REFS, event->trunk_ref); 05213 05214 if (event->trunk_ref->trunk->active_stations == 1) { 05215 /* The station putting it on hold is the only one on the call, so start 05216 * Music on hold to the trunk. */ 05217 event->trunk_ref->trunk->on_hold = 1; 05218 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD); 05219 } 05220 05221 ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV); 05222 event->trunk_ref->chan = NULL; 05223 }
| static void sla_handle_ringing_trunk_event | ( | void | ) | [static] |
Definition at line 5195 of file app_meetme.c.
References ast_mutex_lock(), ast_mutex_unlock(), sla, sla_hangup_stations(), and sla_ring_stations().
Referenced by sla_thread().
05196 { 05197 ast_mutex_lock(&sla.lock); 05198 sla_ring_stations(); 05199 ast_mutex_unlock(&sla.lock); 05200 05201 /* Find stations that shouldn't be ringing anymore. */ 05202 sla_hangup_stations(); 05203 }
| static void sla_hangup_stations | ( | void | ) | [static] |
Definition at line 5167 of file app_meetme.c.
References ast_dial_destroy(), ast_dial_join(), ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock(), ast_mutex_unlock(), sla_station::dial, sla, sla_ringing_station::station, sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_handle_ringing_trunk_event().
05168 { 05169 struct sla_trunk_ref *trunk_ref; 05170 struct sla_ringing_station *ringing_station; 05171 05172 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) { 05173 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) { 05174 struct sla_ringing_trunk *ringing_trunk; 05175 ast_mutex_lock(&sla.lock); 05176 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) { 05177 if (trunk_ref->trunk == ringing_trunk->trunk) 05178 break; 05179 } 05180 ast_mutex_unlock(&sla.lock); 05181 if (ringing_trunk) 05182 break; 05183 } 05184 if (!trunk_ref) { 05185 AST_LIST_REMOVE_CURRENT(entry); 05186 ast_dial_join(ringing_station->station->dial); 05187 ast_dial_destroy(ringing_station->station->dial); 05188 ringing_station->station->dial = NULL; 05189 ast_free(ringing_station); 05190 } 05191 } 05192 AST_LIST_TRAVERSE_SAFE_END 05193 }
| static const char* sla_hold_str | ( | unsigned int | hold_access | ) | [static] |
Definition at line 1525 of file app_meetme.c.
References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.
Referenced by sla_show_stations(), and sla_show_trunks().
01526 { 01527 const char *hold = "Unknown"; 01528 01529 switch (hold_access) { 01530 case SLA_HOLD_OPEN: 01531 hold = "Open"; 01532 break; 01533 case SLA_HOLD_PRIVATE: 01534 hold = "Private"; 01535 default: 01536 break; 01537 } 01538 01539 return hold; 01540 }
| static int sla_load_config | ( | int | reload | ) | [static] |
Definition at line 6341 of file app_meetme.c.
References ast_category_browse(), ast_cond_init(), ast_config_destroy(), ast_config_load, AST_LIST_EMPTY, ast_log(), ast_mutex_init(), ast_pthread_create, ast_true(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_ERROR, LOG_WARNING, sla, sla_build_station(), sla_build_trunk(), SLA_CONFIG_FILE, sla_thread(), and type.
Referenced by load_config(), and sla_check_reload().
06342 { 06343 struct ast_config *cfg; 06344 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06345 const char *cat = NULL; 06346 int res = 0; 06347 const char *val; 06348 06349 if