Meet me conference bridge and Shared Line Appearances. More...
#include "asterisk.h"#include <dahdi/user.h>#include "asterisk/lock.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/module.h"#include "asterisk/config.h"#include "asterisk/app.h"#include "asterisk/dsp.h"#include "asterisk/musiconhold.h"#include "asterisk/manager.h"#include "asterisk/cli.h"#include "asterisk/say.h"#include "asterisk/utils.h"#include "asterisk/translate.h"#include "asterisk/ulaw.h"#include "asterisk/astobj2.h"#include "asterisk/devicestate.h"#include "asterisk/dial.h"#include "asterisk/causes.h"#include "asterisk/paths.h"#include "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 | MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3) |
| #define | MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n" |
| #define | MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n" |
| #define | MEETME_DELAYDETECTENDTALK 1000 |
| #define | MEETME_DELAYDETECTTALK 300 |
| #define | 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 | __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 (char *keyword, 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, void *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 (char *confno, char *pin, 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, void *data) |
| static char * | complete_meetmecmd (const char *line, const char *word, int pos, int state) |
| static int | conf_exec (struct ast_channel *chan, void *data) |
| The meetme() application. | |
| static void | conf_flush (int fd, struct ast_channel *chan) |
| static int | conf_free (struct ast_conference *conf) |
| 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, void *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) |
| 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, char *optargs[], int *too_early) |
| static struct ast_conf_user * | find_user (struct ast_conference *conf, char *callerident) |
| static const char * | get_announce_filename (enum announcetypes type) |
| static char * | istalking (int x) |
| static int | load_config (int reload) |
| static void | load_config_meetme (void) |
| static int | load_module (void) |
| static char * | meetme_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | 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 void * | run_station (void *data) |
| static void | send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking) |
| static int | set_listen_volume (struct ast_conf_user *user, int volume) |
| static int | set_talk_volume (struct ast_conf_user *user, int volume) |
| static void | set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor) |
| static void | sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var) |
| static int | sla_build_station (struct ast_config *cfg, const char *cat) |
| static int | sla_build_trunk (struct ast_config *cfg, const char *cat) |
| static int | sla_calc_station_delays (unsigned int *timeout) |
| Calculate the ring delay for a station. | |
| static int | sla_calc_station_timeouts (unsigned int *timeout) |
| Process station ring timeouts. | |
| static int | sla_calc_trunk_timeouts (unsigned int *timeout) |
| Process trunk ring timeouts. | |
| static void | sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude) |
| static int | sla_check_device (const char *device) |
| static int | sla_check_failed_station (const struct sla_station *station) |
| Check to see if this station has failed to be dialed in the past minute. | |
| static int | sla_check_inuse_station (const struct sla_station *station) |
| Check to see if a station is in use. | |
| static void | sla_check_reload (void) |
| Check if we can do a reload of SLA, and do it if we can. | |
| static int | sla_check_ringing_station (const struct sla_station *station) |
| Check to see if this station is already ringing. | |
| static int | sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk) |
| Calculate the ring delay for a given ringing trunk on a station. | |
| static int | sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station) |
| static int | sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station) |
| Check to see if dialing this station already timed out for this ringing trunk. | |
| static struct sla_trunk_ref * | sla_choose_idle_trunk (const struct sla_station *station) |
| For a given station, choose the highest priority idle trunk. | |
| static struct sla_ringing_trunk * | sla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm) |
| Choose the highest priority ringing trunk for a station. | |
| static struct sla_ringing_station * | sla_create_ringing_station (struct sla_station *station) |
| static struct sla_station_ref * | sla_create_station_ref (struct sla_station *station) |
| static void | sla_destroy (void) |
| static void | sla_dial_state_callback (struct ast_dial *dial) |
| static struct sla_station * | sla_find_station (const char *name) |
| Find an SLA station by name. | |
| static struct sla_trunk * | sla_find_trunk (const char *name) |
| Find an SLA trunk by name. | |
| static struct sla_trunk_ref * | sla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk) |
| static struct sla_trunk_ref * | sla_find_trunk_ref_byname (const struct sla_station *station, const char *name) |
| Find a trunk reference on a station by name. | |
| static void | sla_handle_dial_state_event (void) |
| static void | sla_handle_hold_event (struct sla_event *event) |
| static void | sla_handle_ringing_trunk_event (void) |
| static void | sla_hangup_stations (void) |
| static const char * | sla_hold_str (unsigned int hold_access) |
| static int | sla_load_config (int reload) |
| static int | sla_process_timers (struct timespec *ts) |
| Calculate the time until the next known event. | |
| static void | sla_queue_event (enum sla_event_type type) |
| static void | sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf) |
| Queue a SLA event from the conference. | |
| static void | sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock) |
| static void | sla_queue_event_nolock (enum sla_event_type type) |
| static int | sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station) |
| Ring a station. | |
| static void | sla_ring_stations (void) |
| Ring stations based on current set of ringing trunks. | |
| static char * | sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static enum ast_device_state | sla_state (const char *data) |
| static enum ast_device_state | sla_state_to_devstate (enum sla_trunk_state state) |
| static int | sla_station_exec (struct ast_channel *chan, void *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, void *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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
| static const char * | app = "MeetMe" |
| static const char * | app2 = "MeetMeCount" |
| static const char * | app3 = "MeetMeAdmin" |
| static const char * | app4 = "MeetMeChannelAdmin" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static int | audio_buffers |
| static struct ast_cli_entry | cli_meetme [] |
| static unsigned int | conf_map [1024] = {0, } |
| static const char * | descrip |
| static const char * | descrip2 |
| static const char * | descrip3 |
| static const char * | descrip4 |
| static int | earlyalert |
| static int | endalert |
| static int | fuzzystart |
| static char const | gain_map [] |
| static char | mandescr_meetmelist [] |
| 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 * | slastation_app = "SLAStation" |
| static const char * | slastation_desc |
| static const char * | slastation_synopsis = "Shared Line Appearance Station" |
| static const char * | slatrunk_app = "SLATrunk" |
| static const char * | slatrunk_desc |
| static const char * | slatrunk_synopsis = "Shared Line Appearance Trunk" |
| static const char * | synopsis = "MeetMe conference bridge" |
| static const char * | synopsis2 = "MeetMe participant count" |
| static const char * | synopsis3 = "MeetMe conference Administration" |
| static const char * | synopsis4 = "MeetMe conference Administration (channel specific)" |
Meet me conference bridge and Shared Line Appearances.
Definition in file app_meetme.c.
| #define AST_FRAME_BITS 32 |
Definition at line 86 of file app_meetme.c.
Referenced by conf_free(), conf_run(), and recordthread().
| #define CONF_SIZE 320 |
Definition at line 105 of file app_meetme.c.
| #define CONFIG_FILE_NAME "meetme.conf" |
Definition at line 66 of file app_meetme.c.
| #define DATE_FORMAT "%Y-%m-%d %H:%M:%S" |
String format for scheduled conferences
Definition at line 73 of file app_meetme.c.
Referenced by append_date(), build_radius_record(), execute_cb(), find_conf_realtime(), get_date(), manager_log(), pgsql_log(), and sqlite_log().
| #define DEFAULT_AUDIO_BUFFERS 32 |
each buffer is 20ms, so this is 640ms total
Definition at line 70 of file app_meetme.c.
Referenced by load_config_meetme().
| #define MAX_CONFNUM 80 |
Definition at line 359 of file app_meetme.c.
Referenced by conf_exec(), dial_trunk(), meetme_cmd(), sla_station_exec(), and sla_trunk_exec().
| #define MAX_PIN 80 |
Definition at line 360 of file app_meetme.c.
Referenced by conf_exec().
| #define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3) |
Definition at line 363 of file app_meetme.c.
Referenced by conf_exec(), and find_conf().
| #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n" |
Referenced by meetme_cmd().
| #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n" |
Referenced by meetme_cmd().
| #define MEETME_DELAYDETECTENDTALK 1000 |
Definition at line 84 of file app_meetme.c.
Referenced by conf_run().
| #define MEETME_DELAYDETECTTALK 300 |
Definition at line 83 of file app_meetme.c.
Referenced by conf_run().
| #define S | ( | e | ) | case e: return # e; |
Referenced by sms_readfile(), and trunkstate2str().
| #define SLA_CONFIG_FILE "sla.conf" |
Definition at line 67 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 75 of file app_meetme.c.
00075 { 00076 ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */ 00077 ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */ 00078 ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */ 00079 /*! User has requested to speak */ 00080 ADMINFLAG_T_REQUEST = (1 << 4), 00081 };
| 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 | |
| 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 107 of file app_meetme.c.
00107 { 00108 /*! user has admin access on the conference */ 00109 CONFFLAG_ADMIN = (1 << 0), 00110 /*! If set the user can only receive audio from the conference */ 00111 CONFFLAG_MONITOR = (1 << 1), 00112 /*! If set asterisk will exit conference when key defined in p() option is pressed */ 00113 CONFFLAG_KEYEXIT = (1 << 2), 00114 /*! If set asterisk will provide a menu to the user when '*' is pressed */ 00115 CONFFLAG_STARMENU = (1 << 3), 00116 /*! If set the use can only send audio to the conference */ 00117 CONFFLAG_TALKER = (1 << 4), 00118 /*! If set there will be no enter or leave sounds */ 00119 CONFFLAG_QUIET = (1 << 5), 00120 /*! If set, when user joins the conference, they will be told the number 00121 * of users that are already in */ 00122 CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6), 00123 /*! Set to run AGI Script in Background */ 00124 CONFFLAG_AGI = (1 << 7), 00125 /*! Set to have music on hold when user is alone in conference */ 00126 CONFFLAG_MOH = (1 << 8), 00127 /*! If set the MeetMe will return if all marked with this flag left */ 00128 CONFFLAG_MARKEDEXIT = (1 << 9), 00129 /*! If set, the MeetMe will wait until a marked user enters */ 00130 CONFFLAG_WAITMARKED = (1 << 10), 00131 /*! If set, the MeetMe will exit to the specified context */ 00132 CONFFLAG_EXIT_CONTEXT = (1 << 11), 00133 /*! If set, the user will be marked */ 00134 CONFFLAG_MARKEDUSER = (1 << 12), 00135 /*! If set, user will be ask record name on entry of conference */ 00136 CONFFLAG_INTROUSER = (1 << 13), 00137 /*! If set, the MeetMe will be recorded */ 00138 CONFFLAG_RECORDCONF = (1<< 14), 00139 /*! If set, the user will be monitored if the user is talking or not */ 00140 CONFFLAG_MONITORTALKER = (1 << 15), 00141 CONFFLAG_DYNAMIC = (1 << 16), 00142 CONFFLAG_DYNAMICPIN = (1 << 17), 00143 CONFFLAG_EMPTY = (1 << 18), 00144 CONFFLAG_EMPTYNOPIN = (1 << 19), 00145 CONFFLAG_ALWAYSPROMPT = (1 << 20), 00146 /*! If set, treat talking users as muted users */ 00147 CONFFLAG_OPTIMIZETALKER = (1 << 21), 00148 /*! If set, won't speak the extra prompt when the first person 00149 * enters the conference */ 00150 CONFFLAG_NOONLYPERSON = (1 << 22), 00151 /*! If set, user will be asked to record name on entry of conference 00152 * without review */ 00153 CONFFLAG_INTROUSERNOREVIEW = (1 << 23), 00154 /*! If set, the user will be initially self-muted */ 00155 CONFFLAG_STARTMUTED = (1 << 24), 00156 /*! Pass DTMF through the conference */ 00157 CONFFLAG_PASS_DTMF = (1 << 25), 00158 CONFFLAG_SLA_STATION = (1 << 26), 00159 CONFFLAG_SLA_TRUNK = (1 << 27), 00160 /*! If set, the user should continue in the dialplan if kicked out */ 00161 CONFFLAG_KICK_CONTINUE = (1 << 28), 00162 CONFFLAG_DURATION_STOP = (1 << 29), 00163 CONFFLAG_DURATION_LIMIT = (1 << 30), 00164 /*! Do not write any audio to this channel until the state is up. */ 00165 CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31), 00166 };
| 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 168 of file app_meetme.c.
00168 { 00169 OPT_ARG_WAITMARKED = 0, 00170 OPT_ARG_EXITKEYS = 1, 00171 OPT_ARG_DURATION_STOP = 2, 00172 OPT_ARG_DURATION_LIMIT = 3, 00173 OPT_ARG_MOH_CLASS = 4, 00174 OPT_ARG_ARRAY_SIZE = 5, 00175 };
| anonymous enum |
Definition at line 5250 of file app_meetme.c.
05250 { 05251 SLA_TRUNK_OPT_MOH = (1 << 0), 05252 };
| anonymous enum |
Definition at line 5254 of file app_meetme.c.
05254 { 05255 SLA_TRUNK_OPT_ARG_MOH_CLASS = 0, 05256 SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1, 05257 };
| enum announcetypes |
Definition at line 365 of file app_meetme.c.
00365 { 00366 CONF_HASJOIN, 00367 CONF_HASLEFT 00368 };
| enum entrance_sound |
Definition at line 93 of file app_meetme.c.
| enum recording_state |
Definition at line 98 of file app_meetme.c.
00098 { 00099 MEETME_RECORD_OFF, 00100 MEETME_RECORD_STARTED, 00101 MEETME_RECORD_ACTIVE, 00102 MEETME_RECORD_TERMINATE 00103 };
| 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 555 of file app_meetme.c.
00555 { 00556 /*! A station has put the call on hold */ 00557 SLA_EVENT_HOLD, 00558 /*! The state of a dial has changed */ 00559 SLA_EVENT_DIAL_STATE, 00560 /*! The state of a ringing trunk has changed */ 00561 SLA_EVENT_RINGING_TRUNK, 00562 /*! A reload of configuration has been requested */ 00563 SLA_EVENT_RELOAD, 00564 /*! Poke the SLA thread so it can check if it can perform a reload */ 00565 SLA_EVENT_CHECK_RELOAD, 00566 };
| enum sla_hold_access |
Definition at line 465 of file app_meetme.c.
00465 { 00466 /*! This means that any station can put it on hold, and any station 00467 * can retrieve the call from hold. */ 00468 SLA_HOLD_OPEN, 00469 /*! This means that only the station that put the call on hold may 00470 * retrieve it from hold. */ 00471 SLA_HOLD_PRIVATE, 00472 };
| enum sla_station_hangup |
Definition at line 592 of file app_meetme.c.
00592 { 00593 SLA_STATION_HANGUP_NORMAL, 00594 SLA_STATION_HANGUP_TIMEOUT, 00595 };
| 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 457 of file app_meetme.c.
00457 { 00458 SLA_TRUNK_STATE_IDLE, 00459 SLA_TRUNK_STATE_RINGING, 00460 SLA_TRUNK_STATE_UP, 00461 SLA_TRUNK_STATE_ONHOLD, 00462 SLA_TRUNK_STATE_ONHOLD_BYME, 00463 };
| enum sla_which_trunk_refs |
Definition at line 452 of file app_meetme.c.
00452 { 00453 ALL_TRUNK_REFS, 00454 INACTIVE_TRUNK_REFS, 00455 };
| enum volume_action |
Definition at line 88 of file app_meetme.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 5953 of file app_meetme.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 5953 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 5806 of file app_meetme.c.
References acf_meetme_info_eval(), AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conference::confno, ast_conference::list, LOG_ERROR, LOG_NOTICE, and parse().
05807 { 05808 struct ast_conference *conf; 05809 char *parse; 05810 int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */ 05811 AST_DECLARE_APP_ARGS(args, 05812 AST_APP_ARG(keyword); 05813 AST_APP_ARG(confno); 05814 ); 05815 05816 if (ast_strlen_zero(data)) { 05817 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n"); 05818 return -1; 05819 } 05820 05821 parse = ast_strdupa(data); 05822 AST_STANDARD_APP_ARGS(args, parse); 05823 05824 if (ast_strlen_zero(args.keyword)) { 05825 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n"); 05826 return -1; 05827 } 05828 05829 if (ast_strlen_zero(args.confno)) { 05830 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n"); 05831 return -1; 05832 } 05833 05834 AST_LIST_LOCK(&confs); 05835 AST_LIST_TRAVERSE(&confs, conf, list) { 05836 if (!strcmp(args.confno, conf->confno)) { 05837 result = acf_meetme_info_eval(args.keyword, conf); 05838 break; 05839 } 05840 } 05841 AST_LIST_UNLOCK(&confs); 05842 05843 if (result > -1) { 05844 snprintf(buf, len, "%d", result); 05845 } else if (result == -1) { 05846 ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword); 05847 snprintf(buf, len, "0"); 05848 } else if (result == -2) { 05849 ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 05850 snprintf(buf, len, "0"); 05851 } 05852 05853 return 0; 05854 }
| static int acf_meetme_info_eval | ( | char * | keyword, | |
| struct ast_conference * | conf | |||
| ) | [static] |
Definition at line 5788 of file app_meetme.c.
References ast_conference::isdynamic, ast_conference::locked, ast_conference::start, and ast_conference::users.
Referenced by acf_meetme_info().
05789 { 05790 if (!strcasecmp("lock", keyword)) { 05791 return conf->locked; 05792 } else if (!strcasecmp("parties", keyword)) { 05793 return conf->users; 05794 } else if (!strcasecmp("activity", keyword)) { 05795 time_t now; 05796 now = time(NULL); 05797 return (now - conf->start); 05798 } else if (!strcasecmp("dynamic", keyword)) { 05799 return conf->isdynamic; 05800 } else { 05801 return -1; 05802 } 05803 05804 }
| static int action_meetmelist | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 3758 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, S_OR, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conf_user::userflags, and ast_conference::userlist.
Referenced by load_module().
03759 { 03760 const char *actionid = astman_get_header(m, "ActionID"); 03761 const char *conference = astman_get_header(m, "Conference"); 03762 char idText[80] = ""; 03763 struct ast_conference *cnf; 03764 struct ast_conf_user *user; 03765 int total = 0; 03766 03767 if (!ast_strlen_zero(actionid)) 03768 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid); 03769 03770 if (AST_LIST_EMPTY(&confs)) { 03771 astman_send_error(s, m, "No active conferences."); 03772 return 0; 03773 } 03774 03775 astman_send_listack(s, m, "Meetme user list will follow", "start"); 03776 03777 /* Find the right conference */ 03778 AST_LIST_LOCK(&confs); 03779 AST_LIST_TRAVERSE(&confs, cnf, list) { 03780 /* If we ask for one particular, and this isn't it, skip it */ 03781 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference)) 03782 continue; 03783 03784 /* Show all the users */ 03785 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 03786 total++; 03787 astman_append(s, 03788 "Event: MeetmeList\r\n" 03789 "%s" 03790 "Conference: %s\r\n" 03791 "UserNumber: %d\r\n" 03792 "CallerIDNum: %s\r\n" 03793 "CallerIDName: %s\r\n" 03794 "Channel: %s\r\n" 03795 "Admin: %s\r\n" 03796 "Role: %s\r\n" 03797 "MarkedUser: %s\r\n" 03798 "Muted: %s\r\n" 03799 "Talking: %s\r\n" 03800 "\r\n", 03801 idText, 03802 cnf->confno, 03803 user->user_no, 03804 S_OR(user->chan->cid.cid_num, "<unknown>"), 03805 S_OR(user->chan->cid.cid_name, "<no name>"), 03806 user->chan->name, 03807 user->userflags & CONFFLAG_ADMIN ? "Yes" : "No", 03808 user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen", 03809 user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No", 03810 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No", 03811 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored"); 03812 } 03813 } 03814 AST_LIST_UNLOCK(&confs); 03815 /* Send final confirmation */ 03816 astman_append(s, 03817 "Event: MeetmeListComplete\r\n" 03818 "EventList: Complete\r\n" 03819 "ListItems: %d\r\n" 03820 "%s" 03821 "\r\n", total, idText); 03822 return 0; 03823 }
| static int action_meetmemute | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 3740 of file app_meetme.c.
References meetmemute().
Referenced by load_module().
03741 { 03742 return meetmemute(s, m, 1); 03743 }
| static int action_meetmeunmute | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 3745 of file app_meetme.c.
References meetmemute().
Referenced by load_module().
03746 { 03747 return meetmemute(s, m, 0); 03748 }
| static int admin_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
The MeetMeadmin application.
Definition at line 3470 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, ast_conference::refcount, reset_volumes(), tweak_listen_volume(), tweak_talk_volume(), ast_conf_user::userflags, ast_conference::userlist, VOL_DOWN, and VOL_UP.
Referenced by load_module(), meetme_cmd(), run_station(), sla_station_exec(), and sla_stop_ringing_trunk().
03470 { 03471 char *params; 03472 struct ast_conference *cnf; 03473 struct ast_conf_user *user = NULL; 03474 AST_DECLARE_APP_ARGS(args, 03475 AST_APP_ARG(confno); 03476 AST_APP_ARG(command); 03477 AST_APP_ARG(user); 03478 ); 03479 03480 if (ast_strlen_zero(data)) { 03481 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n"); 03482 return -1; 03483 } 03484 03485 params = ast_strdupa(data); 03486 AST_STANDARD_APP_ARGS(args, params); 03487 03488 if (!args.command) { 03489 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n"); 03490 return -1; 03491 } 03492 03493 AST_LIST_LOCK(&confs); 03494 AST_LIST_TRAVERSE(&confs, cnf, list) { 03495 if (!strcmp(cnf->confno, args.confno)) 03496 break; 03497 } 03498 03499 if (!cnf) { 03500 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno); 03501 AST_LIST_UNLOCK(&confs); 03502 return 0; 03503 } 03504 03505 ast_atomic_fetchadd_int(&cnf->refcount, 1); 03506 03507 if (args.user) 03508 user = find_user(cnf, args.user); 03509 03510 switch (*args.command) { 03511 case 76: /* L: Lock */ 03512 cnf->locked = 1; 03513 break; 03514 case 108: /* l: Unlock */ 03515 cnf->locked = 0; 03516 break; 03517 case 75: /* K: kick all users */ 03518 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 03519 user->adminflags |= ADMINFLAG_KICKME; 03520 break; 03521 case 101: /* e: Eject last user*/ 03522 user = AST_LIST_LAST(&cnf->userlist); 03523 if (!(user->userflags & CONFFLAG_ADMIN)) 03524 user->adminflags |= ADMINFLAG_KICKME; 03525 else 03526 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n"); 03527 break; 03528 case 77: /* M: Mute */ 03529 if (user) { 03530 user->adminflags |= ADMINFLAG_MUTED; 03531 } else 03532 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03533 break; 03534 case 78: /* N: Mute all (non-admin) users */ 03535 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 03536 if (!(user->userflags & CONFFLAG_ADMIN)) 03537 user->adminflags |= ADMINFLAG_MUTED; 03538 } 03539 break; 03540 case 109: /* m: Unmute */ 03541 if (user) { 03542 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); 03543 } else 03544 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03545 break; 03546 case 110: /* n: Unmute all users */ 03547 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 03548 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); 03549 break; 03550 case 107: /* k: Kick user */ 03551 if (user) 03552 user->adminflags |= ADMINFLAG_KICKME; 03553 else 03554 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03555 break; 03556 case 118: /* v: Lower all users listen volume */ 03557 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 03558 tweak_listen_volume(user, VOL_DOWN); 03559 break; 03560 case 86: /* V: Raise all users listen volume */ 03561 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 03562 tweak_listen_volume(user, VOL_UP); 03563 break; 03564 case 115: /* s: Lower all users speaking volume */ 03565 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 03566 tweak_talk_volume(user, VOL_DOWN); 03567 break; 03568 case 83: /* S: Raise all users speaking volume */ 03569 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 03570 tweak_talk_volume(user, VOL_UP); 03571 break; 03572 case 82: /* R: Reset all volume levels */ 03573 AST_LIST_TRAVERSE(&cnf->userlist, user, list) 03574 reset_volumes(user); 03575 break; 03576 case 114: /* r: Reset user's volume level */ 03577 if (user) 03578 reset_volumes(user); 03579 else 03580 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03581 break; 03582 case 85: /* U: Raise user's listen volume */ 03583 if (user) 03584 tweak_listen_volume(user, VOL_UP); 03585 else 03586 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03587 break; 03588 case 117: /* u: Lower user's listen volume */ 03589 if (user) 03590 tweak_listen_volume(user, VOL_DOWN); 03591 else 03592 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03593 break; 03594 case 84: /* T: Raise user's talk volume */ 03595 if (user) 03596 tweak_talk_volume(user, VOL_UP); 03597 else 03598 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03599 break; 03600 case 116: /* t: Lower user's talk volume */ 03601 if (user) 03602 tweak_talk_volume(user, VOL_DOWN); 03603 else 03604 ast_log(LOG_NOTICE, "Specified User not found!\n"); 03605 break; 03606 } 03607 03608 AST_LIST_UNLOCK(&confs); 03609 03610 dispose_conf(cnf); 03611 03612 return 0; 03613 }
| static void* announce_thread | ( | void * | data | ) | [static] |
Definition at line 1573 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().
01574 { 01575 struct announce_listitem *current; 01576 struct ast_conference *conf = data; 01577 int res = 0; 01578 char filename[PATH_MAX] = ""; 01579 AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list; 01580 AST_LIST_HEAD_INIT_NOLOCK(&local_list); 01581 01582 while (!conf->announcethread_stop) { 01583 ast_mutex_lock(&conf->announcelistlock); 01584 if (conf->announcethread_stop) { 01585 ast_mutex_unlock(&conf->announcelistlock); 01586 break; 01587 } 01588 if (AST_LIST_EMPTY(&conf->announcelist)) 01589 ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock); 01590 01591 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry); 01592 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist); 01593 01594 ast_mutex_unlock(&conf->announcelistlock); 01595 if (conf->announcethread_stop) { 01596 break; 01597 } 01598 01599 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) { 01600 ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc); 01601 if (!ast_fileexists(current->namerecloc, NULL, NULL)) 01602 continue; 01603 if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) { 01604 if (!ast_streamfile(current->confchan, current->namerecloc, current->language)) 01605 res = ast_waitstream(current->confchan, ""); 01606 if (!res) { 01607 ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename)); 01608 if (!ast_streamfile(current->confchan, filename, current->language)) 01609 ast_waitstream(current->confchan, ""); 01610 } 01611 } 01612 if (current->announcetype == CONF_HASLEFT) { 01613 ast_filedelete(current->namerecloc, NULL); 01614 } 01615 } 01616 } 01617 01618 /* thread marked to stop, clean up */ 01619 while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) { 01620 ast_filedelete(current->namerecloc, NULL); 01621 ao2_ref(current, -1); 01622 } 01623 return NULL; 01624 }
| static void answer_trunk_chan | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 4122 of file app_meetme.c.
References ast_answer(), and ast_indicate().
Referenced by run_station(), sla_handle_dial_state_event(), and sla_station_exec().
04123 { 04124 ast_answer(chan); 04125 ast_indicate(chan, -1); 04126 }
| static struct ast_conference* build_conf | ( | char * | confno, | |
| char * | pin, | |||
| 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 831 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, and ast_conference::uniqueid.
Referenced by dial_trunk(), find_conf(), find_conf_realtime(), run_station(), sla_station_exec(), and sla_trunk_exec().
00832 { 00833 struct ast_conference *cnf; 00834 struct dahdi_confinfo dahdic = { 0, }; 00835 int confno_int = 0; 00836 00837 AST_LIST_LOCK(&confs); 00838 00839 AST_LIST_TRAVERSE(&confs, cnf, list) { 00840 if (!strcmp(confno, cnf->confno)) 00841 break; 00842 } 00843 00844 if (cnf || (!make && !dynamic)) 00845 goto cnfout; 00846 00847 /* Make a new one */ 00848 if (!(cnf = ast_calloc(1, sizeof(*cnf)))) 00849 goto cnfout; 00850 00851 ast_mutex_init(&cnf->playlock); 00852 ast_mutex_init(&cnf->listenlock); 00853 cnf->recordthread = AST_PTHREADT_NULL; 00854 ast_mutex_init(&cnf->recordthreadlock); 00855 cnf->announcethread = AST_PTHREADT_NULL; 00856 ast_mutex_init(&cnf->announcethreadlock); 00857 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno)); 00858 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin)); 00859 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin)); 00860 ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid)); 00861 00862 /* Setup a new dahdi conference */ 00863 dahdic.confno = -1; 00864 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; 00865 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR); 00866 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) { 00867 ast_log(LOG_WARNING, "Unable to open pseudo device\n"); 00868 if (cnf->fd >= 0) 00869 close(cnf->fd); 00870 ast_free(cnf); 00871 cnf = NULL; 00872 goto cnfout; 00873 } 00874 00875 cnf->dahdiconf = dahdic.confno; 00876 00877 /* Setup a new channel for playback of audio files */ 00878 cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL); 00879 if (cnf->chan) { 00880 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR); 00881 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR); 00882 dahdic.chan = 0; 00883 dahdic.confno = cnf->dahdiconf; 00884 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; 00885 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) { 00886 ast_log(LOG_WARNING, "Error setting conference\n"); 00887 if (cnf->chan) 00888 ast_hangup(cnf->chan); 00889 else 00890 close(cnf->fd); 00891 00892 ast_free(cnf); 00893 cnf = NULL; 00894 goto cnfout; 00895 } 00896 } 00897 00898 /* Fill the conference struct */ 00899 cnf->start = time(NULL); 00900 cnf->maxusers = 0x7fffffff; 00901 cnf->isdynamic = dynamic ? 1 : 0; 00902 ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno); 00903 AST_LIST_INSERT_HEAD(&confs, cnf, list); 00904 00905 /* Reserve conference number in map */ 00906 if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) 00907 conf_map[confno_int] = 1; 00908 00909 cnfout: 00910 if (cnf) 00911 ast_atomic_fetchadd_int(&cnf->refcount, refcount); 00912 00913 AST_LIST_UNLOCK(&confs); 00914 00915 return cnf; 00916 }
| static int can_write | ( | struct ast_channel * | chan, | |
| int | confflags | |||
| ) | [static] |
Definition at line 1626 of file app_meetme.c.
References ast_channel::_state, AST_STATE_UP, and CONFFLAG_NO_AUDIO_UNTIL_UP.
Referenced by conf_run().
01627 { 01628 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) { 01629 return 1; 01630 } 01631 01632 return (chan->_state == AST_STATE_UP); 01633 }
| static int careful_write | ( | int | fd, | |
| unsigned char * | data, | |||
| int | len, | |||
| int | block | |||
| ) | [static] |
Definition at line 665 of file app_meetme.c.
References ast_log(), errno, and LOG_WARNING.
Referenced by conf_play(), and conf_run().
00666 { 00667 int res; 00668 int x; 00669 00670 while (len) { 00671 if (block) { 00672 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT; 00673 res = ioctl(fd, DAHDI_IOMUX, &x); 00674 } else 00675 res = 0; 00676 if (res >= 0) 00677 res = write(fd, data, len); 00678 if (res < 1) { 00679 if (errno != EAGAIN) { 00680 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno)); 00681 return -1; 00682 } else 00683 return 0; 00684 } 00685 len -= res; 00686 data += res; 00687 } 00688 00689 return 0; 00690 }
| static int channel_admin_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 3617 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, and ast_conference::userlist.
Referenced by load_module().
03617 { 03618 char *params; 03619 struct ast_conference *conf = NULL; 03620 struct ast_conf_user *user = NULL; 03621 AST_DECLARE_APP_ARGS(args, 03622 AST_APP_ARG(channel); 03623 AST_APP_ARG(command); 03624 ); 03625 03626 if (ast_strlen_zero(data)) { 03627 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n"); 03628 return -1; 03629 } 03630 03631 params = ast_strdupa(data); 03632 AST_STANDARD_APP_ARGS(args, params); 03633 03634 if (!args.channel) { 03635 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n"); 03636 return -1; 03637 } 03638 03639 if (!args.command) { 03640 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n"); 03641 return -1; 03642 } 03643 03644 AST_LIST_LOCK(&confs); 03645 AST_LIST_TRAVERSE(&confs, conf, list) { 03646 AST_LIST_TRAVERSE(&conf->userlist, user, list) { 03647 if (!strcmp(user->chan->name, args.channel)) 03648 break; 03649 } 03650 } 03651 03652 if (!user) { 03653 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel); 03654 AST_LIST_UNLOCK(&confs); 03655 return 0; 03656 } 03657 03658 /* perform the specified action */ 03659 switch (*args.command) { 03660 case 77: /* M: Mute */ 03661 user->adminflags |= ADMINFLAG_MUTED; 03662 break; 03663 case 109: /* m: Unmute */ 03664 user->adminflags &= ~ADMINFLAG_MUTED; 03665 break; 03666 case 107: /* k: Kick user */ 03667 user->adminflags |= ADMINFLAG_KICKME; 03668 break; 03669 default: /* unknown command */ 03670 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command); 03671 break; 03672 } 03673 03674 AST_LIST_UNLOCK(&confs); 03675 03676 return 0; 03677 }
| static char* complete_meetmecmd | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 919 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().
00920 { 00921 static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL}; 00922 00923 int len = strlen(word); 00924 int which = 0; 00925 struct ast_conference *cnf = NULL; 00926 struct ast_conf_user *usr = NULL; 00927 char *confno = NULL; 00928 char usrno[50] = ""; 00929 char *myline, *ret = NULL; 00930 00931 if (pos == 1) { /* Command */ 00932 return ast_cli_complete(word, cmds, state); 00933 } else if (pos == 2) { /* Conference Number */ 00934 AST_LIST_LOCK(&confs); 00935 AST_LIST_TRAVERSE(&confs, cnf, list) { 00936 if (!strncasecmp(word, cnf->confno, len) && ++which > state) { 00937 ret = cnf->confno; 00938 break; 00939 } 00940 } 00941 ret = ast_strdup(ret); /* dup before releasing the lock */ 00942 AST_LIST_UNLOCK(&confs); 00943 return ret; 00944 } else if (pos == 3) { 00945 /* User Number || Conf Command option*/ 00946 if (strstr(line, "mute") || strstr(line, "kick")) { 00947 if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len)) 00948 return ast_strdup("all"); 00949 which++; 00950 AST_LIST_LOCK(&confs); 00951 00952 /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */ 00953 myline = ast_strdupa(line); 00954 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) { 00955 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0)) 00956 ; 00957 } 00958 00959 AST_LIST_TRAVERSE(&confs, cnf, list) { 00960 if (!strcmp(confno, cnf->confno)) 00961 break; 00962 } 00963 00964 if (cnf) { 00965 /* Search for the user */ 00966 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) { 00967 snprintf(usrno, sizeof(usrno), "%d", usr->user_no); 00968 if (!strncasecmp(word, usrno, len) && ++which > state) 00969 break; 00970 } 00971 } 00972 AST_LIST_UNLOCK(&confs); 00973 return usr ? ast_strdup(usrno) : NULL; 00974 } else if (strstr(line, "list") && (state == 0)) 00975 return ast_strdup("concise"); 00976 } 00977 00978 return NULL; 00979 }
| static int conf_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
The meetme() application.
Definition at line 3207 of file app_meetme.c.
References ast_channel::_state, 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_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), 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, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, strsep(), ast_variable::value, and var.
Referenced by load_module().
03208 { 03209 int res = -1; 03210 char confno[MAX_CONFNUM] = ""; 03211 int allowretry = 0; 03212 int retrycnt = 0; 03213 struct ast_conference *cnf = NULL; 03214 struct ast_flags confflags = {0}, config_flags = { 0 }; 03215 int dynamic = 0; 03216 int empty = 0, empty_no_pin = 0; 03217 int always_prompt = 0; 03218 char *notdata, *info, the_pin[MAX_PIN] = ""; 03219 AST_DECLARE_APP_ARGS(args, 03220 AST_APP_ARG(confno); 03221 AST_APP_ARG(options); 03222 AST_APP_ARG(pin); 03223 ); 03224 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, }; 03225 03226 if (ast_strlen_zero(data)) { 03227 allowretry = 1; 03228 notdata = ""; 03229 } else { 03230 notdata = data; 03231 } 03232 03233 if (chan->_state != AST_STATE_UP) 03234 ast_answer(chan); 03235 03236 info = ast_strdupa(notdata); 03237 03238 AST_STANDARD_APP_ARGS(args, info); 03239 03240 if (args.confno) { 03241 ast_copy_string(confno, args.confno, sizeof(confno)); 03242 if (ast_strlen_zero(confno)) { 03243 allowretry = 1; 03244 } 03245 } 03246 03247 if (args.pin) 03248 ast_copy_string(the_pin, args.pin, sizeof(the_pin)); 03249 03250 if (args.options) { 03251 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options); 03252 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN); 03253 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin)) 03254 strcpy(the_pin, "q"); 03255 03256 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN); 03257 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN); 03258 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN); 03259 } 03260 03261 do { 03262 if (retrycnt > 3) 03263 allowretry = 0; 03264 if (empty) { 03265 int i; 03266 struct ast_config *cfg; 03267 struct ast_variable *var; 03268 int confno_int; 03269 03270 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */ 03271 if ((empty_no_pin) || (!dynamic)) { 03272 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags); 03273 if (cfg) { 03274 var = ast_variable_browse(cfg, "rooms"); 03275 while (var) { 03276 char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp; 03277 if (!strcasecmp(var->name, "conf")) { 03278 int found = 0; 03279 ast_copy_string(parse, var->value, sizeof(parse)); 03280 confno_tmp = strsep(&stringp, "|,"); 03281 if (!dynamic) { 03282 /* For static: run through the list and see if this conference is empty */ 03283 AST_LIST_LOCK(&confs); 03284 AST_LIST_TRAVERSE(&confs, cnf, list) { 03285 if (!strcmp(confno_tmp, cnf->confno)) { 03286 /* The conference exists, therefore it's not empty */ 03287 found = 1; 03288 break; 03289 } 03290 } 03291 AST_LIST_UNLOCK(&confs); 03292 if (!found) { 03293 /* At this point, we have a confno_tmp (static conference) that is empty */ 03294 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) { 03295 /* Case 1: empty_no_pin and pin is nonexistent (NULL) 03296 * Case 2: empty_no_pin and pin is blank (but not NULL) 03297 * Case 3: not empty_no_pin 03298 */ 03299 ast_copy_string(confno, confno_tmp, sizeof(confno)); 03300 break; 03301 /* XXX the map is not complete (but we do have a confno) */ 03302 } 03303 } 03304 } 03305 } 03306 var = var->next; 03307 } 03308 ast_config_destroy(cfg); 03309 } 03310 } 03311 03312 /* Select first conference number not in use */ 03313 if (ast_strlen_zero(confno) && dynamic) { 03314 AST_LIST_LOCK(&confs); 03315 for (i = 0; i < ARRAY_LEN(conf_map); i++) { 03316 if (!conf_map[i]) { 03317 snprintf(confno, sizeof(confno), "%d", i); 03318 conf_map[i] = 1; 03319 break; 03320 } 03321 } 03322 AST_LIST_UNLOCK(&confs); 03323 } 03324 03325 /* Not found? */ 03326 if (ast_strlen_zero(confno)) { 03327 res = ast_streamfile(chan, "conf-noempty", chan->language); 03328 if (!res) 03329 ast_waitstream(chan, ""); 03330 } else { 03331 if (sscanf(confno, "%30d", &confno_int) == 1) { 03332 if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) { 03333 res = ast_streamfile(chan, "conf-enteringno", chan->language); 03334 if (!res) { 03335 ast_waitstream(chan, ""); 03336 res = ast_say_digits(chan, confno_int, "", chan->language); 03337 } 03338 } 03339 } else { 03340 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno); 03341 } 03342 } 03343 } 03344 03345 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) { 03346 /* Prompt user for conference number */ 03347 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0); 03348 if (res < 0) { 03349 /* Don't try to validate when we catch an error */ 03350 confno[0] = '\0'; 03351 allowretry = 0; 03352 break; 03353 } 03354 } 03355 if (!ast_strlen_zero(confno)) { 03356 /* Check the validity of the conference */ 03357 cnf = find_conf(chan, confno, 1, dynamic, the_pin, 03358 sizeof(the_pin), 1, &confflags); 03359 if (!cnf) { 03360 int too_early = 0; 03361 cnf = find_conf_realtime(chan, confno, 1, dynamic, 03362 the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early); 03363 if (rt_schedule && too_early) 03364 allowretry = 0; 03365 } 03366 03367 if (!cnf) { 03368 if (allowretry) { 03369 confno[0] = '\0'; 03370 res = ast_streamfile(chan, "conf-invalid", chan->language); 03371 if (!res) 03372 ast_waitstream(chan, ""); 03373 res = -1; 03374 } 03375 } else { 03376 if ((!ast_strlen_zero(cnf->pin) && 03377 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) || 03378 (!ast_strlen_zero(cnf->pinadmin) && 03379 ast_test_flag(&confflags, CONFFLAG_ADMIN))) { 03380 char pin[MAX_PIN] = ""; 03381 int j; 03382 03383 /* Allow the pin to be retried up to 3 times */ 03384 for (j = 0; j < 3; j++) { 03385 if (*the_pin && (always_prompt == 0)) { 03386 ast_copy_string(pin, the_pin, sizeof(pin)); 03387 res = 0; 03388 } else { 03389 /* Prompt user for pin if pin is required */ 03390 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0); 03391 } 03392 if (res >= 0) { 03393 if (!strcasecmp(pin, cnf->pin) || 03394 (!ast_strlen_zero(cnf->pinadmin) && 03395 !strcasecmp(pin, cnf->pinadmin))) { 03396 /* Pin correct */ 03397 allowretry = 0; 03398 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 03399 ast_set_flag(&confflags, CONFFLAG_ADMIN); 03400 /* Run the conference */ 03401 res = conf_run(chan, cnf, confflags.flags, optargs); 03402 break; 03403 } else { 03404 /* Pin invalid */ 03405 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) { 03406 res = ast_waitstream(chan, AST_DIGIT_ANY); 03407 ast_stopstream(chan); 03408 } 03409 else { 03410 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n"); 03411 break; 03412 } 03413 if (res < 0) 03414 break; 03415 pin[0] = res; 03416 pin[1] = '\0'; 03417 res = -1; 03418 if (allowretry) 03419 confno[0] = '\0'; 03420 } 03421 } else { 03422 /* failed when getting the pin */ 03423 res = -1; 03424 allowretry = 0; 03425 /* see if we need to get rid of the conference */ 03426 break; 03427 } 03428 03429 /* Don't retry pin with a static pin */ 03430 if (*the_pin && (always_prompt == 0)) { 03431 break; 03432 } 03433 } 03434 } else { 03435 /* No pin required */ 03436 allowretry = 0; 03437 03438 /* Run the conference */ 03439 res = conf_run(chan, cnf, confflags.flags, optargs); 03440 } 03441 dispose_conf(cnf); 03442 cnf = NULL; 03443 } 03444 } 03445 } while (allowretry); 03446 03447 if (cnf) 03448 dispose_conf(cnf); 03449 03450 return res; 03451 }
| static void conf_flush | ( | int | fd, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Definition at line 1346 of file app_meetme.c.
References ast_frfree, ast_log(), ast_read(), ast_waitfor(), f, and LOG_WARNING.
Referenced by conf_run().
01347 { 01348 int x; 01349 01350 /* read any frames that may be waiting on the channel 01351 and throw them away 01352 */ 01353 if (chan) { 01354 struct ast_frame *f; 01355 01356 /* when no frames are available, this will wait 01357 for 1 millisecond maximum 01358 */ 01359 while (ast_waitfor(chan, 1)) { 01360 f = ast_read(chan); 01361 if (f) 01362 ast_frfree(f); 01363 else /* channel was hung up or something else happened */ 01364 break; 01365 } 01366 } 01367 01368 /* flush any data sitting in the pseudo channel */ 01369 x = DAHDI_FLUSH_ALL; 01370 if (ioctl(fd, DAHDI_FLUSH, &x)) 01371 ast_log(LOG_WARNING, "Error flushing channel\n"); 01372 01373 }
| static int conf_free | ( | struct ast_conference * | conf | ) | [static] |
Definition at line 1377 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().
01378 { 01379 int x; 01380 struct announce_listitem *item; 01381 01382 AST_LIST_REMOVE(&confs, conf, list); 01383 manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno); 01384 01385 if (conf->recording == MEETME_RECORD_ACTIVE) { 01386 conf->recording = MEETME_RECORD_TERMINATE; 01387 AST_LIST_UNLOCK(&confs); 01388 while (1) { 01389 usleep(1); 01390 AST_LIST_LOCK(&confs); 01391 if (conf->recording == MEETME_RECORD_OFF) 01392 break; 01393 AST_LIST_UNLOCK(&confs); 01394 } 01395 } 01396 01397 for (x = 0; x < AST_FRAME_BITS; x++) { 01398 if (conf->transframe[x]) 01399 ast_frfree(conf->transframe[x]); 01400 if (conf->transpath[x]) 01401 ast_translator_free_path(conf->transpath[x]); 01402 } 01403 if (conf->announcethread != AST_PTHREADT_NULL) { 01404 ast_mutex_lock(&conf->announcelistlock); 01405 conf->announcethread_stop = 1; 01406 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT); 01407 ast_cond_signal(&conf->announcelist_addition); 01408 ast_mutex_unlock(&conf->announcelistlock); 01409 pthread_join(conf->announcethread, NULL); 01410 01411 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) { 01412 ast_filedelete(item->namerecloc, NULL); 01413 ao2_ref(item, -1); 01414 } 01415 ast_mutex_destroy(&conf->announcelistlock); 01416 } 01417 if (conf->origframe) 01418 ast_frfree(conf->origframe); 01419 if (conf->lchan) 01420 ast_hangup(conf->lchan); 01421 if (conf->chan) 01422 ast_hangup(conf->chan); 01423 if (conf->fd >= 0) 01424 close(conf->fd); 01425 if (conf->recordingfilename) { 01426 ast_free(conf->recordingfilename); 01427 } 01428 if (conf->recordingformat) { 01429 ast_free(conf->recordingformat); 01430 } 01431 ast_mutex_destroy(&conf->playlock); 01432 ast_mutex_destroy(&conf->listenlock); 01433 ast_mutex_destroy(&conf->recordthreadlock); 01434 ast_mutex_destroy(&conf->announcethreadlock); 01435 ast_free(conf); 01436 01437 return 0; 01438 }
| static void conf_play | ( | struct ast_channel * | chan, | |
| struct ast_conference * | conf, | |||
| enum entrance_sound | sound | |||
| ) | [static] |
Definition at line 783 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().
00784 { 00785 unsigned char *data; 00786 int len; 00787 int res = -1; 00788 00789 if (!ast_check_hangup(chan)) 00790 res = ast_autoservice_start(chan); 00791 00792 AST_LIST_LOCK(&confs); 00793 00794 switch(sound) { 00795 case ENTER: 00796 data = enter; 00797 len = sizeof(enter); 00798 break; 00799 case LEAVE: 00800 data = leave; 00801 len = sizeof(leave); 00802 break; 00803 default: 00804 data = NULL; 00805 len = 0; 00806 } 00807 if (data) { 00808 careful_write(conf->fd, data, len, 1); 00809 } 00810 00811 AST_LIST_UNLOCK(&confs); 00812 00813 if (!res) 00814 ast_autoservice_stop(chan); 00815 }
| static void conf_queue_dtmf | ( | const struct ast_conference * | conf, | |
| const struct ast_conf_user * | sender, | |||
| struct ast_frame * | f | |||
| ) | [static] |
Definition at line 1440 of file app_meetme.c.
References AST_LIST_TRAVERSE, ast_log(), ast_write(), ast_conf_user::chan, ast_conf_user::list, LOG_WARNING, and ast_conference::userlist.
Referenced by conf_run().
01442 { 01443 struct ast_conf_user *user; 01444 01445 AST_LIST_TRAVERSE(&conf->userlist, user, list) { 01446 if (user == sender) 01447 continue; 01448 if (ast_write(user->chan, f) < 0) 01449 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name); 01450 } 01451 }
| static int conf_run | ( | struct ast_channel * | chan, | |
| struct ast_conference * | conf, | |||
| int | confflags, | |||
| char * | optargs[] | |||
| ) | [static] |
Definition at line 1664 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_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_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), 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_strlen_zero(), ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_verb, 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, 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::frametype, ast_conf_user::jointime, ast_conf_user::kicktime, announce_listitem::language, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_channel::macrocontext, manager_event, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, announce_listitem::namerecloc, ast_conf_user::namerecloc, 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, S_OR, ast_frame::samples, sec, set_talk_volume(), set_user_talking(), 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_conf_user::user_no, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, var, VOL_DOWN, VOL_UP, ast_conf_user::warning_freq, and ast_conf_user::warning_sound.
Referenced by conf_exec(), dial_trunk(), run_station(), sla_station_exec(), and sla_trunk_exec().
01665 { 01666 struct ast_conf_user *user = NULL; 01667 struct ast_conf_user *usr = NULL; 01668 int fd; 01669 struct dahdi_confinfo dahdic, dahdic_empty; 01670 struct ast_frame *f; 01671 struct ast_channel *c; 01672 struct ast_frame fr; 01673 int outfd; 01674 int ms; 01675 int nfds; 01676 int res; 01677 int retrydahdi; 01678 int origfd; 01679 int musiconhold = 0, mohtempstopped = 0; 01680 int firstpass = 0; 01681 int lastmarked = 0; 01682 int currentmarked = 0; 01683 int ret = -1; 01684 int x; 01685 int menu_active = 0; 01686 int talkreq_manager = 0; 01687 int using_pseudo = 0; 01688 int duration = 20; 01689 int hr, min, sec; 01690 int sent_event = 0; 01691 int checked = 0; 01692 int announcement_played = 0; 01693 struct timeval now; 01694 struct ast_dsp *dsp = NULL; 01695 struct ast_app *agi_app; 01696 char *agifile; 01697 const char *agifiledefault = "conf-background.agi", *tmpvar; 01698 char meetmesecs[30] = ""; 01699 char exitcontext[AST_MAX_CONTEXT] = ""; 01700 char recordingtmp[AST_MAX_EXTENSION] = ""; 01701 char members[10] = ""; 01702 int dtmf, opt_waitmarked_timeout = 0; 01703 time_t timeout = 0; 01704 struct dahdi_bufferinfo bi; 01705 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; 01706 char *buf = __buf + AST_FRIENDLY_OFFSET; 01707 char *exitkeys = NULL; 01708 unsigned int calldurationlimit = 0; 01709 long timelimit = 0; 01710 long play_warning = 0; 01711 long warning_freq = 0; 01712 const char *warning_sound = NULL; 01713 const char *end_sound = NULL; 01714 char *parse; 01715 long time_left_ms = 0; 01716 struct timeval nexteventts = { 0, }; 01717 int to; 01718 int setusercount = 0; 01719 int confsilence = 0, totalsilence = 0; 01720 01721 if (!(user = ast_calloc(1, sizeof(*user)))) 01722 return ret; 01723 01724 /* Possible timeout waiting for marked user */ 01725 if ((confflags & CONFFLAG_WAITMARKED) && 01726 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) && 01727 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) && 01728 (opt_waitmarked_timeout > 0)) { 01729 timeout = time(NULL) + opt_waitmarked_timeout; 01730 } 01731 01732 if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) { 01733 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]); 01734 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit); 01735 } 01736 01737 if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) { 01738 char *limit_str, *warning_str, *warnfreq_str; 01739 const char *var; 01740 01741 parse = optargs[OPT_ARG_DURATION_LIMIT]; 01742 limit_str = strsep(&parse, ":"); 01743 warning_str = strsep(&parse, ":"); 01744 warnfreq_str = parse; 01745 01746 timelimit = atol(limit_str); 01747 if (warning_str) 01748 play_warning = atol(warning_str); 01749 if (warnfreq_str) 01750 warning_freq = atol(warnfreq_str); 01751 01752 if (!timelimit) { 01753 timelimit = play_warning = warning_freq = 0; 01754 warning_sound = NULL; 01755 } else if (play_warning > timelimit) { 01756 if (!warning_freq) { 01757 play_warning = 0; 01758 } else { 01759 while (play_warning > timelimit) 01760 play_warning -= warning_freq; 01761 if (play_warning < 1) 01762 play_warning = warning_freq = 0; 01763 } 01764 } 01765 01766 ast_channel_lock(chan); 01767 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) { 01768 var = ast_strdupa(var); 01769 } 01770 ast_channel_unlock(chan); 01771 01772 warning_sound = var ? var : "timeleft"; 01773 01774 ast_channel_lock(chan); 01775 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) { 01776 var = ast_strdupa(var); 01777 } 01778 ast_channel_unlock(chan); 01779 01780 end_sound = var ? var : NULL; 01781 01782 /* undo effect of S(x) in case they are both used */ 01783 calldurationlimit = 0; 01784 /* more efficient do it like S(x) does since no advanced opts */ 01785 if (!play_warning && !end_sound && timelimit) { 01786 calldurationlimit = timelimit / 1000; 01787 timelimit = play_warning = warning_freq = 0; 01788 } else { 01789 ast_debug(2, "Limit Data for this call:\n"); 01790 ast_debug(2, "- timelimit = %ld\n", timelimit); 01791 ast_debug(2, "- play_warning = %ld\n", play_warning); 01792 ast_debug(2, "- warning_freq = %ld\n", warning_freq); 01793 ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF"); 01794 ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF"); 01795 } 01796 } 01797 01798 /* Get exit keys */ 01799 if ((confflags & CONFFLAG_KEYEXIT)) { 01800 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS])) 01801 exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]); 01802 else 01803 exitkeys = ast_strdupa("#"); /* Default */ 01804 } 01805 01806 if (confflags & CONFFLAG_RECORDCONF) { 01807 if (!conf->recordingfilename) { 01808 const char *var; 01809 ast_channel_lock(chan); 01810 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) { 01811 conf->recordingfilename = ast_strdup(var); 01812 } 01813 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) { 01814 conf->recordingformat = ast_strdup(var); 01815 } 01816 ast_channel_unlock(chan); 01817 if (!conf->recordingfilename) { 01818 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid); 01819 conf->recordingfilename = ast_strdup(recordingtmp); 01820 } 01821 if (!conf->recordingformat) { 01822 conf->recordingformat = ast_strdup("wav"); 01823 } 01824 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", 01825 conf->confno, conf->recordingfilename, conf->recordingformat); 01826 } 01827 } 01828 01829 ast_mutex_lock(&conf->recordthreadlock); 01830 if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) { 01831 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR); 01832 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR); 01833 dahdic.chan = 0; 01834 dahdic.confno = conf->dahdiconf; 01835 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON; 01836 if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) { 01837 ast_log(LOG_WARNING, "Error starting listen channel\n"); 01838 ast_hangup(conf->lchan); 01839 conf->lchan = NULL; 01840 } else { 01841 ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf); 01842 } 01843 } 01844 ast_mutex_unlock(&conf->recordthreadlock); 01845 01846 ast_mutex_lock(&conf->announcethreadlock); 01847 if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) { 01848 ast_mutex_init(&conf->announcelistlock); 01849 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist); 01850 ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf); 01851 } 01852 ast_mutex_unlock(&conf->announcethreadlock); 01853 01854 time(&user->jointime); 01855 01856 user->timelimit = timelimit; 01857 user->play_warning = play_warning; 01858 user->warning_freq = warning_freq; 01859 user->warning_sound = warning_sound; 01860 user->end_sound = end_sound; 01861 01862 if (calldurationlimit > 0) { 01863 time(&user->kicktime); 01864 user->kicktime = user->kicktime + calldurationlimit; 01865 } 01866 01867 if (ast_tvzero(user->start_time)) 01868 user->start_time = ast_tvnow(); 01869 time_left_ms = user->timelimit; 01870 01871 if (user->timelimit) { 01872 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000)); 01873 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000)); 01874 } 01875 01876 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) { 01877 /* Sorry, but this conference is locked! */ 01878 if (!ast_streamfile(chan, "conf-locked", chan->language)) 01879 ast_waitstream(chan, ""); 01880 goto outrun; 01881 } 01882 01883 ast_mutex_lock(&conf->playlock); 01884 01885 if (AST_LIST_EMPTY(&conf->userlist)) 01886 user->user_no = 1; 01887 else 01888 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1; 01889 01890 if (rt_schedule && conf->maxusers) 01891 if (conf->users >= conf->maxusers) { 01892 /* Sorry, but this confernce has reached the participant limit! */ 01893 if (!ast_streamfile(chan, "conf-full", chan->language)) 01894 ast_waitstream(chan, ""); 01895 ast_mutex_unlock(&conf->playlock); 01896 user->user_no = 0; 01897 goto outrun; 01898 } 01899 01900 AST_LIST_INSERT_TAIL(&conf->userlist, user, list); 01901 01902 user->chan = chan; 01903 user->userflags = confflags; 01904 user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0; 01905 user->talking = -1; 01906 01907 ast_mutex_unlock(&conf->playlock); 01908 01909 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) { 01910 char destdir[PATH_MAX]; 01911 01912 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR); 01913 01914 if (ast_mkdir(destdir, 0777) != 0) { 01915 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno)); 01916 goto outrun; 01917 } 01918 01919 snprintf(user->namerecloc, sizeof(user->namerecloc), 01920 "%s/meetme-username-%s-%d", destdir, 01921 conf->confno, user->user_no); 01922 if (confflags & CONFFLAG_INTROUSERNOREVIEW) 01923 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL); 01924 else 01925 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL); 01926 if (res == -1) 01927 goto outrun; 01928 } 01929 01930 ast_mutex_lock(&conf->playlock); 01931 01932 if (confflags & CONFFLAG_MARKEDUSER) 01933 conf->markedusers++; 01934 conf->users++; 01935 if (rt_log_members) { 01936 /* Update table */ 01937 snprintf(members, sizeof(members), "%d", conf->users); 01938 ast_realtime_require_field("meetme", 01939 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno), 01940 "members", RQ_UINTEGER1, strlen(members), 01941 NULL); 01942 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL); 01943 } 01944 setusercount = 1; 01945 01946 /* This device changed state now - if this is the first user */ 01947 if (conf->users == 1) 01948 ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno); 01949 01950 ast_mutex_unlock(&conf->playlock); 01951 01952 /* return the unique ID of the conference */ 01953 pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid); 01954 01955 if (confflags & CONFFLAG_EXIT_CONTEXT) { 01956 ast_channel_lock(chan); 01957 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) { 01958 ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext)); 01959 } else if (!ast_strlen_zero(chan->macrocontext)) { 01960 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); 01961 } else { 01962 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); 01963 } 01964 ast_channel_unlock(chan); 01965 } 01966 01967 if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) { 01968 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED)) 01969 if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) 01970 ast_waitstream(chan, ""); 01971 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0) 01972 if (!ast_streamfile(chan, "conf-waitforleader", chan->language)) 01973 ast_waitstream(chan, ""); 01974 } 01975 01976 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) { 01977 int keepplaying = 1; 01978 01979 if (conf->users == 2) { 01980 if (!ast_streamfile(chan, "conf-onlyone", chan->language)) { 01981 res = ast_waitstream(chan, AST_DIGIT_ANY); 01982 ast_stopstream(chan); 01983 if (res > 0) 01984 keepplaying = 0; 01985 else if (res == -1) 01986 goto outrun; 01987 } 01988 } else { 01989 if (!ast_streamfile(chan, "conf-thereare", chan->language)) { 01990 res = ast_waitstream(chan, AST_DIGIT_ANY); 01991 ast_stopstream(chan); 01992 if (res > 0) 01993 keepplaying = 0; 01994 else if (res == -1) 01995 goto outrun; 01996 } 01997 if (keepplaying) { 01998 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); 01999 if (res > 0) 02000 keepplaying = 0; 02001 else if (res == -1) 02002 goto outrun; 02003 } 02004 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) { 02005 res = ast_waitstream(chan, AST_DIGIT_ANY); 02006 ast_stopstream(chan); 02007 if (res > 0) 02008 keepplaying = 0; 02009 else if (res == -1) 02010 goto outrun; 02011 } 02012 } 02013 } 02014 02015 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) { 02016 /* We're leaving this alone until the state gets changed to up */ 02017 ast_indicate(chan, -1); 02018 } 02019 02020 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 02021 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); 02022 goto outrun; 02023 } 02024 02025 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { 02026 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); 02027 goto outrun; 02028 } 02029 02030 retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0); 02031 user->dahdichannel = !retrydahdi; 02032 02033 dahdiretry: 02034 origfd = chan->fds[0]; 02035 if (retrydahdi) { 02036 /* open pseudo in non-blocking mode */ 02037 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK); 02038 if (fd < 0) { 02039 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); 02040 goto outrun; 02041 } 02042 using_pseudo = 1; 02043 /* Setup buffering information */ 02044 memset(&bi, 0, sizeof(bi)); 02045 bi.bufsize = CONF_SIZE / 2; 02046 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; 02047 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; 02048 bi.numbufs = audio_buffers; 02049 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) { 02050 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); 02051 close(fd); 02052 goto outrun; 02053 } 02054 x = 1; 02055 if (ioctl(fd, DAHDI_SETLINEAR, &x)) { 02056 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno)); 02057 close(fd); 02058 goto outrun; 02059 } 02060 nfds = 1; 02061 } else { 02062 /* XXX Make sure we're not running on a pseudo channel XXX */ 02063 fd = chan->fds[0]; 02064 nfds = 0; 02065 } 02066 memset(&dahdic, 0, sizeof(dahdic)); 02067 memset(&dahdic_empty, 0, sizeof(dahdic_empty)); 02068 /* Check to see if we're in a conference... */ 02069 dahdic.chan = 0; 02070 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) { 02071 ast_log(LOG_WARNING, "Error getting conference\n"); 02072 close(fd); 02073 goto outrun; 02074 } 02075 if (dahdic.confmode) { 02076 /* Whoa, already in a conference... Retry... */ 02077 if (!retrydahdi) { 02078 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n"); 02079 retrydahdi = 1; 02080 goto dahdiretry; 02081 } 02082 } 02083 memset(&dahdic, 0, sizeof(dahdic)); 02084 /* Add us to the conference */ 02085 dahdic.chan = 0; 02086 dahdic.confno = conf->dahdiconf; 02087 02088 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) { 02089 struct announce_listitem *item; 02090 if (!(item = ao2_alloc(sizeof(*item), NULL))) 02091 return -1; 02092 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc)); 02093 ast_copy_string(item->language, chan->language, sizeof(item->language)); 02094 item->confchan = conf->chan; 02095 item->confusers = conf->users; 02096 item->announcetype = CONF_HASJOIN; 02097 ast_mutex_lock(&conf->announcelistlock); 02098 ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */ 02099 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry); 02100 ast_cond_signal(&conf->announcelist_addition); 02101 ast_mutex_unlock(&conf->announcelistlock); 02102 02103 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) { 02104 ; 02105 } 02106 ao2_ref(item, -1); 02107 } 02108 02109 if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers) 02110 dahdic.confmode = DAHDI_CONF_CONF; 02111 else if (confflags & CONFFLAG_MONITOR) 02112 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER; 02113 else if (confflags & CONFFLAG_TALKER) 02114 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER; 02115 else 02116 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER; 02117 02118 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02119 ast_log(LOG_WARNING, "Error setting conference\n"); 02120 close(fd); 02121 goto outrun; 02122 } 02123 ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf); 02124 02125 if (!sent_event) { 02126 manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 02127 "Channel: %s\r\n" 02128 "Uniqueid: %s\r\n" 02129 "Meetme: %s\r\n" 02130 "Usernum: %d\r\n" 02131 "CallerIDnum: %s\r\n" 02132 "CallerIDname: %s\r\n", 02133 chan->name, chan->uniqueid, conf->confno, 02134 user->user_no, 02135 S_OR(user->chan->cid.cid_num, "<unknown>"), 02136 S_OR(user->chan->cid.cid_name, "<unknown>") 02137 ); 02138 sent_event = 1; 02139 } 02140 02141 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { 02142 firstpass = 1; 02143 if (!(confflags & CONFFLAG_QUIET)) 02144 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1))) 02145 conf_play(chan, conf, ENTER); 02146 } 02147 02148 conf_flush(fd, chan); 02149 02150 if (!(dsp = ast_dsp_new())) { 02151 ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); 02152 res = -1; 02153 } 02154 02155 if (confflags & CONFFLAG_AGI) { 02156 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) 02157 or use default filename of conf-background.agi */ 02158 02159 ast_channel_lock(chan); 02160 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) { 02161 agifile = ast_strdupa(tmpvar); 02162 } else { 02163 agifile = ast_strdupa(agifiledefault); 02164 } 02165 ast_channel_unlock(chan); 02166 02167 if (user->dahdichannel) { 02168 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */ 02169 x = 1; 02170 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 02171 } 02172 /* Find a pointer to the agi app and execute the script */ 02173 agi_app = pbx_findapp("agi"); 02174 if (agi_app) { 02175 ret = pbx_exec(chan, agi_app, agifile); 02176 } else { 02177 ast_log(LOG_WARNING, "Could not find application (agi)\n"); 02178 ret = -2; 02179 } 02180 if (user->dahdichannel) { 02181 /* Remove CONFMUTE mode on DAHDI channel */ 02182 x = 0; 02183 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 02184 } 02185 } else { 02186 if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) { 02187 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */ 02188 x = 1; 02189 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 02190 } 02191 for (;;) { 02192 int menu_was_active = 0; 02193 02194 outfd = -1; 02195 ms = -1; 02196 now = ast_tvnow(); 02197 02198 if (rt_schedule) { 02199 if (now.tv_sec % 60 == 0) { 02200 if (!checked) { 02201 if (now.tv_sec >= conf->endtime) { 02202 goto outrun; 02203 } 02204 02205 if (!announcement_played && conf->endalert) { 02206 if (now.tv_sec + conf->endalert >= conf->endtime) { 02207 if (!ast_streamfile(chan, "conf-will-end-in", chan->language)) 02208 ast_waitstream(chan, ""); 02209 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language); 02210 if (!ast_streamfile(chan, "minutes", chan->language)) 02211 ast_waitstream(chan, ""); 02212 announcement_played = 1; 02213 } 02214 } 02215 checked = 1; 02216 02217 } 02218 } else { 02219 checked = 0; 02220 } 02221 } 02222 02223 if (user->kicktime && (user->kicktime <= now.tv_sec)) 02224 break; 02225 02226 to = -1; 02227 if (user->timelimit) { 02228 int minutes = 0, seconds = 0, remain = 0; 02229 02230 to = ast_tvdiff_ms(nexteventts, now); 02231 if (to < 0) 02232 to = 0; 02233 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time); 02234 if (time_left_ms < to) 02235 to = time_left_ms; 02236 02237 if (time_left_ms <= 0) { 02238 if (user->end_sound) { 02239 res = ast_streamfile(chan, user->end_sound, chan->language); 02240 res = ast_waitstream(chan, ""); 02241 } 02242 break; 02243 } 02244 02245 if (!to) { 02246 if (time_left_ms >= 5000) { 02247 02248 remain = (time_left_ms + 500) / 1000; 02249 if (remain / 60 >= 1) { 02250 minutes = remain / 60; 02251 seconds = remain % 60; 02252 } else { 02253 seconds = remain; 02254 } 02255 02256 /* force the time left to round up if appropriate */ 02257 if (user->warning_sound && user->play_warning) { 02258 if (!strcmp(user->warning_sound, "timeleft")) { 02259 02260 res = ast_streamfile(chan, "vm-youhave", chan->language); 02261 res = ast_waitstream(chan, ""); 02262 if (minutes) { 02263 res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL); 02264 res = ast_streamfile(chan, "queue-minutes", chan->language); 02265 res = ast_waitstream(chan, ""); 02266 } 02267 if (seconds) { 02268 res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL); 02269 res = ast_streamfile(chan, "queue-seconds", chan->language); 02270 res = ast_waitstream(chan, ""); 02271 } 02272 } else { 02273 res = ast_streamfile(chan, user->warning_sound, chan->language); 02274 res = ast_waitstream(chan, ""); 02275 } 02276 } 02277 } 02278 if (user->warning_freq) 02279 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000)); 02280 else 02281 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000)); 02282 } 02283 } 02284 02285 now = ast_tvnow(); 02286 if (timeout && now.tv_sec >= timeout) 02287 break; 02288 02289 /* if we have just exited from the menu, and the user had a channel-driver 02290 volume adjustment, restore it 02291 */ 02292 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) 02293 set_talk_volume(user, user->listen.desired); 02294 02295 menu_was_active = menu_active; 02296 02297 currentmarked = conf->markedusers; 02298 if (!(confflags & CONFFLAG_QUIET) && 02299 (confflags & CONFFLAG_MARKEDUSER) && 02300 (confflags & CONFFLAG_WAITMARKED) && 02301 lastmarked == 0) { 02302 if (currentmarked == 1 && conf->users > 1) { 02303 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); 02304 if (conf->users - 1 == 1) { 02305 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) 02306 ast_waitstream(chan, ""); 02307 } else { 02308 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) 02309 ast_waitstream(chan, ""); 02310 } 02311 } 02312 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) 02313 if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) 02314 ast_waitstream(chan, ""); 02315 } 02316 02317 /* Update the struct with the actual confflags */ 02318 user->userflags = confflags; 02319 02320 if (confflags & CONFFLAG_WAITMARKED) { 02321 if (currentmarked == 0) { 02322 if (lastmarked != 0) { 02323 if (!(confflags & CONFFLAG_QUIET)) 02324 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) 02325 ast_waitstream(chan, ""); 02326 if (confflags & CONFFLAG_MARKEDEXIT) { 02327 if (confflags & CONFFLAG_KICK_CONTINUE) 02328 ret = 0; 02329 break; 02330 } else { 02331 dahdic.confmode = DAHDI_CONF_CONF; 02332 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02333 ast_log(LOG_WARNING, "Error setting conference\n"); 02334 close(fd); 02335 goto outrun; 02336 } 02337 } 02338 } 02339 if (!musiconhold && (confflags & CONFFLAG_MOH)) { 02340 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]); 02341 musiconhold = 1; 02342 } 02343 } else if (currentmarked >= 1 && lastmarked == 0) { 02344 /* Marked user entered, so cancel timeout */ 02345 timeout = 0; 02346 if (confflags & CONFFLAG_MONITOR) 02347 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER; 02348 else if (confflags & CONFFLAG_TALKER) 02349 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER; 02350 else 02351 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER; 02352 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02353 ast_log(LOG_WARNING, "Error setting conference\n"); 02354 close(fd); 02355 goto outrun; 02356 } 02357 if (musiconhold && (confflags & CONFFLAG_MOH)) { 02358 ast_moh_stop(chan); 02359 musiconhold = 0; 02360 } 02361 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) { 02362 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) 02363 ast_waitstream(chan, ""); 02364 conf_play(chan, conf, ENTER); 02365 } 02366 } 02367 } 02368 02369 /* trying to add moh for single person conf */ 02370 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) { 02371 if (conf->users == 1) { 02372 if (!musiconhold) { 02373 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]); 02374 musiconhold = 1; 02375 } 02376 } else { 02377 if (musiconhold) { 02378 ast_moh_stop(chan); 02379 musiconhold = 0; 02380 } 02381 } 02382 } 02383 02384 /* Leave if the last marked user left */ 02385 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) { 02386 if (confflags & CONFFLAG_KICK_CONTINUE) 02387 ret = 0; 02388 else 02389 ret = -1; 02390 break; 02391 } 02392 02393 /* Check if my modes have changed */ 02394 02395 /* If I should be muted but am still talker, mute me */ 02396 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) { 02397 dahdic.confmode ^= DAHDI_CONF_TALKER; 02398 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02399 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 02400 ret = -1; 02401 break; 02402 } 02403 02404 /* Indicate user is not talking anymore - change him to unmonitored state */ 02405 if ((confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) { 02406 set_user_talking(chan, conf, user, -1, confflags & CONFFLAG_MONITORTALKER); 02407 } 02408 02409 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 02410 "Channel: %s\r\n" 02411 "Uniqueid: %s\r\n" 02412 "Meetme: %s\r\n" 02413 "Usernum: %i\r\n" 02414 "Status: on\r\n", 02415 chan->name, chan->uniqueid, conf->confno, user->user_no); 02416 } 02417 02418 /* If I should be un-muted but am not talker, un-mute me */ 02419 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) { 02420 dahdic.confmode |= DAHDI_CONF_TALKER; 02421 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02422 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 02423 ret = -1; 02424 break; 02425 } 02426 02427 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 02428 "Channel: %s\r\n" 02429 "Uniqueid: %s\r\n" 02430 "Meetme: %s\r\n" 02431 "Usernum: %i\r\n" 02432 "Status: off\r\n", 02433 chan->name, chan->uniqueid, conf->confno, user->user_no); 02434 } 02435 02436 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 02437 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) { 02438 talkreq_manager = 1; 02439 02440 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 02441 "Channel: %s\r\n" 02442 "Uniqueid: %s\r\n" 02443 "Meetme: %s\r\n" 02444 "Usernum: %i\r\n" 02445 "Status: on\r\n", 02446 chan->name, chan->uniqueid, conf->confno, user->user_no); 02447 } 02448 02449 02450 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 02451 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) { 02452 talkreq_manager = 0; 02453 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 02454 "Channel: %s\r\n" 02455 "Uniqueid: %s\r\n" 02456 "Meetme: %s\r\n" 02457 "Usernum: %i\r\n" 02458 "Status: off\r\n", 02459 chan->name, chan->uniqueid, conf->confno, user->user_no); 02460 } 02461 02462 /* If I have been kicked, exit the conference */ 02463 if (user->adminflags & ADMINFLAG_KICKME) { 02464 /* You have been kicked. */ 02465 if (!(confflags & CONFFLAG_QUIET) && 02466 !ast_streamfile(chan, "conf-kicked", chan->language)) { 02467 ast_waitstream(chan, ""); 02468 } 02469 ret = 0; 02470 break; 02471 } 02472 02473 /* Perform an extra hangup check just in case */ 02474 if (ast_check_hangup(chan)) 02475 break; 02476 02477 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); 02478 02479 if (c) { 02480 char dtmfstr[2] = ""; 02481 02482 if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) { 02483 if (using_pseudo) { 02484 /* Kill old pseudo */ 02485 close(fd); 02486 using_pseudo = 0; 02487 } 02488 ast_debug(1, "Ooh, something swapped out under us, starting over\n"); 02489 retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0); 02490 user->dahdichannel = !retrydahdi; 02491 goto dahdiretry; 02492 } 02493 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) 02494 f = ast_read_noaudio(c); 02495 else 02496 f = ast_read(c); 02497 if (!f) 02498 break; 02499 if (f->frametype == AST_FRAME_DTMF) { 02500 dtmfstr[0] = f->subclass; 02501 dtmfstr[1] = '\0'; 02502 } 02503 02504 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) { 02505 if (user->talk.actual) 02506 ast_frame_adjust_volume(f, user->talk.actual); 02507 02508 if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) { 02509 if (user->talking == -1) 02510 user->talking = 0; 02511 02512 res = ast_dsp_silence(dsp, f, &totalsilence); 02513 if (totalsilence < MEETME_DELAYDETECTTALK) { 02514 set_user_talking(chan, conf, user, 1, confflags & CONFFLAG_MONITORTALKER); 02515 } 02516 if (totalsilence > MEETME_DELAYDETECTENDTALK) { 02517 set_user_talking(chan, conf, user, 0, confflags & CONFFLAG_MONITORTALKER); 02518 } 02519 } 02520 if (using_pseudo) { 02521 /* Absolutely do _not_ use careful_write here... 02522 it is important that we read data from the channel 02523 as fast as it arrives, and feed it into the conference. 02524 The buffering in the pseudo channel will take care of any 02525 timing differences, unless they are so drastic as to lose 02526 audio frames (in which case carefully writing would only 02527 have delayed the audio even further). 02528 */ 02529 /* As it turns out, we do want to use careful write. We just 02530 don't want to block, but we do want to at least *try* 02531 to write out all the samples. 02532 */ 02533 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER)) { 02534 careful_write(fd, f->data.ptr, f->datalen, 0); 02535 } 02536 } 02537 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { 02538 if (confflags & CONFFLAG_PASS_DTMF) 02539 conf_queue_dtmf(conf, user, f); 02540 if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) { 02541 ast_log(LOG_WARNING, "Error setting conference\n"); 02542 close(fd); 02543 ast_frfree(f); 02544 goto outrun; 02545 } 02546 02547 /* if we are entering the menu, and the user has a channel-driver 02548 volume adjustment, clear it 02549 */ 02550 if (!menu_active && user->talk.desired && !user->talk.actual) 02551 set_talk_volume(user, 0); 02552 02553 if (musiconhold) { 02554 ast_moh_stop(chan); 02555 } 02556 if ((confflags & CONFFLAG_ADMIN)) { 02557 /* Admin menu */ 02558 if (!menu_active) { 02559 menu_active = 1; 02560 /* Record this sound! */ 02561 if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) { 02562 dtmf = ast_waitstream(chan, AST_DIGIT_ANY); 02563 ast_stopstream(chan); 02564 } else 02565 dtmf = 0; 02566 } else 02567 dtmf = f->subclass; 02568 if (dtmf) { 02569 switch(dtmf) { 02570 case '1': /* Un/Mute */ 02571 menu_active = 0; 02572 02573 /* for admin, change both admin and use flags */ 02574 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) 02575 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED); 02576 else 02577 user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED); 02578 02579 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { 02580 if (!ast_streamfile(chan, "conf-muted", chan->language)) 02581 ast_waitstream(chan, ""); 02582 } else { 02583 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) 02584 ast_waitstream(chan, ""); 02585 } 02586 break; 02587 case '2': /* Un/Lock the Conference */ 02588 menu_active = 0; 02589 if (conf->locked) { 02590 conf->locked = 0; 02591 if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) 02592 ast_waitstream(chan, ""); 02593 } else { 02594 conf->locked = 1; 02595 if (!ast_streamfile(chan, "conf-lockednow", chan->language)) 02596 ast_waitstream(chan, ""); 02597 } 02598 break; 02599 case '3': /* Eject last user */ 02600 menu_active = 0; 02601 usr = AST_LIST_LAST(&conf->userlist); 02602 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) { 02603 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) 02604 ast_waitstream(chan, ""); 02605 } else 02606 usr->adminflags |= ADMINFLAG_KICKME; 02607 ast_stopstream(chan); 02608 break; 02609 case '4': 02610 tweak_listen_volume(user, VOL_DOWN); 02611 break; 02612 case '6': 02613 tweak_listen_volume(user, VOL_UP); 02614 break; 02615 case '7': 02616 tweak_talk_volume(user, VOL_DOWN); 02617 break; 02618 case '8': 02619 menu_active = 0; 02620 break; 02621 case '9': 02622 tweak_talk_volume(user, VOL_UP); 02623 break; 02624 default: 02625 menu_active = 0; 02626 /* Play an error message! */ 02627 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) 02628 ast_waitstream(chan, ""); 02629 break; 02630 } 02631 } 02632 } else { 02633 /* User menu */ 02634 if (!menu_active) { 02635 menu_active = 1; 02636 if (!ast_streamfile(chan, "conf-usermenu", chan->language)) { 02637 dtmf = ast_waitstream(chan, AST_DIGIT_ANY); 02638 ast_stopstream(chan); 02639 } else 02640 dtmf = 0; 02641 } else 02642 dtmf = f->subclass; 02643 if (dtmf) { 02644 switch(dtmf) { 02645 case '1': /* Un/Mute */ 02646 menu_active = 0; 02647 02648 /* user can only toggle the self-muted state */ 02649 user->adminflags ^= ADMINFLAG_SELFMUTED; 02650 02651 /* they can't override the admin mute state */ 02652 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { 02653 if (!ast_streamfile(chan, "conf-muted", chan->language)) 02654 ast_waitstream(chan, ""); 02655 } else { 02656 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) 02657 ast_waitstream(chan, ""); 02658 } 02659 break; 02660 case '2': 02661 menu_active = 0; 02662 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) 02663 user->adminflags |= ADMINFLAG_T_REQUEST; 02664 02665 if (user->adminflags & ADMINFLAG_T_REQUEST) 02666 if (!ast_streamfile(chan, "beep", chan->language)) 02667 ast_waitstream(chan, ""); 02668 break; 02669 case '4': 02670 tweak_listen_volume(user, VOL_DOWN); 02671 break; 02672 case '6': 02673 tweak_listen_volume(user, VOL_UP); 02674 break; 02675 case '7': 02676 tweak_talk_volume(user, VOL_DOWN); 02677 break; 02678 case '8': 02679 menu_active = 0; 02680 break; 02681 case '9': 02682 tweak_talk_volume(user, VOL_UP); 02683 break; 02684 default: 02685 menu_active = 0; 02686 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) 02687 ast_waitstream(chan, ""); 02688 break; 02689 } 02690 } 02691 } 02692 if (musiconhold) 02693 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]); 02694 02695 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02696 ast_log(LOG_WARNING, "Error setting conference\n"); 02697 close(fd); 02698 ast_frfree(f); 02699 goto outrun; 02700 } 02701 02702 conf_flush(fd, chan); 02703 /* Since this option could absorb dtmf meant for the previous (menu), we have to check this one last */ 02704 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) { 02705 if (confflags & CONFFLAG_PASS_DTMF) 02706 conf_queue_dtmf(conf, user, f); 02707 02708 if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) { 02709 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext); 02710 ret = 0; 02711 ast_frfree(f); 02712 break; 02713 } else { 02714 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext); 02715 } 02716 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) { 02717 pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr); 02718 02719 if (confflags & CONFFLAG_PASS_DTMF) 02720 conf_queue_dtmf(conf, user, f); 02721 ret = 0; 02722 ast_frfree(f); 02723 break; 02724 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) 02725 && confflags & CONFFLAG_PASS_DTMF) { 02726 conf_queue_dtmf(conf, user, f); 02727 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) { 02728 switch (f->subclass) { 02729 case AST_CONTROL_HOLD: 02730 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf); 02731 break; 02732 default: 02733 break; 02734 } 02735 } else if (f->frametype == AST_FRAME_NULL) { 02736 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */ 02737 } else { 02738 ast_debug(1, 02739 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n", 02740 chan->name, f->frametype, f->subclass); 02741 } 02742 ast_frfree(f); 02743 } else if (outfd > -1) { 02744 res = read(outfd, buf, CONF_SIZE); 02745 if (res > 0) { 02746 memset(&fr, 0, sizeof(fr)); 02747 fr.frametype = AST_FRAME_VOICE; 02748 fr.subclass = AST_FORMAT_SLINEAR; 02749 fr.datalen = res; 02750 fr.samples = res / 2; 02751 fr.data.ptr = buf; 02752 fr.offset = AST_FRIENDLY_OFFSET; 02753 if (!user->listen.actual && 02754 ((confflags & CONFFLAG_MONITOR) || 02755 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) || 02756 (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER)) 02757 )) { 02758 int idx; 02759 for (idx = 0; idx < AST_FRAME_BITS; idx++) 02760 if (chan->rawwriteformat & (1 << idx)) 02761 break; 02762 if (idx >= AST_FRAME_BITS) 02763 goto bailoutandtrynormal; 02764 ast_mutex_lock(&conf->listenlock); 02765 if (!conf->transframe[idx]) { 02766 if (conf->origframe) { 02767 if (!conf->transpath[idx]) 02768 conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR); 02769 if (conf->transpath[idx]) { 02770 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0); 02771 if (!conf->transframe[idx]) 02772 conf->transframe[idx] = &ast_null_frame; 02773 } 02774 } 02775 } 02776 if (conf->transframe[idx]) { 02777 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) && 02778 can_write(chan, confflags)) { 02779 struct ast_frame *cur; 02780 if (musiconhold && !ast_dsp_silence(dsp, conf->transframe[idx], &confsilence) && confsilence < MEETME_DELAYDETECTTALK) { 02781 ast_moh_stop(chan); 02782 mohtempstopped = 1; 02783 } 02784 02785 /* the translator may have returned a list of frames, so 02786 write each one onto the channel 02787 */ 02788 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 02789 if (ast_write(chan, cur)) { 02790 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name); 02791 break; 02792 } 02793 } 02794 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) { 02795 mohtempstopped = 0; 02796 ast_moh_start(chan, NULL, NULL); 02797 } 02798 } 02799 } else { 02800 ast_mutex_unlock(&conf->listenlock); 02801 goto bailoutandtrynormal; 02802 } 02803 ast_mutex_unlock(&conf->listenlock); 02804 } else { 02805 bailoutandtrynormal: 02806 if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) { 02807 ast_moh_stop(chan); 02808 mohtempstopped = 1; 02809 } 02810 if (user->listen.actual) 02811 ast_frame_adjust_volume(&fr, user->listen.actual); 02812 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) { 02813 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name); 02814 } 02815 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) { 02816 mohtempstopped = 0; 02817 ast_moh_start(chan, NULL, NULL); 02818 } 02819 } 02820 } else 02821 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); 02822 } 02823 lastmarked = currentmarked; 02824 } 02825 } 02826 02827 if (musiconhold) 02828 ast_moh_stop(chan); 02829 02830 if (using_pseudo) 02831 close(fd); 02832 else { 02833 /* Take out of conference */ 02834 dahdic.chan = 0; 02835 dahdic.confno = 0; 02836 dahdic.confmode = 0; 02837 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { 02838 ast_log(LOG_WARNING, "Error setting conference\n"); 02839 } 02840 } 02841 02842 reset_volumes(user); 02843 02844 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) 02845 conf_play(chan, conf, LEAVE); 02846 02847 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) { 02848 struct announce_listitem *item; 02849 if (!(item = ao2_alloc(sizeof(*item), NULL))) 02850 return -1; 02851 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc)); 02852 ast_copy_string(item->language, chan->language, sizeof(item->language)); 02853 item->confchan = conf->chan; 02854 item->confusers = conf->users; 02855 item->announcetype = CONF_HASLEFT; 02856 ast_mutex_lock(&conf->announcelistlock); 02857 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry); 02858 ast_cond_signal(&conf->announcelist_addition); 02859 ast_mutex_unlock(&conf->announcelistlock); 02860 } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) { 02861 /* Last person is leaving, so no reason to try and announce, but should delete the name recording */ 02862 ast_filedelete(user->namerecloc, NULL); 02863 } 02864 02865 outrun: 02866 AST_LIST_LOCK(&confs); 02867 02868 if (dsp) 02869 ast_dsp_free(dsp); 02870 02871 if (user->user_no) { /* Only cleanup users who really joined! */ 02872 now = ast_tvnow(); 02873 hr = (now.tv_sec - user->jointime) / 3600; 02874 min = ((now.tv_sec - user->jointime) % 3600) / 60; 02875 sec = (now.tv_sec - user->jointime) % 60; 02876 02877 if (sent_event) { 02878 manager_event(EVENT_FLAG_CALL, "MeetmeLeave", 02879 "Channel: %s\r\n" 02880 "Uniqueid: %s\r\n" 02881 "Meetme: %s\r\n" 02882 "Usernum: %d\r\n" 02883 "CallerIDNum: %s\r\n" 02884 "CallerIDName: %s\r\n" 02885 "Duration: %ld\r\n", 02886 chan->name, chan->uniqueid, conf->confno, 02887 user->user_no, 02888 S_OR(user->chan->cid.cid_num, "<unknown>"), 02889 S_OR(user->chan->cid.cid_name, "<unknown>"), 02890 (long)(now.tv_sec - user->jointime)); 02891 } 02892 02893 if (setusercount) { 02894 conf->users--; 02895 if (rt_log_members) { 02896 /* Update table */ 02897 snprintf(members, sizeof(members), "%d", conf->users); 02898 ast_realtime_require_field("meetme", 02899 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno), 02900 "members", RQ_UINTEGER1, strlen(members), 02901 NULL); 02902 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL); 02903 } 02904 if (confflags & CONFFLAG_MARKEDUSER) 02905 conf->markedusers--; 02906 } 02907 /* Remove ourselves from the list */ 02908 AST_LIST_REMOVE(&conf->userlist, user, list); 02909 02910 /* Change any states */ 02911 if (!conf->users) 02912 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno); 02913 02914 /* Return the number of seconds the user was in the conf */ 02915 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime)); 02916 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); 02917 } 02918 ast_free(user); 02919 AST_LIST_UNLOCK(&confs); 02920 02921 return ret; 02922 }
| static void conf_start_moh | ( | struct ast_channel * | chan, | |
| const char * | musicclass | |||
| ) | [static] |
Definition at line 1543 of file app_meetme.c.
References ast_channel_lock, ast_channel_unlock, ast_moh_start(), ast_strdupa, and ast_string_field_set.
Referenced by conf_run().
01544 { 01545 char *original_moh; 01546 01547 ast_channel_lock(chan); 01548 original_moh = ast_strdupa(chan->musicclass); 01549 ast_string_field_set(chan, musicclass, musicclass); 01550 ast_channel_unlock(chan); 01551 01552 ast_moh_start(chan, original_moh, NULL); 01553 01554 ast_channel_lock(chan); 01555 ast_string_field_set(chan, musicclass, original_moh); 01556 ast_channel_unlock(chan); 01557 }
| static int count_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
The MeetmeCount application.
Definition at line 3162 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(), LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.
Referenced by load_module().
03163 { 03164 int res = 0; 03165 struct ast_conference *conf; 03166 int count; 03167 char *localdata; 03168 char val[80] = "0"; 03169 AST_DECLARE_APP_ARGS(args, 03170 AST_APP_ARG(confno); 03171 AST_APP_ARG(varname); 03172 ); 03173 03174 if (ast_strlen_zero(data)) { 03175 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n"); 03176 return -1; 03177 } 03178 03179 if (!(localdata = ast_strdupa(data))) 03180 return -1; 03181 03182 AST_STANDARD_APP_ARGS(args, localdata); 03183 03184 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL); 03185 03186 if (conf) { 03187 count = conf->users; 03188 dispose_conf(conf); 03189 conf = NULL; 03190 } else 03191 count = 0; 03192 03193 if (!ast_strlen_zero(args.varname)) { 03194 /* have var so load it and exit */ 03195 snprintf(val, sizeof(val), "%d", count); 03196 pbx_builtin_setvar_helper(chan, args.varname, val); 03197 } else { 03198 if (chan->_state != AST_STATE_UP) 03199 ast_answer(chan); 03200 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */ 03201 } 03202 03203 return res; 03204 }
| static struct sla_trunk_ref* create_trunk_ref | ( | struct sla_trunk * | trunk | ) | [static, read] |
Definition at line 5217 of file app_meetme.c.
References ast_calloc, and sla_trunk_ref::trunk.
Referenced by sla_add_trunk_to_station().
05218 { 05219 struct sla_trunk_ref *trunk_ref; 05220 05221 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref)))) 05222 return NULL; 05223 05224 trunk_ref->trunk = trunk; 05225 05226 return trunk_ref; 05227 }
| static void destroy_station | ( | struct sla_station * | station | ) | [static] |
Definition at line 5428 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().
05429 { 05430 struct sla_trunk_ref *trunk_ref; 05431 05432 if (!ast_strlen_zero(station->autocontext)) { 05433 AST_RWLIST_RDLOCK(&sla_trunks); 05434 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 05435 char exten[AST_MAX_EXTENSION]; 05436 char hint[AST_MAX_APP]; 05437 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name); 05438 snprintf(hint, sizeof(hint), "SLA:%s", exten); 05439 ast_context_remove_extension(station->autocontext, exten, 05440 1, sla_registrar); 05441 ast_context_remove_extension(station->autocontext, hint, 05442 PRIORITY_HINT, sla_registrar); 05443 } 05444 AST_RWLIST_UNLOCK(&sla_trunks); 05445 } 05446 05447 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) 05448 ast_free(trunk_ref); 05449 05450 ast_string_field_free_memory(station); 05451 ast_free(station); 05452 }
| static void destroy_trunk | ( | struct sla_trunk * | trunk | ) | [static] |
Definition at line 5414 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().
05415 { 05416 struct sla_station_ref *station_ref; 05417 05418 if (!ast_strlen_zero(trunk->autocontext)) 05419 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar); 05420 05421 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) 05422 ast_free(station_ref); 05423 05424 ast_string_field_free_memory(trunk); 05425 ast_free(trunk); 05426 }
| static void* dial_trunk | ( | void * | data | ) | [static] |
Definition at line 4929 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().
04930 { 04931 struct dial_trunk_args *args = data; 04932 struct ast_dial *dial; 04933 char *tech, *tech_data; 04934 enum ast_dial_result dial_res; 04935 char conf_name[MAX_CONFNUM]; 04936 struct ast_conference *conf; 04937 struct ast_flags conf_flags = { 0 }; 04938 struct sla_trunk_ref *trunk_ref = args->trunk_ref; 04939 const char *cid_name = NULL, *cid_num = NULL; 04940 04941 if (!(dial = ast_dial_create())) { 04942 ast_mutex_lock(args->cond_lock); 04943 ast_cond_signal(args->cond); 04944 ast_mutex_unlock(args->cond_lock); 04945 return NULL; 04946 } 04947 04948 tech_data = ast_strdupa(trunk_ref->trunk->device); 04949 tech = strsep(&tech_data, "/"); 04950 if (ast_dial_append(dial, tech, tech_data) == -1) { 04951 ast_mutex_lock(args->cond_lock); 04952 ast_cond_signal(args->cond); 04953 ast_mutex_unlock(args->cond_lock); 04954 ast_dial_destroy(dial); 04955 return NULL; 04956 } 04957 04958 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) { 04959 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name); 04960 ast_free(trunk_ref->chan->cid.cid_name); 04961 trunk_ref->chan->cid.cid_name = NULL; 04962 } 04963 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) { 04964 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num); 04965 ast_free(trunk_ref->chan->cid.cid_num); 04966 trunk_ref->chan->cid.cid_num = NULL; 04967 } 04968 04969 dial_res = ast_dial_run(dial, trunk_ref->chan, 1); 04970 04971 if (cid_name) 04972 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name); 04973 if (cid_num) 04974 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num); 04975 04976 if (dial_res != AST_DIAL_RESULT_TRYING) { 04977 ast_mutex_lock(args->cond_lock); 04978 ast_cond_signal(args->cond); 04979 ast_mutex_unlock(args->cond_lock); 04980 ast_dial_destroy(dial); 04981 return NULL; 04982 } 04983 04984 for (;;) { 04985 unsigned int done = 0; 04986 switch ((dial_res = ast_dial_state(dial))) { 04987 case AST_DIAL_RESULT_ANSWERED: 04988 trunk_ref->trunk->chan = ast_dial_answered(dial); 04989 case AST_DIAL_RESULT_HANGUP: 04990 case AST_DIAL_RESULT_INVALID: 04991 case AST_DIAL_RESULT_FAILED: 04992 case AST_DIAL_RESULT_TIMEOUT: 04993 case AST_DIAL_RESULT_UNANSWERED: 04994 done = 1; 04995 case AST_DIAL_RESULT_TRYING: 04996 case AST_DIAL_RESULT_RINGING: 04997 case AST_DIAL_RESULT_PROGRESS: 04998 case AST_DIAL_RESULT_PROCEEDING: 04999 break; 05000 } 05001 if (done) 05002 break; 05003 } 05004 05005 if (!trunk_ref->trunk->chan) { 05006 ast_mutex_lock(args->cond_lock); 05007 ast_cond_signal(args->cond); 05008 ast_mutex_unlock(args->cond_lock); 05009 ast_dial_join(dial); 05010 ast_dial_destroy(dial); 05011 return NULL; 05012 } 05013 05014 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name); 05015 ast_set_flag(&conf_flags, 05016 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 05017 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK); 05018 conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan); 05019 05020 ast_mutex_lock(args->cond_lock); 05021 ast_cond_signal(args->cond); 05022 ast_mutex_unlock(args->cond_lock); 05023 05024 if (conf) { 05025 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL); 05026 dispose_conf(conf); 05027 conf = NULL; 05028 } 05029 05030 /* If the trunk is going away, it is definitely now IDLE. */ 05031 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 05032 05033 trunk_ref->trunk->chan = NULL; 05034 trunk_ref->trunk->on_hold = 0; 05035 05036 ast_dial_join(dial); 05037 ast_dial_destroy(dial); 05038 05039 return NULL; 05040 }
| static int dispose_conf | ( | struct ast_conference * | conf | ) | [static] |
Definition at line 1525 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().
01526 { 01527 int res = 0; 01528 int confno_int = 0; 01529 01530 AST_LIST_LOCK(&confs); 01531 if (ast_atomic_dec_and_test(&conf->refcount)) { 01532 /* Take the conference room number out of an inuse state */ 01533 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) 01534 conf_map[confno_int] = 0; 01535 conf_free(conf); 01536 res = 1; 01537 } 01538 AST_LIST_UNLOCK(&confs); 01539 01540 return res; 01541 }
| 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 3062 of file app_meetme.c.
References AST_APP_ARG, ast_app_getdata(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_test_flag, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, ast_conference::confno, ast_conference::list, LOG_WARNING, MAX_SETTINGS, ast_variable::name, ast_variable::next, parse(), ast_conference::refcount, S_OR, ast_variable::value, and var.
Referenced by conf_exec(), and count_exec().
03064 { 03065 struct ast_config *cfg; 03066 struct ast_variable *var; 03067 struct ast_flags config_flags = { 0 }; 03068 struct ast_conference *cnf; 03069 03070 AST_DECLARE_APP_ARGS(args, 03071 AST_APP_ARG(confno); 03072 AST_APP_ARG(pin); 03073 AST_APP_ARG(pinadmin); 03074 ); 03075 03076 /* Check first in the conference list */ 03077 ast_debug(1, "The requested confno is '%s'?\n", confno); 03078 AST_LIST_LOCK(&confs); 03079 AST_LIST_TRAVERSE(&confs, cnf, list) { 03080 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno); 03081 if (!strcmp(confno, cnf->confno)) 03082 break; 03083 } 03084 if (cnf) { 03085 cnf->refcount += refcount; 03086 } 03087 AST_LIST_UNLOCK(&confs); 03088 03089 if (!cnf) { 03090 if (dynamic) { 03091 /* No need to parse meetme.conf */ 03092 ast_debug(1, "Building dynamic conference '%s'\n", confno); 03093 if (dynamic_pin) { 03094 if (dynamic_pin[0] == 'q') { 03095 /* Query the user to enter a PIN */ 03096 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0) 03097 return NULL; 03098 } 03099 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan); 03100 } else { 03101 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan); 03102 } 03103 } else { 03104 /* Check the config */ 03105 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags); 03106 if (!cfg) { 03107 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME); 03108 return NULL; 03109 } 03110 03111 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) { 03112 char parse[MAX_SETTINGS]; 03113 03114 if (strcasecmp(var->name, "conf")) 03115 continue; 03116 03117 ast_copy_string(parse, var->value, sizeof(parse)); 03118 03119 AST_STANDARD_APP_ARGS(args, parse); 03120 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno); 03121 if (!strcasecmp(args.confno, confno)) { 03122 /* Bingo it's a valid conference */ 03123 cnf = build_conf(args.confno, 03124 S_OR(args.pin, ""), 03125 S_OR(args.pinadmin, ""), 03126 make, dynamic, refcount, chan); 03127 break; 03128 } 03129 } 03130 if (!var) { 03131 ast_debug(1, "%s isn't a valid conference\n", confno); 03132 } 03133 ast_config_destroy(cfg); 03134 } 03135 } else if (dynamic_pin) { 03136 /* Correct for the user selecting 'D' instead of 'd' to have 03137 someone join into a conference that has already been created 03138 with a pin. */ 03139 if (dynamic_pin[0] == 'q') 03140 dynamic_pin[0] = '\0'; 03141 } 03142 03143 if (cnf) { 03144 if (confflags && !cnf->chan && 03145 !ast_test_flag(confflags, CONFFLAG_QUIET) && 03146 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) { 03147 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n"); 03148 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW); 03149 } 03150 03151 if (confflags && !cnf->chan && 03152 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) { 03153 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n"); 03154 ast_clear_flag(confflags, CONFFLAG_RECORDCONF); 03155 } 03156 } 03157 03158 return cnf; 03159 }
| 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, | |||
| char * | optargs[], | |||
| int * | too_early | |||
| ) | [static, read] |
Definition at line 2924 of file app_meetme.c.
References ast_clear_flag, ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), ast_mktime(), ast_strdupa, ast_streamfile(), ast_strftime(), ast_test_flag, ast_tvnow(), ast_variables_destroy(), ast_waitstream(), 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_conference::list, LOG_WARNING, ast_conference::maxusers, ast_variable::name, ast_variable::next, ast_conference::refcount, ast_variable::value, and var.
Referenced by conf_exec().
02927 { 02928 struct ast_variable *var; 02929 struct ast_conference *cnf; 02930 02931 *too_early = 0; 02932 02933 /* Check first in the conference list */ 02934 AST_LIST_LOCK(&confs); 02935 AST_LIST_TRAVERSE(&confs, cnf, list) { 02936 if (!strcmp(confno, cnf->confno)) 02937 break; 02938 } 02939 if (cnf) { 02940 cnf->refcount += refcount; 02941 } 02942 AST_LIST_UNLOCK(&confs); 02943 02944 if (!cnf) { 02945 char *pin = NULL, *pinadmin = NULL; /* For temp use */ 02946 int maxusers = 0; 02947 struct timeval now; 02948 char currenttime[19] = ""; 02949 char eatime[19] = ""; 02950 char useropts[32] = ""; 02951 char adminopts[32] = ""; 02952 struct ast_tm tm, etm; 02953 struct timeval endtime = { .tv_sec = 0 }; 02954 02955 if (rt_schedule) { 02956 now = ast_tvnow(); 02957 02958 ast_localtime(&now, &tm, NULL); 02959 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); 02960 02961 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime); 02962 02963 var = ast_load_realtime("meetme", "confno", 02964 confno, "starttime <= ", currenttime, "endtime >= ", 02965 currenttime, NULL); 02966 02967 if (!var && fuzzystart) { 02968 now = ast_tvnow(); 02969 now.tv_sec += fuzzystart; 02970 02971 ast_localtime(&now, &tm, NULL); 02972 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); 02973 var = ast_load_realtime("meetme", "confno", 02974 confno, "starttime <= ", currenttime, "endtime >= ", 02975 currenttime, NULL); 02976 } 02977 02978 if (!var && earlyalert) { 02979 now = ast_tvnow(); 02980 now.tv_sec += earlyalert; 02981 ast_localtime(&now, &etm, NULL); 02982 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm); 02983 var = ast_load_realtime("meetme", "confno", 02984 confno, "starttime <= ", eatime, "endtime >= ", 02985 currenttime, NULL); 02986 if (var) 02987 *too_early = 1; 02988 } 02989 02990 } else 02991 var = ast_load_realtime("meetme", "confno", confno, NULL); 02992 02993 if (!var) 02994 return NULL; 02995 02996 if (rt_schedule && *too_early) { 02997 /* Announce that the caller is early and exit */ 02998 if (!ast_streamfile(chan, "conf-has-not-started", chan->language)) 02999 ast_waitstream(chan, ""); 03000 ast_variables_destroy(var); 03001 return NULL; 03002 } 03003 03004 while (var) { 03005 if (!strcasecmp(var->name, "pin")) { 03006 pin = ast_strdupa(var->value); 03007 } else if (!strcasecmp(var->name, "adminpin")) { 03008 pinadmin = ast_strdupa(var->value); 03009 } else if (!strcasecmp(var->name, "opts")) { 03010 ast_copy_string(useropts, var->value, sizeof(useropts)); 03011 } else if (!strcasecmp(var->name, "maxusers")) { 03012 maxusers = atoi(var->value); 03013 } else if (!strcasecmp(var->name, "adminopts")) { 03014 ast_copy_string(adminopts, var->value, sizeof(adminopts)); 03015 } else if (!strcasecmp(var->name, "endtime")) { 03016 union { 03017 struct ast_tm atm; 03018 struct tm tm; 03019 } t = { { 0, }, }; 03020 strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm); 03021 /* strptime does not determine if a time is 03022 * in DST or not. Set tm_isdst to -1 to 03023 * allow ast_mktime to adjust for DST 03024 * if needed */ 03025 t.tm.tm_isdst = -1; 03026 endtime = ast_mktime(&t.atm, NULL); 03027 } 03028 03029 var = var->next; 03030 } 03031 03032 ast_variables_destroy(var); 03033 03034 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan); 03035 03036 if (cnf) { 03037 cnf->maxusers = maxusers; 03038 cnf->endalert = endalert; 03039 cnf->endtime = endtime.tv_sec; 03040 } 03041 } 03042 03043 if (cnf) { 03044 if (confflags && !cnf->chan && 03045 !ast_test_flag(confflags, CONFFLAG_QUIET) && 03046 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) { 03047 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n"); 03048 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW); 03049 } 03050 03051 if (confflags && !cnf->chan && 03052 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) { 03053 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n"); 03054 ast_clear_flag(confflags, CONFFLAG_RECORDCONF); 03055 } 03056 } 03057 03058 return cnf; 03059 }
| static struct ast_conf_user* find_user | ( | struct ast_conference * | conf, | |
| char * | callerident | |||
| ) | [static, read] |
Definition at line 3453 of file app_meetme.c.
References AST_LIST_TRAVERSE, ast_conf_user::list, ast_conf_user::user_no, and ast_conference::userlist.
Referenced by admin_exec().
03454 { 03455 struct ast_conf_user *user = NULL; 03456 int cid; 03457 03458 sscanf(callerident, "%30i", &cid); 03459 if (conf && callerident) { 03460 AST_LIST_TRAVERSE(&conf->userlist, user, list) { 03461 if (cid == user->user_no) 03462 return user; 03463 } 03464 } 03465 return NULL; 03466 }
| static const char* get_announce_filename | ( | enum announcetypes | type | ) | [static] |
Definition at line 1559 of file app_meetme.c.
References CONF_HASJOIN, and CONF_HASLEFT.
Referenced by announce_thread().
01560 { 01561 switch (type) { 01562 case CONF_HASLEFT: 01563 return "conf-hasleft"; 01564 break; 01565 case CONF_HASJOIN: 01566 return "conf-hasjoin"; 01567 break; 01568 default: 01569 return ""; 01570 } 01571 }
| static char* istalking | ( | int | x | ) | [static] |
Definition at line 655 of file app_meetme.c.
Referenced by meetme_cmd().
| static int load_config | ( | int | reload | ) | [static] |
Definition at line 5872 of file app_meetme.c.
References ast_log(), load_config_meetme(), LOG_NOTICE, SLA_EVENT_RELOAD, sla_load_config(), and sla_queue_event().
Referenced by load_module(), and reload().
05873 { 05874 load_config_meetme(); 05875 05876 if (reload) { 05877 sla_queue_event(SLA_EVENT_RELOAD); 05878 ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested " 05879 "and will be completed when the system is idle.\n"); 05880 return 0; 05881 } 05882 05883 return sla_load_config(0); 05884 }
| static void load_config_meetme | ( | void | ) | [static] |
Definition at line 3912 of file app_meetme.c.
References ast_config_destroy(), ast_config_load, ast_log(), ast_true(), ast_variable_retrieve(), CONFIG_FILE_NAME, DEFAULT_AUDIO_BUFFERS, LOG_NOTICE, and LOG_WARNING.
Referenced by load_config().
03913 { 03914 struct ast_config *cfg; 03915 struct ast_flags config_flags = { 0 }; 03916 const char *val; 03917 03918 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) 03919 return; 03920 03921 audio_buffers = DEFAULT_AUDIO_BUFFERS; 03922 03923 /* Scheduling support is off by default */ 03924 rt_schedule = 0; 03925 fuzzystart = 0; 03926 earlyalert = 0; 03927 endalert = 0; 03928 03929 /* Logging of participants defaults to ON for compatibility reasons */ 03930 rt_log_members = 1; 03931 03932 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) { 03933 if ((sscanf(val, "%30d", &audio_buffers) != 1)) { 03934 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val); 03935 audio_buffers = DEFAULT_AUDIO_BUFFERS; 03936 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) { 03937 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n", 03938 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS); 03939 audio_buffers = DEFAULT_AUDIO_BUFFERS; 03940 } 03941 if (audio_buffers != DEFAULT_AUDIO_BUFFERS) 03942 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers); 03943 } 03944 03945 if ((val = ast_variable_retrieve(cfg, "general", "schedule"))) 03946 rt_schedule = ast_true(val); 03947 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount"))) 03948 rt_log_members = ast_true(val); 03949 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) { 03950 if ((sscanf(val, "%30d", &fuzzystart) != 1)) { 03951 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val); 03952 fuzzystart = 0; 03953 } 03954 } 03955 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) { 03956 if ((sscanf(val, "%30d", &earlyalert) != 1)) { 03957 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val); 03958 earlyalert = 0; 03959 } 03960 } 03961 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) { 03962 if ((sscanf(val, "%30d", &endalert) != 1)) { 03963 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val); 03964 endalert = 0; 03965 } 03966 } 03967 03968 ast_config_destroy(cfg); 03969 }
| static int load_module | ( | void | ) | [static] |
Definition at line 5912 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, ast_manager_register2(), ast_realtime_require_field(), ast_register_application, 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().
05913 { 05914 int res = 0; 05915 05916 res |= load_config(0); 05917 05918 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme)); 05919 res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 05920 action_meetmemute, "Mute a Meetme user"); 05921 res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 05922 action_meetmeunmute, "Unmute a Meetme user"); 05923 res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING, 05924 action_meetmelist, "List participants in a conference", mandescr_meetmelist); 05925 res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4); 05926 res |= ast_register_application(app3, admin_exec, synopsis3, descrip3); 05927 res |= ast_register_application(app2, count_exec, synopsis2, descrip2); 05928 res |= ast_register_application(app, conf_exec, synopsis, descrip); 05929 res |= ast_register_application(slastation_app, sla_station_exec, 05930 slastation_synopsis, slastation_desc); 05931 res |= ast_register_application(slatrunk_app, sla_trunk_exec, 05932 slatrunk_synopsis, slatrunk_desc); 05933 05934 res |= ast_devstate_prov_add("Meetme", meetmestate); 05935 res |= ast_devstate_prov_add("SLA", sla_state); 05936 05937 res |= ast_custom_function_register(&meetme_info_acf); 05938 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL); 05939 05940 return res; 05941 }
| static char* meetme_cmd | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 981 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_append(), 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_cli_args::pos, S_OR, sec, ast_conference::start, ast_str::str, 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.
00982 { 00983 /* Process the command */ 00984 struct ast_conference *cnf; 00985 struct ast_conf_user *user; 00986 int hr, min, sec; 00987 int i = 0, total = 0; 00988 time_t now; 00989 struct ast_str *cmdline = NULL; 00990 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n" 00991 #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n" 00992 00993 switch (cmd) { 00994 case CLI_INIT: 00995 e->command = "meetme"; 00996 e->usage = 00997 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n" 00998 " Executes a command for the conference or on a conferee\n"; 00999 return NULL; 01000 case CLI_GENERATE: 01001 return complete_meetmecmd(a->line, a->word, a->pos, a->n); 01002 } 01003 01004 if (a->argc > 8) 01005 ast_cli(a->fd, "Invalid Arguments.\n"); 01006 /* Check for length so no buffer will overflow... */ 01007 for (i = 0; i < a->argc; i++) { 01008 if (strlen(a->argv[i]) > 100) 01009 ast_cli(a->fd, "Invalid Arguments.\n"); 01010 } 01011 01012 /* Max confno length */ 01013 if (!(cmdline = ast_str_create(MAX_CONFNUM))) { 01014 return CLI_FAILURE; 01015 } 01016 01017 if (a->argc == 1 || (a->argc == 2 && !strcasecmp(a->argv[1], "concise"))) { 01018 /* 'MeetMe': List all the conferences */ 01019 int concise = (a->argc == 2 && !strcasecmp(a->argv[1], "concise")); 01020 now = time(NULL); 01021 AST_LIST_LOCK(&confs); 01022 if (AST_LIST_EMPTY(&confs)) { 01023 if (!concise) { 01024 ast_cli(a->fd, "No active MeetMe conferences.\n"); 01025 } 01026 AST_LIST_UNLOCK(&confs); 01027 ast_free(cmdline); 01028 return CLI_SUCCESS; 01029 } 01030 if (!concise) { 01031 ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked"); 01032 } 01033 AST_LIST_TRAVERSE(&confs, cnf, list) { 01034 if (cnf->markedusers == 0) { 01035 ast_str_set(&cmdline, 0, "N/A "); 01036 } else { 01037 ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers); 01038 } 01039 hr = (now - cnf->start) / 3600; 01040 min = ((now - cnf->start) % 3600) / 60; 01041 sec = (now - cnf->start) % 60; 01042 if (!concise) { 01043 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No"); 01044 } else { 01045 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n", 01046 cnf->confno, 01047 cnf->users, 01048 cnf->markedusers, 01049 hr, min, sec, 01050 cnf->isdynamic, 01051 cnf->locked); 01052 } 01053 01054 total += cnf->users; 01055 } 01056 AST_LIST_UNLOCK(&confs); 01057 if (!concise) { 01058 ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total); 01059 } 01060 ast_free(cmdline); 01061 return CLI_SUCCESS; 01062 } 01063 if (a->argc < 3) { 01064 ast_free(cmdline); 01065 return CLI_SHOWUSAGE; 01066 } 01067 01068 ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */ 01069 if (strstr(a->argv[1], "lock")) { 01070 if (strcmp(a->argv[1], "lock") == 0) { 01071 /* Lock */ 01072 ast_str_append(&cmdline, 0, ",L"); 01073 } else { 01074 /* Unlock */ 01075 ast_str_append(&cmdline, 0, ",l"); 01076 } 01077 } else if (strstr(a->argv[1], "mute")) { 01078 if (a->argc < 4) { 01079 ast_free(cmdline); 01080 return CLI_SHOWUSAGE; 01081 } 01082 if (strcmp(a->argv[1], "mute") == 0) { 01083 /* Mute */ 01084 if (strcmp(a->argv[3], "all") == 0) { 01085 ast_str_append(&cmdline, 0, ",N"); 01086 } else { 01087 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]); 01088 } 01089 } else { 01090 /* Unmute */ 01091 if (strcmp(a->argv[3], "all") == 0) { 01092 ast_str_append(&cmdline, 0, ",n"); 01093 } else { 01094 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]); 01095 } 01096 } 01097 } else if (strcmp(a->argv[1], "kick") == 0) { 01098 if (a->argc < 4) { 01099 ast_free(cmdline); 01100 return CLI_SHOWUSAGE; 01101 } 01102 if (strcmp(a->argv[3], "all") == 0) { 01103 /* Kick all */ 01104 ast_str_append(&cmdline, 0, ",K"); 01105 } else { 01106 /* Kick a single user */ 01107 ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]); 01108 } 01109 } else if (strcmp(a->argv[1], "list") == 0) { 01110 int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise"))); 01111 /* List all the users in a conference */ 01112 if (AST_LIST_EMPTY(&confs)) { 01113 if (!concise) { 01114 ast_cli(a->fd, "No active conferences.\n"); 01115 } 01116 ast_free(cmdline); 01117 return CLI_SUCCESS; 01118 } 01119 /* Find the right conference */ 01120 AST_LIST_LOCK(&confs); 01121 AST_LIST_TRAVERSE(&confs, cnf, list) { 01122 if (strcmp(cnf->confno, a->argv[2]) == 0) { 01123 break; 01124 } 01125 } 01126 if (!cnf) { 01127 if (!concise) 01128 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]); 01129 AST_LIST_UNLOCK(&confs); 01130 ast_free(cmdline); 01131 return CLI_SUCCESS; 01132 } 01133 /* Show all the users */ 01134 time(&now); 01135 AST_LIST_TRAVERSE(&cnf->userlist, user, list) { 01136 hr = (now - user->jointime) / 3600; 01137 min = ((now - user->jointime) % 3600) / 60; 01138 sec = (now - user->jointime) % 60; 01139 if (!concise) { 01140 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n", 01141 user->user_no, 01142 S_OR(user->chan->cid.cid_num, "<unknown>"), 01143 S_OR(user->chan->cid.cid_name, "<no name>"), 01144 user->chan->name, 01145 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "", 01146 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "", 01147 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "", 01148 user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "", 01149 istalking(user->talking), hr, min, sec); 01150 } else { 01151 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n", 01152 user->user_no, 01153 S_OR(user->chan->cid.cid_num, ""), 01154 S_OR(user->chan->cid.cid_name, ""), 01155 user->chan->name, 01156 user->userflags & CONFFLAG_ADMIN ? "1" : "", 01157 user->userflags & CONFFLAG_MONITOR ? "1" : "", 01158 user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "", 01159 user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "", 01160 user->talking, hr, min, sec); 01161 } 01162 } 01163 if (!concise) { 01164 ast_cli(a->fd, "%d users in that conference.\n", cnf->users); 01165 } 01166 AST_LIST_UNLOCK(&confs); 01167 ast_free(cmdline); 01168 return CLI_SUCCESS; 01169 } else { 01170 ast_free(cmdline); 01171 return CLI_SHOWUSAGE; 01172 } 01173 01174 ast_debug(1, "Cmdline: %s\n", cmdline->str); 01175 01176 admin_exec(NULL, cmdline->str); 01177 ast_free(cmdline); 01178 01179 return CLI_SUCCESS; 01180 }
| static int meetmemute | ( | struct mansession * | s, | |
| const struct message * | m, | |||
| int | mute | |||
| ) | [static] |
Definition at line 3679 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_conf_user::user_no, and ast_conference::userlist.
Referenced by action_meetmemute(), and action_meetmeunmute().
03680 { 03681 struct ast_conference *conf; 03682 struct ast_conf_user *user; 03683 const char *confid = astman_get_header(m, "Meetme"); 03684 char *userid = ast_strdupa(astman_get_header(m, "Usernum")); 03685 int userno; 03686 03687 if (ast_strlen_zero(confid)) { 03688 astman_send_error(s, m, "Meetme conference not specified"); 03689 return 0; 03690 } 03691 03692 if (ast_strlen_zero(userid)) { 03693 astman_send_error(s, m, "Meetme user number not specified"); 03694 return 0; 03695 } 03696 03697 userno = strtoul(userid, &userid, 10); 03698 03699 if (*userid) { 03700 astman_send_error(s, m, "Invalid user number"); 03701 return 0; 03702 } 03703 03704 /* Look in the conference list */ 03705 AST_LIST_LOCK(&confs); 03706 AST_LIST_TRAVERSE(&confs, conf, list) { 03707 if (!strcmp(confid, conf->confno)) 03708 break; 03709 } 03710 03711 if (!conf) { 03712 AST_LIST_UNLOCK(&confs); 03713 astman_send_error(s, m, "Meetme conference does not exist"); 03714 return 0; 03715 } 03716 03717 AST_LIST_TRAVERSE(&conf->userlist, user, list) 03718 if (user->user_no == userno) 03719 break; 03720 03721 if (!user) { 03722 AST_LIST_UNLOCK(&confs); 03723 astman_send_error(s, m, "User number not found"); 03724 return 0; 03725 } 03726 03727 if (mute) 03728 user->adminflags |= ADMINFLAG_MUTED; /* request user muting */ 03729 else 03730 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */ 03731 03732 AST_LIST_UNLOCK(&confs); 03733 03734 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); 03735 03736 astman_send_ack(s, m, mute ? "User muted" : "User unmuted"); 03737 return 0; 03738 }
| static enum ast_device_state meetmestate | ( | const char * | data | ) | [static] |
Callback for devicestate providers.
Definition at line 3890 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().
03891 { 03892 struct ast_conference *conf; 03893 03894 /* Find conference */ 03895 AST_LIST_LOCK(&confs); 03896 AST_LIST_TRAVERSE(&confs, conf, list) { 03897 if (!strcmp(data, conf->confno)) 03898 break; 03899 } 03900 AST_LIST_UNLOCK(&confs); 03901 if (!conf) 03902 return AST_DEVICE_INVALID; 03903 03904 03905 /* SKREP to fill */ 03906 if (!conf->users) 03907 return AST_DEVICE_NOT_INUSE; 03908 03909 return AST_DEVICE_INUSE; 03910 }
| static struct sla_ringing_trunk* queue_ringing_trunk | ( | struct sla_trunk * | trunk | ) | [static, read] |
Definition at line 5229 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().
05230 { 05231 struct sla_ringing_trunk *ringing_trunk; 05232 05233 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) 05234 return NULL; 05235 05236 ringing_trunk->trunk = trunk; 05237 ringing_trunk->ring_begin = ast_tvnow(); 05238 05239 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL); 05240 05241 ast_mutex_lock(&sla.lock); 05242 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry); 05243 ast_mutex_unlock(&sla.lock); 05244 05245 sla_queue_event(SLA_EVENT_RINGING_TRUNK); 05246 05247 return ringing_trunk; 05248 }
| static void * recordthread | ( | void * | args | ) | [static] |
Definition at line 3825 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.
03826 { 03827 struct ast_conference *cnf = args; 03828 struct ast_frame *f = NULL; 03829 int flags; 03830 struct ast_filestream *s = NULL; 03831 int res = 0; 03832 int x; 03833 const char *oldrecordingfilename = NULL; 03834 03835 if (!cnf || !cnf->lchan) { 03836 pthread_exit(0); 03837 } 03838 03839 ast_stopstream(cnf->lchan); 03840 flags = O_CREAT | O_TRUNC | O_WRONLY; 03841 03842 03843 cnf->recording = MEETME_RECORD_ACTIVE; 03844 while (ast_waitfor(cnf->lchan, -1) > -1) { 03845 if (cnf->recording == MEETME_RECORD_TERMINATE) { 03846 AST_LIST_LOCK(&confs); 03847 AST_LIST_UNLOCK(&confs); 03848 break; 03849 } 03850 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) { 03851 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE); 03852 oldrecordingfilename = cnf->recordingfilename; 03853 } 03854 03855 f = ast_read(cnf->lchan); 03856 if (!f) { 03857 res = -1; 03858 break; 03859 } 03860 if (f->frametype == AST_FRAME_VOICE) { 03861 ast_mutex_lock(&cnf->listenlock); 03862 for (x = 0; x < AST_FRAME_BITS; x++) { 03863 /* Free any translations that have occured */ 03864 if (cnf->transframe[x]) { 03865 ast_frfree(cnf->transframe[x]); 03866 cnf->transframe[x] = NULL; 03867 } 03868 } 03869 if (cnf->origframe) 03870 ast_frfree(cnf->origframe); 03871 cnf->origframe = ast_frdup(f); 03872 ast_mutex_unlock(&cnf->listenlock); 03873 if (s) 03874 res = ast_writestream(s, f); 03875 if (res) { 03876 ast_frfree(f); 03877 break; 03878 } 03879 } 03880 ast_frfree(f); 03881 } 03882 cnf->recording = MEETME_RECORD_OFF; 03883 if (s) 03884 ast_closestream(s); 03885 03886 pthread_exit(0); 03887 }
| static int reload | ( | void | ) | [static] |
Definition at line 5943 of file app_meetme.c.
References ast_unload_realtime(), and load_config().
05944 { 05945 ast_unload_realtime("meetme"); 05946 return load_config(1); 05947 }
| static void reset_volumes | ( | struct ast_conf_user * | user | ) | [static] |
Definition at line 775 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().
00776 { 00777 signed char zero_volume = 0; 00778 00779 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00780 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0); 00781 }
| static void* run_station | ( | void * | data | ) | [static] |
Definition at line 4128 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_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, ast_str::str, sla_trunk_ref::trunk, and run_station_args::trunk_ref.
Referenced by sla_handle_dial_state_event().
04129 { 04130 struct sla_station *station; 04131 struct sla_trunk_ref *trunk_ref; 04132 struct ast_str *conf_name = ast_str_create(16); 04133 struct ast_flags conf_flags = { 0 }; 04134 struct ast_conference *conf; 04135 04136 { 04137 struct run_station_args *args = data; 04138 station = args->station; 04139 trunk_ref = args->trunk_ref; 04140 ast_mutex_lock(args->cond_lock); 04141 ast_cond_signal(args->cond); 04142 ast_mutex_unlock(args->cond_lock); 04143 /* args is no longer valid here. */ 04144 } 04145 04146 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1); 04147 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name); 04148 ast_set_flag(&conf_flags, 04149 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION); 04150 answer_trunk_chan(trunk_ref->chan); 04151 conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan); 04152 if (conf) { 04153 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL); 04154 dispose_conf(conf); 04155 conf = NULL; 04156 } 04157 trunk_ref->chan = NULL; 04158 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) && 04159 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) { 04160 ast_str_append(&conf_name, 0, ",K"); 04161 admin_exec(NULL, conf_name->str); 04162 trunk_ref->trunk->hold_stations = 0; 04163 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 04164 } 04165 04166 ast_dial_join(station->dial); 04167 ast_dial_destroy(station->dial); 04168 station->dial = NULL; 04169 ast_free(conf_name); 04170 04171 return NULL; 04172 }
| static void send_talking_event | ( | struct ast_channel * | chan, | |
| struct ast_conference * | conf, | |||
| struct ast_conf_user * | user, | |||
| int | talking | |||
| ) | [static] |
Definition at line 1635 of file app_meetme.c.
References ast_conference::confno, EVENT_FLAG_CALL, manager_event, and ast_conf_user::user_no.
Referenced by set_user_talking().
01636 { 01637 manager_event(EVENT_FLAG_CALL, "MeetmeTalking", 01638 "Channel: %s\r\n" 01639 "Uniqueid: %s\r\n" 01640 "Meetme: %s\r\n" 01641 "Usernum: %d\r\n" 01642 "Status: %s\r\n", 01643 chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off"); 01644 }
| static int set_listen_volume | ( | struct ast_conf_user * | user, | |
| int | volume | |||
| ) | [static] |
Definition at line 704 of file app_meetme.c.
References ast_channel_setoption(), AST_OPTION_TXGAIN, and ast_conf_user::chan.
Referenced by tweak_listen_volume().
00705 { 00706 char gain_adjust; 00707 00708 /* attempt to make the adjustment in the channel driver; 00709 if successful, don't adjust in the frame reading routine 00710 */ 00711 gain_adjust = gain_map[volume + 5]; 00712 00713 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0); 00714 }
| static int set_talk_volume | ( | struct ast_conf_user * | user, | |
| int | volume | |||
| ) | [static] |
Definition at line 692 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().
00693 { 00694 char gain_adjust; 00695 00696 /* attempt to make the adjustment in the channel driver; 00697 if successful, don't adjust in the frame reading routine 00698 */ 00699 gain_adjust = gain_map[volume + 5]; 00700 00701 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0); 00702 }
| static void set_user_talking | ( | struct ast_channel * | chan, | |
| struct ast_conference * | conf, | |||
| struct ast_conf_user * | user, | |||
| int | talking, | |||
| int | monitor | |||
| ) | [static] |
Definition at line 1646 of file app_meetme.c.
References send_talking_event(), and ast_conf_user::talking.
Referenced by conf_run().
01647 { 01648 int last_talking = user->talking; 01649 if (last_talking == talking) 01650 return; 01651 01652 user->talking = talking; 01653 01654 if (monitor) { 01655 /* Check if talking state changed. Take care of -1 which means unmonitored */ 01656 int was_talking = (last_talking > 0); 01657 int now_talking = (talking > 0); 01658 if (was_talking != now_talking) { 01659 send_talking_event(chan, conf, user, now_talking); 01660 } 01661 } 01662 }
| static void sla_add_trunk_to_station | ( | struct sla_station * | station, | |
| struct ast_variable * | var | |||
| ) | [static] |
Definition at line 5575 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, and ast_variable::value.
Referenced by sla_build_station().
05576 { 05577 struct sla_trunk *trunk; 05578 struct sla_trunk_ref *trunk_ref; 05579 struct sla_station_ref *station_ref; 05580 char *trunk_name, *options, *cur; 05581 05582 options = ast_strdupa(var->value); 05583 trunk_name = strsep(&options, ","); 05584 05585 AST_RWLIST_RDLOCK(&sla_trunks); 05586 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) { 05587 if (!strcasecmp(trunk->name, trunk_name)) 05588 break; 05589 } 05590 05591 AST_RWLIST_UNLOCK(&sla_trunks); 05592 if (!trunk) { 05593 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value); 05594 return; 05595 } 05596 if (!(trunk_ref = create_trunk_ref(trunk))) 05597 return; 05598 trunk_ref->state = SLA_TRUNK_STATE_IDLE; 05599 05600 while ((cur = strsep(&options, ","))) { 05601 char *name, *value = cur; 05602 name = strsep(&value, "="); 05603 if (!strcasecmp(name, "ringtimeout")) { 05604 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) { 05605 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for " 05606 "trunk '%s' on station '%s'\n", value, trunk->name, station->name); 05607 trunk_ref->ring_timeout = 0; 05608 } 05609 } else if (!strcasecmp(name, "ringdelay")) { 05610 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) { 05611 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for " 05612 "trunk '%s' on station '%s'\n", value, trunk->name, station->name); 05613 trunk_ref->ring_delay = 0; 05614 } 05615 } else { 05616 ast_log(LOG_WARNING, "Invalid option '%s' for " 05617 "trunk '%s' on station '%s'\n", name, trunk->name, station->name); 05618 } 05619 } 05620 05621 if (!(station_ref = sla_create_station_ref(station))) { 05622 ast_free(trunk_ref); 05623 return; 05624 } 05625 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1); 05626 AST_RWLIST_WRLOCK(&sla_trunks); 05627 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry); 05628 AST_RWLIST_UNLOCK(&sla_trunks); 05629 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry); 05630 }
| static int sla_build_station | ( | struct ast_config * | cfg, | |
| const char * | cat | |||
| ) | [static] |
Definition at line 5632 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().
05633 { 05634 struct sla_station *station; 05635 struct ast_variable *var; 05636 const char *dev; 05637 05638 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) { 05639 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat); 05640 return -1; 05641 } 05642 05643 if (!(station = ast_calloc(1, sizeof(*station)))) 05644 return -1; 05645 if (ast_string_field_init(station, 32)) { 05646 ast_free(station); 05647 return -1; 05648 } 05649 05650 ast_string_field_set(station, name, cat); 05651 ast_string_field_set(station, device, dev); 05652 05653 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 05654 if (!strcasecmp(var->name, "trunk")) 05655 sla_add_trunk_to_station(station, var); 05656 else if (!strcasecmp(var->name, "autocontext")) 05657 ast_string_field_set(station, autocontext, var->value); 05658 else if (!strcasecmp(var->name, "ringtimeout")) { 05659 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) { 05660 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n", 05661 var->value, station->name); 05662 station->ring_timeout = 0; 05663 } 05664 } else if (!strcasecmp(var->name, "ringdelay")) { 05665 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) { 05666 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n", 05667 var->value, station->name); 05668 station->ring_delay = 0; 05669 } 05670 } else if (!strcasecmp(var->name, "hold")) { 05671 if (!strcasecmp(var->value, "private")) 05672 station->hold_access = SLA_HOLD_PRIVATE; 05673 else if (!strcasecmp(var->value, "open")) 05674 station->hold_access = SLA_HOLD_OPEN; 05675 else { 05676 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n", 05677 var->value, station->name); 05678 } 05679 05680 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) { 05681 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", 05682 var->name, var->lineno, SLA_CONFIG_FILE); 05683 } 05684 } 05685 05686 if (!ast_strlen_zero(station->autocontext)) { 05687 struct ast_context *context; 05688 struct sla_trunk_ref *trunk_ref; 05689 context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar); 05690 if (!context) { 05691 ast_log(LOG_ERROR, "Failed to automatically find or create " 05692 "context '%s' for SLA!\n", station->autocontext); 05693 destroy_station(station); 05694 return -1; 05695 } 05696 /* The extension for when the handset goes off-hook. 05697 * exten => station1,1,SLAStation(station1) */ 05698 if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1, 05699 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) { 05700 ast_log(LOG_ERROR, "Failed to automatically create extension " 05701 "for trunk '%s'!\n", station->name); 05702 destroy_station(station); 05703 return -1; 05704 } 05705 AST_RWLIST_RDLOCK(&sla_trunks); 05706 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 05707 char exten[AST_MAX_EXTENSION]; 05708 char hint[AST_MAX_APP]; 05709 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name); 05710 snprintf(hint, sizeof(hint), "SLA:%s", exten); 05711 /* Extension for this line button 05712 * exten => station1_line1,1,SLAStation(station1_line1) */ 05713 if (ast_add_extension2(context, 0 /* don't replace */, exten, 1, 05714 NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) { 05715 ast_log(LOG_ERROR, "Failed to automatically create extension " 05716 "for trunk '%s'!\n", station->name); 05717 destroy_station(station); 05718 return -1; 05719 } 05720 /* Hint for this line button 05721 * exten => station1_line1,hint,SLA:station1_line1 */ 05722 if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT, 05723 NULL, NULL, hint, NULL, NULL, sla_registrar)) { 05724 ast_log(LOG_ERROR, "Failed to automatically create hint " 05725 "for trunk '%s'!\n", station->name); 05726 destroy_station(station); 05727 return -1; 05728 } 05729 } 05730 AST_RWLIST_UNLOCK(&sla_trunks); 05731 } 05732 05733 AST_RWLIST_WRLOCK(&sla_stations); 05734 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry); 05735 AST_RWLIST_UNLOCK(&sla_stations); 05736 05737 return 0; 05738 }
| static int sla_build_trunk | ( | struct ast_config * | cfg, | |
| const char * | cat | |||
| ) | [static] |
Definition at line 5497 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().
05498 { 05499 struct sla_trunk *trunk; 05500 struct ast_variable *var; 05501 const char *dev; 05502 05503 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) { 05504 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat); 05505 return -1; 05506 } 05507 05508 if (sla_check_device(dev)) { 05509 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n", 05510 cat, dev); 05511 return -1; 05512 } 05513 05514 if (!(trunk = ast_calloc(1, sizeof(*trunk)))) 05515 return -1; 05516 if (ast_string_field_init(trunk, 32)) { 05517 ast_free(trunk); 05518 return -1; 05519 } 05520 05521 ast_string_field_set(trunk, name, cat); 05522 ast_string_field_set(trunk, device, dev); 05523 05524 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 05525 if (!strcasecmp(var->name, "autocontext")) 05526 ast_string_field_set(trunk, autocontext, var->value); 05527 else if (!strcasecmp(var->name, "ringtimeout")) { 05528 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) { 05529 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n", 05530 var->value, trunk->name); 05531 trunk->ring_timeout = 0; 05532 } 05533 } else if (!strcasecmp(var->name, "barge")) 05534 trunk->barge_disabled = ast_false(var->value); 05535 else if (!strcasecmp(var->name, "hold")) { 05536 if (!strcasecmp(var->value, "private")) 05537 trunk->hold_access = SLA_HOLD_PRIVATE; 05538 else if (!strcasecmp(var->value, "open")) 05539 trunk->hold_access = SLA_HOLD_OPEN; 05540 else { 05541 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n", 05542 var->value, trunk->name); 05543 } 05544 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) { 05545 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", 05546 var->name, var->lineno, SLA_CONFIG_FILE); 05547 } 05548 } 05549 05550 if (!ast_strlen_zero(trunk->autocontext)) { 05551 struct ast_context *context; 05552 context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar); 05553 if (!context) { 05554 ast_log(LOG_ERROR, "Failed to automatically find or create " 05555 "context '%s' for SLA!\n", trunk->autocontext); 05556 destroy_trunk(trunk); 05557 return -1; 05558 } 05559 if (ast_add_extension2(context, 0 /* don't replace */, "s", 1, 05560 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) { 05561 ast_log(LOG_ERROR, "Failed to automatically create extension " 05562 "for trunk '%s'!\n", trunk->name); 05563 destroy_trunk(trunk); 05564 return -1; 05565 } 05566 } 05567 05568 AST_RWLIST_WRLOCK(&sla_trunks); 05569 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry); 05570 AST_RWLIST_UNLOCK(&sla_trunks); 05571 05572 return 0; 05573 }
| static int sla_calc_station_delays | ( | unsigned int * | timeout | ) | [static] |
Calculate the ring delay for a station.
Definition at line 4741 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().
04742 { 04743 struct sla_station *station; 04744 int res = 0; 04745 04746 AST_LIST_TRAVERSE(&sla_stations, station, entry) { 04747 struct sla_ringing_trunk *ringing_trunk; 04748 int time_left; 04749 04750 /* Ignore stations already ringing */ 04751 if (sla_check_ringing_station(station)) 04752 continue; 04753 04754 /* Ignore stations already on a call */ 04755 if (sla_check_inuse_station(station)) 04756 continue; 04757 04758 /* Ignore stations that don't have one of their trunks ringing */ 04759 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0))) 04760 continue; 04761 04762 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX) 04763 continue; 04764 04765 /* If there is no time left, then the station needs to start ringing. 04766 * Return non-zero so that an event will be queued up an event to 04767 * make that happen. */ 04768 if (time_left <= 0) { 04769 res = 1; 04770 continue; 04771 } 04772 04773 if (time_left < *timeout) 04774 *timeout = time_left; 04775 } 04776 04777 return res; 04778 }
| static int sla_calc_station_timeouts | ( | unsigned int * | timeout | ) | [static] |
Process station ring timeouts.
Definition at line 4658 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().
04659 { 04660 struct sla_ringing_trunk *ringing_trunk; 04661 struct sla_ringing_station *ringing_station; 04662 int res = 0; 04663 04664 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) { 04665 unsigned int ring_timeout = 0; 04666 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN; 04667 struct sla_trunk_ref *trunk_ref; 04668 04669 /* If there are any ring timeouts specified for a specific trunk 04670 * on the station, then use the highest per-trunk ring timeout. 04671 * Otherwise, use the ring timeout set for the entire station. */ 04672 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) { 04673 struct sla_station_ref *station_ref; 04674 int trunk_time_elapsed, trunk_time_left; 04675 04676 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) { 04677 if (ringing_trunk->trunk == trunk_ref->trunk) 04678 break; 04679 } 04680 if (!ringing_trunk) 04681 continue; 04682 04683 /* If there is a trunk that is ringing without a timeout, then the 04684 * only timeout that could matter is a global station ring timeout. */ 04685 if (!trunk_ref->ring_timeout) 04686 break; 04687 04688 /* This trunk on this station is ringing and has a timeout. 04689 * However, make sure this trunk isn't still ringing from a 04690 * previous timeout. If so, don't consider it. */ 04691 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) { 04692 if (station_ref->station == ringing_station->station) 04693 break; 04694 } 04695 if (station_ref) 04696 continue; 04697 04698 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin); 04699 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed; 04700 if (trunk_time_left > final_trunk_time_left) 04701 final_trunk_time_left = trunk_time_left; 04702 } 04703 04704 /* No timeout was found for ringing trunks, and no timeout for the entire station */ 04705 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout) 04706 continue; 04707 04708 /* Compute how much time is left for a global station timeout */ 04709 if (ringing_station->station->ring_timeout) { 04710 ring_timeout = ringing_station->station->ring_timeout; 04711 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin); 04712 time_left = (ring_timeout * 1000) - time_elapsed; 04713 } 04714 04715 /* If the time left based on the per-trunk timeouts is smaller than the 04716 * global station ring timeout, use that. */ 04717 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left) 04718 time_left = final_trunk_time_left; 04719 04720 /* If there is no time left, the station needs to stop ringing */ 04721 if (time_left <= 0) { 04722 AST_LIST_REMOVE_CURRENT(entry); 04723 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT); 04724 res = 1; 04725 continue; 04726 } 04727 04728 /* There is still some time left for this station to ring, so save that 04729 * timeout if it is the first event scheduled to occur */ 04730 if (time_left < *timeout) 04731 *timeout = time_left; 04732 } 04733 AST_LIST_TRAVERSE_SAFE_END; 04734 04735 return res; 04736 }
| static int sla_calc_trunk_timeouts | ( | unsigned int * | timeout | ) | [static] |
Process trunk ring timeouts.
Definition at line 4628 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().
04629 { 04630 struct sla_ringing_trunk *ringing_trunk; 04631 int res = 0; 04632 04633 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) { 04634 int time_left, time_elapsed; 04635 if (!ringing_trunk->trunk->ring_timeout) 04636 continue; 04637 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin); 04638 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed; 04639 if (time_left <= 0) { 04640 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT"); 04641 AST_LIST_REMOVE_CURRENT(entry); 04642 sla_stop_ringing_trunk(ringing_trunk); 04643 res = 1; 04644 continue; 04645 } 04646 if (time_left < *timeout) 04647 *timeout = time_left; 04648 } 04649 AST_LIST_TRAVERSE_SAFE_END; 04650 04651 return res; 04652 }
| 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 4096 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().
04098 { 04099 struct sla_station *station; 04100 struct sla_trunk_ref *trunk_ref; 04101 04102 AST_LIST_TRAVERSE(&sla_stations, station, entry) { 04103 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 04104 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0) 04105 || trunk_ref == exclude) 04106 continue; 04107 trunk_ref->state = state; 04108 ast_devstate_changed(sla_state_to_devstate(state), 04109 "SLA:%s_%s", station->name, trunk->name); 04110 break; 04111 } 04112 } 04113 }
| static int sla_check_device | ( | const char * | device | ) | [static] |
Definition at line 5484 of file app_meetme.c.
References ast_strdupa, ast_strlen_zero(), and strsep().
Referenced by sla_build_trunk().
05485 { 05486 char *tech, *tech_data; 05487 05488 tech_data = ast_strdupa(device); 05489 tech = strsep(&tech_data, "/"); 05490 05491 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data)) 05492 return -1; 05493 05494 return 0; 05495 }
| 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 4376 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().
04377 { 04378 struct sla_failed_station *failed_station; 04379 int res = 0; 04380 04381 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) { 04382 if (station != failed_station->station) 04383 continue; 04384 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) { 04385 AST_LIST_REMOVE_CURRENT(entry); 04386 ast_free(failed_station); 04387 break; 04388 } 04389 res = 1; 04390 } 04391 AST_LIST_TRAVERSE_SAFE_END 04392 04393 return res; 04394 }
| static int sla_check_inuse_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if a station is in use.
Definition at line 4462 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().
04463 { 04464 struct sla_trunk_ref *trunk_ref; 04465 04466 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 04467 if (trunk_ref->chan) 04468 return 1; 04469 } 04470 04471 return 0; 04472 }
| 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 4820 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().
04821 { 04822 struct sla_station *station; 04823 struct sla_trunk *trunk; 04824 04825 ast_mutex_lock(&sla.lock); 04826 04827 if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 04828 || !AST_LIST_EMPTY(&sla.ringing_stations)) { 04829 ast_mutex_unlock(&sla.lock); 04830 return; 04831 } 04832 04833 AST_RWLIST_RDLOCK(&sla_stations); 04834 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) { 04835 if (station->ref_count) 04836 break; 04837 } 04838 AST_RWLIST_UNLOCK(&sla_stations); 04839 if (station) { 04840 ast_mutex_unlock(&sla.lock); 04841 return; 04842 } 04843 04844 AST_RWLIST_RDLOCK(&sla_trunks); 04845 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) { 04846 if (trunk->ref_count) 04847 break; 04848 } 04849 AST_RWLIST_UNLOCK(&sla_trunks); 04850 if (trunk) { 04851 ast_mutex_unlock(&sla.lock); 04852 return; 04853 } 04854 04855 /* yay */ 04856 sla_load_config(1); 04857 sla.reload = 0; 04858 04859 ast_mutex_unlock(&sla.lock); 04860 }
| static int sla_check_ringing_station | ( | const struct sla_station * | station | ) | [static] |
Check to see if this station is already ringing.
Definition at line 4361 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().
04362 { 04363 struct sla_ringing_station *ringing_station; 04364 04365 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) { 04366 if (station == ringing_station->station) 04367 return 1; 04368 } 04369 04370 return 0; 04371 }
| 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 4492 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().
04494 { 04495 struct sla_trunk_ref *trunk_ref; 04496 unsigned int delay = UINT_MAX; 04497 int time_left, time_elapsed; 04498 04499 if (!ringing_trunk) 04500 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0); 04501 else 04502 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk); 04503 04504 if (!ringing_trunk || !trunk_ref) 04505 return delay; 04506 04507 /* If this station has a ring delay specific to the highest priority 04508 * ringing trunk, use that. Otherwise, use the ring delay specified 04509 * globally for the station. */ 04510 delay = trunk_ref->ring_delay; 04511 if (!delay) 04512 delay = station->ring_delay; 04513 if (!delay) 04514 return INT_MAX; 04515 04516 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin); 04517 time_left = (delay * 1000) - time_elapsed; 04518 04519 return time_left; 04520 }
| static int sla_check_station_hold_access | ( | const struct sla_trunk * | trunk, | |
| const struct sla_station * | station | |||
| ) | [static] |
Definition at line 4001 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().
04003 { 04004 struct sla_station_ref *station_ref; 04005 struct sla_trunk_ref *trunk_ref; 04006 04007 /* For each station that has this call on hold, check for private hold. */ 04008 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) { 04009 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) { 04010 if (trunk_ref->trunk != trunk || station_ref->station == station) 04011 continue; 04012 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME && 04013 station_ref->station->hold_access == SLA_HOLD_PRIVATE) 04014 return 1; 04015 return 0; 04016 } 04017 } 04018 04019 return 0; 04020 }
| 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 4232 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().
04234 { 04235 struct sla_station_ref *timed_out_station; 04236 04237 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) { 04238 if (station == timed_out_station->station) 04239 return 1; 04240 } 04241 04242 return 0; 04243 }
| 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 5044 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().
05045 { 05046 struct sla_trunk_ref *trunk_ref = NULL; 05047 05048 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 05049 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) 05050 break; 05051 } 05052 05053 return trunk_ref; 05054 }
| 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 4253 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().
04255 { 04256 struct sla_trunk_ref *s_trunk_ref; 04257 struct sla_ringing_trunk *ringing_trunk = NULL; 04258 04259 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) { 04260 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) { 04261 /* Make sure this is the trunk we're looking for */ 04262 if (s_trunk_ref->trunk != ringing_trunk->trunk) 04263 continue; 04264 04265 /* This trunk on the station is ringing. But, make sure this station 04266 * didn't already time out while this trunk was ringing. */ 04267 if (sla_check_timed_out_station(ringing_trunk, station)) 04268 continue; 04269 04270 if (rm) 04271 AST_LIST_REMOVE_CURRENT(entry); 04272 04273 if (trunk_ref) 04274 *trunk_ref = s_trunk_ref; 04275 04276 break; 04277 } 04278 AST_LIST_TRAVERSE_SAFE_END; 04279 04280 if (ringing_trunk) 04281 break; 04282 } 04283 04284 return ringing_trunk; 04285 }
| static struct sla_ringing_station* sla_create_ringing_station | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 4066 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().
04067 { 04068 struct sla_ringing_station *ringing_station; 04069 04070 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station)))) 04071 return NULL; 04072 04073 ringing_station->station = station; 04074 ringing_station->ring_begin = ast_tvnow(); 04075 04076 return ringing_station; 04077 }
| static struct sla_station_ref* sla_create_station_ref | ( | struct sla_station * | station | ) | [static, read] |
Definition at line 4054 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().
04055 { 04056 struct sla_station_ref *station_ref; 04057 04058 if (!(station_ref = ast_calloc(1, sizeof(*station_ref)))) 04059 return NULL; 04060 04061 station_ref->station = station; 04062 04063 return station_ref; 04064 }
| static void sla_destroy | ( | void | ) | [static] |
Definition at line 5454 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().
05455 { 05456 struct sla_trunk *trunk; 05457 struct sla_station *station; 05458 05459 AST_RWLIST_WRLOCK(&sla_trunks); 05460 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry))) 05461 destroy_trunk(trunk); 05462 AST_RWLIST_UNLOCK(&sla_trunks); 05463 05464 AST_RWLIST_WRLOCK(&sla_stations); 05465 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry))) 05466 destroy_station(station); 05467 AST_RWLIST_UNLOCK(&sla_stations); 05468 05469 if (sla.thread != AST_PTHREADT_NULL) { 05470 ast_mutex_lock(&sla.lock); 05471 sla.stop = 1; 05472 ast_cond_signal(&sla.cond); 05473 ast_mutex_unlock(&sla.lock); 05474 pthread_join(sla.thread, NULL); 05475 } 05476 05477 /* Drop any created contexts from the dialplan */ 05478 ast_context_destroy(NULL, sla_registrar); 05479 05480 ast_mutex_destroy(&sla.lock); 05481 ast_cond_destroy(&sla.cond); 05482 }
| static void sla_dial_state_callback | ( | struct ast_dial * | dial | ) | [static] |
Definition at line 4224 of file app_meetme.c.
References SLA_EVENT_DIAL_STATE, and sla_queue_event().
Referenced by sla_ring_station().
04225 { 04226 sla_queue_event(SLA_EVENT_DIAL_STATE); 04227 }
| static struct sla_station* sla_find_station | ( | const char * | name | ) | [static, read] |
Find an SLA station by name.
Definition at line 3989 of file app_meetme.c.
References AST_RWLIST_TRAVERSE, and sla_station::name.
Referenced by sla_station_exec().
03990 { 03991 struct sla_station *station = NULL; 03992 03993 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) { 03994 if (!strcasecmp(station->name, name)) 03995 break; 03996 } 03997 03998 return station; 03999 }
| static struct sla_trunk* sla_find_trunk | ( | const char * | name | ) | [static, read] |
Find an SLA trunk by name.
Definition at line 3974 of file app_meetme.c.
References AST_RWLIST_TRAVERSE, and sla_trunk::name.
Referenced by sla_trunk_exec().
03975 { 03976 struct sla_trunk *trunk = NULL; 03977 03978 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) { 03979 if (!strcasecmp(trunk->name, name)) 03980 break; 03981 } 03982 03983 return trunk; 03984 }
| static struct sla_trunk_ref* sla_find_trunk_ref | ( | const struct sla_station * | station, | |
| const struct sla_trunk * | trunk | |||
| ) | [static, read] |
Definition at line 4474 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by sla_check_station_delay().
04476 { 04477 struct sla_trunk_ref *trunk_ref = NULL; 04478 04479 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 04480 if (trunk_ref->trunk == trunk) 04481 break; 04482 } 04483 04484 return trunk_ref; 04485 }
| 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 4029 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().
04031 { 04032 struct sla_trunk_ref *trunk_ref = NULL; 04033 04034 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 04035 if (strcasecmp(trunk_ref->trunk->name, name)) 04036 continue; 04037 04038 if ( (trunk_ref->trunk->barge_disabled 04039 && trunk_ref->state == SLA_TRUNK_STATE_UP) || 04040 (trunk_ref->trunk->hold_stations 04041 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE 04042 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) || 04043 sla_check_station_hold_access(trunk_ref->trunk, station) ) 04044 { 04045 trunk_ref = NULL; 04046 } 04047 04048 break; 04049 } 04050 04051 return trunk_ref; 04052 }
| static void sla_handle_dial_state_event | ( | void | ) | [static] |
Definition at line 4287 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().
04288 { 04289 struct sla_ringing_station *ringing_station; 04290 04291 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) { 04292 struct sla_trunk_ref *s_trunk_ref = NULL; 04293 struct sla_ringing_trunk *ringing_trunk = NULL; 04294 struct run_station_args args; 04295 enum ast_dial_result dial_res; 04296 pthread_t dont_care; 04297 ast_mutex_t cond_lock; 04298 ast_cond_t cond; 04299 04300 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) { 04301 case AST_DIAL_RESULT_HANGUP: 04302 case AST_DIAL_RESULT_INVALID: 04303 case AST_DIAL_RESULT_FAILED: 04304 case AST_DIAL_RESULT_TIMEOUT: 04305 case AST_DIAL_RESULT_UNANSWERED: 04306 AST_LIST_REMOVE_CURRENT(entry); 04307 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL); 04308 break; 04309 case AST_DIAL_RESULT_ANSWERED: 04310 AST_LIST_REMOVE_CURRENT(entry); 04311 /* Find the appropriate trunk to answer. */ 04312 ast_mutex_lock(&sla.lock); 04313 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1); 04314 ast_mutex_unlock(&sla.lock); 04315 if (!ringing_trunk) { 04316 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name); 04317 break; 04318 } 04319 /* Track the channel that answered this trunk */ 04320 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial); 04321 /* Actually answer the trunk */ 04322 answer_trunk_chan(ringing_trunk->trunk->chan); 04323 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL); 04324 /* Now, start a thread that will connect this station to the trunk. The rest of 04325 * the code here sets up the thread and ensures that it is able to save the arguments 04326 * before they are no longer valid since they are allocated on the stack. */ 04327 args.trunk_ref = s_trunk_ref; 04328 args.station = ringing_station->station; 04329 args.cond = &cond; 04330 args.cond_lock = &cond_lock; 04331 ast_free(ringing_trunk); 04332 ast_free(ringing_station); 04333 ast_mutex_init(&cond_lock); 04334 ast_cond_init(&cond, NULL); 04335 ast_mutex_lock(&cond_lock); 04336 ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args); 04337 ast_cond_wait(&cond, &cond_lock); 04338 ast_mutex_unlock(&cond_lock); 04339 ast_mutex_destroy(&cond_lock); 04340 ast_cond_destroy(&cond); 04341 break; 04342 case AST_DIAL_RESULT_TRYING: 04343 case AST_DIAL_RESULT_RINGING: 04344 case AST_DIAL_RESULT_PROGRESS: 04345 case AST_DIAL_RESULT_PROCEEDING: 04346 break; 04347 } 04348 if (dial_res == AST_DIAL_RESULT_ANSWERED) { 04349 /* Queue up reprocessing ringing trunks, and then ringing stations again */ 04350 sla_queue_event(SLA_EVENT_RINGING_TRUNK); 04351 sla_queue_event(SLA_EVENT_DIAL_STATE); 04352 break; 04353 } 04354 } 04355 AST_LIST_TRAVERSE_SAFE_END; 04356 }
| static void sla_handle_hold_event | ( | struct sla_event * | event | ) | [static] |
Definition at line 4604 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().
04605 { 04606 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1); 04607 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME; 04608 ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 04609 event->station->name, event->trunk_ref->trunk->name); 04610 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 04611 INACTIVE_TRUNK_REFS, event->trunk_ref); 04612 04613 if (event->trunk_ref->trunk->active_stations == 1) { 04614 /* The station putting it on hold is the only one on the call, so start 04615 * Music on hold to the trunk. */ 04616 event->trunk_ref->trunk->on_hold = 1; 04617 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD); 04618 } 04619 04620 ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV); 04621 event->trunk_ref->chan = NULL; 04622 }
| static void sla_handle_ringing_trunk_event | ( | void | ) | [static] |
Definition at line 4594 of file app_meetme.c.
References ast_mutex_lock(), ast_mutex_unlock(), sla, sla_hangup_stations(), and sla_ring_stations().
Referenced by sla_thread().
04595 { 04596 ast_mutex_lock(&sla.lock); 04597 sla_ring_stations(); 04598 ast_mutex_unlock(&sla.lock); 04599 04600 /* Find stations that shouldn't be ringing anymore. */ 04601 sla_hangup_stations(); 04602 }
| static void sla_hangup_stations | ( | void | ) | [static] |
Definition at line 4566 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().
04567 { 04568 struct sla_trunk_ref *trunk_ref; 04569 struct sla_ringing_station *ringing_station; 04570 04571 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) { 04572 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) { 04573 struct sla_ringing_trunk *ringing_trunk; 04574 ast_mutex_lock(&sla.lock); 04575 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) { 04576 if (trunk_ref->trunk == ringing_trunk->trunk) 04577 break; 04578 } 04579 ast_mutex_unlock(&sla.lock); 04580 if (ringing_trunk) 04581 break; 04582 } 04583 if (!trunk_ref) { 04584 AST_LIST_REMOVE_CURRENT(entry); 04585 ast_dial_join(ringing_station->station->dial); 04586 ast_dial_destroy(ringing_station->station->dial); 04587 ringing_station->station->dial = NULL; 04588 ast_free(ringing_station); 04589 } 04590 } 04591 AST_LIST_TRAVERSE_SAFE_END 04592 }
| static const char* sla_hold_str | ( | unsigned int | hold_access | ) | [static] |
Definition at line 1182 of file app_meetme.c.
References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.
Referenced by sla_show_stations(), and sla_show_trunks().
01183 { 01184 const char *hold = "Unknown"; 01185 01186 switch (hold_access) { 01187 case SLA_HOLD_OPEN: 01188 hold = "Open"; 01189 break; 01190 case SLA_HOLD_PRIVATE: 01191 hold = "Private"; 01192 default: 01193 break; 01194 } 01195 01196 return hold; 01197 }
| static int sla_load_config | ( | int | reload | ) | [static] |
Definition at line 5740 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_FILEUNCHANGED, LOG_WARNING, sla, sla_build_station(), sla_build_trunk(), SLA_CONFIG_FILE, sla_thread(), and type.
Referenced by load_config(), and sla_check_reload().
05741 { 05742 struct ast_config *cfg; 05743 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05744 const char *cat = NULL; 05745 int res = 0; 05746 const char *val; 05747 05748 if (!reload) { 05749 ast_mutex_init(&sla.lock); 05750 ast_cond_init(&sla.cond, NULL); 05751 } 05752 05753 if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) 05754 return 0; /* Treat no config as normal */ 05755 else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 05756 return 0; 05757 05758 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid"))) 05759 sla.attempt_callerid = ast_true(val); 05760 05761 while ((cat = ast_category_browse(cfg, cat)) && !res) { 05762 const char *type; 05763 if (!strcasecmp(cat, "general")) 05764 continue; 05765 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) { 05766 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n", 05767 SLA_CONFIG_FILE); 05768 continue; 05769 } 05770 if (!strcasecmp(type, "trunk")) 05771 res = sla_build_trunk(cfg, cat); 05772 else if (!strcasecmp(type, "station")) 05773 res = sla_build_station(cfg, cat); 05774 else { 05775 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n", 05776 SLA_CONFIG_FILE, type); 05777 } 05778 } 05779 05780 ast_config_destroy(cfg); 05781 05782 if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations))) 05783 ast_pthread_create(&sla.thread, NULL, sla_thread, NULL); 05784 05785 return res; 05786 }
| static int sla_process_timers | ( | struct timespec * | ts | ) | [static] |
Calculate the time until the next known event.
Definition at line 4782 of file app_meetme.c.
References ast_samp2tv(), ast_tvadd(), ast_tvnow(), sla_calc_station_delays(), sla_calc_station_timeouts(), sla_calc_trunk_timeouts(), SLA_EVENT_RINGING_TRUNK, and sla_queue_event_nolock().
Referenced by sla_thread().
04783 { 04784 unsigned int timeout = UINT_MAX; 04785 struct timeval wait; 04786 unsigned int change_made = 0; 04787 04788 /* Check for ring timeouts on ringing trunks */ 04789 if (sla_calc_trunk_timeouts(&timeout)) 04790 change_made = 1; 04791 04792 /* Check for ring timeouts on ringing stations */ 04793 if (sla_calc_station_timeouts(&timeout)) 04794 change_made = 1; 04795 04796 /* Check for station ring delays */ 04797 if (sla_calc_station_delays(&timeout)) 04798 change_made = 1; 04799 04800 /* queue reprocessing of ringing trunks */ 04801 if (change_made) 04802 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK); 04803 04804 /* No timeout */ 04805 if (timeout == UINT_MAX) 04806 return 0; 04807 04808 if (ts) { 04809 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000)); 04810 ts->tv_sec = wait.tv_sec; 04811 ts->tv_nsec = wait.tv_usec * 1000; 04812 } 04813 04814 return 1; 04815 }
| static void sla_queue_event | ( | enum sla_event_type | type | ) | [static] |
Definition at line 1485 of file app_meetme.c.
References sla_queue_event_full().
Referenced by load_config(), queue_ringing_trunk(), sla_dial_state_callback(), sla_handle_dial_state_event(), sla_station_exec(), and sla_trunk_exec().
01486 { 01487 sla_queue_event_full(type, NULL, NULL, 1); 01488 }
| static void sla_queue_event_conf | ( | enum sla_event_type | type, | |
| struct ast_channel * | chan, | |||
| struct ast_conference * | conf | |||
| ) | [static] |
Queue a SLA event from the conference.
Definition at line 1491 of file app_meetme.c.
References ast_debug, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, ast_strlen_zero(), sla_trunk_ref::chan, ast_conference::confno, LOG_ERROR, sla_trunk::name, sla_queue_event_full(), strsep(), sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by conf_run().
01493 { 01494 struct sla_station *station; 01495 struct sla_trunk_ref *trunk_ref = NULL; 01496 char *trunk_name; 01497 01498 trunk_name = ast_strdupa(conf->confno); 01499 strsep(&trunk_name, "_"); 01500 if (ast_strlen_zero(trunk_name)) { 01501 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno); 01502 return; 01503 } 01504 01505 AST_RWLIST_RDLOCK(&sla_stations); 01506 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) { 01507 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 01508 if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) 01509 break; 01510 } 01511 if (trunk_ref) 01512 break; 01513 } 01514 AST_RWLIST_UNLOCK(&sla_stations); 01515 01516 if (!trunk_ref) { 01517 ast_debug(1, "Trunk not found for event!\n"); 01518 return; 01519 } 01520 01521 sla_queue_event_full(type, trunk_ref, station, 1); 01522 }
| static void sla_queue_event_full | ( | enum sla_event_type | type, | |
| struct sla_trunk_ref * | trunk_ref, | |||
| struct sla_station * | station, | |||
| int | lock | |||
| ) | [static] |
Definition at line 1453 of file app_meetme.c.
References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, and sla.
Referenced by sla_queue_event(), sla_queue_event_conf(), and sla_queue_event_nolock().
01455 { 01456 struct sla_event *event; 01457 01458 if (sla.thread == AST_PTHREADT_NULL) { 01459 return; 01460 } 01461 01462 if (!(event = ast_calloc(1, sizeof(*event)))) 01463 return; 01464 01465 event->type = type; 01466 event->trunk_ref = trunk_ref; 01467 event->station = station; 01468 01469 if (!lock) { 01470 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry); 01471 return; 01472 } 01473 01474 ast_mutex_lock(&sla.lock); 01475 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry); 01476 ast_cond_signal(&sla.cond); 01477 ast_mutex_unlock(&sla.lock); 01478 }
| static void sla_queue_event_nolock | ( | enum sla_event_type | type | ) | [static] |
Definition at line 1480 of file app_meetme.c.
References sla_queue_event_full().
Referenced by sla_process_timers().
01481 { 01482 sla_queue_event_full(type, NULL, NULL, 0); 01483 }
| static int sla_ring_station | ( | struct sla_ringing_trunk * | ringing_trunk, | |
| struct sla_station * | station | |||
| ) | [static] |
Ring a station.
Definition at line 4399 of file app_meetme.c.
References ast_calloc, ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), ast_free, AST_LIST_INSERT_HEAD, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvnow(), sla_trunk::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, sla_station::device, sla_station::dial, sla_failed_station::last_try, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, strsep(), and sla_ringing_trunk::trunk.
Referenced by sla_ring_stations().
04400 { 04401 char *tech, *tech_data; 04402 struct ast_dial *dial; 04403 struct sla_ringing_station *ringing_station; 04404 const char *cid_name = NULL, *cid_num = NULL; 04405 enum ast_dial_result res; 04406 04407 if (!(dial = ast_dial_create())) 04408 return -1; 04409 04410 ast_dial_set_state_callback(dial, sla_dial_state_callback); 04411 tech_data = ast_strdupa(station->device); 04412 tech = strsep(&tech_data, "/"); 04413 04414 if (ast_dial_append(dial, tech, tech_data) == -1) { 04415 ast_dial_destroy(dial); 04416 return -1; 04417 } 04418 04419 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) { 04420 cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name); 04421 ast_free(ringing_trunk->trunk->chan->cid.cid_name); 04422 ringing_trunk->trunk->chan->cid.cid_name = NULL; 04423 } 04424 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) { 04425 cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num); 04426 ast_free(ringing_trunk->trunk->chan->cid.cid_num); 04427 ringing_trunk->trunk->chan->cid.cid_num = NULL; 04428 } 04429 04430 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1); 04431 04432 if (cid_name) 04433 ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name); 04434 if (cid_num) 04435 ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num); 04436 04437 if (res != AST_DIAL_RESULT_TRYING) { 04438 struct sla_failed_station *failed_station; 04439 ast_dial_destroy(dial); 04440 if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) 04441 return -1; 04442 failed_station->station = station; 04443 failed_station->last_try = ast_tvnow(); 04444 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry); 04445 return -1; 04446 } 04447 if (!(ringing_station = sla_create_ringing_station(station))) { 04448 ast_dial_join(dial); 04449 ast_dial_destroy(dial); 04450 return -1; 04451 } 04452 04453 station->dial = dial; 04454 04455 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry); 04456 04457 return 0; 04458 }
| static void sla_ring_stations | ( | void | ) | [static] |
Ring stations based on current set of ringing trunks.
Definition at line 4525 of file app_meetme.c.
References AST_LIST_TRAVERSE, sla, sla_check_failed_station(), sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), sla_check_timed_out_station(), sla_ring_station(), sla_station_ref::station, sla_trunk::stations, and sla_ringing_trunk::trunk.
Referenced by sla_handle_ringing_trunk_event().
04526 { 04527 struct sla_station_ref *station_ref; 04528 struct sla_ringing_trunk *ringing_trunk; 04529 04530 /* Make sure that every station that uses at least one of the ringing 04531 * trunks, is ringing. */ 04532 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) { 04533 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) { 04534 int time_left; 04535 04536 /* Is this station already ringing? */ 04537 if (sla_check_ringing_station(station_ref->station)) 04538 continue; 04539 04540 /* Is this station already in a call? */ 04541 if (sla_check_inuse_station(station_ref->station)) 04542 continue; 04543 04544 /* Did we fail to dial this station earlier? If so, has it been 04545 * a minute since we tried? */ 04546 if (sla_check_failed_station(station_ref->station)) 04547 continue; 04548 04549 /* If this station already timed out while this trunk was ringing, 04550 * do not dial it again for this ringing trunk. */ 04551 if (sla_check_timed_out_station(ringing_trunk, station_ref->station)) 04552 continue; 04553 04554 /* Check for a ring delay in progress */ 04555 time_left = sla_check_station_delay(station_ref->station, ringing_trunk); 04556 if (time_left != INT_MAX && time_left > 0) 04557 continue; 04558 04559 /* It is time to make this station begin to ring. Do it! */ 04560 sla_ring_station(ringing_trunk, station_ref->station); 04561 } 04562 } 04563 /* Now, all of the stations that should be ringing, are ringing. */ 04564 }
| static char* sla_show_stations | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1264 of file app_meetme.c.
References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_station::autocontext, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, sla_station::device, ast_cli_args::fd, sla_station::hold_access, sla_trunk::name, sla_station::name, sla_trunk_ref::ring_delay, sla_station::ring_delay, sla_trunk_ref::ring_timeout, sla_station::ring_timeout, S_OR, sla_hold_str(), sla_trunk_ref::state, sla_trunk_ref::trunk, sla_station::trunks, trunkstate2str(), and ast_cli_entry::usage.
01265 { 01266 const struct sla_station *station; 01267 01268 switch (cmd) { 01269 case CLI_INIT: 01270 e->command = "sla show stations"; 01271 e->usage = 01272 "Usage: sla show stations\n" 01273 " This will list all stations defined in sla.conf\n"; 01274 return NULL; 01275 case CLI_GENERATE: 01276 return NULL; 01277 } 01278 01279 ast_cli(a->fd, "\n" 01280 "=============================================================\n" 01281 "=== Configured SLA Stations =================================\n" 01282 "=============================================================\n" 01283 "===\n"); 01284 AST_RWLIST_RDLOCK(&sla_stations); 01285 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) { 01286 struct sla_trunk_ref *trunk_ref; 01287 char ring_timeout[16] = "(none)"; 01288 char ring_delay[16] = "(none)"; 01289 if (station->ring_timeout) { 01290 snprintf(ring_timeout, sizeof(ring_timeout), 01291 "%u", station->ring_timeout); 01292 } 01293 if (station->ring_delay) { 01294 snprintf(ring_delay, sizeof(ring_delay), 01295 "%u", station->ring_delay); 01296 } 01297 ast_cli(a->fd, "=== ---------------------------------------------------------\n" 01298 "=== Station Name: %s\n" 01299 "=== ==> Device: %s\n" 01300 "=== ==> AutoContext: %s\n" 01301 "=== ==> RingTimeout: %s\n" 01302 "=== ==> RingDelay: %s\n" 01303 "=== ==> HoldAccess: %s\n" 01304 "=== ==> Trunks ...\n", 01305 station->name, station->device, 01306 S_OR(station->autocontext, "(none)"), 01307 ring_timeout, ring_delay, 01308 sla_hold_str(station->hold_access)); 01309 AST_RWLIST_RDLOCK(&sla_trunks); 01310 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 01311 if (trunk_ref->ring_timeout) { 01312 snprintf(ring_timeout, sizeof(ring_timeout), 01313 "%u", trunk_ref->ring_timeout); 01314 } else 01315 strcpy(ring_timeout, "(none)"); 01316 if (trunk_ref->ring_delay) { 01317 snprintf(ring_delay, sizeof(ring_delay), 01318 "%u", trunk_ref->ring_delay); 01319 } else 01320 strcpy(ring_delay, "(none)"); 01321 ast_cli(a->fd, "=== ==> Trunk Name: %s\n" 01322 "=== ==> State: %s\n" 01323 "=== ==> RingTimeout: %s\n" 01324 "=== ==> RingDelay: %s\n", 01325 trunk_ref->trunk->name, 01326 trunkstate2str(trunk_ref->state), 01327 ring_timeout, ring_delay); 01328 } 01329 AST_RWLIST_UNLOCK(&sla_trunks); 01330 ast_cli(a->fd, "=== ---------------------------------------------------------\n" 01331 "===\n"); 01332 } 01333 AST_RWLIST_UNLOCK(&sla_stations); 01334 ast_cli(a->fd, "============================================================\n" 01335 "\n"); 01336 01337 return CLI_SUCCESS; 01338 }
| static char* sla_show_trunks | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1199 of file app_meetme.c.
References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_trunk::autocontext, sla_trunk::barge_disabled, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, sla_trunk::device, ast_cli_args::fd, sla_trunk::hold_access, sla_station::name, sla_trunk::name, sla_trunk::ring_timeout, S_OR, sla_hold_str(), sla_station_ref::station, sla_trunk::stations, and ast_cli_entry::usage.
01200 { 01201 const struct sla_trunk *trunk; 01202 01203 switch (cmd) { 01204 case CLI_INIT: 01205 e->command = "sla show trunks"; 01206 e->usage = 01207 "Usage: sla show trunks\n" 01208 " This will list all trunks defined in sla.conf\n"; 01209 return NULL; 01210 case CLI_GENERATE: 01211 return NULL; 01212 } 01213 01214 ast_cli(a->fd, "\n" 01215 "=============================================================\n" 01216 "=== Configured SLA Trunks ===================================\n" 01217 "=============================================================\n" 01218 "===\n"); 01219 AST_RWLIST_RDLOCK(&sla_trunks); 01220 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) { 01221 struct sla_station_ref *station_ref; 01222 char ring_timeout[16] = "(none)"; 01223 if (trunk->ring_timeout) 01224 snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout); 01225 ast_cli(a->fd, "=== ---------------------------------------------------------\n" 01226 "=== Trunk Name: %s\n" 01227 "=== ==> Device: %s\n" 01228 "=== ==> AutoContext: %s\n" 01229 "=== ==> RingTimeout: %s\n" 01230 "=== ==> BargeAllowed: %s\n" 01231 "=== ==> HoldAccess: %s\n" 01232 "=== ==> Stations ...\n", 01233 trunk->name, trunk->device, 01234 S_OR(trunk->autocontext, "(none)"), 01235 ring_timeout, 01236 trunk->barge_disabled ? "No" : "Yes", 01237 sla_hold_str(trunk->hold_access)); 01238 AST_RWLIST_RDLOCK(&sla_stations); 01239 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) 01240 ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name); 01241 AST_RWLIST_UNLOCK(&sla_stations); 01242 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n"); 01243 } 01244 AST_RWLIST_UNLOCK(&sla_trunks); 01245 ast_cli(a->fd, "=============================================================\n\n"); 01246 01247 return CLI_SUCCESS; 01248 }
| static enum ast_device_state sla_state | ( | const char * | data | ) | [static] |
Definition at line 5378 of file app_meetme.c.
References AST_DEVICE_INVALID, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, buf, LOG_ERROR, sla_trunk::name, sla_station::name, sla_state_to_devstate(), sla_trunk_ref::state, strsep(), sla_trunk_ref::trunk, and sla_station::trunks.
Referenced by load_module().
05379 { 05380 char *buf, *station_name, *trunk_name; 05381 struct sla_station *station; 05382 struct sla_trunk_ref *trunk_ref; 05383 enum ast_device_state res = AST_DEVICE_INVALID; 05384 05385 trunk_name = buf = ast_strdupa(data); 05386 station_name = strsep(&trunk_name, "_"); 05387 05388 AST_RWLIST_RDLOCK(&sla_stations); 05389 AST_LIST_TRAVERSE(&sla_stations, station, entry) { 05390 if (strcasecmp(station_name, station->name)) 05391 continue; 05392 AST_RWLIST_RDLOCK(&sla_trunks); 05393 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { 05394 if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) 05395 break; 05396 } 05397 if (!trunk_ref) { 05398 AST_RWLIST_UNLOCK(&sla_trunks); 05399 break; 05400 } 05401 res = sla_state_to_devstate(trunk_ref->state); 05402 AST_RWLIST_UNLOCK(&sla_trunks); 05403 } 05404 AST_RWLIST_UNLOCK(&sla_stations); 05405 05406 if (res == AST_DEVICE_INVALID) { 05407 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n", 05408 trunk_name, station_name); 05409 } 05410 05411 return res; 05412 }
| static enum ast_device_state sla_state_to_devstate | ( | enum sla_trunk_state | state | ) | [static] |
Definition at line 4079 of file app_meetme.c.
References AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_UNKNOWN, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.
Referenced by sla_change_trunk_state(), and sla_state().
04080 { 04081 switch (state) { 04082 case SLA_TRUNK_STATE_IDLE: 04083 return AST_DEVICE_NOT_INUSE; 04084 case SLA_TRUNK_STATE_RINGING: 04085 return AST_DEVICE_RINGING; 04086 case SLA_TRUNK_STATE_UP: 04087 return AST_DEVICE_INUSE; 04088 case SLA_TRUNK_STATE_ONHOLD: 04089 case SLA_TRUNK_STATE_ONHOLD_BYME: 04090 return AST_DEVICE_ONHOLD; 04091 } 04092 04093 return AST_DEVICE_UNKNOWN; 04094 }
| static int sla_station_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 5056 of file app_meetme.c.
References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ast_answer(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_INUSE, ast_devstate_changed(), ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), build_conf(), sla_trunk_ref::chan, sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), ast_flags::flags, free, sla_trunk::hold_stations, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, sla_trunk::name, sla_station::name, sla_trunk::on_hold, pbx_builtin_setvar_helper(), sla_station::ref_count, sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, strsep(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.
Referenced by load_module().
05057 { 05058 char *station_name, *trunk_name; 05059 struct sla_station *station; 05060 struct sla_trunk_ref *trunk_ref = NULL; 05061 char conf_name[MAX_CONFNUM]; 05062 struct ast_flags conf_flags = { 0 }; 05063 struct ast_conference *conf; 05064 05065 if (ast_strlen_zero(data)) { 05066 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n"); 05067 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE"); 05068 return 0; 05069 } 05070 05071 trunk_name = ast_strdupa(data); 05072 station_name = strsep(&trunk_name, "_"); 05073 05074 if (ast_strlen_zero(station_name)) { 05075 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n"); 05076 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE"); 05077 return 0; 05078 } 05079 05080 AST_RWLIST_RDLOCK(&sla_stations); 05081 station = sla_find_station(station_name); 05082 if (station) 05083 ast_atomic_fetchadd_int((int *) &station->ref_count, 1); 05084 AST_RWLIST_UNLOCK(&sla_stations); 05085 05086 if (!station) { 05087 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name); 05088 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE"); 05089 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05090 return 0; 05091 } 05092 05093 AST_RWLIST_RDLOCK(&sla_trunks); 05094 if (!ast_strlen_zero(trunk_name)) { 05095 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name); 05096 } else 05097 trunk_ref = sla_choose_idle_trunk(station); 05098 AST_RWLIST_UNLOCK(&sla_trunks); 05099 05100 if (!trunk_ref) { 05101 if (ast_strlen_zero(trunk_name)) 05102 ast_log(LOG_NOTICE, "No trunks available for call.\n"); 05103 else { 05104 ast_log(LOG_NOTICE, "Can't join existing call on trunk " 05105 "'%s' due to access controls.\n", trunk_name); 05106 } 05107 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION"); 05108 ast_atomic_fetchadd_int((int *) &station->ref_count, -1); 05109 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05110 return 0; 05111 } 05112 05113 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) { 05114 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1) 05115 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL); 05116 else { 05117 trunk_ref->state = SLA_TRUNK_STATE_UP; 05118 ast_devstate_changed(AST_DEVICE_INUSE, 05119 "SLA:%s_%s", station->name, trunk_ref->trunk->name); 05120 } 05121 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) { 05122 struct sla_ringing_trunk *ringing_trunk; 05123 05124 ast_mutex_lock(&sla.lock); 05125 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) { 05126 if (ringing_trunk->trunk == trunk_ref->trunk) { 05127 AST_LIST_REMOVE_CURRENT(entry); 05128 break; 05129 } 05130 } 05131 AST_LIST_TRAVERSE_SAFE_END 05132 ast_mutex_unlock(&sla.lock); 05133 05134 if (ringing_trunk) { 05135 answer_trunk_chan(ringing_trunk->trunk->chan); 05136 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL); 05137 05138 free(ringing_trunk); 05139 05140 /* Queue up reprocessing ringing trunks, and then ringing stations again */ 05141 sla_queue_event(SLA_EVENT_RINGING_TRUNK); 05142 sla_queue_event(SLA_EVENT_DIAL_STATE); 05143 } 05144 } 05145 05146 trunk_ref->chan = chan; 05147 05148 if (!trunk_ref->trunk->chan) { 05149 ast_mutex_t cond_lock; 05150 ast_cond_t cond; 05151 pthread_t dont_care; 05152 struct dial_trunk_args args = { 05153 .trunk_ref = trunk_ref, 05154 .station = station, 05155 .cond_lock = &cond_lock, 05156 .cond = &cond, 05157 }; 05158 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL); 05159 /* Create a thread to dial the trunk and dump it into the conference. 05160 * However, we want to wait until the trunk has been dialed and the 05161 * conference is created before continuing on here. */ 05162 ast_autoservice_start(chan); 05163 ast_mutex_init(&cond_lock); 05164 ast_cond_init(&cond, NULL); 05165 ast_mutex_lock(&cond_lock); 05166 ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args); 05167 ast_cond_wait(&cond, &cond_lock); 05168 ast_mutex_unlock(&cond_lock); 05169 ast_mutex_destroy(&cond_lock); 05170 ast_cond_destroy(&cond); 05171 ast_autoservice_stop(chan); 05172 if (!trunk_ref->trunk->chan) { 05173 ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan); 05174 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION"); 05175 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 05176 trunk_ref->chan = NULL; 05177 ast_atomic_fetchadd_int((int *) &station->ref_count, -1); 05178 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05179 return 0; 05180 } 05181 } 05182 05183 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 && 05184 trunk_ref->trunk->on_hold) { 05185 trunk_ref->trunk->on_hold = 0; 05186 ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD); 05187 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL); 05188 } 05189 05190 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name); 05191 ast_set_flag(&conf_flags, 05192 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION); 05193 ast_answer(chan); 05194 conf = build_conf(conf_name, "", "", 0, 0, 1, chan); 05195 if (conf) { 05196 conf_run(chan, conf, conf_flags.flags, NULL); 05197 dispose_conf(conf); 05198 conf = NULL; 05199 } 05200 trunk_ref->chan = NULL; 05201 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) && 05202 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) { 05203 strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1); 05204 admin_exec(NULL, conf_name); 05205 trunk_ref->trunk->hold_stations = 0; 05206 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 05207 } 05208 05209 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS"); 05210 05211 ast_atomic_fetchadd_int((int *) &station->ref_count, -1); 05212 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05213 05214 return 0; 05215 }
| static void sla_stop_ringing_station | ( | struct sla_ringing_station * | ringing_station, | |
| enum sla_station_hangup | hangup | |||
| ) | [static] |
Definition at line 4189 of file app_meetme.c.
References ast_dial_destroy(), ast_dial_join(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, sla_station::dial, sla, sla_create_station_ref(), SLA_STATION_HANGUP_NORMAL, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.
Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().
04191 { 04192 struct sla_ringing_trunk *ringing_trunk; 04193 struct sla_trunk_ref *trunk_ref; 04194 struct sla_station_ref *station_ref; 04195 04196 ast_dial_join(ringing_station->station->dial); 04197 ast_dial_destroy(ringing_station->station->dial); 04198 ringing_station->station->dial = NULL; 04199 04200 if (hangup == SLA_STATION_HANGUP_NORMAL) 04201 goto done; 04202 04203 /* If the station is being hung up because of a timeout, then add it to the 04204 * list of timed out stations on each of the ringing trunks. This is so 04205 * that when doing further processing to figure out which stations should be 04206 * ringing, which trunk to answer, determining timeouts, etc., we know which 04207 * ringing trunks we should ignore. */ 04208 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) { 04209 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) { 04210 if (ringing_trunk->trunk == trunk_ref->trunk) 04211 break; 04212 } 04213 if (!trunk_ref) 04214 continue; 04215 if (!(station_ref = sla_create_station_ref(ringing_station->station))) 04216 continue; 04217 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry); 04218 } 04219 04220 done: 04221 ast_free(ringing_station); 04222 }
| static void sla_stop_ringing_trunk | ( | struct sla_ringing_trunk * | ringing_trunk | ) | [static] |
Definition at line 4174 of file app_meetme.c.
References admin_exec(), ALL_TRUNK_REFS, ast_free, AST_LIST_REMOVE_HEAD, buf, sla_trunk::name, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, sla_ringing_trunk::timed_out_stations, and sla_ringing_trunk::trunk.
Referenced by sla_calc_trunk_timeouts().
04175 { 04176 char buf[80]; 04177 struct sla_station_ref *station_ref; 04178 04179 snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name); 04180 admin_exec(NULL, buf); 04181 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 04182 04183 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) 04184 ast_free(station_ref); 04185 04186 ast_free(ringing_trunk); 04187 }
| static void* sla_thread | ( | void * | data | ) | [static] |
Definition at line 4862 of file app_meetme.c.
References ast_cond_timedwait(), ast_cond_wait(), ast_free, AST_LIST_EMPTY, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), sla, sla_check_reload(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_HOLD, SLA_EVENT_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_handle_dial_state_event(), sla_handle_hold_event(), sla_handle_ringing_trunk_event(), sla_process_timers(), and sla_event::type.
Referenced by sla_load_config().
04863 { 04864 struct sla_failed_station *failed_station; 04865 struct sla_ringing_station *ringing_station; 04866 04867 ast_mutex_lock(&sla.lock); 04868 04869 while (!sla.stop) { 04870 struct sla_event *event; 04871 struct timespec ts = { 0, }; 04872 unsigned int have_timeout = 0; 04873 04874 if (AST_LIST_EMPTY(&sla.event_q)) { 04875 if ((have_timeout = sla_process_timers(&ts))) 04876 ast_cond_timedwait(&sla.cond, &sla.lock, &ts); 04877 else 04878 ast_cond_wait(&sla.cond, &sla.lock); 04879 if (sla.stop) 04880 break; 04881 } 04882 04883 if (have_timeout) 04884 sla_process_timers(NULL); 04885 04886 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) { 04887 ast_mutex_unlock(&sla.lock); 04888 switch (event->type) { 04889 case SLA_EVENT_HOLD: 04890 sla_handle_hold_event(event); 04891 break; 04892 case SLA_EVENT_DIAL_STATE: 04893 sla_handle_dial_state_event(); 04894 break; 04895 case SLA_EVENT_RINGING_TRUNK: 04896 sla_handle_ringing_trunk_event(); 04897 break; 04898 case SLA_EVENT_RELOAD: 04899 sla.reload = 1; 04900 case SLA_EVENT_CHECK_RELOAD: 04901 break; 04902 } 04903 ast_free(event); 04904 ast_mutex_lock(&sla.lock); 04905 } 04906 04907 if (sla.reload) 04908 sla_check_reload(); 04909 } 04910 04911 ast_mutex_unlock(&sla.lock); 04912 04913 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) 04914 ast_free(ringing_station); 04915 04916 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) 04917 ast_free(failed_station); 04918 04919 return NULL; 04920 }
| static int sla_trunk_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 5263 of file app_meetme.c.
References ALL_TRUNK_REFS, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, build_conf(), sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), ast_flags::flags, LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, OPT_ARG_ARRAY_SIZE, OPT_ARG_MOH_CLASS, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla_trunk::ref_count, sla, sla_change_trunk_state(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_ARG_MOH_CLASS, SLA_TRUNK_OPT_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.
Referenced by load_module().
05264 { 05265 char conf_name[MAX_CONFNUM]; 05266 struct ast_conference *conf; 05267 struct ast_flags conf_flags = { 0 }; 05268 struct sla_trunk *trunk; 05269 struct sla_ringing_trunk *ringing_trunk; 05270 AST_DECLARE_APP_ARGS(args, 05271 AST_APP_ARG(trunk_name); 05272 AST_APP_ARG(options); 05273 ); 05274 char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, }; 05275 char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, }; 05276 struct ast_flags opt_flags = { 0 }; 05277 char *parse; 05278 05279 if (ast_strlen_zero(data)) { 05280 ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n"); 05281 return -1; 05282 } 05283 05284 parse = ast_strdupa(data); 05285 AST_STANDARD_APP_ARGS(args, parse); 05286 if (args.argc == 2) { 05287 if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) { 05288 ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n"); 05289 return -1; 05290 } 05291 } 05292 05293 AST_RWLIST_RDLOCK(&sla_trunks); 05294 trunk = sla_find_trunk(args.trunk_name); 05295 if (trunk) 05296 ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1); 05297 AST_RWLIST_UNLOCK(&sla_trunks); 05298 05299 if (!trunk) { 05300 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name); 05301 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE"); 05302 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1); 05303 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05304 return 0; 05305 } 05306 05307 if (trunk->chan) { 05308 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n", 05309 args.trunk_name); 05310 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE"); 05311 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1); 05312 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05313 return 0; 05314 } 05315 05316 trunk->chan = chan; 05317 05318 if (!(ringing_trunk = queue_ringing_trunk(trunk))) { 05319 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE"); 05320 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1); 05321 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05322 return 0; 05323 } 05324 05325 snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name); 05326 conf = build_conf(conf_name, "", "", 1, 1, 1, chan); 05327 if (!conf) { 05328 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE"); 05329 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1); 05330 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05331 return 0; 05332 } 05333 ast_set_flag(&conf_flags, 05334 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP); 05335 05336 if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) { 05337 ast_indicate(chan, -1); 05338 ast_set_flag(&conf_flags, CONFFLAG_MOH); 05339 conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS]; 05340 } else 05341 ast_indicate(chan, AST_CONTROL_RINGING); 05342 05343 conf_run(chan, conf, conf_flags.flags, opts); 05344 dispose_conf(conf); 05345 conf = NULL; 05346 trunk->chan = NULL; 05347 trunk->on_hold = 0; 05348 05349 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); 05350 05351 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS")) 05352 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS"); 05353 05354 /* Remove the entry from the list of ringing trunks if it is still there. */ 05355 ast_mutex_lock(&sla.lock); 05356 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) { 05357 if (ringing_trunk->trunk == trunk) { 05358 AST_LIST_REMOVE_CURRENT(entry); 05359 break; 05360 } 05361 } 05362 AST_LIST_TRAVERSE_SAFE_END; 05363 ast_mutex_unlock(&sla.lock); 05364 if (ringing_trunk) { 05365 ast_free(ringing_trunk); 05366 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED"); 05367 /* Queue reprocessing of ringing trunks to make stations stop ringing 05368 * that shouldn't be ringing after this trunk stopped. */ 05369 sla_queue_event(SLA_EVENT_RINGING_TRUNK); 05370 } 05371 05372 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1); 05373 sla_queue_event(SLA_EVENT_CHECK_RELOAD); 05374 05375 return 0; 05376 }
| static const char* trunkstate2str | ( | enum sla_trunk_state | state | ) | [static] |
Definition at line 1250 of file app_meetme.c.
References S, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.
Referenced by sla_show_stations().
01251 { 01252 #define S(e) case e: return # e; 01253 switch (state) { 01254 S(SLA_TRUNK_STATE_IDLE) 01255 S(SLA_TRUNK_STATE_RINGING) 01256 S(SLA_TRUNK_STATE_UP) 01257 S(SLA_TRUNK_STATE_ONHOLD) 01258 S(SLA_TRUNK_STATE_ONHOLD_BYME) 01259 } 01260 return "Uknown State"; 01261 #undef S 01262 }
| static void tweak_listen_volume | ( | struct ast_conf_user * | user, | |
| enum volume_action | action | |||
| ) | [static] |
Definition at line 763 of file app_meetme.c.
References volume::actual, volume::desired, ast_conf_user::listen, set_listen_volume(), and tweak_volume().
Referenced by admin_exec(), and conf_run().
00764 { 00765 tweak_volume(&user->listen, action); 00766 /* attempt to make the adjustment in the channel driver; 00767 if successful, don't adjust in the frame reading routine 00768 */ 00769 if (!set_listen_volume(user, user->listen.desired)) 00770 user->listen.actual = 0; 00771 else 00772 user->listen.actual = user->listen.desired; 00773 }
| static void tweak_talk_volume | ( | struct ast_conf_user * | user, | |
| enum volume_action | action | |||
| ) | [static] |
Definition at line 751 of file app_meetme.c.
References volume::actual, volume::desired, set_talk_volume(), ast_conf_user::talk, and tweak_volume().
Referenced by admin_exec(), and conf_run().
00752 { 00753 tweak_volume(&user->talk, action); 00754 /* attempt to make the adjustment in the channel driver; 00755 if successful, don't adjust in the frame reading routine 00756 */ 00757 if (!set_talk_volume(user, user->talk.desired)) 00758 user->talk.actual = 0; 00759 else 00760 user->talk.actual = user->talk.desired; 00761 }
| static void tweak_volume | ( | struct volume * | vol, | |
| enum volume_action | action | |||
| ) | [static] |
Definition at line 716 of file app_meetme.c.
References volume::desired, VOL_DOWN, and VOL_UP.
Referenced by tweak_listen_volume(), and tweak_talk_volume().
00717 { 00718 switch (action) { 00719 case VOL_UP: 00720 switch (vol->desired) { 00721 case 5: 00722 break; 00723 case 0: 00724 vol->desired = 2; 00725 break; 00726 case -2: 00727 vol->desired = 0; 00728 break; 00729 default: 00730 vol->desired++; 00731 break; 00732 } 00733 break; 00734 case VOL_DOWN: 00735 switch (vol->desired) { 00736 case -5: 00737 break; 00738 case 2: 00739 vol->desired = 0; 00740 break; 00741 case 0: 00742 vol->desired = -2; 00743 break; 00744 default: 00745 vol->desired--; 00746 break; 00747 } 00748 } 00749 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 5886 of file app_meetme.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_prov_del(), ast_manager_unregister(), ast_unload_realtime(), ast_unregister_application(), and sla_destroy().
05887 { 05888 int res = 0; 05889 05890 ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme)); 05891 res = ast_manager_unregister("MeetmeMute"); 05892 res |= ast_manager_unregister("MeetmeUnmute"); 05893 res |= ast_manager_unregister("MeetmeList"); 05894 res |= ast_unregister_application(app4); 05895 res |= ast_unregister_application(app3); 05896 res |= ast_unregister_application(app2); 05897 res |= ast_unregister_application(app); 05898 res |= ast_unregister_application(slastation_app); 05899 res |= ast_unregister_application(slatrunk_app); 05900 05901 ast_devstate_prov_del("Meetme"); 05902 ast_devstate_prov_del("SLA"); 05903 05904 sla_destroy(); 05905 05906 res |= ast_custom_function_unregister(&meetme_info_acf); 05907 ast_unload_realtime("meetme"); 05908 05909 return res; 05910 }
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 5953 of file app_meetme.c.
const char* app = "MeetMe" [static] |
Definition at line 209 of file app_meetme.c.
const char* app2 = "MeetMeCount" [static] |
Definition at line 210 of file app_meetme.c.
const char* app3 = "MeetMeAdmin" [static] |
Definition at line 211 of file app_meetme.c.
const char* app4 = "MeetMeChannelAdmin" [static] |
Definition at line 212 of file app_meetme.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 5953 of file app_meetme.c.
| unsigned int attempt_callerid |
Attempt to handle CallerID, even though it is known not to work properly in some situations.
Definition at line 620 of file app_meetme.c.
int audio_buffers [static] |
The number of audio buffers to be allocated on pseudo channels when in a conference
Definition at line 629 of file app_meetme.c.
struct ast_cli_entry cli_meetme[] [static] |
{
AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
}
Definition at line 1340 of file app_meetme.c.
Definition at line 611 of file app_meetme.c.
unsigned int conf_map[1024] = {0, } [static] |
Definition at line 422 of file app_meetme.c.
Referenced by build_conf(), conf_exec(), and dispose_conf().
const char* descrip [static] |
Definition at line 232 of file app_meetme.c.
const char* descrip2 [static] |
Definition at line 295 of file app_meetme.c.
const char* descrip3 [static] |
Definition at line 303 of file app_meetme.c.
const char* descrip4 [static] |
Definition at line 326 of file app_meetme.c.
int earlyalert [static] |
Definition at line 226 of file app_meetme.c.
int endalert [static] |
Definition at line 227 of file app_meetme.c.
| struct { ... } event_q |
| struct { ... } failed_stations |
Definition at line 613 of file app_meetme.c.
Referenced by ast_format_str_reduce(), ast_print_group(), context_merge(), h261_encap(), h263_encap(), h263p_encap(), h264_encap(), log_jack_status(), misdn_lib_init(), mpeg4_encap(), and schedule().
int fuzzystart [static] |
Definition at line 225 of file app_meetme.c.
char const gain_map[] [static] |
Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers Note: these are not a straight linear-to-dB conversion... the numbers have been modified to give the user a better level of adjustability
Definition at line 637 of file app_meetme.c.
Definition at line 613 of file app_meetme.c.
Referenced by __ao2_callback(), __verboser(), aji_handle_presence(), apply_outgoing(), ast_config_engine_deregister(), ast_db_freetree(), ast_db_gettree(), config_odbc(), config_pgsql(), do_monitor(), gtalk_free_candidates(), jingle_free_candidates(), load_password(), node_lookup(), scan_thread(), schedule(), and try_firmware().
Definition at line 612 of file app_meetme.c.
char mandescr_meetmelist[] [static] |
Definition at line 3750 of file app_meetme.c.
struct ast_custom_function meetme_info_acf [static] |
Definition at line 5857 of file app_meetme.c.
struct ast_app_option meetme_opts[128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, } [static] |
Definition at line 207 of file app_meetme.c.
Referenced by conf_exec().
| static int reload |
A reload has been requested
reload: Part of Asterisk module interface ---
Definition at line 622 of file app_meetme.c.
Referenced by handle_cli_moh_reload(), handle_minivm_reload(), reload(), rpt_do_reload(), and show_console().
| struct { ... } ringing_stations |
| struct { ... } ringing_trunks |
int rt_log_members [static] |
Definition at line 230 of file app_meetme.c.
int rt_schedule [static] |
Definition at line 224 of file app_meetme.c.
struct { ... } sla [static] |
A structure for data used by the sla thread.
Referenced by dial_trunk(), queue_ringing_trunk(), sla_calc_station_timeouts(), sla_calc_trunk_timeouts(), sla_check_failed_station(), sla_check_reload(), sla_check_ringing_station(), sla_choose_ringing_trunk(), sla_destroy(), sla_handle_dial_state_event(), sla_handle_ringing_trunk_event(), sla_hangup_stations(), sla_load_config(), sla_queue_event_full(), sla_ring_station(), sla_ring_stations(), sla_station_exec(), sla_stop_ringing_station(), sla_thread(), and sla_trunk_exec().
const char sla_registrar[] = "SLA" [static] |
Definition at line 552 of file app_meetme.c.
Referenced by destroy_station(), destroy_trunk(), sla_build_station(), sla_build_trunk(), and sla_destroy().
struct ast_app_option sla_trunk_opts[128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, } [static] |
Definition at line 5261 of file app_meetme.c.
Referenced by sla_trunk_exec().
const char* slastation_app = "SLAStation" [static] |
Definition at line 213 of file app_meetme.c.
const char* slastation_desc [static] |
Definition at line 334 of file app_meetme.c.
const char* slastation_synopsis = "Shared Line Appearance Station" [static] |
Definition at line 220 of file app_meetme.c.
const char* slatrunk_app = "SLATrunk" [static] |
Definition at line 214 of file app_meetme.c.
const char* slatrunk_desc [static] |
Definition at line 347 of file app_meetme.c.
const char* slatrunk_synopsis = "Shared Line Appearance Trunk" [static] |
Definition at line 221 of file app_meetme.c.
| unsigned int stop |
Definition at line 617 of file app_meetme.c.
Referenced by controlplayback_exec(), handle_controlstreamfile(), and queue_exec().
const char* synopsis = "MeetMe conference bridge" [static] |
Definition at line 216 of file app_meetme.c.
const char* synopsis2 = "MeetMe participant count" [static] |
Definition at line 217 of file app_meetme.c.
const char* synopsis3 = "MeetMe conference Administration" [static] |
Definition at line 218 of file app_meetme.c.
const char* synopsis4 = "MeetMe conference Administration (channel specific)" [static] |
Definition at line 219 of file app_meetme.c.
| pthread_t thread |
The SLA thread ID
Definition at line 610 of file app_meetme.c.
1.6.1